summaryrefslogtreecommitdiffstats
path: root/hw/intc/arm_gicv3_redist.c
diff options
context:
space:
mode:
authorPeter Maydell2022-01-28 17:59:56 +0100
committerPeter Maydell2022-01-28 17:59:57 +0100
commit95a6af2a006e7160c958215c20e513ed29a0a76c (patch)
treea9a59028cf7a68b2cea32629c2666dbdf0af9717 /hw/intc/arm_gicv3_redist.c
parentMerge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into ... (diff)
parenttarget/arm: Use correct entrypoint for SVC taken from Hyp to Hyp (diff)
downloadqemu-95a6af2a006e7160c958215c20e513ed29a0a76c.tar.gz
qemu-95a6af2a006e7160c958215c20e513ed29a0a76c.tar.xz
qemu-95a6af2a006e7160c958215c20e513ed29a0a76c.zip
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20220128' into staging
target-arm queue: * Update copyright dates to 2022 * hw/armv7m: Fix broken VMStateDescription * hw/char/exynos4210_uart: Fix crash on trying to load VM state * rtc: Move RTC function prototypes to their own header * xlnx-versal-virt: Support PMC SLCR * xlnx-versal-virt: Support OSPI flash memory controller * scripts: Explain the difference between linux-headers and standard-headers * target/arm: Log CPU index in 'Taking exception' log * arm_gicv3_its: Various bugfixes and cleanups * arm_gicv3_its: Implement the missing MOVI and MOVALL commands * ast2600: Fix address mapping of second SPI controller * target/arm: Use correct entrypoint for SVC taken from Hyp to Hyp # gpg: Signature made Fri 28 Jan 2022 15:29:36 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20220128: (32 commits) target/arm: Use correct entrypoint for SVC taken from Hyp to Hyp hw/arm: ast2600: Fix address mapping of second SPI controller hw/intc/arm_gicv3_its: Implement MOVI hw/intc/arm_gicv3_its: Implement MOVALL hw/intc/arm_gicv3_its: Check table bounds against correct limit hw/intc/arm_gicv3_its: Make GITS_BASER<n> RAZ/WI for unimplemented registers hw/intc/arm_gicv3_its: Provide read accessor for translation_ops hw/intc/arm_gicv3: Set GICR_CTLR.CES if LPIs are supported hw/intc/arm_gicv3_redist: Remove unnecessary zero checks hw/intc/arm_gicv3_its: Sort ITS command list into numeric order hw/intc/arm_gicv3: Honour GICD_CTLR.EnableGrp1NS for LPIs hw/intc/arm_gicv3_its: Don't clear GITS_CWRITER on writes to GITS_CBASER hw/intc/arm_gicv3_its: Don't clear GITS_CREADR when GITS_CTLR.ENABLED is set hw/intc/arm_gicv3: Initialise dma_as in GIC, not ITS hw/intc/arm_gicv3_its: Add tracepoints target/arm: Log CPU index in 'Taking exception' log scripts: Explain the difference between linux-headers and standard-headers MAINTAINERS: Remove myself (for raspi). MAINTAINERS: Add an entry for Xilinx Versal OSPI hw/arm/xlnx-versal-virt: Connect mt35xu01g flashes to the OSPI ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc/arm_gicv3_redist.c')
-rw-r--r--hw/intc/arm_gicv3_redist.c115
1 files changed, 110 insertions, 5 deletions
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 99b11ca5ee..412a04f59c 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -591,8 +591,7 @@ void gicv3_redist_update_lpi_only(GICv3CPUState *cs)
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
GICD_TYPER_IDBITS);
- if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
- !cs->gicr_pendbaser) {
+ if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
return;
}
@@ -673,9 +672,8 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
GICD_TYPER_IDBITS);
- if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
- !cs->gicr_pendbaser || (irq > (1ULL << (idbits + 1)) - 1) ||
- irq < GICV3_LPI_INTID_START) {
+ if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ (irq > (1ULL << (idbits + 1)) - 1) || irq < GICV3_LPI_INTID_START) {
return;
}
@@ -683,6 +681,113 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
gicv3_redist_lpi_pending(cs, irq, level);
}
+void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq)
+{
+ /*
+ * Move the specified LPI's pending state from the source redistributor
+ * to the destination.
+ *
+ * If LPIs are disabled on dest this is CONSTRAINED UNPREDICTABLE:
+ * we choose to NOP. If LPIs are disabled on source there's nothing
+ * to be transferred anyway.
+ */
+ AddressSpace *as = &src->gic->dma_as;
+ uint64_t idbits;
+ uint32_t pendt_size;
+ uint64_t src_baddr;
+ uint8_t src_pend;
+
+ if (!(src->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ !(dest->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
+ return;
+ }
+
+ idbits = MIN(FIELD_EX64(src->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ GICD_TYPER_IDBITS);
+ idbits = MIN(FIELD_EX64(dest->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ idbits);
+
+ pendt_size = 1ULL << (idbits + 1);
+ if ((irq / 8) >= pendt_size) {
+ return;
+ }
+
+ src_baddr = src->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+
+ address_space_read(as, src_baddr + (irq / 8),
+ MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend));
+ if (!extract32(src_pend, irq % 8, 1)) {
+ /* Not pending on source, nothing to do */
+ return;
+ }
+ src_pend &= ~(1 << (irq % 8));
+ address_space_write(as, src_baddr + (irq / 8),
+ MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend));
+ if (irq == src->hpplpi.irq) {
+ /*
+ * We just made this LPI not-pending so only need to update
+ * if it was previously the highest priority pending LPI
+ */
+ gicv3_redist_update_lpi(src);
+ }
+ /* Mark it pending on the destination */
+ gicv3_redist_lpi_pending(dest, irq, 1);
+}
+
+void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest)
+{
+ /*
+ * We must move all pending LPIs from the source redistributor
+ * to the destination. That is, for every pending LPI X on
+ * src, we must set it not-pending on src and pending on dest.
+ * LPIs that are already pending on dest are not cleared.
+ *
+ * If LPIs are disabled on dest this is CONSTRAINED UNPREDICTABLE:
+ * we choose to NOP. If LPIs are disabled on source there's nothing
+ * to be transferred anyway.
+ */
+ AddressSpace *as = &src->gic->dma_as;
+ uint64_t idbits;
+ uint32_t pendt_size;
+ uint64_t src_baddr, dest_baddr;
+ int i;
+
+ if (!(src->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ !(dest->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
+ return;
+ }
+
+ idbits = MIN(FIELD_EX64(src->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ GICD_TYPER_IDBITS);
+ idbits = MIN(FIELD_EX64(dest->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ idbits);
+
+ pendt_size = 1ULL << (idbits + 1);
+ src_baddr = src->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+ dest_baddr = dest->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+
+ for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) {
+ uint8_t src_pend, dest_pend;
+
+ address_space_read(as, src_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &src_pend, sizeof(src_pend));
+ if (!src_pend) {
+ continue;
+ }
+ address_space_read(as, dest_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &dest_pend, sizeof(dest_pend));
+ dest_pend |= src_pend;
+ src_pend = 0;
+ address_space_write(as, src_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &src_pend, sizeof(src_pend));
+ address_space_write(as, dest_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &dest_pend, sizeof(dest_pend));
+ }
+
+ gicv3_redist_update_lpi(src);
+ gicv3_redist_update_lpi(dest);
+}
+
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
{
/* Update redistributor state for a change in an external PPI input line */