On Fri, May 06, 2022 at 09:55:49PM +0100, Nikos Nikoleris wrote: > For systems with ACPI support, we can discover timers through the ACPI > GTDT table. This change implements the code to discover timers through > the GTDT and adds ACPI support in timer_save_state. This change > retains the default behavior; we check if a valid DT is provided, if > not, we try to discover timers using ACPI. > > Signed-off-by: Nikos Nikoleris <nikos.nikoleris@xxxxxxx> > --- > arm/Makefile.common | 1 + > lib/arm/asm/timer.h | 2 ++ > lib/acpi.h | 18 +++++++++++ > lib/arm/setup.c | 39 ------------------------ > lib/arm/timer.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 94 insertions(+), 39 deletions(-) > create mode 100644 lib/arm/timer.c > > diff --git a/arm/Makefile.common b/arm/Makefile.common > index 8e9b3bb..5be42c0 100644 > --- a/arm/Makefile.common > +++ b/arm/Makefile.common > @@ -53,6 +53,7 @@ cflatobjs += lib/arm/psci.o > cflatobjs += lib/arm/smp.o > cflatobjs += lib/arm/delay.o > cflatobjs += lib/arm/gic.o lib/arm/gic-v2.o lib/arm/gic-v3.o > +cflatobjs += lib/arm/timer.o > > OBJDIRS += lib/arm > > diff --git a/lib/arm/asm/timer.h b/lib/arm/asm/timer.h > index f75cc67..aaf839f 100644 > --- a/lib/arm/asm/timer.h > +++ b/lib/arm/asm/timer.h > @@ -27,5 +27,7 @@ extern struct timer_state __timer_state; > #define TIMER_PTIMER_IRQ (__timer_state.ptimer.irq) > #define TIMER_VTIMER_IRQ (__timer_state.vtimer.irq) > > +void timer_save_state(void); > + > #endif /* !__ASSEMBLY__ */ > #endif /* _ASMARM_TIMER_H_ */ > diff --git a/lib/acpi.h b/lib/acpi.h > index 5213299..297ad87 100644 > --- a/lib/acpi.h > +++ b/lib/acpi.h > @@ -17,6 +17,7 @@ > #define FACP_SIGNATURE ACPI_SIGNATURE('F','A','C','P') > #define FACS_SIGNATURE ACPI_SIGNATURE('F','A','C','S') > #define SPCR_SIGNATURE ACPI_SIGNATURE('S','P','C','R') > +#define GTDT_SIGNATURE ACPI_SIGNATURE('G','T','D','T') > > > #define ACPI_SIGNATURE_8BYTE(c1, c2, c3, c4, c5, c6, c7, c8) \ > @@ -172,6 +173,23 @@ struct spcr_descriptor { > u32 reserved2; > } __attribute__ ((packed)); > > +struct acpi_table_gtdt { > + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ > + u64 counter_block_addresss; > + u32 reserved; > + u32 secure_el1_interrupt; > + u32 secure_el1_flags; > + u32 non_secure_el1_interrupt; > + u32 non_secure_el1_flags; > + u32 virtual_timer_interrupt; > + u32 virtual_timer_flags; > + u32 non_secure_el2_interrupt; > + u32 non_secure_el2_flags; > + u64 counter_read_block_address; > + u32 platform_timer_count; > + u32 platform_timer_offset; > +} __attribute__ ((packed)); > + > void set_efi_rsdp(struct rsdp_descriptor *rsdp); > void* find_acpi_table_addr(u32 sig); > > diff --git a/lib/arm/setup.c b/lib/arm/setup.c > index bcdf0d7..1572c64 100644 > --- a/lib/arm/setup.c > +++ b/lib/arm/setup.c > @@ -35,8 +35,6 @@ > > extern unsigned long etext; > > -struct timer_state __timer_state; > - > char *initrd; > u32 initrd_size; > > @@ -199,43 +197,6 @@ static void mem_init(phys_addr_t freemem_start) > page_alloc_ops_enable(); > } > > -static void timer_save_state(void) > -{ > - const struct fdt_property *prop; > - const void *fdt = dt_fdt(); > - int node, len; > - u32 *data; > - > - node = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer"); > - assert(node >= 0 || node == -FDT_ERR_NOTFOUND); > - > - if (node == -FDT_ERR_NOTFOUND) { > - __timer_state.ptimer.irq = -1; > - __timer_state.vtimer.irq = -1; > - return; > - } > - > - /* > - * From Linux devicetree timer binding documentation > - * > - * interrupts <type irq flags>: > - * secure timer irq > - * non-secure timer irq (ptimer) > - * virtual timer irq (vtimer) > - * hypervisor timer irq > - */ > - prop = fdt_get_property(fdt, node, "interrupts", &len); > - assert(prop && len == (4 * 3 * sizeof(u32))); > - > - data = (u32 *)prop->data; > - assert(fdt32_to_cpu(data[3]) == 1 /* PPI */); > - __timer_state.ptimer.irq = fdt32_to_cpu(data[4]); > - __timer_state.ptimer.irq_flags = fdt32_to_cpu(data[5]); > - assert(fdt32_to_cpu(data[6]) == 1 /* PPI */); > - __timer_state.vtimer.irq = fdt32_to_cpu(data[7]); > - __timer_state.vtimer.irq_flags = fdt32_to_cpu(data[8]); > -} > - > void setup(const void *fdt, phys_addr_t freemem_start) > { > void *freemem; > diff --git a/lib/arm/timer.c b/lib/arm/timer.c > new file mode 100644 > index 0000000..eceabdf > --- /dev/null > +++ b/lib/arm/timer.c > @@ -0,0 +1,73 @@ > +/* > + * Initialize timers. > + * > + * Copyright (C) 2022, Arm Ltd., Nikos Nikoleris <nikos.nikoleris@xxxxxxx> > + * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@xxxxxxxxxx> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#include <libcflat.h> > +#include <asm/timer.h> nit: I usually prefer an order like this for #includes #include <lib-include1, usually libcflat.h> #include <lib-include2> ... #include <sublib-include1, libfdt/* and linux/*> #include <sublib-include2> ... #include <asm-include1> #include <asm-include2> > + > +#include <acpi.h> > +#include <devicetree.h> > +#include <libfdt/libfdt.h> > + > +struct timer_state __timer_state; > + > +static void timer_save_state_fdt(void) > +{ > + const struct fdt_property *prop; > + const void *fdt = dt_fdt(); > + int node, len; > + u32 *data; > + > + node = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer"); > + assert(node >= 0 || node == -FDT_ERR_NOTFOUND); > + > + if (node == -FDT_ERR_NOTFOUND) { > + __timer_state.ptimer.irq = -1; > + __timer_state.vtimer.irq = -1; > + return; > + } > + > + /* > + * From Linux devicetree timer binding documentation > + * > + * interrupts <type irq flags>: > + * secure timer irq > + * non-secure timer irq (ptimer) > + * virtual timer irq (vtimer) > + * hypervisor timer irq > + */ > + prop = fdt_get_property(fdt, node, "interrupts", &len); > + assert(prop && len == (4 * 3 * sizeof(u32))); > + > + data = (u32 *)prop->data; > + assert(fdt32_to_cpu(data[3]) == 1 /* PPI */); > + __timer_state.ptimer.irq = fdt32_to_cpu(data[4]); > + __timer_state.ptimer.irq_flags = fdt32_to_cpu(data[5]); > + assert(fdt32_to_cpu(data[6]) == 1 /* PPI */); > + __timer_state.vtimer.irq = fdt32_to_cpu(data[7]); > + __timer_state.vtimer.irq_flags = fdt32_to_cpu(data[8]); > +} > + > +static void timer_save_state_acpi(void) > +{ > + struct acpi_table_gtdt *gtdt = find_acpi_table_addr(GTDT_SIGNATURE); > + > + assert_msg(gtdt, "Unable to find ACPI GTDT"); > + __timer_state.ptimer.irq = gtdt->non_secure_el1_interrupt; > + __timer_state.ptimer.irq_flags = gtdt->non_secure_el1_flags; > + > + __timer_state.vtimer.irq = gtdt->virtual_timer_interrupt; > + __timer_state.vtimer.irq_flags = gtdt->virtual_timer_flags; > +} > + > +void timer_save_state(void) > +{ > + if (dt_available()) > + timer_save_state_fdt(); > + else > + timer_save_state_acpi(); > +} > -- > 2.25.1 > Reviewed-by: Andrew Jones <drjones@xxxxxxxxxx> Thanks, drew