1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #include <arch/ioapic.h>
6 #include <arch/smp/mpspec.h>
7 #include <commonlib/sort.h>
9 #include <device/device.h>
11 static int acpi_create_madt_lapic(acpi_madt_lapic_t
*lapic
, u8 cpu
, u8 apic
)
13 lapic
->type
= LOCAL_APIC
; /* Local APIC structure */
14 lapic
->length
= sizeof(acpi_madt_lapic_t
);
15 lapic
->flags
= ACPI_MADT_LAPIC_ENABLED
;
16 lapic
->processor_id
= cpu
;
17 lapic
->apic_id
= apic
;
22 static int acpi_create_madt_lx2apic(acpi_madt_lx2apic_t
*lapic
, u32 cpu
, u32 apic
)
24 lapic
->type
= LOCAL_X2APIC
; /* Local APIC structure */
26 lapic
->length
= sizeof(acpi_madt_lx2apic_t
);
27 lapic
->flags
= ACPI_MADT_LAPIC_ENABLED
;
28 lapic
->processor_id
= cpu
;
29 lapic
->x2apic_id
= apic
;
34 unsigned long acpi_create_madt_one_lapic(unsigned long current
, u32 index
, u32 lapic_id
)
36 if (lapic_id
<= ACPI_MADT_MAX_LAPIC_ID
)
37 current
+= acpi_create_madt_lapic((acpi_madt_lapic_t
*)current
, index
,
40 current
+= acpi_create_madt_lx2apic((acpi_madt_lx2apic_t
*)current
, index
,
46 /* Increase if necessary. Currently all x86 CPUs only have 2 SMP threads */
47 #define MAX_THREAD_ID 1
50 * "The advent of multi-threaded processors yielded multiple logical processors
51 * executing on common processor hardware. ACPI defines logical processors in
52 * an identical manner as physical processors. To ensure that non
53 * multi-threading aware OSPM implementations realize optimal performance on
54 * platforms containing multi-threaded processors, two guidelines should be
55 * followed. The first is the same as above, that is, OSPM should initialize
56 * processors in the order that they appear in the MADT. The second is that
57 * platform firmware should list the first logical processor of each of the
58 * individual multi-threaded processors in the MADT before listing any of the
59 * second logical processors. This approach should be used for all successive
60 * logical processors."
62 static unsigned long acpi_create_madt_lapics(unsigned long current
)
65 int index
, apic_ids
[CONFIG_MAX_CPUS
] = {0}, num_cpus
= 0, sort_start
= 0;
66 for (unsigned int thread_id
= 0; thread_id
<= MAX_THREAD_ID
; thread_id
++) {
67 for (cpu
= all_devices
; cpu
; cpu
= cpu
->next
) {
68 if (!is_enabled_cpu(cpu
))
70 if (num_cpus
>= ARRAY_SIZE(apic_ids
))
72 if (cpu
->path
.apic
.thread_id
!= thread_id
)
74 apic_ids
[num_cpus
++] = cpu
->path
.apic
.apic_id
;
76 bubblesort(&apic_ids
[sort_start
], num_cpus
- sort_start
, NUM_ASCENDING
);
77 sort_start
= num_cpus
;
79 for (index
= 0; index
< num_cpus
; index
++)
80 current
= acpi_create_madt_one_lapic(current
, index
, apic_ids
[index
]);
85 static int acpi_create_madt_ioapic(acpi_madt_ioapic_t
*ioapic
, u8 id
, u32 addr
,
88 ioapic
->type
= IO_APIC
; /* I/O APIC structure */
89 ioapic
->length
= sizeof(acpi_madt_ioapic_t
);
90 ioapic
->reserved
= 0x00;
91 ioapic
->gsi_base
= gsi_base
;
92 ioapic
->ioapic_id
= id
;
93 ioapic
->ioapic_addr
= addr
;
95 return ioapic
->length
;
98 /* For a system with multiple I/O APICs it's required that the one potentially
99 routing i8259 via ExtNMI delivery calls this first to get GSI #0. */
100 int acpi_create_madt_ioapic_from_hw(acpi_madt_ioapic_t
*ioapic
, u32 addr
)
104 u8 id
= get_ioapic_id((uintptr_t)addr
);
105 u8 count
= ioapic_get_max_vectors((uintptr_t)addr
);
109 return acpi_create_madt_ioapic(ioapic
, id
, addr
, my_base
);
112 static int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t
*irqoverride
,
113 u8 bus
, u8 source
, u32 gsirq
, u16 flags
)
115 irqoverride
->type
= IRQ_SOURCE_OVERRIDE
; /* Interrupt source override */
116 irqoverride
->length
= sizeof(acpi_madt_irqoverride_t
);
117 irqoverride
->bus
= bus
;
118 irqoverride
->source
= source
;
119 irqoverride
->gsirq
= gsirq
;
120 irqoverride
->flags
= flags
;
122 return irqoverride
->length
;
125 static int acpi_create_madt_sci_override(acpi_madt_irqoverride_t
*irqoverride
)
129 ioapic_get_sci_pin(&gsi
, &irq
, &flags
);
131 /* In systems without 8259, the SCI_INT field in the FADT contains the SCI GSI number
132 instead of the 8259 IRQ number */
133 if (!CONFIG(ACPI_HAVE_PCAT_8259
))
136 return acpi_create_madt_irqoverride(irqoverride
, MP_BUS_ISA
, irq
, gsi
, flags
);
139 static unsigned long acpi_create_madt_ioapic_gsi0_default(unsigned long current
)
141 current
+= acpi_create_madt_ioapic_from_hw((acpi_madt_ioapic_t
*)current
, IO_APIC_ADDR
);
143 current
+= acpi_create_madt_irqoverride((void *)current
, MP_BUS_ISA
, 0, 2,
144 MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
);
146 current
+= acpi_create_madt_sci_override((void *)current
);
151 static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t
*lapic_nmi
, u8 cpu
,
154 lapic_nmi
->type
= LOCAL_APIC_NMI
; /* Local APIC NMI structure */
155 lapic_nmi
->length
= sizeof(acpi_madt_lapic_nmi_t
);
156 lapic_nmi
->flags
= flags
;
157 lapic_nmi
->processor_id
= cpu
;
158 lapic_nmi
->lint
= lint
;
160 return lapic_nmi
->length
;
163 static int acpi_create_madt_lx2apic_nmi(acpi_madt_lx2apic_nmi_t
*lapic_nmi
, u32 cpu
,
166 lapic_nmi
->type
= LOCAL_X2APIC_NMI
; /* Local APIC NMI structure */
167 lapic_nmi
->length
= sizeof(acpi_madt_lx2apic_nmi_t
);
168 lapic_nmi
->flags
= flags
;
169 lapic_nmi
->processor_id
= cpu
;
170 lapic_nmi
->lint
= lint
;
171 lapic_nmi
->reserved
[0] = 0;
172 lapic_nmi
->reserved
[1] = 0;
173 lapic_nmi
->reserved
[2] = 0;
175 return lapic_nmi
->length
;
178 unsigned long acpi_create_madt_lapic_nmis(unsigned long current
)
180 const u16 flags
= MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
;
182 /* 1: LINT1 connect to NMI */
183 /* create all subtables for processors */
184 current
+= acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t
*)current
,
185 ACPI_MADT_LAPIC_NMI_ALL_PROCESSORS
, flags
, 1);
187 if (!CONFIG(XAPIC_ONLY
))
188 current
+= acpi_create_madt_lx2apic_nmi((acpi_madt_lx2apic_nmi_t
*)current
,
189 ACPI_MADT_LX2APIC_NMI_ALL_PROCESSORS
, flags
, 1);
194 static unsigned long acpi_create_madt_lapics_with_nmis(unsigned long current
)
196 current
= acpi_create_madt_lapics(current
);
197 current
= acpi_create_madt_lapic_nmis(current
);
201 int acpi_create_srat_lapic(acpi_srat_lapic_t
*lapic
, u8 node
, u8 apic
)
203 memset((void *)lapic
, 0, sizeof(acpi_srat_lapic_t
));
205 lapic
->type
= 0; /* Processor local APIC/SAPIC affinity structure */
206 lapic
->length
= sizeof(acpi_srat_lapic_t
);
207 lapic
->flags
= (1 << 0); /* Enabled (the use of this structure). */
208 lapic
->proximity_domain_7_0
= node
;
209 /* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */
210 lapic
->apic_id
= apic
;
212 return lapic
->length
;
215 int acpi_create_srat_x2apic(acpi_srat_x2apic_t
*x2apic
, u32 node
, u32 apic
)
217 memset((void *)x2apic
, 0, sizeof(acpi_srat_x2apic_t
));
219 x2apic
->type
= 2; /* Processor x2APIC structure */
220 x2apic
->length
= sizeof(acpi_srat_x2apic_t
);
221 x2apic
->flags
= (1 << 0); /* Enabled (the use of this structure). */
222 x2apic
->proximity_domain
= node
;
223 x2apic
->x2apic_id
= apic
;
225 return x2apic
->length
;
228 unsigned long acpi_arch_fill_madt(acpi_madt_t
*madt
, unsigned long current
)
230 struct device
*dev
= NULL
;
232 madt
->lapic_addr
= cpu_get_lapic_addr();
234 if (CONFIG(ACPI_HAVE_PCAT_8259
))
235 madt
->flags
|= ACPI_MADT_PCAT_COMPAT
;
237 if (CONFIG(ACPI_COMMON_MADT_LAPIC
))
238 current
= acpi_create_madt_lapics_with_nmis(current
);
240 if (CONFIG(ACPI_COMMON_MADT_IOAPIC
))
241 current
= acpi_create_madt_ioapic_gsi0_default(current
);
243 while ((dev
= dev_find_path(dev
, DEVICE_PATH_IOAPIC
)) != NULL
) {
245 CONFIG(ACPI_COMMON_MADT_IOAPIC) adds the IOAPIC with gsi_base = 0 above.
246 Make sure to not add it twice when it's also part of the devicetree.
247 Currently no SoC adds ioapic_gsi0 to the devicetree.
248 TODO: Add the ioapic_gsi0 to the device-tree on all SoCs and remove this check.
250 assert(!CONFIG(ACPI_COMMON_MADT_IOAPIC
) || dev
->path
.ioapic
.gsi_base
!= 0);
251 assert(dev
->path
.ioapic
.addr
);
253 current
+= acpi_create_madt_ioapic((void *)(uintptr_t)current
,
254 dev
->path
.ioapic
.ioapic_id
,
255 dev
->path
.ioapic
.addr
,
256 dev
->path
.ioapic
.gsi_base
);