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 <xen/xen.h> 14 15 #include <asm/io_apic.h> 16 #include <asm/apic.h> 17 #include <asm/acpi.h> 18 19 #include "local.h" 20 21 static u32 default_get_apic_id(u32 x) 22 { 23 unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR)); 24 25 if (APIC_XAPIC(ver) || boot_cpu_has(X86_FEATURE_EXTD_APICID)) 26 return (x >> 24) & 0xFF; 27 else 28 return (x >> 24) & 0x0F; 29 } 30 31 /* should be called last. */ 32 static int probe_default(void) 33 { 34 return 1; 35 } 36 37 static struct apic apic_default __ro_after_init = { 38 39 .name = "default", 40 .probe = probe_default, 41 42 .dest_mode_logical = true, 43 44 .disable_esr = 0, 45 46 .init_apic_ldr = default_init_apic_ldr, 47 .cpu_present_to_apicid = default_cpu_present_to_apicid, 48 49 .max_apic_id = 0xFE, 50 .get_apic_id = default_get_apic_id, 51 52 .calc_dest_apicid = apic_flat_calc_apicid, 53 54 .send_IPI = default_send_IPI_single, 55 .send_IPI_mask = default_send_IPI_mask_logical, 56 .send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical, 57 .send_IPI_allbutself = default_send_IPI_allbutself, 58 .send_IPI_all = default_send_IPI_all, 59 .send_IPI_self = default_send_IPI_self, 60 61 .read = native_apic_mem_read, 62 .write = native_apic_mem_write, 63 .eoi = native_apic_mem_eoi, 64 .icr_read = native_apic_icr_read, 65 .icr_write = native_apic_icr_write, 66 .wait_icr_idle = apic_mem_wait_icr_idle, 67 .safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout, 68 }; 69 70 apic_driver(apic_default); 71 72 struct apic *apic __ro_after_init = &apic_default; 73 EXPORT_SYMBOL_GPL(apic); 74 75 static int cmdline_apic __initdata; 76 static int __init parse_apic(char *arg) 77 { 78 struct apic **drv; 79 80 if (!arg) 81 return -EINVAL; 82 83 for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { 84 if (!strcmp((*drv)->name, arg)) { 85 apic_install_driver(*drv); 86 cmdline_apic = 1; 87 return 0; 88 } 89 } 90 91 /* Parsed again by __setup for debug/verbose */ 92 return 0; 93 } 94 early_param("apic", parse_apic); 95 96 void __init x86_32_probe_bigsmp_early(void) 97 { 98 if (nr_cpu_ids <= 8 || xen_pv_domain()) 99 return; 100 101 if (IS_ENABLED(CONFIG_X86_BIGSMP)) { 102 switch (boot_cpu_data.x86_vendor) { 103 case X86_VENDOR_INTEL: 104 if (!APIC_XAPIC(boot_cpu_apic_version)) 105 break; 106 /* P4 and above */ 107 fallthrough; 108 case X86_VENDOR_HYGON: 109 case X86_VENDOR_AMD: 110 if (apic_bigsmp_possible(cmdline_apic)) 111 return; 112 break; 113 } 114 } 115 pr_info("Limiting to 8 possible CPUs\n"); 116 set_nr_cpu_ids(8); 117 } 118 119 void __init x86_32_install_bigsmp(void) 120 { 121 if (nr_cpu_ids > 8 && !xen_pv_domain()) 122 apic_bigsmp_force(); 123 } 124 125 void __init x86_32_probe_apic(void) 126 { 127 if (!cmdline_apic) { 128 struct apic **drv; 129 130 for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { 131 if ((*drv)->probe()) { 132 apic_install_driver(*drv); 133 break; 134 } 135 } 136 /* Not visible without early console */ 137 if (drv == __apicdrivers_end) 138 panic("Didn't find an APIC driver"); 139 } 140 } 141
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.