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
This commit is contained in:
parent
43530095e1
commit
b6f96009ac
@ -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_mapti(GICv3ITSState *s, uint64_t value,
|
||||
uint32_t offset, bool ignore_pInt)
|
||||
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, 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;
|
||||
icid = cmdpkt[2] & ICID_MASK;
|
||||
|
||||
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;
|
||||
|
||||
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:
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user