blob: fe0459b559025ae0a628b1f3247af392853ab5ef [file] [log] [blame]
Arthur Heymans92a3b672023-06-22 21:30:58 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <acpi/acpi.h>
4#include <arch/ioapic.h>
5#include <arch/smp/mpspec.h>
6#include <commonlib/sort.h>
7#include <cpu/cpu.h>
Felix Held4a9ed702023-12-05 22:09:14 +01008#include <device/device.h>
Arthur Heymans92a3b672023-06-22 21:30:58 +02009
10static int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
11{
12 lapic->type = LOCAL_APIC; /* Local APIC structure */
13 lapic->length = sizeof(acpi_madt_lapic_t);
Felix Held42445272024-05-24 14:16:20 +020014 lapic->flags = ACPI_MADT_LAPIC_ENABLED;
Arthur Heymans92a3b672023-06-22 21:30:58 +020015 lapic->processor_id = cpu;
16 lapic->apic_id = apic;
17
18 return lapic->length;
19}
20
21static int acpi_create_madt_lx2apic(acpi_madt_lx2apic_t *lapic, u32 cpu, u32 apic)
22{
23 lapic->type = LOCAL_X2APIC; /* Local APIC structure */
24 lapic->reserved = 0;
25 lapic->length = sizeof(acpi_madt_lx2apic_t);
Felix Held42445272024-05-24 14:16:20 +020026 lapic->flags = ACPI_MADT_LAPIC_ENABLED;
Arthur Heymans92a3b672023-06-22 21:30:58 +020027 lapic->processor_id = cpu;
28 lapic->x2apic_id = apic;
29
30 return lapic->length;
31}
32
33unsigned long acpi_create_madt_one_lapic(unsigned long current, u32 index, u32 lapic_id)
34{
35 if (lapic_id <= ACPI_MADT_MAX_LAPIC_ID)
36 current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, index,
37 lapic_id);
38 else
39 current += acpi_create_madt_lx2apic((acpi_madt_lx2apic_t *)current, index,
40 lapic_id);
41
42 return current;
43}
44
45/* Increase if necessary. Currently all x86 CPUs only have 2 SMP threads */
46#define MAX_THREAD_ID 1
47/*
48 * From ACPI 6.4 spec:
49 * "The advent of multi-threaded processors yielded multiple logical processors
50 * executing on common processor hardware. ACPI defines logical processors in
51 * an identical manner as physical processors. To ensure that non
52 * multi-threading aware OSPM implementations realize optimal performance on
53 * platforms containing multi-threaded processors, two guidelines should be
54 * followed. The first is the same as above, that is, OSPM should initialize
55 * processors in the order that they appear in the MADT. The second is that
56 * platform firmware should list the first logical processor of each of the
57 * individual multi-threaded processors in the MADT before listing any of the
58 * second logical processors. This approach should be used for all successive
59 * logical processors."
60 */
61static unsigned long acpi_create_madt_lapics(unsigned long current)
62{
63 struct device *cpu;
64 int index, apic_ids[CONFIG_MAX_CPUS] = {0}, num_cpus = 0, sort_start = 0;
65 for (unsigned int thread_id = 0; thread_id <= MAX_THREAD_ID; thread_id++) {
66 for (cpu = all_devices; cpu; cpu = cpu->next) {
67 if (!is_enabled_cpu(cpu))
68 continue;
69 if (num_cpus >= ARRAY_SIZE(apic_ids))
70 break;
71 if (cpu->path.apic.thread_id != thread_id)
72 continue;
73 apic_ids[num_cpus++] = cpu->path.apic.apic_id;
74 }
75 bubblesort(&apic_ids[sort_start], num_cpus - sort_start, NUM_ASCENDING);
76 sort_start = num_cpus;
77 }
78 for (index = 0; index < num_cpus; index++)
79 current = acpi_create_madt_one_lapic(current, index, apic_ids[index]);
80
81 return current;
82}
83
84static int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
85 u32 gsi_base)
86{
87 ioapic->type = IO_APIC; /* I/O APIC structure */
88 ioapic->length = sizeof(acpi_madt_ioapic_t);
89 ioapic->reserved = 0x00;
90 ioapic->gsi_base = gsi_base;
91 ioapic->ioapic_id = id;
92 ioapic->ioapic_addr = addr;
93
94 return ioapic->length;
95}
96
97/* For a system with multiple I/O APICs it's required that the one potentially
98 routing i8259 via ExtNMI delivery calls this first to get GSI #0. */
99int acpi_create_madt_ioapic_from_hw(acpi_madt_ioapic_t *ioapic, u32 addr)
100{
101 static u32 gsi_base;
102 u32 my_base;
Felix Held0d192892024-02-06 16:55:29 +0100103 u8 id = get_ioapic_id((uintptr_t)addr);
104 u8 count = ioapic_get_max_vectors((uintptr_t)addr);
Arthur Heymans92a3b672023-06-22 21:30:58 +0200105
106 my_base = gsi_base;
107 gsi_base += count;
108 return acpi_create_madt_ioapic(ioapic, id, addr, my_base);
109}
110
111static int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
112 u8 bus, u8 source, u32 gsirq, u16 flags)
113{
114 irqoverride->type = IRQ_SOURCE_OVERRIDE; /* Interrupt source override */
115 irqoverride->length = sizeof(acpi_madt_irqoverride_t);
116 irqoverride->bus = bus;
117 irqoverride->source = source;
118 irqoverride->gsirq = gsirq;
119 irqoverride->flags = flags;
120
121 return irqoverride->length;
122}
123
124static int acpi_create_madt_sci_override(acpi_madt_irqoverride_t *irqoverride)
125{
126 u8 gsi, irq, flags;
127
128 ioapic_get_sci_pin(&gsi, &irq, &flags);
129
Felix Helddfad3182024-05-24 17:44:57 +0200130 /* In systems without 8259, the SCI_INT field in the FADT contains the SCI GSI number
131 instead of the 8259 IRQ number */
Arthur Heymans92a3b672023-06-22 21:30:58 +0200132 if (!CONFIG(ACPI_HAVE_PCAT_8259))
133 irq = gsi;
134
Felix Heldca88b5f2024-05-24 17:59:23 +0200135 return acpi_create_madt_irqoverride(irqoverride, MP_BUS_ISA, irq, gsi, flags);
Arthur Heymans92a3b672023-06-22 21:30:58 +0200136}
137
Arthur Heymanscd46e5f2023-06-22 21:34:16 +0200138static unsigned long acpi_create_madt_ioapic_gsi0_default(unsigned long current)
Arthur Heymans92a3b672023-06-22 21:30:58 +0200139{
140 current += acpi_create_madt_ioapic_from_hw((acpi_madt_ioapic_t *)current, IO_APIC_ADDR);
141
142 current += acpi_create_madt_irqoverride((void *)current, MP_BUS_ISA, 0, 2,
143 MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH);
144
145 current += acpi_create_madt_sci_override((void *)current);
146
147 return current;
148}
149
150static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
151 u16 flags, u8 lint)
152{
153 lapic_nmi->type = LOCAL_APIC_NMI; /* Local APIC NMI structure */
154 lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t);
155 lapic_nmi->flags = flags;
156 lapic_nmi->processor_id = cpu;
157 lapic_nmi->lint = lint;
158
159 return lapic_nmi->length;
160}
161
162static int acpi_create_madt_lx2apic_nmi(acpi_madt_lx2apic_nmi_t *lapic_nmi, u32 cpu,
163 u16 flags, u8 lint)
164{
165 lapic_nmi->type = LOCAL_X2APIC_NMI; /* Local APIC NMI structure */
166 lapic_nmi->length = sizeof(acpi_madt_lx2apic_nmi_t);
167 lapic_nmi->flags = flags;
168 lapic_nmi->processor_id = cpu;
169 lapic_nmi->lint = lint;
170 lapic_nmi->reserved[0] = 0;
171 lapic_nmi->reserved[1] = 0;
172 lapic_nmi->reserved[2] = 0;
173
174 return lapic_nmi->length;
175}
176
177unsigned long acpi_create_madt_lapic_nmis(unsigned long current)
178{
179 const u16 flags = MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH;
180
181 /* 1: LINT1 connect to NMI */
182 /* create all subtables for processors */
183 current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current,
184 ACPI_MADT_LAPIC_NMI_ALL_PROCESSORS, flags, 1);
185
186 if (!CONFIG(XAPIC_ONLY))
187 current += acpi_create_madt_lx2apic_nmi((acpi_madt_lx2apic_nmi_t *)current,
188 ACPI_MADT_LX2APIC_NMI_ALL_PROCESSORS, flags, 1);
189
190 return current;
191}
192
Arthur Heymanscd46e5f2023-06-22 21:34:16 +0200193static unsigned long acpi_create_madt_lapics_with_nmis(unsigned long current)
Arthur Heymans92a3b672023-06-22 21:30:58 +0200194{
195 current = acpi_create_madt_lapics(current);
196 current = acpi_create_madt_lapic_nmis(current);
197 return current;
198}
199
200int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic)
201{
202 memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t));
203
204 lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */
205 lapic->length = sizeof(acpi_srat_lapic_t);
206 lapic->flags = (1 << 0); /* Enabled (the use of this structure). */
207 lapic->proximity_domain_7_0 = node;
208 /* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */
209 lapic->apic_id = apic;
210
211 return lapic->length;
212}
213
214int acpi_create_srat_x2apic(acpi_srat_x2apic_t *x2apic, u32 node, u32 apic)
215{
216 memset((void *)x2apic, 0, sizeof(acpi_srat_x2apic_t));
217
218 x2apic->type = 2; /* Processor x2APIC structure */
219 x2apic->length = sizeof(acpi_srat_x2apic_t);
220 x2apic->flags = (1 << 0); /* Enabled (the use of this structure). */
221 x2apic->proximity_domain = node;
222 x2apic->x2apic_id = apic;
223
224 return x2apic->length;
225}
Arthur Heymanscd46e5f2023-06-22 21:34:16 +0200226
227unsigned long acpi_arch_fill_madt(acpi_madt_t *madt, unsigned long current)
228{
229 madt->lapic_addr = cpu_get_lapic_addr();
230
231 if (CONFIG(ACPI_HAVE_PCAT_8259))
Felix Held824d9302024-05-24 13:58:34 +0200232 madt->flags |= ACPI_MADT_PCAT_COMPAT;
Arthur Heymanscd46e5f2023-06-22 21:34:16 +0200233
234 if (CONFIG(ACPI_COMMON_MADT_LAPIC))
235 current = acpi_create_madt_lapics_with_nmis(current);
236
237 if (CONFIG(ACPI_COMMON_MADT_IOAPIC))
238 current = acpi_create_madt_ioapic_gsi0_default(current);
239
240 return current;
241}