[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 20/61] hw/intc/arm_gicv3_its: Implement VMOVI
From: |
Peter Maydell |
Subject: |
[PULL 20/61] hw/intc/arm_gicv3_its: Implement VMOVI |
Date: |
Fri, 22 Apr 2022 11:03:51 +0100 |
Implement the GICv4 VMOVI command, which moves the pending state
of a virtual interrupt from one redistributor to another. As with
MOVI, we handle the "parse and validate command arguments and
table lookups" part in the ITS source file, and pass the final
results to a function in the redistributor which will do the
actual operation. As with the "make a VLPI pending" change,
for the moment we leave that redistributor function as a stub,
to be implemented in a later commit.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20220408141550.1271295-21-peter.maydell@linaro.org
---
hw/intc/gicv3_internal.h | 23 +++++++++++
hw/intc/arm_gicv3_its.c | 82 ++++++++++++++++++++++++++++++++++++++
hw/intc/arm_gicv3_redist.c | 10 +++++
hw/intc/trace-events | 1 +
4 files changed, 116 insertions(+)
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 2f653a9b917..050e19d133b 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -329,6 +329,7 @@ FIELD(GITS_TYPER, CIL, 36, 1)
#define GITS_CMD_INVALL 0x0D
#define GITS_CMD_MOVALL 0x0E
#define GITS_CMD_DISCARD 0x0F
+#define GITS_CMD_VMOVI 0x21
#define GITS_CMD_VMOVP 0x22
#define GITS_CMD_VSYNC 0x25
#define GITS_CMD_VMAPP 0x29
@@ -403,6 +404,13 @@ FIELD(VMOVP_2, RDBASE, 16, 36)
FIELD(VMOVP_2, DB, 63, 1) /* GICv4.1 only */
FIELD(VMOVP_3, DEFAULT_DOORBELL, 0, 32) /* GICv4.1 only */
+/* VMOVI command fields */
+FIELD(VMOVI_0, DEVICEID, 32, 32)
+FIELD(VMOVI_1, EVENTID, 0, 32)
+FIELD(VMOVI_1, VPEID, 32, 16)
+FIELD(VMOVI_2, D, 0, 1)
+FIELD(VMOVI_2, DOORBELL, 32, 32)
+
/*
* 12 bytes Interrupt translation Table Entry size
* as per Table 5.3 in GICv3 spec
@@ -614,6 +622,21 @@ void gicv3_redist_mov_lpi(GICv3CPUState *src,
GICv3CPUState *dest, int irq);
* by the ITS MOVALL command.
*/
void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest);
+/**
+ * gicv3_redist_mov_vlpi:
+ * @src: source redistributor
+ * @src_vptaddr: (guest) address of source VLPI table
+ * @dest: destination redistributor
+ * @dest_vptaddr: (guest) address of destination VLPI table
+ * @irq: VLPI to update
+ * @doorbell: doorbell for destination (1023 for "no doorbell")
+ *
+ * Move the pending state of the specified VLPI from @src to @dest,
+ * as required by the ITS VMOVI command.
+ */
+void gicv3_redist_mov_vlpi(GICv3CPUState *src, uint64_t src_vptaddr,
+ GICv3CPUState *dest, uint64_t dest_vptaddr,
+ int irq, int doorbell);
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
void gicv3_init_cpuif(GICv3State *s);
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index f7c01c2be19..c718ef2ff92 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -1084,6 +1084,85 @@ static ItsCmdResult process_vmovp(GICv3ITSState *s,
const uint64_t *cmdpkt)
return cbdata.result;
}
+static ItsCmdResult process_vmovi(GICv3ITSState *s, const uint64_t *cmdpkt)
+{
+ uint32_t devid, eventid, vpeid, doorbell;
+ bool doorbell_valid;
+ DTEntry dte;
+ ITEntry ite;
+ VTEntry old_vte, new_vte;
+ ItsCmdResult cmdres;
+
+ if (!its_feature_virtual(s)) {
+ return CMD_CONTINUE;
+ }
+
+ devid = FIELD_EX64(cmdpkt[0], VMOVI_0, DEVICEID);
+ eventid = FIELD_EX64(cmdpkt[1], VMOVI_1, EVENTID);
+ vpeid = FIELD_EX64(cmdpkt[1], VMOVI_1, VPEID);
+ doorbell_valid = FIELD_EX64(cmdpkt[2], VMOVI_2, D);
+ doorbell = FIELD_EX64(cmdpkt[2], VMOVI_2, DOORBELL);
+
+ trace_gicv3_its_cmd_vmovi(devid, eventid, vpeid, doorbell_valid, doorbell);
+
+ if (doorbell_valid && !valid_doorbell(doorbell)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid doorbell 0x%x\n", __func__, doorbell);
+ return CMD_CONTINUE;
+ }
+
+ cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte);
+ if (cmdres != CMD_CONTINUE_OK) {
+ return cmdres;
+ }
+
+ if (ite.inttype != ITE_INTTYPE_VIRTUAL) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: ITE is not for virtual
interrupt\n",
+ __func__);
+ return CMD_CONTINUE;
+ }
+
+ cmdres = lookup_vte(s, __func__, ite.vpeid, &old_vte);
+ if (cmdres != CMD_CONTINUE_OK) {
+ return cmdres;
+ }
+ cmdres = lookup_vte(s, __func__, vpeid, &new_vte);
+ if (cmdres != CMD_CONTINUE_OK) {
+ return cmdres;
+ }
+
+ if (!intid_in_lpi_range(ite.intid) ||
+ ite.intid >= (1ULL << (old_vte.vptsize + 1)) ||
+ ite.intid >= (1ULL << (new_vte.vptsize + 1))) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: ITE intid 0x%x out of range\n",
+ __func__, ite.intid);
+ return CMD_CONTINUE;
+ }
+
+ ite.vpeid = vpeid;
+ if (doorbell_valid) {
+ ite.doorbell = doorbell;
+ }
+
+ /*
+ * Move the LPI from the old redistributor to the new one. We don't
+ * need to do anything if the guest somehow specified the
+ * same pending table for source and destination.
+ */
+ if (old_vte.vptaddr != new_vte.vptaddr) {
+ gicv3_redist_mov_vlpi(&s->gicv3->cpu[old_vte.rdbase],
+ old_vte.vptaddr << 16,
+ &s->gicv3->cpu[new_vte.rdbase],
+ new_vte.vptaddr << 16,
+ ite.intid,
+ ite.doorbell);
+ }
+
+ /* Update the ITE to the new VPEID and possibly doorbell values */
+ return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
+}
+
static ItsCmdResult process_inv(GICv3ITSState *s, const uint64_t *cmdpkt)
{
uint32_t devid, eventid;
@@ -1282,6 +1361,9 @@ static void process_cmdq(GICv3ITSState *s)
case GITS_CMD_VMOVP:
result = process_vmovp(s, cmdpkt);
break;
+ case GITS_CMD_VMOVI:
+ result = process_vmovi(s, cmdpkt);
+ break;
default:
trace_gicv3_its_cmd_unknown(cmd);
break;
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 856494b4e8f..dc25997d1f9 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -808,6 +808,16 @@ void gicv3_redist_process_vlpi(GICv3CPUState *cs, int irq,
uint64_t vptaddr,
*/
}
+void gicv3_redist_mov_vlpi(GICv3CPUState *src, uint64_t src_vptaddr,
+ GICv3CPUState *dest, uint64_t dest_vptaddr,
+ int irq, int doorbell)
+{
+ /*
+ * The redistributor handling for moving a VLPI will be added
+ * in a subsequent commit.
+ */
+}
+
void gicv3_redist_inv_vlpi(GICv3CPUState *cs, int irq, uint64_t vptaddr)
{
/*
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index ae4a3cfb004..9894756e55a 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -193,6 +193,7 @@ gicv3_its_cmd_vmapti(uint32_t devid, uint32_t eventid,
uint32_t vpeid, uint32_t
gicv3_its_cmd_vmapp(uint32_t vpeid, uint64_t rdbase, int valid, uint64_t
vptaddr, uint32_t vptsize) "GICv3 ITS: command VMAPP vPEID 0x%x RDbase 0x%"
PRIx64 " V %d VPT_addr 0x%" PRIx64 " VPT_size 0x%x"
gicv3_its_cmd_vmovp(uint32_t vpeid, uint64_t rdbase) "GICv3 ITS: command VMOVP
vPEID 0x%x RDbase 0x%" PRIx64
gicv3_its_cmd_vsync(void) "GICv3 ITS: command VSYNC"
+gicv3_its_cmd_vmovi(uint32_t devid, uint32_t eventid, uint32_t vpeid, int
dbvalid, uint32_t doorbell) "GICv3 ITS: command VMOVI DeviceID 0x%x EventID
0x%x vPEID 0x%x D %d Dbell_pINTID 0x%x"
gicv3_its_cmd_unknown(unsigned cmd) "GICv3 ITS: unknown command 0x%x"
gicv3_its_cte_read(uint32_t icid, int valid, uint32_t rdbase) "GICv3 ITS:
Collection Table read for ICID 0x%x: valid %d RDBase 0x%x"
gicv3_its_cte_write(uint32_t icid, int valid, uint32_t rdbase) "GICv3 ITS:
Collection Table write for ICID 0x%x: valid %d RDBase 0x%x"
--
2.25.1
- [PULL 17/61] hw/intc/arm_gicv3_its: Implement VSYNC, (continued)
- [PULL 17/61] hw/intc/arm_gicv3_its: Implement VSYNC, Peter Maydell, 2022/04/22
- [PULL 15/61] hw/intc/arm_gicv3: Keep pointers to every connected ITS, Peter Maydell, 2022/04/22
- [PULL 03/61] hw/intc/arm_gicv3: Insist that redist region capacity matches CPU count, Peter Maydell, 2022/04/22
- [PULL 02/61] hw/intc/arm_gicv3: Sanity-check num-cpu property, Peter Maydell, 2022/04/22
- [PULL 08/61] hw/intc/arm_gicv3_its: Implement VMAPI and VMAPTI, Peter Maydell, 2022/04/22
- [PULL 11/61] hw/intc/arm_gicv3_its: Factor out "find ITE given devid, eventid", Peter Maydell, 2022/04/22
- [PULL 13/61] hw/intc/arm_gicv3_its: Split out process_its_cmd() physical interrupt code, Peter Maydell, 2022/04/22
- [PULL 19/61] hw/intc/arm_gicv3_its: Implement INV for virtual interrupts, Peter Maydell, 2022/04/22
- [PULL 14/61] hw/intc/arm_gicv3_its: Handle virtual interrupts in process_its_cmd(), Peter Maydell, 2022/04/22
- [PULL 21/61] hw/intc/arm_gicv3_its: Implement VINVALL, Peter Maydell, 2022/04/22
- [PULL 20/61] hw/intc/arm_gicv3_its: Implement VMOVI,
Peter Maydell <=
- [PULL 26/61] hw/intc/arm_gicv3_cpuif: Don't recalculate maintenance irq unnecessarily, Peter Maydell, 2022/04/22
- [PULL 24/61] hw/intc/arm_gicv3_cpuif: Split "update vIRQ/vFIQ" from gicv3_cpuif_virt_update(), Peter Maydell, 2022/04/22
- [PULL 16/61] hw/intc/arm_gicv3_its: Implement VMOVP, Peter Maydell, 2022/04/22
- [PULL 18/61] hw/intc/arm_gicv3_its: Implement INV command properly, Peter Maydell, 2022/04/22
- [PULL 22/61] hw/intc/arm_gicv3: Implement GICv4's new redistributor frame, Peter Maydell, 2022/04/22
- [PULL 23/61] hw/intc/arm_gicv3: Implement new GICv4 redistributor registers, Peter Maydell, 2022/04/22
- [PULL 25/61] hw/intc/arm_gicv3_cpuif: Support vLPIs, Peter Maydell, 2022/04/22
- [PULL 27/61] hw/intc/arm_gicv3_redist: Factor out "update hpplpi for one LPI" logic, Peter Maydell, 2022/04/22
- [PULL 29/61] hw/intc/arm_gicv3_redist: Recalculate hppvlpi on VPENDBASER writes, Peter Maydell, 2022/04/22
- [PULL 34/61] hw/intc/arm_gicv3_redist: Implement gicv3_redist_mov_vlpi(), Peter Maydell, 2022/04/22