1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/init.h> |
3 | #include <linux/thread_info.h> |
4 | |
5 | #include <asm/x86_init.h> |
6 | #include <asm/apic.h> |
7 | #include <asm/io_apic.h> |
8 | #include <asm/xen/hypercall.h> |
9 | |
10 | #include <xen/xen.h> |
11 | #include <xen/interface/physdev.h> |
12 | #include "xen-ops.h" |
13 | #include "pmu.h" |
14 | #include "smp.h" |
15 | |
16 | static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) |
17 | { |
18 | struct physdev_apic apic_op; |
19 | int ret; |
20 | |
21 | apic_op.apic_physbase = mpc_ioapic_addr(ioapic: apic); |
22 | apic_op.reg = reg; |
23 | ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, arg: &apic_op); |
24 | if (!ret) |
25 | return apic_op.value; |
26 | |
27 | /* fallback to return an emulated IO_APIC values */ |
28 | if (reg == 0x1) |
29 | return 0x00170020; |
30 | else if (reg == 0x0) |
31 | return apic << 24; |
32 | |
33 | return 0xfd; |
34 | } |
35 | |
36 | static u32 xen_set_apic_id(u32 x) |
37 | { |
38 | WARN_ON(1); |
39 | return x; |
40 | } |
41 | |
42 | static u32 xen_get_apic_id(u32 x) |
43 | { |
44 | return ((x)>>24) & 0xFFu; |
45 | } |
46 | |
47 | static u32 xen_apic_read(u32 reg) |
48 | { |
49 | struct xen_platform_op op = { |
50 | .cmd = XENPF_get_cpuinfo, |
51 | .interface_version = XENPF_INTERFACE_VERSION, |
52 | .u.pcpu_info.xen_cpuid = 0, |
53 | }; |
54 | int ret; |
55 | |
56 | /* Shouldn't need this as APIC is turned off for PV, and we only |
57 | * get called on the bootup processor. But just in case. */ |
58 | if (!xen_initial_domain() || smp_processor_id()) |
59 | return 0; |
60 | |
61 | if (reg == APIC_LVR) |
62 | return 0x14; |
63 | if (reg != APIC_ID) |
64 | return 0; |
65 | |
66 | ret = HYPERVISOR_platform_op(op: &op); |
67 | if (ret) |
68 | op.u.pcpu_info.apic_id = BAD_APICID; |
69 | |
70 | return op.u.pcpu_info.apic_id << 24; |
71 | } |
72 | |
73 | static void xen_apic_write(u32 reg, u32 val) |
74 | { |
75 | if (reg == APIC_LVTPC) { |
76 | (void)pmu_apic_update(reg); |
77 | return; |
78 | } |
79 | |
80 | /* Warn to see if there's any stray references */ |
81 | WARN(1,"register: %x, value: %x\n" , reg, val); |
82 | } |
83 | |
84 | static void xen_apic_eoi(void) |
85 | { |
86 | WARN_ON_ONCE(1); |
87 | } |
88 | |
89 | static u64 xen_apic_icr_read(void) |
90 | { |
91 | return 0; |
92 | } |
93 | |
94 | static void xen_apic_icr_write(u32 low, u32 id) |
95 | { |
96 | /* Warn to see if there's any stray references */ |
97 | WARN_ON(1); |
98 | } |
99 | |
100 | static int xen_apic_probe_pv(void) |
101 | { |
102 | if (xen_pv_domain()) |
103 | return 1; |
104 | |
105 | return 0; |
106 | } |
107 | |
108 | static int xen_madt_oem_check(char *oem_id, char *oem_table_id) |
109 | { |
110 | return xen_pv_domain(); |
111 | } |
112 | |
113 | static u32 xen_phys_pkg_id(u32 initial_apic_id, int index_msb) |
114 | { |
115 | return initial_apic_id >> index_msb; |
116 | } |
117 | |
118 | static u32 xen_cpu_present_to_apicid(int cpu) |
119 | { |
120 | if (cpu_present(cpu)) |
121 | return cpu_data(cpu).topo.apicid; |
122 | else |
123 | return BAD_APICID; |
124 | } |
125 | |
126 | static struct apic xen_pv_apic __ro_after_init = { |
127 | .name = "Xen PV" , |
128 | .probe = xen_apic_probe_pv, |
129 | .acpi_madt_oem_check = xen_madt_oem_check, |
130 | |
131 | /* .delivery_mode and .dest_mode_logical not used by XENPV */ |
132 | |
133 | .disable_esr = 0, |
134 | |
135 | .cpu_present_to_apicid = xen_cpu_present_to_apicid, |
136 | .phys_pkg_id = xen_phys_pkg_id, /* detect_ht */ |
137 | |
138 | .max_apic_id = UINT_MAX, |
139 | .get_apic_id = xen_get_apic_id, |
140 | .set_apic_id = xen_set_apic_id, |
141 | |
142 | .calc_dest_apicid = apic_flat_calc_apicid, |
143 | |
144 | #ifdef CONFIG_SMP |
145 | .send_IPI_mask = xen_send_IPI_mask, |
146 | .send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself, |
147 | .send_IPI_allbutself = xen_send_IPI_allbutself, |
148 | .send_IPI_all = xen_send_IPI_all, |
149 | .send_IPI_self = xen_send_IPI_self, |
150 | #endif |
151 | .read = xen_apic_read, |
152 | .write = xen_apic_write, |
153 | .eoi = xen_apic_eoi, |
154 | |
155 | .icr_read = xen_apic_icr_read, |
156 | .icr_write = xen_apic_icr_write, |
157 | }; |
158 | apic_driver(xen_pv_apic); |
159 | |
160 | void __init xen_init_apic(void) |
161 | { |
162 | x86_apic_ops.io_apic_read = xen_io_apic_read; |
163 | } |
164 | |