Message ID | 20230428120405.3770496-15-nikos.nikoleris@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | EFI and ACPI support for arm64 | expand |
On 4/28/23 20:03, Nikos Nikoleris wrote: > In systems with ACPI support and when a DT is not provided, we can use > the MADTs to discover the number of CPUs and their corresponding MIDR. > This change implements this but retains the default behavior; we check > if a valid DT is provided, if not, we try to discover the cores in the > system using ACPI. > > Signed-off-by: Nikos Nikoleris <nikos.nikoleris@arm.com> > Reviewed-by: Andrew Jones <drjones@redhat.com> Reviewed-by: Shaoqin Huang <shahuang@redhat.com> > --- > lib/acpi.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ > lib/acpi.c | 20 ++++++++++++++++ > lib/arm/setup.c | 42 ++++++++++++++++++++++++++++++--- > 3 files changed, 122 insertions(+), 3 deletions(-) > > diff --git a/lib/acpi.h b/lib/acpi.h > index 04e4d1c3..4a59f543 100644 > --- a/lib/acpi.h > +++ b/lib/acpi.h > @@ -17,6 +17,7 @@ > #define XSDT_SIGNATURE ACPI_SIGNATURE('X','S','D','T') > #define FACP_SIGNATURE ACPI_SIGNATURE('F','A','C','P') > #define FACS_SIGNATURE ACPI_SIGNATURE('F','A','C','S') > +#define MADT_SIGNATURE ACPI_SIGNATURE('A','P','I','C') > #define SPCR_SIGNATURE ACPI_SIGNATURE('S','P','C','R') > #define GTDT_SIGNATURE ACPI_SIGNATURE('G','T','D','T') > > @@ -147,6 +148,67 @@ struct acpi_table_facs_rev1 { > u8 reserved3[40]; /* Reserved - must be zero */ > }; > > +struct acpi_table_madt { > + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ > + u32 address; /* Physical address of local APIC */ > + u32 flags; > +}; > + > +struct acpi_subtable_header { > + u8 type; > + u8 length; > +}; > + > +typedef int (*acpi_table_handler)(struct acpi_subtable_header *header); > + > +/* 11: Generic interrupt - GICC (ACPI 5.0 + ACPI 6.0 + ACPI 6.3 changes) */ > + > +struct acpi_madt_generic_interrupt { > + u8 type; > + u8 length; > + u16 reserved; /* reserved - must be zero */ > + u32 cpu_interface_number; > + u32 uid; > + u32 flags; > + u32 parking_version; > + u32 performance_interrupt; > + u64 parked_address; > + u64 base_address; > + u64 gicv_base_address; > + u64 gich_base_address; > + u32 vgic_interrupt; > + u64 gicr_base_address; > + u64 arm_mpidr; > + u8 efficiency_class; > + u8 reserved2[1]; > + u16 spe_interrupt; /* ACPI 6.3 */ > +}; > + > +/* Values for MADT subtable type in struct acpi_subtable_header */ > + > +enum acpi_madt_type { > + ACPI_MADT_TYPE_LOCAL_APIC = 0, > + ACPI_MADT_TYPE_IO_APIC = 1, > + ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2, > + ACPI_MADT_TYPE_NMI_SOURCE = 3, > + ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4, > + ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5, > + ACPI_MADT_TYPE_IO_SAPIC = 6, > + ACPI_MADT_TYPE_LOCAL_SAPIC = 7, > + ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, > + ACPI_MADT_TYPE_LOCAL_X2APIC = 9, > + ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10, > + ACPI_MADT_TYPE_GENERIC_INTERRUPT = 11, > + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12, > + ACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13, > + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14, > + ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15, > + ACPI_MADT_TYPE_RESERVED = 16 /* 16 and greater are reserved */ > +}; > + > +/* MADT Local APIC flags */ > +#define ACPI_MADT_ENABLED (1) /* 00: Processor is usable if set */ > + > struct spcr_descriptor { > ACPI_TABLE_HEADER_DEF /* ACPI common table header */ > u8 interface_type; /* 0=full 16550, 1=subset of 16550 */ > @@ -192,5 +254,6 @@ struct acpi_table_gtdt { > > void set_efi_rsdp(struct acpi_table_rsdp *rsdp); > void *find_acpi_table_addr(u32 sig); > +void acpi_table_parse_madt(enum acpi_madt_type mtype, acpi_table_handler handler); > > #endif > diff --git a/lib/acpi.c b/lib/acpi.c > index a197f3dd..bbe33d08 100644 > --- a/lib/acpi.c > +++ b/lib/acpi.c > @@ -102,3 +102,23 @@ void *find_acpi_table_addr(u32 sig) > > return NULL; > } > + > +void acpi_table_parse_madt(enum acpi_madt_type mtype, acpi_table_handler handler) > +{ > + struct acpi_table_madt *madt; > + struct acpi_subtable_header *header; > + void *end; > + > + madt = find_acpi_table_addr(MADT_SIGNATURE); > + assert(madt); > + > + header = (void *)(ulong) madt + sizeof(struct acpi_table_madt); > + end = (void *)((ulong) madt + madt->length); > + > + while ((void *)header < end) { > + if (header->type == mtype) > + handler(header); > + > + header = (void *)(ulong) header + header->length; > + } > +} > diff --git a/lib/arm/setup.c b/lib/arm/setup.c > index 1572c64e..59b0aedd 100644 > --- a/lib/arm/setup.c > +++ b/lib/arm/setup.c > @@ -55,7 +55,7 @@ int mpidr_to_cpu(uint64_t mpidr) > return -1; > } > > -static void cpu_set(int fdtnode __unused, u64 regval, void *info __unused) > +static void cpu_set_fdt(int fdtnode __unused, u64 regval, void *info __unused) > { > int cpu = nr_cpus++; > > @@ -65,13 +65,49 @@ static void cpu_set(int fdtnode __unused, u64 regval, void *info __unused) > set_cpu_present(cpu, true); > } > > +#ifdef CONFIG_EFI > + > +#include <acpi.h> > + > +static int cpu_set_acpi(struct acpi_subtable_header *header) > +{ > + int cpu = nr_cpus++; > + struct acpi_madt_generic_interrupt *gicc = (void *)header; > + > + assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); > + > + cpus[cpu] = gicc->arm_mpidr; > + set_cpu_present(cpu, true); > + > + return 0; > +} > + > +static void cpu_init_acpi(void) > +{ > + acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, cpu_set_acpi); > +} > + > +#else > + > +static void cpu_init_acpi(void) > +{ > + assert_msg(false, "ACPI not available"); > +} > + > +#endif > + > static void cpu_init(void) > { > int ret; > > nr_cpus = 0; > - ret = dt_for_each_cpu_node(cpu_set, NULL); > - assert(ret == 0); > + if (dt_available()) { > + ret = dt_for_each_cpu_node(cpu_set_fdt, NULL); > + assert(ret == 0); > + } else { > + cpu_init_acpi(); > + } > + > set_cpu_online(0, true); > } >
diff --git a/lib/acpi.h b/lib/acpi.h index 04e4d1c3..4a59f543 100644 --- a/lib/acpi.h +++ b/lib/acpi.h @@ -17,6 +17,7 @@ #define XSDT_SIGNATURE ACPI_SIGNATURE('X','S','D','T') #define FACP_SIGNATURE ACPI_SIGNATURE('F','A','C','P') #define FACS_SIGNATURE ACPI_SIGNATURE('F','A','C','S') +#define MADT_SIGNATURE ACPI_SIGNATURE('A','P','I','C') #define SPCR_SIGNATURE ACPI_SIGNATURE('S','P','C','R') #define GTDT_SIGNATURE ACPI_SIGNATURE('G','T','D','T') @@ -147,6 +148,67 @@ struct acpi_table_facs_rev1 { u8 reserved3[40]; /* Reserved - must be zero */ }; +struct acpi_table_madt { + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + u32 address; /* Physical address of local APIC */ + u32 flags; +}; + +struct acpi_subtable_header { + u8 type; + u8 length; +}; + +typedef int (*acpi_table_handler)(struct acpi_subtable_header *header); + +/* 11: Generic interrupt - GICC (ACPI 5.0 + ACPI 6.0 + ACPI 6.3 changes) */ + +struct acpi_madt_generic_interrupt { + u8 type; + u8 length; + u16 reserved; /* reserved - must be zero */ + u32 cpu_interface_number; + u32 uid; + u32 flags; + u32 parking_version; + u32 performance_interrupt; + u64 parked_address; + u64 base_address; + u64 gicv_base_address; + u64 gich_base_address; + u32 vgic_interrupt; + u64 gicr_base_address; + u64 arm_mpidr; + u8 efficiency_class; + u8 reserved2[1]; + u16 spe_interrupt; /* ACPI 6.3 */ +}; + +/* Values for MADT subtable type in struct acpi_subtable_header */ + +enum acpi_madt_type { + ACPI_MADT_TYPE_LOCAL_APIC = 0, + ACPI_MADT_TYPE_IO_APIC = 1, + ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2, + ACPI_MADT_TYPE_NMI_SOURCE = 3, + ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4, + ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5, + ACPI_MADT_TYPE_IO_SAPIC = 6, + ACPI_MADT_TYPE_LOCAL_SAPIC = 7, + ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, + ACPI_MADT_TYPE_LOCAL_X2APIC = 9, + ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10, + ACPI_MADT_TYPE_GENERIC_INTERRUPT = 11, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12, + ACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14, + ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15, + ACPI_MADT_TYPE_RESERVED = 16 /* 16 and greater are reserved */ +}; + +/* MADT Local APIC flags */ +#define ACPI_MADT_ENABLED (1) /* 00: Processor is usable if set */ + struct spcr_descriptor { ACPI_TABLE_HEADER_DEF /* ACPI common table header */ u8 interface_type; /* 0=full 16550, 1=subset of 16550 */ @@ -192,5 +254,6 @@ struct acpi_table_gtdt { void set_efi_rsdp(struct acpi_table_rsdp *rsdp); void *find_acpi_table_addr(u32 sig); +void acpi_table_parse_madt(enum acpi_madt_type mtype, acpi_table_handler handler); #endif diff --git a/lib/acpi.c b/lib/acpi.c index a197f3dd..bbe33d08 100644 --- a/lib/acpi.c +++ b/lib/acpi.c @@ -102,3 +102,23 @@ void *find_acpi_table_addr(u32 sig) return NULL; } + +void acpi_table_parse_madt(enum acpi_madt_type mtype, acpi_table_handler handler) +{ + struct acpi_table_madt *madt; + struct acpi_subtable_header *header; + void *end; + + madt = find_acpi_table_addr(MADT_SIGNATURE); + assert(madt); + + header = (void *)(ulong) madt + sizeof(struct acpi_table_madt); + end = (void *)((ulong) madt + madt->length); + + while ((void *)header < end) { + if (header->type == mtype) + handler(header); + + header = (void *)(ulong) header + header->length; + } +} diff --git a/lib/arm/setup.c b/lib/arm/setup.c index 1572c64e..59b0aedd 100644 --- a/lib/arm/setup.c +++ b/lib/arm/setup.c @@ -55,7 +55,7 @@ int mpidr_to_cpu(uint64_t mpidr) return -1; } -static void cpu_set(int fdtnode __unused, u64 regval, void *info __unused) +static void cpu_set_fdt(int fdtnode __unused, u64 regval, void *info __unused) { int cpu = nr_cpus++; @@ -65,13 +65,49 @@ static void cpu_set(int fdtnode __unused, u64 regval, void *info __unused) set_cpu_present(cpu, true); } +#ifdef CONFIG_EFI + +#include <acpi.h> + +static int cpu_set_acpi(struct acpi_subtable_header *header) +{ + int cpu = nr_cpus++; + struct acpi_madt_generic_interrupt *gicc = (void *)header; + + assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); + + cpus[cpu] = gicc->arm_mpidr; + set_cpu_present(cpu, true); + + return 0; +} + +static void cpu_init_acpi(void) +{ + acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, cpu_set_acpi); +} + +#else + +static void cpu_init_acpi(void) +{ + assert_msg(false, "ACPI not available"); +} + +#endif + static void cpu_init(void) { int ret; nr_cpus = 0; - ret = dt_for_each_cpu_node(cpu_set, NULL); - assert(ret == 0); + if (dt_available()) { + ret = dt_for_each_cpu_node(cpu_set_fdt, NULL); + assert(ret == 0); + } else { + cpu_init_acpi(); + } + set_cpu_online(0, true); }