Commit | Line | Data |
---|---|---|
7e300dab | 1 | // SPDX-License-Identifier: GPL-2.0-only |
9b0c5028 | 2 | /* |
7b387253 IM |
3 | * Default generic APIC driver. This handles up to 8 CPUs. |
4 | * | |
9b0c5028 | 5 | * Copyright 2003 Andi Kleen, SuSE Labs. |
9b0c5028 | 6 | * |
1da177e4 | 7 | * Generic x86 APIC driver probe layer. |
9b0c5028 | 8 | */ |
186f4360 | 9 | #include <linux/export.h> |
1a3f239d | 10 | #include <linux/errno.h> |
7b387253 | 11 | #include <linux/smp.h> |
7b387253 | 12 | |
79c9a17c TG |
13 | #include <xen/xen.h> |
14 | ||
13c01139 | 15 | #include <asm/io_apic.h> |
521b82fe | 16 | #include <asm/apic.h> |
6bda2c8b | 17 | #include <asm/acpi.h> |
6bda2c8b | 18 | |
c94f0718 | 19 | #include "local.h" |
6bda2c8b | 20 | |
59f7928c TG |
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 | ||
7b387253 IM |
31 | /* should be called last. */ |
32 | static int probe_default(void) | |
33 | { | |
34 | return 1; | |
35 | } | |
36 | ||
404f6aac | 37 | static struct apic apic_default __ro_after_init = { |
7b387253 IM |
38 | |
39 | .name = "default", | |
40 | .probe = probe_default, | |
7b387253 | 41 | |
8c44963b | 42 | .dest_mode_logical = true, |
7b387253 | 43 | |
7b387253 | 44 | .disable_esr = 0, |
7b387253 | 45 | |
7b387253 | 46 | .init_apic_ldr = default_init_apic_ldr, |
7b387253 | 47 | .cpu_present_to_apicid = default_cpu_present_to_apicid, |
7b387253 | 48 | |
d92e5e7c | 49 | .max_apic_id = 0xFE, |
7b387253 | 50 | .get_apic_id = default_get_apic_id, |
7b387253 | 51 | |
9f9e3bb1 | 52 | .calc_dest_apicid = apic_flat_calc_apicid, |
7b387253 | 53 | |
6153058a | 54 | .send_IPI = default_send_IPI_single, |
43f39890 YL |
55 | .send_IPI_mask = default_send_IPI_mask_logical, |
56 | .send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical, | |
7b387253 IM |
57 | .send_IPI_allbutself = default_send_IPI_allbutself, |
58 | .send_IPI_all = default_send_IPI_all, | |
6b64ee02 | 59 | .send_IPI_self = default_send_IPI_self, |
7b387253 | 60 | |
c1eeb2de YL |
61 | .read = native_apic_mem_read, |
62 | .write = native_apic_mem_write, | |
185c8f33 | 63 | .eoi = native_apic_mem_eoi, |
c1eeb2de YL |
64 | .icr_read = native_apic_icr_read, |
65 | .icr_write = native_apic_icr_write, | |
cfebd007 | 66 | .wait_icr_idle = apic_mem_wait_icr_idle, |
e7b6a023 | 67 | .safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout, |
7b387253 IM |
68 | }; |
69 | ||
107e0e0c SS |
70 | apic_driver(apic_default); |
71 | ||
404f6aac | 72 | struct apic *apic __ro_after_init = &apic_default; |
7d01d32d | 73 | EXPORT_SYMBOL_GPL(apic); |
1da177e4 | 74 | |
1a3f239d RR |
75 | static int cmdline_apic __initdata; |
76 | static int __init parse_apic(char *arg) | |
77 | { | |
8b37e880 | 78 | struct apic **drv; |
1a3f239d RR |
79 | |
80 | if (!arg) | |
81 | return -EINVAL; | |
82 | ||
8b37e880 SS |
83 | for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { |
84 | if (!strcmp((*drv)->name, arg)) { | |
3af1e415 | 85 | apic_install_driver(*drv); |
1a3f239d RR |
86 | cmdline_apic = 1; |
87 | return 0; | |
88 | } | |
89 | } | |
9a8cb626 AK |
90 | |
91 | /* Parsed again by __setup for debug/verbose */ | |
92 | return 0; | |
1a3f239d RR |
93 | } |
94 | early_param("apic", parse_apic); | |
911a62d4 | 95 | |
79c9a17c | 96 | void __init x86_32_probe_bigsmp_early(void) |
911a62d4 | 97 | { |
79c9a17c TG |
98 | if (nr_cpu_ids <= 8 || xen_pv_domain()) |
99 | return; | |
69c252ff | 100 | |
79c9a17c | 101 | if (IS_ENABLED(CONFIG_X86_BIGSMP)) { |
69c252ff SS |
102 | switch (boot_cpu_data.x86_vendor) { |
103 | case X86_VENDOR_INTEL: | |
79c9a17c | 104 | if (!APIC_XAPIC(boot_cpu_apic_version)) |
69c252ff | 105 | break; |
5785675d | 106 | /* P4 and above */ |
df561f66 | 107 | fallthrough; |
da33dfef | 108 | case X86_VENDOR_HYGON: |
69c252ff | 109 | case X86_VENDOR_AMD: |
79c9a17c TG |
110 | if (apic_bigsmp_possible(cmdline_apic)) |
111 | return; | |
112 | break; | |
69c252ff SS |
113 | } |
114 | } | |
79c9a17c TG |
115 | pr_info("Limiting to 8 possible CPUs\n"); |
116 | set_nr_cpu_ids(8); | |
117 | } | |
69c252ff | 118 | |
9d87f5b6 | 119 | void __init x86_32_install_bigsmp(void) |
79c9a17c TG |
120 | { |
121 | if (nr_cpu_ids > 8 && !xen_pv_domain()) | |
122 | apic_bigsmp_force(); | |
911a62d4 VP |
123 | } |
124 | ||
9d87f5b6 | 125 | void __init x86_32_probe_apic(void) |
9b0c5028 | 126 | { |
1a3f239d | 127 | if (!cmdline_apic) { |
8b37e880 SS |
128 | struct apic **drv; |
129 | ||
130 | for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { | |
131 | if ((*drv)->probe()) { | |
3af1e415 | 132 | apic_install_driver(*drv); |
1a3f239d | 133 | break; |
1da177e4 LT |
134 | } |
135 | } | |
1a3f239d | 136 | /* Not visible without early console */ |
8b37e880 | 137 | if (drv == __apicdrivers_end) |
1a3f239d | 138 | panic("Didn't find an APIC driver"); |
1da177e4 | 139 | } |
9b0c5028 | 140 | } |