git: cb4a83cff01c - main - gicv3: If the LPI is already allocated, remember it
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 28 Feb 2024 14:10:48 UTC
The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=cb4a83cff01cdf871c78115c942c5b34412914d2 commit cb4a83cff01cdf871c78115c942c5b34412914d2 Author: Warner Losh <imp@FreeBSD.org> AuthorDate: 2024-02-28 14:09:17 +0000 Commit: Warner Losh <imp@FreeBSD.org> CommitDate: 2024-02-28 14:09:43 +0000 gicv3: If the LPI is already allocated, remember it If the LPI Configuration Tabel has been pre-allocated by the boot loader, then we have to remember PROPBASER and use it rather than allocating memory for it ourselves. Linux provides us with a reserved table that contains all the gicv3 allocations, so make sure what we read from PROPBASER matches something in that table. Normally, bare metal boot loaders leave the gic in a reset state. However, Linux brings it up fully so it can do I/O to boot the next kernel via kexec. Since the gicv3 PENDBASER can't be reset while running due to undefined behavior, we must reuse what's there for both PENDBASER and PROPBASER. With this commit, the workaround is complete. Details are at https://lkml.iu.edu/hypermail/linux/kernel/1809.2/06246.html and pointers in the thread. Sponsored by: Netflix Reviewed by: andrew Differential Revision: https://reviews.freebsd.org/D44038 --- sys/arm64/arm64/gicv3_its.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c index 71620eec8fce..9fcf13fe433b 100644 --- a/sys/arm64/arm64/gicv3_its.c +++ b/sys/arm64/arm64/gicv3_its.c @@ -685,6 +685,8 @@ gicv3_its_conftable_init(struct gicv3_its_softc *sc) int extra_flags = 0; device_t gicv3; uint32_t ctlr; + vm_paddr_t conf_pa; + vm_offset_t conf_va; /* * The PROPBASER is a singleton in our parent. We only set it up the @@ -699,8 +701,32 @@ gicv3_its_conftable_init(struct gicv3_its_softc *sc) gicv3 = device_get_parent(sc->dev); ctlr = gic_r_read_4(gicv3, GICR_CTLR); if ((ctlr & GICR_CTLR_LPI_ENABLE) != 0) { - extra_flags = ITS_FLAGS_LPI_PREALLOC; - panic("gicv3 already enabled, can't reprogram."); + conf_pa = gic_r_read_8(gicv3, GICR_PROPBASER); + conf_pa &= GICR_PROPBASER_PA_MASK; + /* + * If there was a pre-existing PROPBASER, then we need to honor + * it because implemenetation defined behavior in gicv3 makes it + * impossible to quiesce to change it out. We will only see a + * pre-existing one when we've been kexec'd from a Linux kernel, + * or from a LinuxBoot environment. + * + * Linux provides us with a MEMRESERVE table that we put into + * the excluded physmem area. If PROPBASER isn't in this tabke, + * the system cannot run due to random memory corruption, + * so we panic for this case. + */ + if (!physmem_excluded(conf_pa, LPI_CONFTAB_SIZE)) + panic("gicv3 PROPBASER needs to reuse %#lx, but not reserved\n", + conf_pa); + conf_va = PHYS_TO_DMAP(conf_pa); + if (!pmap_klookup(conf_va, NULL)) + panic("Can't mapped prior LPI mapping into VA\n"); + conf_table = (void *)conf_va; + extra_flags = ITS_FLAGS_LPI_PREALLOC | ITS_FLAGS_LPI_CONF_FLUSH; + if (bootverbose) + device_printf(sc->dev, + "LPI enabled, conf table using pa %#lx va %lx\n", + conf_pa, conf_va); } else { /*