feat(gicv3): detect GICv4 feature at runtime

At the moment we have a GIC_ENABLE_V4_EXTN build time variable to
determine whether the GIC interrupt controller is compliant to version
4.0 of the spec or not. This just changes the number of 64K MMIO pages
we expect per redistributor.

To support firmware builds which run on variable systems (emulators,
fast model or FPGAs), let's make this decision at runtime.
The GIC specification provides several architected flags to learn the
size of the MMIO frame per redistributor, we use GICR_TYPER[VLPI] here.

Provide a (static inline) function to return the size of each
redistributor.
We keep the GIC_ENABLE_V4_EXTN build time variable around, but change
its meaning to enable this autodetection code. Systems not defining this
rely on a "pure" GICv3 (as before), but platforms setting it to "1" can
now deal with both configurations.

Change-Id: I9ede4acf058846157a0a9e2ef6103bf07c7655d9
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
This commit is contained in:
Andre Przywara 2021-05-18 15:51:06 +01:00
parent feb7081863
commit 858f40e379
4 changed files with 26 additions and 19 deletions

View File

@ -86,8 +86,7 @@ void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
if (proc_num < rdistif_num) {
rdistif_base_addrs[proc_num] = rdistif_base;
}
rdistif_base += (1U << GICR_PCPUBASE_SHIFT);
rdistif_base += gicv3_redist_size(typer_val);
} while ((typer_val & TYPER_LAST_BIT) == 0U);
}
@ -383,11 +382,13 @@ unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame)
uintptr_t rdistif_base = gicr_frame;
unsigned int count;
for (count = 1; count < PLATFORM_CORE_COUNT; count++) {
if ((gicr_read_typer(rdistif_base) & TYPER_LAST_BIT) != 0U) {
for (count = 1U; count < PLATFORM_CORE_COUNT; count++) {
uint64_t typer_val = gicr_read_typer(rdistif_base);
if ((typer_val & TYPER_LAST_BIT) != 0U) {
break;
}
rdistif_base += (1U << GICR_PCPUBASE_SHIFT);
rdistif_base += gicv3_redist_size(typer_val);
}
return count;

View File

@ -123,13 +123,7 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
gic_version &= PIDR2_ARCH_REV_MASK;
/* Check GIC version */
#if GIC_ENABLE_V4_EXTN
assert(gic_version == ARCH_REV_GICV4);
/* GICv4 supports Direct Virtual LPI injection */
assert((gicd_read_typer(plat_driver_data->gicd_base)
& TYPER_DVIS) != 0);
#else
#if !GIC_ENABLE_V4_EXTN
assert(gic_version == ARCH_REV_GICV3);
#endif
/*
@ -1298,7 +1292,7 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame)
gicr_frame_found = true;
break;
}
rdistif_base += (uintptr_t)(ULL(1) << GICR_PCPUBASE_SHIFT);
rdistif_base += gicv3_redist_size(typer_val);
} while ((typer_val & TYPER_LAST_BIT) == 0U);
if (!gicr_frame_found) {

View File

@ -153,11 +153,8 @@
/*******************************************************************************
* Common GIC Redistributor interface registers & constants
******************************************************************************/
#if GIC_ENABLE_V4_EXTN
#define GICR_PCPUBASE_SHIFT 0x12
#else
#define GICR_PCPUBASE_SHIFT 0x11
#endif
#define GICR_V4_PCPUBASE_SHIFT 0x12
#define GICR_V3_PCPUBASE_SHIFT 0x11
#define GICR_SGIBASE_OFFSET U(65536) /* 64 KB */
#define GICR_CTLR U(0x0)
#define GICR_IIDR U(0x04)
@ -212,12 +209,14 @@
#define TYPER_AFF_VAL_SHIFT 32
#define TYPER_PROC_NUM_SHIFT 8
#define TYPER_LAST_SHIFT 4
#define TYPER_VLPI_SHIFT 1
#define TYPER_AFF_VAL_MASK U(0xffffffff)
#define TYPER_PROC_NUM_MASK U(0xffff)
#define TYPER_LAST_MASK U(0x1)
#define TYPER_LAST_BIT BIT_32(TYPER_LAST_SHIFT)
#define TYPER_VLPI_BIT BIT_32(TYPER_VLPI_SHIFT)
#define TYPER_PPI_NUM_SHIFT U(27)
#define TYPER_PPI_NUM_MASK U(0x1f)
@ -312,6 +311,19 @@
#include <drivers/arm/gic_common.h>
#include <lib/utils_def.h>
static inline uintptr_t gicv3_redist_size(uint64_t typer_val)
{
#if GIC_ENABLE_V4_EXTN
if ((typer_val & TYPER_VLPI_BIT) != 0U) {
return 1U << GICR_V4_PCPUBASE_SHIFT;
} else {
return 1U << GICR_V3_PCPUBASE_SHIFT;
}
#else
return 1U << GICR_V3_PCPUBASE_SHIFT;
#endif
}
static inline bool gicv3_is_intr_id_special_identifier(unsigned int id)
{
return (id >= PENDING_G1S_INTID) && (id <= GIC_SPURIOUS_INTERRUPT);

View File

@ -218,7 +218,7 @@ static void fpga_prepare_dtb(void)
INFO("Adjusting GICR DT region to cover %u cores\n",
nr_cores);
err = fdt_adjust_gic_redist(fdt, nr_cores,
1U << GICR_PCPUBASE_SHIFT);
1U << GICR_V3_PCPUBASE_SHIFT);
if (err < 0) {
ERROR("Error %d fixing up GIC DT node\n", err);
}