Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115654603
D40902.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D40902.diff
View Options
diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c
--- a/sys/arm64/arm64/gicv3_its.c
+++ b/sys/arm64/arm64/gicv3_its.c
@@ -47,6 +47,7 @@
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
+#include <sys/physmem.h>
#include <sys/proc.h>
#include <sys/taskqueue.h>
#include <sys/tree.h>
@@ -59,6 +60,7 @@
#include <vm/vm.h>
#include <vm/pmap.h>
+#include <vm/vm_map.h>
#include <vm/vm_page.h>
#include <machine/bus.h>
@@ -277,13 +279,12 @@
#define ITS_FLAGS_CMDQ_FLUSH 0x00000001
#define ITS_FLAGS_LPI_CONF_FLUSH 0x00000002
#define ITS_FLAGS_ERRATA_CAVIUM_22375 0x00000004
+#define ITS_FLAGS_LPI_PREALLOC 0x00000008
u_int sc_its_flags;
bool trace_enable;
vm_page_t ma; /* fake msi page */
};
-static void *conf_base;
-
typedef void (its_quirk_func_t)(device_t);
static its_quirk_func_t its_quirk_cavium_22375;
@@ -572,20 +573,65 @@
static void
gicv3_its_conftable_init(struct gicv3_its_softc *sc)
{
- void *conf_table;
+ /* note: we assume the ITS children are serialized by the parent */
+ static int extra_flags;
+ static void *conf_table;
+ vm_paddr_t conf_pa;
+ vm_offset_t conf_va;
+ device_t gicv3;
+ int unit;
+ uint32_t ctlr;
+
+ /*
+ * The PROPBASER is a singleton in our parent, so only unit 0 will set
+ * it up. Skip all the other units, but make a note of where it was done
+ * and how we set it up.
+ */
+ unit = device_get_unit(sc->dev);
+ if (unit != 0) {
+ KASSERT(conf_table != NULL, ("Conf table null for unit %d", unit));
+ sc->sc_its_flags |= extra_flags;
+ sc->sc_conf_base = conf_table;
+ return;
+ }
- conf_table = atomic_load_ptr(&conf_base);
- if (conf_table == NULL) {
+ gicv3 = device_get_parent(sc->dev);
+ ctlr = gic_r_read_4(gicv3, GICR_CTLR);
+ if (ctlr & GICR_CTLR_LPI_ENABLE) {
+ conf_pa = gic_r_read_8(gicv3, GICR_PROPBASER);
+ conf_pa &= ~((PAGE_SIZE_4K - 1) | GICR_PROPBASER_OUTER_CACHE_MASK); /* mask off */
+ /*
+ * 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 memory 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;
+ device_printf(sc->dev, "LPI enabled, conf table using pa %#lx va %lx\n",
+ conf_pa, conf_va);
+ } else {
+ /*
+ * Otherwise just allocate contiguous pages. We'll configure the
+ * PROPBASER register later in its_init_cpu_lpi().
+ */
conf_table = contigmalloc(LPI_CONFTAB_SIZE,
M_GICV3_ITS, M_WAITOK, 0, LPI_CONFTAB_MAX_ADDR,
LPI_CONFTAB_ALIGN, 0);
-
- if (atomic_cmpset_ptr((uintptr_t *)&conf_base,
- (uintptr_t)NULL, (uintptr_t)conf_table) == 0) {
- contigfree(conf_table, LPI_CONFTAB_SIZE, M_GICV3_ITS);
- conf_table = atomic_load_ptr(&conf_base);
- }
}
+ sc->sc_its_flags |= extra_flags;
sc->sc_conf_base = conf_table;
/* Set the default configuration */
@@ -601,17 +647,18 @@
{
int i;
- for (i = 0; i <= mp_maxid; i++) {
- if (CPU_ISSET(i, &sc->sc_cpus) == 0)
- continue;
-
- sc->sc_pend_base[i] = (vm_offset_t)contigmalloc(
- LPI_PENDTAB_SIZE, M_GICV3_ITS, M_WAITOK | M_ZERO,
- 0, LPI_PENDTAB_MAX_ADDR, LPI_PENDTAB_ALIGN, 0);
+ if ((sc->sc_its_flags & ITS_FLAGS_LPI_PREALLOC) == 0) {
+ for (i = 0; i <= mp_maxid; i++) {
+ if (CPU_ISSET(i, &sc->sc_cpus) == 0)
+ continue;
+ sc->sc_pend_base[i] = (vm_offset_t)contigmalloc(
+ LPI_PENDTAB_SIZE, M_GICV3_ITS, M_WAITOK | M_ZERO,
+ 0, LPI_PENDTAB_MAX_ADDR, LPI_PENDTAB_ALIGN, 0);
- /* Flush so the ITS can see the memory */
- cpu_dcache_wb_range((vm_offset_t)sc->sc_pend_base[i],
- LPI_PENDTAB_SIZE);
+ /* Flush so the ITS can see the memory */
+ cpu_dcache_wb_range((vm_offset_t)sc->sc_pend_base[i],
+ LPI_PENDTAB_SIZE);
+ }
}
}
@@ -619,81 +666,105 @@
its_init_cpu_lpi(device_t dev, struct gicv3_its_softc *sc)
{
device_t gicv3;
- uint64_t xbaser, tmp;
- uint32_t ctlr;
+ uint64_t xbaser, tmp, size;
u_int cpuid;
+ uint32_t ctlr;
gicv3 = device_get_parent(dev);
cpuid = PCPU_GET(cpuid);
- /* Disable LPIs */
- ctlr = gic_r_read_4(gicv3, GICR_CTLR);
- ctlr &= ~GICR_CTLR_LPI_ENABLE;
- gic_r_write_4(gicv3, GICR_CTLR, ctlr);
-
- /* Make sure changes are observable my the GIC */
- dsb(sy);
-
/*
- * Set the redistributor base
+ * Set the redistributor base. If we're reusing what we found on boot
+ * since the gic was already running, then don't touch it here. We also
+ * don't need to disable / enable LPI if we're not changing PROPBASER.
*/
- xbaser = vtophys(sc->sc_conf_base) |
- (GICR_PROPBASER_SHARE_IS << GICR_PROPBASER_SHARE_SHIFT) |
- (GICR_PROPBASER_CACHE_NIWAWB << GICR_PROPBASER_CACHE_SHIFT) |
- (flsl(LPI_CONFTAB_SIZE | GIC_FIRST_LPI) - 1);
- gic_r_write_8(gicv3, GICR_PROPBASER, xbaser);
-
- /* Check the cache attributes we set */
- tmp = gic_r_read_8(gicv3, GICR_PROPBASER);
-
- if ((tmp & GICR_PROPBASER_SHARE_MASK) !=
- (xbaser & GICR_PROPBASER_SHARE_MASK)) {
- if ((tmp & GICR_PROPBASER_SHARE_MASK) ==
- (GICR_PROPBASER_SHARE_NS << GICR_PROPBASER_SHARE_SHIFT)) {
- /* We need to mark as non-cacheable */
- xbaser &= ~(GICR_PROPBASER_SHARE_MASK |
- GICR_PROPBASER_CACHE_MASK);
- /* Non-cacheable */
- xbaser |= GICR_PROPBASER_CACHE_NIN <<
- GICR_PROPBASER_CACHE_SHIFT;
- /* Non-shareable */
- xbaser |= GICR_PROPBASER_SHARE_NS <<
- GICR_PROPBASER_SHARE_SHIFT;
- gic_r_write_8(gicv3, GICR_PROPBASER, xbaser);
+ if ((sc->sc_its_flags & ITS_FLAGS_LPI_PREALLOC) == 0) {
+ size = (flsl(LPI_CONFTAB_SIZE | GIC_FIRST_LPI) - 1);
+
+ xbaser = vtophys(sc->sc_conf_base) |
+ (GICR_PROPBASER_SHARE_IS << GICR_PROPBASER_SHARE_SHIFT) |
+ (GICR_PROPBASER_CACHE_NIWAWB << GICR_PROPBASER_CACHE_SHIFT) |
+ size;
+
+ gic_r_write_8(gicv3, GICR_PROPBASER, xbaser);
+
+ /* Check the cache attributes we set */
+ tmp = gic_r_read_8(gicv3, GICR_PROPBASER);
+
+ if ((tmp & GICR_PROPBASER_SHARE_MASK) !=
+ (xbaser & GICR_PROPBASER_SHARE_MASK)) {
+ if ((tmp & GICR_PROPBASER_SHARE_MASK) ==
+ (GICR_PROPBASER_SHARE_NS << GICR_PROPBASER_SHARE_SHIFT)) {
+ /* We need to mark as non-cacheable */
+ xbaser &= ~(GICR_PROPBASER_SHARE_MASK |
+ GICR_PROPBASER_CACHE_MASK);
+ /* Non-cacheable */
+ xbaser |= GICR_PROPBASER_CACHE_NIN <<
+ GICR_PROPBASER_CACHE_SHIFT;
+ /* Non-shareable */
+ xbaser |= GICR_PROPBASER_SHARE_NS <<
+ GICR_PROPBASER_SHARE_SHIFT;
+ gic_r_write_8(gicv3, GICR_PROPBASER, xbaser);
+ }
+ sc->sc_its_flags |= ITS_FLAGS_LPI_CONF_FLUSH;
}
- sc->sc_its_flags |= ITS_FLAGS_LPI_CONF_FLUSH;
}
/*
* Set the LPI pending table base
*/
- xbaser = vtophys(sc->sc_pend_base[cpuid]) |
- (GICR_PENDBASER_CACHE_NIWAWB << GICR_PENDBASER_CACHE_SHIFT) |
- (GICR_PENDBASER_SHARE_IS << GICR_PENDBASER_SHARE_SHIFT);
-
- gic_r_write_8(gicv3, GICR_PENDBASER, xbaser);
-
- tmp = gic_r_read_8(gicv3, GICR_PENDBASER);
-
- if ((tmp & GICR_PENDBASER_SHARE_MASK) ==
- (GICR_PENDBASER_SHARE_NS << GICR_PENDBASER_SHARE_SHIFT)) {
- /* Clear the cahce and shareability bits */
- xbaser &= ~(GICR_PENDBASER_CACHE_MASK |
- GICR_PENDBASER_SHARE_MASK);
- /* Mark as non-shareable */
- xbaser |= GICR_PENDBASER_SHARE_NS << GICR_PENDBASER_SHARE_SHIFT;
- /* And non-cacheable */
- xbaser |= GICR_PENDBASER_CACHE_NIN <<
- GICR_PENDBASER_CACHE_SHIFT;
+ if (sc->sc_pend_base[cpuid] == 0) {
+ tmp = gic_r_read_8(gicv3, GICR_PENDBASER);
+ tmp &= ~((PAGE_SIZE_4K - 1) | GICR_PENDBASER_OUTER_CACHE_MASK);
+ if (!physmem_excluded(tmp, LPI_PENDTAB_SIZE))
+ panic("gicv3: Forced to reuse %#lx, but not reserved\n",
+ tmp);
+ sc->sc_pend_base[cpuid] = PHYS_TO_DMAP(tmp);
}
- /* Enable LPIs */
- ctlr = gic_r_read_4(gicv3, GICR_CTLR);
- ctlr |= GICR_CTLR_LPI_ENABLE;
- gic_r_write_4(gicv3, GICR_CTLR, ctlr);
+ if ((sc->sc_its_flags & ITS_FLAGS_LPI_PREALLOC) == 0) {
+ xbaser = vtophys(sc->sc_pend_base[cpuid]) |
+ (GICR_PENDBASER_CACHE_NIWAWB << GICR_PENDBASER_CACHE_SHIFT) |
+ (GICR_PENDBASER_SHARE_IS << GICR_PENDBASER_SHARE_SHIFT);
+
+ gic_r_write_8(gicv3, GICR_PENDBASER, xbaser);
+
+ tmp = gic_r_read_8(gicv3, GICR_PENDBASER);
+
+ if ((tmp & GICR_PENDBASER_SHARE_MASK) ==
+ (GICR_PENDBASER_SHARE_NS << GICR_PENDBASER_SHARE_SHIFT)) {
+ /* Clear the cahce and shareability bits */
+ xbaser &= ~(GICR_PENDBASER_CACHE_MASK |
+ GICR_PENDBASER_SHARE_MASK);
+ /* Mark as non-shareable */
+ xbaser |= GICR_PENDBASER_SHARE_NS << GICR_PENDBASER_SHARE_SHIFT;
+ /* And non-cacheable */
+ xbaser |= GICR_PENDBASER_CACHE_NIN <<
+ GICR_PENDBASER_CACHE_SHIFT;
+
+ /*
+ * I added the following, but I'm unsure if we need to
+ * do any of this. It seemed missing and likely should
+ * be committed separately, or not done at all. It's
+ * not hit in any test cases I've seen.
+ */
+ printf("****** WEIRD *******\n");
+ /* gic_r_write_8(gicv3, GICR_PENDBASER, xbaser); */
+ }
+
+ /* Enable LPIs -- already enabled if LPI_PREALLOC is true */
+ ctlr = gic_r_read_4(gicv3, GICR_CTLR);
+ ctlr |= GICR_CTLR_LPI_ENABLE;
+ gic_r_write_4(gicv3, GICR_CTLR, ctlr);
+
+ /* Make sure the GIC has seen everything */
+ dsb(sy);
+ }
- /* Make sure the GIC has seen everything */
- dsb(sy);
+ if (bootverbose)
+ device_printf(gicv3, "using %sPENDBASE of %#lx on cpu %d\n",
+ (sc->sc_its_flags & ITS_FLAGS_LPI_PREALLOC) ? "pre-existing " : "",
+ vtophys(sc->sc_pend_base[cpuid]), cpuid);
}
static int
diff --git a/sys/arm64/arm64/mp_machdep.c b/sys/arm64/arm64/mp_machdep.c
--- a/sys/arm64/arm64/mp_machdep.c
+++ b/sys/arm64/arm64/mp_machdep.c
@@ -570,7 +570,8 @@
naps = atomic_load_int(&aps_started);
bootstack = (char *)bootstacks[cpuid] + MP_BOOTSTACK_SIZE;
- printf("Starting CPU %u (%lx)\n", cpuid, target_cpu);
+ if (bootverbose)
+ printf("Starting CPU %u (%lx)\n", cpuid, target_cpu);
pa = pmap_extract(kernel_pmap, (vm_offset_t)mpentry);
/*
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 27, 3:23 PM (14 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17819277
Default Alt Text
D40902.diff (10 KB)
Attached To
Mode
D40902: arm64/gicv3: Allow us to inherit the LPI mappings
Attached
Detach File
Event Timeline
Log In to Comment