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/threads.h>
  10#include <linux/cpumask.h>
  11#include <linux/export.h>
  12#include <linux/string.h>
  13#include <linux/kernel.h>
  14#include <linux/ctype.h>
  15#include <linux/init.h>
  16#include <linux/errno.h>
  17#include <asm/fixmap.h>
  18#include <asm/mpspec.h>
  19#include <asm/apicdef.h>
  20#include <asm/apic.h>
  21#include <asm/setup.h>
  22
  23#include <linux/smp.h>
  24#include <asm/ipi.h>
  25
  26#include <linux/interrupt.h>
  27#include <asm/acpi.h>
  28#include <asm/e820/api.h>
  29
  30#ifdef CONFIG_HOTPLUG_CPU
  31#define DEFAULT_SEND_IPI        (1)
  32#else
  33#define DEFAULT_SEND_IPI        (0)
  34#endif
  35
  36int no_broadcast = DEFAULT_SEND_IPI;
  37
  38static __init int no_ipi_broadcast(char *str)
  39{
  40        get_option(&str, &no_broadcast);
  41        pr_info("Using %s mode\n",
  42                no_broadcast ? "No IPI Broadcast" : "IPI Broadcast");
  43        return 1;
  44}
  45__setup("no_ipi_broadcast=", no_ipi_broadcast);
  46
  47static int __init print_ipi_mode(void)
  48{
  49        pr_info("Using IPI %s mode\n",
  50                no_broadcast ? "No-Shortcut" : "Shortcut");
  51        return 0;
  52}
  53late_initcall(print_ipi_mode);
  54
  55static int default_x86_32_early_logical_apicid(int cpu)
  56{
  57        return 1 << cpu;
  58}
  59
  60static void setup_apic_flat_routing(void)
  61{
  62#ifdef CONFIG_X86_IO_APIC
  63        printk(KERN_INFO
  64                "Enabling APIC mode:  Flat.  Using %d I/O APICs\n",
  65                nr_ioapics);
  66#endif
  67}
  68
  69static int default_apic_id_registered(void)
  70{
  71        return physid_isset(read_apic_id(), phys_cpu_present_map);
  72}
  73
  74/*
  75 * Set up the logical destination ID.  Intel recommends to set DFR, LDR and
  76 * TPR before enabling an APIC.  See e.g. "AP-388 82489DX User's Manual"
  77 * (Intel document number 292116).
  78 */
  79static void default_init_apic_ldr(void)
  80{
  81        unsigned long val;
  82
  83        apic_write(APIC_DFR, APIC_DFR_VALUE);
  84        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
  85        val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
  86        apic_write(APIC_LDR, val);
  87}
  88
  89static int default_phys_pkg_id(int cpuid_apic, int index_msb)
  90{
  91        return cpuid_apic >> index_msb;
  92}
  93
  94/* should be called last. */
  95static int probe_default(void)
  96{
  97        return 1;
  98}
  99
 100static struct apic apic_default __ro_after_init = {
 101
 102        .name                           = "default",
 103        .probe                          = probe_default,
 104        .acpi_madt_oem_check            = NULL,
 105        .apic_id_valid                  = default_apic_id_valid,
 106        .apic_id_registered             = default_apic_id_registered,
 107
 108        .irq_delivery_mode              = dest_Fixed,
 109        /* logical delivery broadcast to all CPUs: */
 110        .irq_dest_mode                  = 1,
 111
 112        .disable_esr                    = 0,
 113        .dest_logical                   = APIC_DEST_LOGICAL,
 114        .check_apicid_used              = default_check_apicid_used,
 115
 116        .init_apic_ldr                  = default_init_apic_ldr,
 117
 118        .ioapic_phys_id_map             = default_ioapic_phys_id_map,
 119        .setup_apic_routing             = setup_apic_flat_routing,
 120        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 121        .apicid_to_cpu_present          = physid_set_mask_of_physid,
 122        .check_phys_apicid_present      = default_check_phys_apicid_present,
 123        .phys_pkg_id                    = default_phys_pkg_id,
 124
 125        .get_apic_id                    = default_get_apic_id,
 126        .set_apic_id                    = NULL,
 127
 128        .calc_dest_apicid               = apic_flat_calc_apicid,
 129
 130        .send_IPI                       = default_send_IPI_single,
 131        .send_IPI_mask                  = default_send_IPI_mask_logical,
 132        .send_IPI_mask_allbutself       = default_send_IPI_mask_allbutself_logical,
 133        .send_IPI_allbutself            = default_send_IPI_allbutself,
 134        .send_IPI_all                   = default_send_IPI_all,
 135        .send_IPI_self                  = default_send_IPI_self,
 136
 137        .inquire_remote_apic            = default_inquire_remote_apic,
 138
 139        .read                           = native_apic_mem_read,
 140        .write                          = native_apic_mem_write,
 141        .eoi_write                      = native_apic_mem_write,
 142        .icr_read                       = native_apic_icr_read,
 143        .icr_write                      = native_apic_icr_write,
 144        .wait_icr_idle                  = native_apic_wait_icr_idle,
 145        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 146
 147        .x86_32_early_logical_apicid    = default_x86_32_early_logical_apicid,
 148};
 149
 150apic_driver(apic_default);
 151
 152struct apic *apic __ro_after_init = &apic_default;
 153EXPORT_SYMBOL_GPL(apic);
 154
 155static int cmdline_apic __initdata;
 156static int __init parse_apic(char *arg)
 157{
 158        struct apic **drv;
 159
 160        if (!arg)
 161                return -EINVAL;
 162
 163        for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
 164                if (!strcmp((*drv)->name, arg)) {
 165                        apic = *drv;
 166                        cmdline_apic = 1;
 167                        return 0;
 168                }
 169        }
 170
 171        /* Parsed again by __setup for debug/verbose */
 172        return 0;
 173}
 174early_param("apic", parse_apic);
 175
 176void __init default_setup_apic_routing(void)
 177{
 178        int version = boot_cpu_apic_version;
 179
 180        if (num_possible_cpus() > 8) {
 181                switch (boot_cpu_data.x86_vendor) {
 182                case X86_VENDOR_INTEL:
 183                        if (!APIC_XAPIC(version)) {
 184                                def_to_bigsmp = 0;
 185                                break;
 186                        }
 187                        /* P4 and above */
 188                        /* fall through */
 189                case X86_VENDOR_HYGON:
 190                case X86_VENDOR_AMD:
 191                        def_to_bigsmp = 1;
 192                }
 193        }
 194
 195#ifdef CONFIG_X86_BIGSMP
 196        /*
 197         * This is used to switch to bigsmp mode when
 198         * - There is no apic= option specified by the user
 199         * - generic_apic_probe() has chosen apic_default as the sub_arch
 200         * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
 201         */
 202
 203        if (!cmdline_apic && apic == &apic_default)
 204                generic_bigsmp_probe();
 205#endif
 206
 207        if (apic->setup_apic_routing)
 208                apic->setup_apic_routing();
 209
 210        if (x86_platform.apic_post_init)
 211                x86_platform.apic_post_init();
 212}
 213
 214void __init generic_apic_probe(void)
 215{
 216        if (!cmdline_apic) {
 217                struct apic **drv;
 218
 219                for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
 220                        if ((*drv)->probe()) {
 221                                apic = *drv;
 222                                break;
 223                        }
 224                }
 225                /* Not visible without early console */
 226                if (drv == __apicdrivers_end)
 227                        panic("Didn't find an APIC driver");
 228        }
 229        printk(KERN_INFO "Using APIC driver %s\n", apic->name);
 230}
 231
 232/* This function can switch the APIC even after the initial ->probe() */
 233int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 234{
 235        struct apic **drv;
 236
 237        for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
 238                if (!(*drv)->acpi_madt_oem_check)
 239                        continue;
 240                if (!(*drv)->acpi_madt_oem_check(oem_id, oem_table_id))
 241                        continue;
 242
 243                if (!cmdline_apic) {
 244                        apic = *drv;
 245                        printk(KERN_INFO "Switched to APIC driver `%s'.\n",
 246                               apic->name);
 247                }
 248                return 1;
 249        }
 250        return 0;
 251}
 252