The device/device.h provides the definition for struct device used in those files, so include this header file to make sure that it's not only included indirectly via some other header file. Signed-off-by: Felix Held <felix-coreboot@felixheld.de> Change-Id: I6ff7cdbf0f53ada92adb53cf268e5feee9df4629 Reviewed-on: https://review.coreboot.org/c/coreboot/+/79401 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Tim Wawrzynczak <inforichland@gmail.com>
246 lines
7.5 KiB
C
246 lines
7.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <acpi/acpi.h>
|
|
#include <arch/ioapic.h>
|
|
#include <arch/smp/mpspec.h>
|
|
#include <commonlib/sort.h>
|
|
#include <cpu/cpu.h>
|
|
#include <device/device.h>
|
|
|
|
static int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
|
|
{
|
|
lapic->type = LOCAL_APIC; /* Local APIC structure */
|
|
lapic->length = sizeof(acpi_madt_lapic_t);
|
|
lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
|
|
lapic->processor_id = cpu;
|
|
lapic->apic_id = apic;
|
|
|
|
return lapic->length;
|
|
}
|
|
|
|
static int acpi_create_madt_lx2apic(acpi_madt_lx2apic_t *lapic, u32 cpu, u32 apic)
|
|
{
|
|
lapic->type = LOCAL_X2APIC; /* Local APIC structure */
|
|
lapic->reserved = 0;
|
|
lapic->length = sizeof(acpi_madt_lx2apic_t);
|
|
lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
|
|
lapic->processor_id = cpu;
|
|
lapic->x2apic_id = apic;
|
|
|
|
return lapic->length;
|
|
}
|
|
|
|
unsigned long acpi_create_madt_one_lapic(unsigned long current, u32 index, u32 lapic_id)
|
|
{
|
|
if (lapic_id <= ACPI_MADT_MAX_LAPIC_ID)
|
|
current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, index,
|
|
lapic_id);
|
|
else
|
|
current += acpi_create_madt_lx2apic((acpi_madt_lx2apic_t *)current, index,
|
|
lapic_id);
|
|
|
|
return current;
|
|
}
|
|
|
|
/* Increase if necessary. Currently all x86 CPUs only have 2 SMP threads */
|
|
#define MAX_THREAD_ID 1
|
|
/*
|
|
* From ACPI 6.4 spec:
|
|
* "The advent of multi-threaded processors yielded multiple logical processors
|
|
* executing on common processor hardware. ACPI defines logical processors in
|
|
* an identical manner as physical processors. To ensure that non
|
|
* multi-threading aware OSPM implementations realize optimal performance on
|
|
* platforms containing multi-threaded processors, two guidelines should be
|
|
* followed. The first is the same as above, that is, OSPM should initialize
|
|
* processors in the order that they appear in the MADT. The second is that
|
|
* platform firmware should list the first logical processor of each of the
|
|
* individual multi-threaded processors in the MADT before listing any of the
|
|
* second logical processors. This approach should be used for all successive
|
|
* logical processors."
|
|
*/
|
|
static unsigned long acpi_create_madt_lapics(unsigned long current)
|
|
{
|
|
struct device *cpu;
|
|
int index, apic_ids[CONFIG_MAX_CPUS] = {0}, num_cpus = 0, sort_start = 0;
|
|
for (unsigned int thread_id = 0; thread_id <= MAX_THREAD_ID; thread_id++) {
|
|
for (cpu = all_devices; cpu; cpu = cpu->next) {
|
|
if (!is_enabled_cpu(cpu))
|
|
continue;
|
|
if (num_cpus >= ARRAY_SIZE(apic_ids))
|
|
break;
|
|
if (cpu->path.apic.thread_id != thread_id)
|
|
continue;
|
|
apic_ids[num_cpus++] = cpu->path.apic.apic_id;
|
|
}
|
|
bubblesort(&apic_ids[sort_start], num_cpus - sort_start, NUM_ASCENDING);
|
|
sort_start = num_cpus;
|
|
}
|
|
for (index = 0; index < num_cpus; index++)
|
|
current = acpi_create_madt_one_lapic(current, index, apic_ids[index]);
|
|
|
|
return current;
|
|
}
|
|
|
|
static int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
|
|
u32 gsi_base)
|
|
{
|
|
ioapic->type = IO_APIC; /* I/O APIC structure */
|
|
ioapic->length = sizeof(acpi_madt_ioapic_t);
|
|
ioapic->reserved = 0x00;
|
|
ioapic->gsi_base = gsi_base;
|
|
ioapic->ioapic_id = id;
|
|
ioapic->ioapic_addr = addr;
|
|
|
|
return ioapic->length;
|
|
}
|
|
|
|
/* For a system with multiple I/O APICs it's required that the one potentially
|
|
routing i8259 via ExtNMI delivery calls this first to get GSI #0. */
|
|
int acpi_create_madt_ioapic_from_hw(acpi_madt_ioapic_t *ioapic, u32 addr)
|
|
{
|
|
static u32 gsi_base;
|
|
u32 my_base;
|
|
u8 id = get_ioapic_id((void *)(uintptr_t)addr);
|
|
u8 count = ioapic_get_max_vectors((void *)(uintptr_t)addr);
|
|
|
|
my_base = gsi_base;
|
|
gsi_base += count;
|
|
return acpi_create_madt_ioapic(ioapic, id, addr, my_base);
|
|
}
|
|
|
|
static int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
|
|
u8 bus, u8 source, u32 gsirq, u16 flags)
|
|
{
|
|
irqoverride->type = IRQ_SOURCE_OVERRIDE; /* Interrupt source override */
|
|
irqoverride->length = sizeof(acpi_madt_irqoverride_t);
|
|
irqoverride->bus = bus;
|
|
irqoverride->source = source;
|
|
irqoverride->gsirq = gsirq;
|
|
irqoverride->flags = flags;
|
|
|
|
return irqoverride->length;
|
|
}
|
|
|
|
static int acpi_create_madt_sci_override(acpi_madt_irqoverride_t *irqoverride)
|
|
{
|
|
u8 gsi, irq, flags;
|
|
|
|
ioapic_get_sci_pin(&gsi, &irq, &flags);
|
|
|
|
if (!CONFIG(ACPI_HAVE_PCAT_8259))
|
|
irq = gsi;
|
|
|
|
irqoverride->type = IRQ_SOURCE_OVERRIDE; /* Interrupt source override */
|
|
irqoverride->length = sizeof(acpi_madt_irqoverride_t);
|
|
irqoverride->bus = MP_BUS_ISA;
|
|
irqoverride->source = irq;
|
|
irqoverride->gsirq = gsi;
|
|
irqoverride->flags = flags;
|
|
|
|
return irqoverride->length;
|
|
}
|
|
|
|
static unsigned long acpi_create_madt_ioapic_gsi0_default(unsigned long current)
|
|
{
|
|
current += acpi_create_madt_ioapic_from_hw((acpi_madt_ioapic_t *)current, IO_APIC_ADDR);
|
|
|
|
current += acpi_create_madt_irqoverride((void *)current, MP_BUS_ISA, 0, 2,
|
|
MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH);
|
|
|
|
current += acpi_create_madt_sci_override((void *)current);
|
|
|
|
return current;
|
|
}
|
|
|
|
static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
|
|
u16 flags, u8 lint)
|
|
{
|
|
lapic_nmi->type = LOCAL_APIC_NMI; /* Local APIC NMI structure */
|
|
lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t);
|
|
lapic_nmi->flags = flags;
|
|
lapic_nmi->processor_id = cpu;
|
|
lapic_nmi->lint = lint;
|
|
|
|
return lapic_nmi->length;
|
|
}
|
|
|
|
static int acpi_create_madt_lx2apic_nmi(acpi_madt_lx2apic_nmi_t *lapic_nmi, u32 cpu,
|
|
u16 flags, u8 lint)
|
|
{
|
|
lapic_nmi->type = LOCAL_X2APIC_NMI; /* Local APIC NMI structure */
|
|
lapic_nmi->length = sizeof(acpi_madt_lx2apic_nmi_t);
|
|
lapic_nmi->flags = flags;
|
|
lapic_nmi->processor_id = cpu;
|
|
lapic_nmi->lint = lint;
|
|
lapic_nmi->reserved[0] = 0;
|
|
lapic_nmi->reserved[1] = 0;
|
|
lapic_nmi->reserved[2] = 0;
|
|
|
|
return lapic_nmi->length;
|
|
}
|
|
|
|
unsigned long acpi_create_madt_lapic_nmis(unsigned long current)
|
|
{
|
|
const u16 flags = MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH;
|
|
|
|
/* 1: LINT1 connect to NMI */
|
|
/* create all subtables for processors */
|
|
current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current,
|
|
ACPI_MADT_LAPIC_NMI_ALL_PROCESSORS, flags, 1);
|
|
|
|
if (!CONFIG(XAPIC_ONLY))
|
|
current += acpi_create_madt_lx2apic_nmi((acpi_madt_lx2apic_nmi_t *)current,
|
|
ACPI_MADT_LX2APIC_NMI_ALL_PROCESSORS, flags, 1);
|
|
|
|
return current;
|
|
}
|
|
|
|
static unsigned long acpi_create_madt_lapics_with_nmis(unsigned long current)
|
|
{
|
|
current = acpi_create_madt_lapics(current);
|
|
current = acpi_create_madt_lapic_nmis(current);
|
|
return current;
|
|
}
|
|
|
|
int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic)
|
|
{
|
|
memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t));
|
|
|
|
lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */
|
|
lapic->length = sizeof(acpi_srat_lapic_t);
|
|
lapic->flags = (1 << 0); /* Enabled (the use of this structure). */
|
|
lapic->proximity_domain_7_0 = node;
|
|
/* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */
|
|
lapic->apic_id = apic;
|
|
|
|
return lapic->length;
|
|
}
|
|
|
|
int acpi_create_srat_x2apic(acpi_srat_x2apic_t *x2apic, u32 node, u32 apic)
|
|
{
|
|
memset((void *)x2apic, 0, sizeof(acpi_srat_x2apic_t));
|
|
|
|
x2apic->type = 2; /* Processor x2APIC structure */
|
|
x2apic->length = sizeof(acpi_srat_x2apic_t);
|
|
x2apic->flags = (1 << 0); /* Enabled (the use of this structure). */
|
|
x2apic->proximity_domain = node;
|
|
x2apic->x2apic_id = apic;
|
|
|
|
return x2apic->length;
|
|
}
|
|
|
|
unsigned long acpi_arch_fill_madt(acpi_madt_t *madt, unsigned long current)
|
|
{
|
|
madt->lapic_addr = cpu_get_lapic_addr();
|
|
|
|
if (CONFIG(ACPI_HAVE_PCAT_8259))
|
|
madt->flags |= 1;
|
|
|
|
if (CONFIG(ACPI_COMMON_MADT_LAPIC))
|
|
current = acpi_create_madt_lapics_with_nmis(current);
|
|
|
|
if (CONFIG(ACPI_COMMON_MADT_IOAPIC))
|
|
current = acpi_create_madt_ioapic_gsi0_default(current);
|
|
|
|
return current;
|
|
}
|