aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-02-01 19:31:55 +0000
committerPeter Maydell <peter.maydell@linaro.org>2022-02-08 10:56:28 +0000
commitb6f96009acc90a88db7f8913788f989b521eb938 (patch)
tree1fbc389f27ffef1f800ffaaeec7dbdc3432cf8b3 /hw
parent43530095e18fd16dcd51a4b385ad2a22c36f5698 (diff)
hw/intc/arm_gicv3_its: Use address_space_map() to access command queue packets
Currently the ITS accesses each 8-byte doubleword in a 4-doubleword command packet with a separate address_space_ldq_le() call. This is awkward because the individual command processing functions have ended up with code to handle "load more doublewords out of the packet", which is both unwieldy and also a potential source of bugs because it's not obvious when looking at a line that pulls a field out of the 'value' variable which of the 4 doublewords that variable currently holds. Switch to using address_space_map() to map the whole command packet at once and fish the four doublewords out of it. Then each process_* function can start with a few lines of code that extract the fields it cares about. This requires us to split out the guts of process_its_cmd() into a new do_process_its_cmd(), because we were previously overloading the value and offset arguments as a backdoor way to directly pass the devid and eventid from a write to GITS_TRANSLATER. The new do_process_its_cmd() takes those arguments directly, and process_its_cmd() is just a wrapper that does the "read fields from command packet" part. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220201193207.2771604-2-peter.maydell@linaro.org
Diffstat (limited to 'hw')
-rw-r--r--hw/intc/arm_gicv3_its.c206
-rw-r--r--hw/intc/gicv3_internal.h4
2 files changed, 61 insertions, 149 deletions
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index 51d9be4ae6..b74753fb8f 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -224,11 +224,9 @@ static uint64_t get_dte(GICv3ITSState *s, uint32_t devid, MemTxResult *res)
* 3. handling of ITS CLEAR command
* 4. handling of ITS DISCARD command
*/
-static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
- uint32_t offset, ItsCmdType cmd)
+static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
+ uint32_t eventid, ItsCmdType cmd)
{
- AddressSpace *as = &s->gicv3->dma_as;
- uint32_t devid, eventid;
MemTxResult res = MEMTX_OK;
bool dte_valid;
uint64_t dte = 0;
@@ -240,22 +238,6 @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
bool cte_valid = false;
uint64_t rdbase;
- if (cmd == NONE) {
- devid = offset;
- } else {
- devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
-
- 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;
- }
-
- eventid = (value & EVENTID_MASK);
-
if (devid >= s->dt.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid command attributes: devid %d>=%d",
@@ -342,11 +324,19 @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
}
return CMD_CONTINUE;
}
+static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt,
+ ItsCmdType cmd)
+{
+ uint32_t devid, eventid;
+
+ devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
+ eventid = cmdpkt[1] & EVENTID_MASK;
+ return do_process_its_cmd(s, devid, eventid, cmd);
+}
-static ItsCmdResult process_mapti(GICv3ITSState *s, uint64_t value,
- uint32_t offset, bool ignore_pInt)
+static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
+ bool ignore_pInt)
{
- AddressSpace *as = &s->gicv3->dma_as;
uint32_t devid, eventid;
uint32_t pIntid = 0;
uint64_t num_eventids;
@@ -357,32 +347,16 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, uint64_t value,
uint64_t dte = 0;
IteEntry ite = {};
- devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
- 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;
- }
-
- eventid = (value & EVENTID_MASK);
+ devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
+ eventid = cmdpkt[1] & EVENTID_MASK;
if (ignore_pInt) {
pIntid = eventid;
} else {
- pIntid = ((value & pINTID_MASK) >> pINTID_SHIFT);
+ pIntid = (cmdpkt[1] & pINTID_MASK) >> pINTID_SHIFT;
}
- 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;
- }
-
- icid = value & ICID_MASK;
+ icid = cmdpkt[2] & ICID_MASK;
if (devid >= s->dt.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -459,31 +433,18 @@ static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
return res == MEMTX_OK;
}
-static ItsCmdResult process_mapc(GICv3ITSState *s, uint32_t offset)
+static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
{
- AddressSpace *as = &s->gicv3->dma_as;
uint16_t icid;
uint64_t rdbase;
bool valid;
- MemTxResult res = MEMTX_OK;
- uint64_t value;
-
- offset += NUM_BYTES_IN_DW;
- offset += NUM_BYTES_IN_DW;
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
- MEMTXATTRS_UNSPECIFIED, &res);
+ icid = cmdpkt[2] & ICID_MASK;
- if (res != MEMTX_OK) {
- return CMD_STALL;
- }
-
- icid = value & ICID_MASK;
-
- rdbase = (value & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
+ rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
rdbase &= RDBASE_PROCNUM_MASK;
- valid = (value & CMD_FIELD_VALID_MASK);
+ valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
if ((icid >= s->ct.num_entries) || (rdbase >= s->gicv3->num_cpu)) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -532,39 +493,17 @@ static bool update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
return res == MEMTX_OK;
}
-static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
- uint32_t offset)
+static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
{
- AddressSpace *as = &s->gicv3->dma_as;
uint32_t devid;
uint8_t size;
uint64_t itt_addr;
bool valid;
- MemTxResult res = MEMTX_OK;
- devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
-
- 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;
- }
-
- size = (value & SIZE_MASK);
-
- 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;
- }
-
- itt_addr = (value & ITTADDR_MASK) >> ITTADDR_SHIFT;
-
- valid = (value & CMD_FIELD_VALID_MASK);
+ devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
+ size = cmdpkt[1] & SIZE_MASK;
+ itt_addr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
+ valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
if ((devid >= s->dt.num_entries) ||
(size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
@@ -582,23 +521,13 @@ 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)
+static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
{
- 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(cmdpkt[2], MOVALL_2, RDBASE1);
+ rd2 = FIELD_EX64(cmdpkt[3], MOVALL_3, RDBASE2);
- rd1 = FIELD_EX64(value, MOVALL_2, RDBASE1);
if (rd1 >= s->gicv3->num_cpu) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: RDBASE1 %" PRId64
@@ -606,15 +535,6 @@ static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,
__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
@@ -634,10 +554,8 @@ static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,
return CMD_CONTINUE;
}
-static ItsCmdResult process_movi(GICv3ITSState *s, uint64_t value,
- uint32_t offset)
+static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
{
- AddressSpace *as = &s->gicv3->dma_as;
MemTxResult res = MEMTX_OK;
uint32_t devid, eventid, intid;
uint16_t old_icid, new_icid;
@@ -648,23 +566,9 @@ static ItsCmdResult process_movi(GICv3ITSState *s, uint64_t value,
uint64_t num_eventids;
IteEntry ite = {};
- devid = FIELD_EX64(value, MOVI_0, DEVICEID);
-
- 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;
- }
- eventid = FIELD_EX64(value, MOVI_1, EVENTID);
-
- 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;
- }
- new_icid = FIELD_EX64(value, MOVI_2, ICID);
+ devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
+ eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
+ new_icid = FIELD_EX64(cmdpkt[2], MOVI_2, ICID);
if (devid >= s->dt.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -786,9 +690,7 @@ static void process_cmdq(GICv3ITSState *s)
uint32_t wr_offset = 0;
uint32_t rd_offset = 0;
uint32_t cq_offset = 0;
- uint64_t data;
AddressSpace *as = &s->gicv3->dma_as;
- MemTxResult res = MEMTX_OK;
uint8_t cmd;
int i;
@@ -816,28 +718,40 @@ static void process_cmdq(GICv3ITSState *s)
while (wr_offset != rd_offset) {
ItsCmdResult result = CMD_CONTINUE;
+ void *hostmem;
+ hwaddr buflen;
+ uint64_t cmdpkt[GITS_CMDQ_ENTRY_WORDS];
cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
- data = address_space_ldq_le(as, s->cq.base_addr + cq_offset,
- MEMTXATTRS_UNSPECIFIED, &res);
- if (res != MEMTX_OK) {
+
+ buflen = GITS_CMDQ_ENTRY_SIZE;
+ hostmem = address_space_map(as, s->cq.base_addr + cq_offset,
+ &buflen, false, MEMTXATTRS_UNSPECIFIED);
+ if (!hostmem || buflen != GITS_CMDQ_ENTRY_SIZE) {
+ if (hostmem) {
+ address_space_unmap(as, hostmem, buflen, false, 0);
+ }
s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
qemu_log_mask(LOG_GUEST_ERROR,
"%s: could not read command at 0x%" PRIx64 "\n",
__func__, s->cq.base_addr + cq_offset);
break;
}
+ for (i = 0; i < ARRAY_SIZE(cmdpkt); i++) {
+ cmdpkt[i] = ldq_le_p(hostmem + i * sizeof(uint64_t));
+ }
+ address_space_unmap(as, hostmem, buflen, false, 0);
- cmd = (data & CMD_MASK);
+ cmd = cmdpkt[0] & CMD_MASK;
trace_gicv3_its_process_command(rd_offset, cmd);
switch (cmd) {
case GITS_CMD_INT:
- result = process_its_cmd(s, data, cq_offset, INTERRUPT);
+ result = process_its_cmd(s, cmdpkt, INTERRUPT);
break;
case GITS_CMD_CLEAR:
- result = process_its_cmd(s, data, cq_offset, CLEAR);
+ result = process_its_cmd(s, cmdpkt, CLEAR);
break;
case GITS_CMD_SYNC:
/*
@@ -848,19 +762,19 @@ static void process_cmdq(GICv3ITSState *s)
*/
break;
case GITS_CMD_MAPD:
- result = process_mapd(s, data, cq_offset);
+ result = process_mapd(s, cmdpkt);
break;
case GITS_CMD_MAPC:
- result = process_mapc(s, cq_offset);
+ result = process_mapc(s, cmdpkt);
break;
case GITS_CMD_MAPTI:
- result = process_mapti(s, data, cq_offset, false);
+ result = process_mapti(s, cmdpkt, false);
break;
case GITS_CMD_MAPI:
- result = process_mapti(s, data, cq_offset, true);
+ result = process_mapti(s, cmdpkt, true);
break;
case GITS_CMD_DISCARD:
- result = process_its_cmd(s, data, cq_offset, DISCARD);
+ result = process_its_cmd(s, cmdpkt, DISCARD);
break;
case GITS_CMD_INV:
case GITS_CMD_INVALL:
@@ -875,10 +789,10 @@ static void process_cmdq(GICv3ITSState *s)
}
break;
case GITS_CMD_MOVI:
- result = process_movi(s, data, cq_offset);
+ result = process_movi(s, cmdpkt);
break;
case GITS_CMD_MOVALL:
- result = process_movall(s, data, cq_offset);
+ result = process_movall(s, cmdpkt);
break;
default:
break;
@@ -1032,15 +946,13 @@ static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
{
GICv3ITSState *s = (GICv3ITSState *)opaque;
bool result = true;
- uint32_t devid = 0;
trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
switch (offset) {
case GITS_TRANSLATER:
if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
- devid = attrs.requester_id;
- result = process_its_cmd(s, data, devid, NONE);
+ result = do_process_its_cmd(s, attrs.requester_id, data, NONE);
}
break;
default:
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index b1af26df9f..60c8617e4e 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -309,8 +309,8 @@ FIELD(GITS_TYPER, CIL, 36, 1)
#define LPI_CTE_ENABLED TABLE_ENTRY_VALID_MASK
#define LPI_PRIORITY_MASK 0xfc
-#define GITS_CMDQ_ENTRY_SIZE 32
-#define NUM_BYTES_IN_DW 8
+#define GITS_CMDQ_ENTRY_WORDS 4
+#define GITS_CMDQ_ENTRY_SIZE (GITS_CMDQ_ENTRY_WORDS * sizeof(uint64_t))
#define CMD_MASK 0xff