[PATCH v2 1/4] KVM: arm64: Allow userspace to write GICD_TYPER.num_LPIs
Zhou Wang
wangzhou1 at hisilicon.com
Sun Aug 24 19:39:51 PDT 2025
Allow userspace to write GICD_TYPER.num_LPIs. If GICD_TYPER.num_LPIs is
0, number of LPIs is indicated by GICD_TYPER.IDbits, so the default
value of GICD_TYPER.num_LPIs is still set as 0.
Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
---
arch/arm64/kvm/vgic/vgic-init.c | 2 ++
arch/arm64/kvm/vgic/vgic-its.c | 9 +++++++--
arch/arm64/kvm/vgic/vgic-kvm-device.c | 1 +
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 16 ++++++++++++++++
include/kvm/arm_vgic.h | 1 +
include/linux/irqchip/arm-gic-v3.h | 1 +
6 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 1e680ad6e863..46468cb97536 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -389,6 +389,7 @@ int vgic_init(struct kvm *kvm)
/* freeze the number of spis */
if (!dist->nr_spis)
dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
+ dist->nr_lpis = 0;
ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
if (ret)
@@ -428,6 +429,7 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
kfree(dist->spis);
dist->spis = NULL;
dist->nr_spis = 0;
+ dist->nr_lpis = 0;
dist->vgic_dist_base = VGIC_ADDR_UNDEF;
if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
index 7368c13f16b7..d8ee617cfa6f 100644
--- a/arch/arm64/kvm/vgic/vgic-its.c
+++ b/arch/arm64/kvm/vgic/vgic-its.c
@@ -377,9 +377,14 @@ static void update_affinity_collection(struct kvm *kvm, struct vgic_its *its,
}
}
-static u32 max_lpis_propbaser(u64 propbaser)
+static u32 max_lpis_propbaser(struct vgic_dist *dist)
{
+ u64 propbaser = dist->propbaser;
int nr_idbits = (propbaser & 0x1f) + 1;
+ int nr_lpis = dist->nr_lpis;
+
+ if (nr_lpis)
+ return min(8192 + nr_lpis, 1 << nr_idbits);
return 1U << min(nr_idbits, INTERRUPT_ID_BITS_ITS);
}
@@ -1047,7 +1052,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
else
lpi_nr = event_id;
if (lpi_nr < GIC_LPI_OFFSET ||
- lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser))
+ lpi_nr >= max_lpis_propbaser(&kvm->arch.vgic))
return E_ITS_MAPTI_PHYSICALID_OOR;
/* If there is an existing mapping, behavior is UNPREDICTABLE. */
diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index 3d1a776b716d..f4268b60c4dd 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -514,6 +514,7 @@ static bool reg_allowed_pre_init(struct kvm_device_attr *attr)
return false;
switch (attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK) {
+ case GICD_TYPER:
case GICD_IIDR:
case GICD_TYPER2:
return true;
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index a3ef185209e9..3a53b63f7b20 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -90,6 +90,8 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
if (vgic_has_its(vcpu->kvm)) {
value |= (INTERRUPT_ID_BITS_ITS - 1) << 19;
value |= GICD_TYPER_LPIS;
+ if (vgic->nr_lpis)
+ value |= (ilog2(vgic->nr_lpis) - 1) << 11;
} else {
value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
}
@@ -167,6 +169,20 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
u32 reg;
switch (addr & 0x0c) {
+ case GICD_TYPER:
+ reg = vgic_mmio_read_v3_misc(vcpu, addr, len);
+
+ if (reg == val)
+ return 0;
+ if (vgic_initialized(vcpu->kvm))
+ return -EBUSY;
+ if ((reg ^ val) & ~GICD_TYPER_NUM_LPIS_MASK)
+ return -EINVAL;
+ if (GICD_TYPER_NUM_LPIS(val) > INTERRUPT_ID_BITS_ITS)
+ return -EINVAL;
+
+ dist->nr_lpis = 2 ^ GICD_TYPER_NUM_LPIS(val);
+ return 0;
case GICD_TYPER2:
reg = vgic_mmio_read_v3_misc(vcpu, addr, len);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 404883c7af6e..774bfd008230 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -303,6 +303,7 @@ struct vgic_dist {
* else.
*/
struct its_vm its_vm;
+ int nr_lpis;
};
struct vgic_v2_cpu_if {
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 70c0948f978e..517d9f2edc44 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -85,6 +85,7 @@
#define GICD_TYPER_ESPI (1U << 8)
#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1)
+#define GICD_TYPER_NUM_LPIS_MASK GENMASK(15, 11)
#define GICD_TYPER_NUM_LPIS(typer) ((((typer) >> 11) & 0x1f) + 1)
#define GICD_TYPER_SPIS(typer) ((((typer) & 0x1f) + 1) * 32)
#define GICD_TYPER_ESPIS(typer) \
--
2.33.0
More information about the linux-arm-kernel
mailing list