[PATCH v2 06/16] KVM: arm64: gic-v5: Add ITS MMIO state emulation
Sascha Bischoff
sascha.bischoff at arm.com
Mon Nov 2 11:44:44 PST 2026
In order to expose a virtual GICv5 ITS to the guest, KVM needs to
emulate the ITS CONFIG_FRAME and its translation-control registers.
Replace the placeholder ITS IODEV region with the GICv5 ITS register
layout and handlers for the architected MMIO state.
Provide read/write emulation for the ITS ID registers, IIDR, AIDR,
CR0, CR1, DT_BASER, DT_CFGR, DIDR, EIDR, invalidation registers,
READ_EVENT, GEN_EVENT, status registers, and the RAZ/WI MMIO
registers that KVM does not implement. Reuse the shared CoreSight
identification-register helper so the ITS reports the same component
identification values as the IRS.
At this stage the translation-triggering registers only record state.
Walking the guest's DT/ITT, generating READ_EVENT results, and
injecting GEN_EVENT LPIs are added by later commits.
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
arch/arm64/kvm/vgic/vgic-its-v5.c | 415 +++++++++++++++++++++++++++++-
include/kvm/arm_vgic.h | 77 ++++++
2 files changed, 490 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-its-v5.c b/arch/arm64/kvm/vgic/vgic-its-v5.c
index 5790b029f09b6..f04161c315b78 100644
--- a/arch/arm64/kvm/vgic/vgic-its-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-its-v5.c
@@ -6,19 +6,286 @@
#include <linux/kvm_host.h>
#include <linux/slab.h>
+#include <asm/kvm_arm.h>
#include <asm/kvm_mmu.h>
#include <kvm/arm_vgic.h>
+#include <linux/irqchip/arm-gic-v5.h>
+
#include "vgic.h"
#include "vgic-mmio.h"
+#define VITS_V5_DEVICE_ID_BITS 16
+#define VITS_V5_EVENT_ID_BITS 16
+
+static unsigned long vgic_v5_mmio_read_its_misc(struct kvm *kvm, void *dev,
+ gpa_t addr, unsigned int len)
+{
+ struct vgic_v5_its *its = dev;
+ u64 value = 0;
+ size_t offset = addr & (SZ_64K - 1);
+
+ guard(mutex)(&its->its_lock);
+
+ switch (offset) {
+ case GICV5_ITS_IDR0:
+ value = FIELD_PREP(GICV5_ITS_IDR0_ITSID, its->idr0.its_id);
+ value |= FIELD_PREP(GICV5_ITS_IDR0_SWE, its->idr0.swe);
+ value |= FIELD_PREP(GICV5_ITS_IDR0_MPAM, its->idr0.mpam);
+ value |= FIELD_PREP(GICV5_ITS_IDR0_MEC, its->idr0.mec);
+ value |= FIELD_PREP(GICV5_ITS_IDR0_PA_RANGE,
+ its->idr0.pa_range);
+ value |= FIELD_PREP(GICV5_ITS_IDR0_DOM, its->idr0.domain);
+ break;
+ case GICV5_ITS_IDR1:
+ value = FIELD_PREP(GICV5_ITS_IDR1_L2SZ, its->idr1.l2sz);
+ value |= FIELD_PREP(GICV5_ITS_IDR1_ITT_LEVELS,
+ its->idr1.itt_levels);
+ value |= FIELD_PREP(GICV5_ITS_IDR1_DT_LEVELS,
+ its->idr1.dt_levels);
+ value |= FIELD_PREP(GICV5_ITS_IDR1_DEVICEID_BITS,
+ its->idr1.device_id_bits);
+ break;
+ case GICV5_ITS_IDR2:
+ value = FIELD_PREP(GICV5_ITS_IDR2_XDMN_EVENTS,
+ its->idr2.xdmn_events);
+ value |= FIELD_PREP(GICV5_ITS_IDR2_EVENTID_BITS,
+ its->idr2.event_id_bits);
+ break;
+ case GICV5_ITS_IIDR:
+ value = FIELD_PREP(GICV5_ITS_IIDR_PRODUCT_ID, PRODUCT_ID_KVM);
+ value |= FIELD_PREP(GICV5_ITS_IIDR_VARIANT, 0);
+ value |= FIELD_PREP(GICV5_ITS_IIDR_REVISION, 0);
+ value |= FIELD_PREP(GICV5_ITS_IIDR_IMPLEMENTER,
+ IMPLEMENTER_ARM);
+ break;
+ case GICV5_ITS_AIDR:
+ value = FIELD_PREP(GICV5_ITS_AIDR_COMPONENT,
+ GICV5_AIDR_COMPONENT_ITS);
+ value |= FIELD_PREP(GICV5_ITS_AIDR_ARCHMAJORREV,
+ GICV5_AIDR_ARCH_MAJ_REV_V5);
+ value |= FIELD_PREP(GICV5_ITS_AIDR_ARCHMINORREV,
+ GICV5_AIDR_ARCH_MIN_REV_V0);
+ break;
+ case GICV5_ITS_CR0:
+ value = GICV5_ITS_CR0_IDLE;
+ value |= FIELD_PREP(GICV5_ITS_CR0_ITSEN, its->enabled);
+ break;
+ case GICV5_ITS_CR1:
+ value = FIELD_PREP(GICV5_ITS_CR1_ITT_RA, its->cr1.itt_ra);
+ value |= FIELD_PREP(GICV5_ITS_CR1_DT_RA, its->cr1.dt_ra);
+ value |= FIELD_PREP(GICV5_ITS_CR1_IC, its->cr1.ic);
+ value |= FIELD_PREP(GICV5_ITS_CR1_OC, its->cr1.oc);
+ value |= FIELD_PREP(GICV5_ITS_CR1_SH, its->cr1.sh);
+ break;
+ default:
+ return 0;
+ }
+
+ return value;
+}
+
+static void vgic_v5_mmio_write_its_misc(struct kvm *kvm, void *dev, gpa_t addr,
+ unsigned int len, unsigned long val)
+{
+ struct vgic_v5_its *its = dev;
+ size_t offset = addr & (SZ_64K - 1);
+
+ guard(mutex)(&its->its_lock);
+
+ switch (offset) {
+ case GICV5_ITS_CR0:
+ its->enabled = FIELD_GET(GICV5_ITS_CR0_ITSEN, val);
+ return;
+ case GICV5_ITS_CR1:
+ its->cr1.sh = FIELD_GET(GICV5_ITS_CR1_SH, val);
+ its->cr1.oc = FIELD_GET(GICV5_ITS_CR1_OC, val);
+ its->cr1.ic = FIELD_GET(GICV5_ITS_CR1_IC, val);
+ its->cr1.dt_ra = FIELD_GET(GICV5_ITS_CR1_DT_RA, val);
+ its->cr1.itt_ra = FIELD_GET(GICV5_ITS_CR1_ITT_RA, val);
+ return;
+ default:
+ return;
+ }
+}
+
+static void vgic_v5_write_its_dt_reg(struct vgic_v5_its *its, size_t offset,
+ unsigned long val)
+{
+ switch (offset) {
+ case GICV5_ITS_DT_CFGR:
+ its->dt_cfgr.device_id_bits =
+ FIELD_GET(GICV5_ITS_DT_CFGR_DEVICEID_BITS, val);
+ its->dt_cfgr.l2sz =
+ FIELD_GET(GICV5_ITS_DT_CFGR_L2SZ, val);
+ its->dt_cfgr.structure =
+ FIELD_GET(GICV5_ITS_DT_CFGR_STRUCTURE, val);
+ return;
+ case GICV5_ITS_DT_BASER:
+ its->dt_baser.addr =
+ FIELD_GET(GICV5_ITS_DT_BASER_ADDR_MASK, val)
+ << GICV5_ITS_DT_BASER_ADDR_SHIFT;
+ return;
+ }
+}
+
+static u64 vgic_v5_read_its_dt_baser(struct vgic_v5_its *its)
+{
+ return FIELD_PREP(GICV5_ITS_DT_BASER_ADDR_MASK,
+ its->dt_baser.addr >> GICV5_ITS_DT_BASER_ADDR_SHIFT);
+}
+
+static unsigned long vgic_v5_mmio_read_its_dt_itt(struct kvm *kvm, void *dev,
+ gpa_t addr, unsigned int len)
+{
+ struct vgic_v5_its *its = dev;
+ u64 value = 0;
+ size_t offset = addr & (SZ_64K - 1);
+
+ guard(mutex)(&its->its_lock);
+
+ switch (offset) {
+ case GICV5_ITS_DT_CFGR:
+ value = FIELD_PREP(GICV5_ITS_DT_CFGR_STRUCTURE,
+ its->dt_cfgr.structure);
+ value |= FIELD_PREP(GICV5_ITS_DT_CFGR_L2SZ,
+ its->dt_cfgr.l2sz);
+ value |= FIELD_PREP(GICV5_ITS_DT_CFGR_DEVICEID_BITS,
+ its->dt_cfgr.device_id_bits);
+ break;
+ case GICV5_ITS_DT_BASER:
+ case GICV5_ITS_DT_BASER + 4:
+ value = vgic_v5_read_its_dt_baser(its);
+ return extract_bytes(value, offset & 4, len);
+ case GICV5_ITS_DIDR:
+ case GICV5_ITS_DIDR + 4:
+ value = FIELD_PREP(GICV5_ITS_DIDR_DEVICEID,
+ its->didr.device_id);
+ return extract_bytes(value, offset & 4, len);
+ case GICV5_ITS_EIDR:
+ value = FIELD_PREP(GICV5_ITS_EIDR_EVENTID,
+ its->eidr.event_id);
+ break;
+ case GICV5_ITS_STATUSR:
+ value = GICV5_ITS_STATUSR_IDLE;
+ break;
+ case GICV5_ITS_SYNC_STATUSR:
+ value = GICV5_ITS_SYNC_STATUSR_IDLE;
+ break;
+ case GICV5_ITS_READ_EVENT_DATAR:
+ case GICV5_ITS_READ_EVENT_DATAR + 4:
+ value = FIELD_PREP(GICV5_ITS_READ_EVENT_DATAR_VIRT,
+ its->read_event_datar.virt);
+ value |= FIELD_PREP(GICV5_ITS_READ_EVENT_DATAR_VM_ID,
+ its->read_event_datar.vm_id);
+ value |= FIELD_PREP(GICV5_ITS_READ_EVENT_DATAR_VALID,
+ its->read_event_datar.valid);
+ value |= FIELD_PREP(GICV5_ITS_READ_EVENT_DATAR_LPI_ID,
+ its->read_event_datar.lpi_id);
+ return extract_bytes(value, offset & 4, len);
+ case GICV5_ITS_GEN_EVENT_EIDR:
+ value = FIELD_PREP(GICV5_ITS_GEN_EVENT_EIDR_EVENTID,
+ its->gen_event_eidr.event_id);
+ break;
+ case GICV5_ITS_GEN_EVENT_DIDR:
+ case GICV5_ITS_GEN_EVENT_DIDR + 4:
+ value = FIELD_PREP(GICV5_ITS_GEN_EVENT_DIDR_DEVICEID,
+ its->gen_event_didr.device_id);
+ return extract_bytes(value, offset & 4, len);
+ case GICV5_ITS_GEN_EVENT_STATUSR:
+ value = GICV5_ITS_GEN_EVENT_STATUSR_IDLE;
+ break;
+ default:
+ return 0;
+ }
+
+ return value;
+}
+
+static void vgic_v5_mmio_write_its_dt_itt(struct kvm *kvm, void *dev,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ struct vgic_v5_its *its = dev;
+ size_t offset = addr & (SZ_64K - 1);
+
+ guard(mutex)(&its->its_lock);
+
+ switch (offset) {
+ case GICV5_ITS_DT_CFGR:
+ if (!its->enabled)
+ vgic_v5_write_its_dt_reg(its, offset, val);
+ return;
+ case GICV5_ITS_DT_BASER:
+ case GICV5_ITS_DT_BASER + 4:
+ if (!its->enabled) {
+ u64 baser = vgic_v5_read_its_dt_baser(its);
+
+ baser = update_64bit_reg(baser, offset & 4, len, val);
+ vgic_v5_write_its_dt_reg(its, GICV5_ITS_DT_BASER,
+ baser);
+ }
+ return;
+ case GICV5_ITS_INV_DEVICER:
+ its->inv_devicer.l1 =
+ FIELD_GET(GICV5_ITS_INV_DEVICER_L1, val);
+ its->inv_devicer.event_id_bits =
+ FIELD_GET(GICV5_ITS_INV_DEVICER_EVENTID_BITS, val);
+ its->inv_devicer.i =
+ FIELD_GET(GICV5_ITS_INV_DEVICER_I, val);
+ return;
+ case GICV5_ITS_DIDR:
+ case GICV5_ITS_DIDR + 4:
+ if (offset & 4)
+ return;
+ its->didr.device_id = FIELD_GET(GICV5_ITS_DIDR_DEVICEID, val);
+ return;
+ case GICV5_ITS_EIDR:
+ its->eidr.event_id = FIELD_GET(GICV5_ITS_EIDR_EVENTID, val);
+ return;
+ case GICV5_ITS_INV_EVENTR:
+ its->inv_eventr.l1 =
+ FIELD_GET(GICV5_ITS_INV_EVENTR_L1, val);
+ its->inv_eventr.itt_l2sz =
+ FIELD_GET(GICV5_ITS_INV_EVENTR_ITT_L2SZ, val);
+ its->inv_eventr.i = FIELD_GET(GICV5_ITS_INV_EVENTR_I, val);
+ return;
+ case GICV5_ITS_SYNCR:
+ case GICV5_ITS_READ_EVENTR:
+ return;
+ case GICV5_ITS_GEN_EVENT_EIDR:
+ its->gen_event_eidr.event_id =
+ FIELD_GET(GICV5_ITS_GEN_EVENT_EIDR_EVENTID, val);
+ return;
+ case GICV5_ITS_GEN_EVENT_DIDR:
+ case GICV5_ITS_GEN_EVENT_DIDR + 4:
+ if (offset & 4)
+ return;
+ its->gen_event_didr.device_id =
+ FIELD_GET(GICV5_ITS_GEN_EVENT_DIDR_DEVICEID, val);
+ return;
+ case GICV5_ITS_GEN_EVENTR:
+ return;
+ default:
+ return;
+ }
+}
+
static unsigned long vgic_v5_mmio_read_its_raz(struct kvm *kvm, void *dev,
gpa_t addr, unsigned int len)
{
return 0;
}
+static unsigned long vgic_v5_its_coresight_read(struct kvm *kvm, void *dev,
+ gpa_t addr, unsigned int len)
+{
+ u32 offset = addr & (SZ_64K - 1);
+
+ return vgic_v5_handle_guest_coresight_idreg_read(offset);
+}
+
static void vgic_v5_mmio_write_its_wi(struct kvm *kvm, void *dev, gpa_t addr,
unsigned int len, unsigned long val)
{
@@ -31,11 +298,153 @@ static void vgic_v5_mmio_write_its_wi(struct kvm *kvm, void *dev, gpa_t addr,
}
static const struct vgic_register_region vgic_v5_its_registers[] = {
- REGISTER_ITS_V5_DESC(0, vgic_v5_mmio_read_its_raz,
- vgic_v5_mmio_write_its_wi, KVM_VGIC_V5_ITS_SIZE,
+ REGISTER_ITS_V5_DESC(GICV5_ITS_IDR0, vgic_v5_mmio_read_its_misc,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_IDR1, vgic_v5_mmio_read_its_misc,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_IDR2, vgic_v5_mmio_read_its_misc,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_IIDR, vgic_v5_mmio_read_its_misc,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_AIDR, vgic_v5_mmio_read_its_misc,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_CR0, vgic_v5_mmio_read_its_misc,
+ vgic_v5_mmio_write_its_misc, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_CR1, vgic_v5_mmio_read_its_misc,
+ vgic_v5_mmio_write_its_misc, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_DT_BASER,
+ vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_dt_itt, 8,
+ VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_DT_CFGR,
+ vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_dt_itt, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_DIDR, vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_dt_itt, 8,
+ VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_EIDR, vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_dt_itt, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_INV_EVENTR, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_dt_itt, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_INV_DEVICER, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_dt_itt, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_READ_EVENTR, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_dt_itt, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_READ_EVENT_DATAR,
+ vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_wi, 8,
+ VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_STATUSR, vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_SYNCR, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_dt_itt, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_SYNC_STATUSR,
+ vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_GEN_EVENT_DIDR,
+ vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_dt_itt, 8,
+ VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_GEN_EVENT_EIDR,
+ vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_dt_itt, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_GEN_EVENTR, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_dt_itt, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_GEN_EVENT_STATUSR,
+ vgic_v5_mmio_read_its_dt_itt,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_MEC_IDR, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_MEC_MECID_R, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_MPAM_IDR, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_MPAM_PARTID_R,
+ vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_wi, 4, VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_SWERR_STATUSR, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_wi, 8, VGIC_ACCESS_64bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_SWERR_SYNDROMER0,
+ vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_wi, 8, VGIC_ACCESS_64bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_SWERR_SYNDROMER1,
+ vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_wi, 8,
+ VGIC_ACCESS_64bit),
+ REGISTER_ITS_V5_DESC(GICV5_ITS_MPAM_PMGR, vgic_v5_mmio_read_its_raz,
+ vgic_v5_mmio_write_its_wi, 8, VGIC_ACCESS_64bit),
+ /* Split the ranges so KVM_HAS_DEVICE_ATTR only reports actual registers. */
+ REGISTER_ITS_V5_DESC(GICV5_CORESIGHT_DEVARCH,
+ vgic_v5_its_coresight_read,
+ vgic_v5_mmio_write_its_wi, 4,
+ VGIC_ACCESS_32bit),
+ REGISTER_ITS_V5_DESC(GICV5_CORESIGHT_PIDR4,
+ vgic_v5_its_coresight_read,
+ vgic_v5_mmio_write_its_wi,
+ GICV5_CORESIGHT_PIDR_CIDR_SIZE,
VGIC_ACCESS_32bit),
};
+static void vgic_v5_its_reset(struct vgic_v5_its *its)
+{
+ u64 mmfr0;
+
+ its->enabled = false;
+
+ mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+ its->idr0.pa_range = cpuid_feature_extract_unsigned_field(
+ mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
+ its->idr0.domain = GICV5_ITS_IDR0_DOMAIN_NON_SECURE;
+ its->idr0.mec = 0;
+ its->idr0.mpam = 0;
+ its->idr0.swe = 0;
+ its->idr0.its_id = 0;
+
+ its->idr1.dt_levels = 1;
+ its->idr1.itt_levels = 1;
+ its->idr1.l2sz = 0;
+ its->idr2.xdmn_events = 0;
+
+ its->cr1.sh = 0;
+ its->cr1.oc = 0;
+ its->cr1.ic = 0;
+ its->cr1.dt_ra = false;
+ its->cr1.itt_ra = false;
+
+ its->idr1.device_id_bits = VITS_V5_DEVICE_ID_BITS;
+ its->idr2.event_id_bits = VITS_V5_EVENT_ID_BITS;
+
+ its->dt_cfgr.device_id_bits = 0;
+ its->dt_cfgr.l2sz = 0;
+ its->dt_cfgr.structure = false;
+ its->dt_baser.addr = 0;
+
+ its->inv_devicer.l1 = false;
+ its->inv_devicer.event_id_bits = 0;
+ its->inv_devicer.i = false;
+ its->didr.device_id = 0;
+ its->eidr.event_id = 0;
+ its->inv_eventr.l1 = false;
+ its->inv_eventr.itt_l2sz = 0;
+ its->inv_eventr.i = false;
+
+ its->read_event_datar.lpi_id = 0;
+ its->read_event_datar.valid = false;
+ its->read_event_datar.vm_id = 0;
+ its->read_event_datar.virt = false;
+ its->gen_event_eidr.event_id = 0;
+ its->gen_event_didr.device_id = 0;
+
+}
+
static int vgic_v5_its_create(struct kvm_device *dev, u32 type)
{
struct vgic_v5_its *its;
@@ -60,6 +469,8 @@ static int vgic_v5_its_create(struct kvm_device *dev, u32 type)
its->vgic_v5_its_base = VGIC_ADDR_UNDEF;
its->dev = dev;
+ vgic_v5_its_reset(its);
+
dev->kvm->arch.vgic.msis_require_devid = true;
dev->kvm->arch.vgic.its_model = KVM_DEV_TYPE_ARM_VGIC_V5;
dev->private = its;
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 4f9909d6c5b11..53aa5c857e295 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -507,6 +507,83 @@ struct vgic_v5_its {
struct vgic_io_device iodev;
struct kvm_device *dev;
+ bool enabled;
+
+ /* ITS state - used for registers etc */
+ struct its_idr0 {
+ u8 domain;
+ u8 pa_range;
+ bool mec;
+ bool mpam;
+ bool swe;
+ u16 its_id;
+ } idr0;
+
+ struct its_idr1 {
+ u8 device_id_bits;
+ u8 dt_levels;
+ u8 itt_levels;
+ u8 l2sz;
+ } idr1;
+
+ struct its_idr2 {
+ u8 event_id_bits;
+ u8 xdmn_events;
+ } idr2;
+
+ struct its_cr1 {
+ u8 sh;
+ u8 oc;
+ u8 ic;
+ bool dt_ra;
+ bool itt_ra;
+ } cr1;
+
+ struct its_dt_cfgr {
+ u8 device_id_bits;
+ u8 l2sz;
+ bool structure;
+ } dt_cfgr;
+
+ struct its_dt_baser {
+ u64 addr;
+ } dt_baser;
+
+ struct its_inv_devicer {
+ bool l1;
+ u8 event_id_bits;
+ bool i;
+ } inv_devicer;
+
+ struct its_didr {
+ u32 device_id;
+ } didr;
+
+ struct its_eidr {
+ u16 event_id;
+ } eidr;
+
+ struct its_inv_eventr {
+ bool l1;
+ u8 itt_l2sz;
+ bool i;
+ } inv_eventr;
+
+ struct its_read_event_datar {
+ u32 lpi_id;
+ bool valid;
+ u16 vm_id;
+ bool virt;
+ } read_event_datar;
+
+ struct its_gen_event_eidr {
+ u16 event_id;
+ } gen_event_eidr;
+
+ struct its_gen_event_didr {
+ u32 device_id;
+ } gen_event_didr;
+
/* Protects the device in general */
struct mutex its_lock;
};
--
2.34.1
More information about the linux-arm-kernel
mailing list