Commit 68b10e85 authored by Huifeng Zhang's avatar Huifeng Zhang Committed by Fabio Baltieri
Browse files

drivers: intc_gicv3: fix gic_rdists[cpu] points to a wrong address



In old way, gic_rdists[cpu] is calculated via MPIDR_TO_CORE(), but in
real hardware, MPIDR_TO_CORE() isn't a value increment from 0 one by
one, and that will lead gic_rdists[cpu] to point to a wrong address.

GICv3 provides the register GICR_TYPER[1] and it has a field named
Affinity_Value. This field can help to determine where gic_rdists[cpu]
should point.

Signed-off-by: default avatarHuifeng Zhang <Huifeng.Zhang@arm.com>
parent d614e6e3
Loading
Loading
Loading
Loading
+44 −1
Original line number Diff line number Diff line
@@ -477,12 +477,55 @@ static void gicv3_dist_init(void)
#endif
}

static uint64_t arm_gic_mpidr_to_affinity(uint64_t mpidr)
{
	uint64_t aff3, aff2, aff1, aff0;

#if defined(CONFIG_ARM)
	/* There is no Aff3 in AArch32 MPIDR */
	aff3 = 0;
#else
	aff3 = MPIDR_AFFLVL(mpidr, 3);
#endif

	aff2 = MPIDR_AFFLVL(mpidr, 2);
	aff1 = MPIDR_AFFLVL(mpidr, 1);
	aff0 = MPIDR_AFFLVL(mpidr, 0);

	return (aff3 << 24 | aff2 << 16 | aff1 << 8 | aff0);
}

static mem_addr_t arm_gic_iterate_rdists(void)
{
	uint64_t aff = arm_gic_mpidr_to_affinity(GET_MPIDR());

	for (mem_addr_t rdist_addr = GIC_RDIST_BASE;
		rdist_addr < GIC_RDIST_BASE + GIC_RDIST_SIZE;
		rdist_addr += 0x20000) {
		uint64_t val = sys_read64(rdist_addr + GICR_TYPER);

		if (GICR_TYPER_AFFINITY_VALUE_GET(val) == aff) {
			return rdist_addr;
		}

		if (GICR_TYPER_LAST_GET(val) == 1) {
			return (mem_addr_t)NULL;
		}
	}

	return (mem_addr_t)NULL;
}

static void __arm_gic_init(void)
{
	uint8_t cpu;
	mem_addr_t gic_rd_base;

	cpu = arch_curr_cpu()->id;
	gic_rdists[cpu] = GIC_RDIST_BASE + MPIDR_TO_CORE(GET_MPIDR()) * 0x20000;
	gic_rd_base = arm_gic_iterate_rdists();
	__ASSERT(gic_rd_base != (mem_addr_t)NULL, "");

	gic_rdists[cpu] = gic_rd_base;

#ifdef CONFIG_GIC_V3_ITS
	/* Enable LPIs in Redistributor */
+7 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
 */

#define GIC_RDIST_BASE	DT_REG_ADDR_BY_IDX(DT_INST(0, arm_gic), 1)
#define GIC_RDIST_SIZE	DT_REG_SIZE_BY_IDX(DT_INST(0, arm_gic), 1)

/* SGI base is at 64K offset from Redistributor */
#define GICR_SGI_BASE_OFF		0x10000
@@ -62,6 +63,12 @@
#define GICR_CTLR_RWP			3

/* GICR_TYPER */
#define GICR_TYPER_AFFINITY_VALUE_SHIFT		32
#define GICR_TYPER_AFFINITY_VALUE_MASK		0xFFFFFFFFUL
#define GICR_TYPER_AFFINITY_VALUE_GET(_val)	MASK_GET(_val, GICR_TYPER_AFFINITY_VALUE)
#define GICR_TYPER_LAST_SHIFT			4
#define GICR_TYPER_LAST_MASK			0x10UL
#define GICR_TYPER_LAST_GET(_val)		MASK_GET(_val, GICR_TYPER_LAST)
#define GICR_TYPER_PROCESSOR_NUMBER_SHIFT	8
#define GICR_TYPER_PROCESSOR_NUMBER_MASK	0xFFFFUL
#define GICR_TYPER_PROCESSOR_NUMBER_GET(_val)	MASK_GET(_val, GICR_TYPER_PROCESSOR_NUMBER)