mb/google/nissa/var/pujjo: Add new supported memory part
[coreboot2.git] / src / acpi / acpi_apic.c
blob1862195e7f4f0d1650d0522312ddccf938d1f9ea
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <assert.h>
4 #include <acpi/acpi.h>
5 #include <arch/ioapic.h>
6 #include <arch/smp/mpspec.h>
7 #include <commonlib/sort.h>
8 #include <cpu/cpu.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;
19 return lapic->length;
22 static int acpi_create_madt_lx2apic(acpi_madt_lx2apic_t *lapic, u32 cpu, u32 apic)
24 lapic->type = LOCAL_X2APIC; /* Local APIC structure */
25 lapic->reserved = 0;
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;
31 return lapic->length;
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,
38 lapic_id);
39 else
40 current += acpi_create_madt_lx2apic((acpi_madt_lx2apic_t *)current, index,
41 lapic_id);
43 return current;
46 /* Increase if necessary. Currently all x86 CPUs only have 2 SMP threads */
47 #define MAX_THREAD_ID 1
49 * From ACPI 6.4 spec:
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)
64 struct device *cpu;
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))
69 continue;
70 if (num_cpus >= ARRAY_SIZE(apic_ids))
71 break;
72 if (cpu->path.apic.thread_id != thread_id)
73 continue;
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]);
82 return current;
85 static int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
86 u32 gsi_base)
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)
102 static u32 gsi_base;
103 u32 my_base;
104 u8 id = get_ioapic_id((uintptr_t)addr);
105 u8 count = ioapic_get_max_vectors((uintptr_t)addr);
107 my_base = gsi_base;
108 gsi_base += count;
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)
127 u8 gsi, irq, flags;
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))
134 irq = gsi;
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);
148 return current;
151 static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
152 u16 flags, u8 lint)
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,
164 u16 flags, u8 lint)
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);
191 return current;
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);
198 return 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);
259 return current;