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(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_selected: 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(driver: *drv); |
133 | break; |
134 | } |
135 | } |
136 | /* Not visible without early console */ |
137 | if (drv == __apicdrivers_end) |
138 | panic(fmt: "Didn't find an APIC driver" ); |
139 | } |
140 | } |
141 | |