1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <arch/ioapic.h>
5 #include <arch/smp/mpspec.h>
6 #include <commonlib/sort.h>
8 #include <device/device.h>
10 static int acpi_create_madt_lapic(acpi_madt_lapic_t
*lapic
, u8 cpu
, u8 apic
)
12 lapic
->type
= LOCAL_APIC
; /* Local APIC structure */
13 lapic
->length
= sizeof(acpi_madt_lapic_t
);
14 lapic
->flags
= ACPI_MADT_LAPIC_ENABLED
;
15 lapic
->processor_id
= cpu
;
16 lapic
->apic_id
= apic
;
21 static int acpi_create_madt_lx2apic(acpi_madt_lx2apic_t
*lapic
, u32 cpu
, u32 apic
)
23 lapic
->type
= LOCAL_X2APIC
; /* Local APIC structure */
25 lapic
->length
= sizeof(acpi_madt_lx2apic_t
);
26 lapic
->flags
= ACPI_MADT_LAPIC_ENABLED
;
27 lapic
->processor_id
= cpu
;
28 lapic
->x2apic_id
= apic
;
33 unsigned long acpi_create_madt_one_lapic(unsigned long current
, u32 index
, u32 lapic_id
)
35 if (lapic_id
<= ACPI_MADT_MAX_LAPIC_ID
)
36 current
+= acpi_create_madt_lapic((acpi_madt_lapic_t
*)current
, index
,
39 current
+= acpi_create_madt_lx2apic((acpi_madt_lx2apic_t
*)current
, index
,
45 /* Increase if necessary. Currently all x86 CPUs only have 2 SMP threads */
46 #define MAX_THREAD_ID 1
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."
61 static unsigned long acpi_create_madt_lapics(unsigned long current
)
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
))
69 if (num_cpus
>= ARRAY_SIZE(apic_ids
))
71 if (cpu
->path
.apic
.thread_id
!= thread_id
)
73 apic_ids
[num_cpus
++] = cpu
->path
.apic
.apic_id
;
75 bubblesort(&apic_ids
[sort_start
], num_cpus
- sort_start
, NUM_ASCENDING
);
76 sort_start
= num_cpus
;
78 for (index
= 0; index
< num_cpus
; index
++)
79 current
= acpi_create_madt_one_lapic(current
, index
, apic_ids
[index
]);
84 static int acpi_create_madt_ioapic(acpi_madt_ioapic_t
*ioapic
, u8 id
, u32 addr
,
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
;
94 return ioapic
->length
;
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. */
99 int acpi_create_madt_ioapic_from_hw(acpi_madt_ioapic_t
*ioapic
, u32 addr
)
103 u8 id
= get_ioapic_id((uintptr_t)addr
);
104 u8 count
= ioapic_get_max_vectors((uintptr_t)addr
);
108 return acpi_create_madt_ioapic(ioapic
, id
, addr
, my_base
);
111 static int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t
*irqoverride
,
112 u8 bus
, u8 source
, u32 gsirq
, u16 flags
)
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
;
121 return irqoverride
->length
;
124 static int acpi_create_madt_sci_override(acpi_madt_irqoverride_t
*irqoverride
)
128 ioapic_get_sci_pin(&gsi
, &irq
, &flags
);
130 /* In systems without 8259, the SCI_INT field in the FADT contains the SCI GSI number
131 instead of the 8259 IRQ number */
132 if (!CONFIG(ACPI_HAVE_PCAT_8259
))
135 return acpi_create_madt_irqoverride(irqoverride
, MP_BUS_ISA
, irq
, gsi
, flags
);
138 static unsigned long acpi_create_madt_ioapic_gsi0_default(unsigned long current
)
140 current
+= acpi_create_madt_ioapic_from_hw((acpi_madt_ioapic_t
*)current
, IO_APIC_ADDR
);
142 current
+= acpi_create_madt_irqoverride((void *)current
, MP_BUS_ISA
, 0, 2,
143 MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
);
145 current
+= acpi_create_madt_sci_override((void *)current
);
150 static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t
*lapic_nmi
, u8 cpu
,
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
;
159 return lapic_nmi
->length
;
162 static int acpi_create_madt_lx2apic_nmi(acpi_madt_lx2apic_nmi_t
*lapic_nmi
, u32 cpu
,
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;
174 return lapic_nmi
->length
;
177 unsigned long acpi_create_madt_lapic_nmis(unsigned long current
)
179 const u16 flags
= MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
;
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);
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);
193 static unsigned long acpi_create_madt_lapics_with_nmis(unsigned long current
)
195 current
= acpi_create_madt_lapics(current
);
196 current
= acpi_create_madt_lapic_nmis(current
);
200 int acpi_create_srat_lapic(acpi_srat_lapic_t
*lapic
, u8 node
, u8 apic
)
202 memset((void *)lapic
, 0, sizeof(acpi_srat_lapic_t
));
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
;
211 return lapic
->length
;
214 int acpi_create_srat_x2apic(acpi_srat_x2apic_t
*x2apic
, u32 node
, u32 apic
)
216 memset((void *)x2apic
, 0, sizeof(acpi_srat_x2apic_t
));
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
;
224 return x2apic
->length
;
227 unsigned long acpi_arch_fill_madt(acpi_madt_t
*madt
, unsigned long current
)
229 madt
->lapic_addr
= cpu_get_lapic_addr();
231 if (CONFIG(ACPI_HAVE_PCAT_8259
))
232 madt
->flags
|= ACPI_MADT_PCAT_COMPAT
;
234 if (CONFIG(ACPI_COMMON_MADT_LAPIC
))
235 current
= acpi_create_madt_lapics_with_nmis(current
);
237 if (CONFIG(ACPI_COMMON_MADT_IOAPIC
))
238 current
= acpi_create_madt_ioapic_gsi0_default(current
);