aboutsummaryrefslogtreecommitdiff
path: root/hw/intc/arm_gicv3_its.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-01-22 18:24:43 +0000
committerPeter Maydell <peter.maydell@linaro.org>2022-01-28 14:29:47 +0000
commitf6d1d9b4074d64de92f3ab4dfa50dc19548fdfd7 (patch)
tree1c1a0a2c6b16d600d497cd94ac7db43f1cde0ffb /hw/intc/arm_gicv3_its.c
parent8b8bb0146b5383188e045ab75a53a0e179614cad (diff)
hw/intc/arm_gicv3_its: Implement MOVALL
Implement the ITS MOVALL command, which takes all the pending interrupts on a source redistributor and makes the not-pending on that source redistributor and pending on a destination redistributor. This is a GICv3 ITS command which we forgot to implement. (It is not used by Linux guests.) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220122182444.724087-14-peter.maydell@linaro.org
Diffstat (limited to 'hw/intc/arm_gicv3_its.c')
-rw-r--r--hw/intc/arm_gicv3_its.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index 3f2ead4536..ebc0403b3c 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -582,6 +582,58 @@ static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
return update_dte(s, devid, valid, size, itt_addr) ? CMD_CONTINUE : CMD_STALL;
}
+static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,
+ uint32_t offset)
+{
+ AddressSpace *as = &s->gicv3->dma_as;
+ MemTxResult res = MEMTX_OK;
+ uint64_t rd1, rd2;
+
+ /* No fields in dwords 0 or 1 */
+ offset += NUM_BYTES_IN_DW;
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ rd1 = FIELD_EX64(value, MOVALL_2, RDBASE1);
+ if (rd1 >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: RDBASE1 %" PRId64
+ " out of range (must be less than %d)\n",
+ __func__, rd1, s->gicv3->num_cpu);
+ return CMD_CONTINUE;
+ }
+
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ rd2 = FIELD_EX64(value, MOVALL_3, RDBASE2);
+ if (rd2 >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: RDBASE2 %" PRId64
+ " out of range (must be less than %d)\n",
+ __func__, rd2, s->gicv3->num_cpu);
+ return CMD_CONTINUE;
+ }
+
+ if (rd1 == rd2) {
+ /* Move to same target must succeed as a no-op */
+ return CMD_CONTINUE;
+ }
+
+ /* Move all pending LPIs from redistributor 1 to redistributor 2 */
+ gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]);
+
+ return CMD_CONTINUE;
+}
+
/*
* Current implementation blocks until all
* commands are processed
@@ -679,6 +731,9 @@ static void process_cmdq(GICv3ITSState *s)
gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
}
break;
+ case GITS_CMD_MOVALL:
+ result = process_movall(s, data, cq_offset);
+ break;
default:
break;
}