KVM: arm64: GICv4.1: Plumb SGI implementation selection in the distributor
The GICv4.1 architecture gives the hypervisor the option to let the guest choose whether it wants the good old SGIs with an active state, or the new, HW-based ones that do not have one. For this, plumb the configuration of SGIs into the GICv3 MMIO handling, present the GICD_TYPER2.nASSGIcap to the guest, and handle the GICD_CTLR.nASSGIreq setting. In order to be able to deal with the restore of a guest, also apply the GICD_CTLR.nASSGIreq setting at first run so that we can move the restored SGIs to the HW if that's what the guest had selected in a previous life. Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Zenghui Yu <yuzenghui@huawei.com> Link: https://lore.kernel.org/r/20200304203330.4967-21-maz@kernel.org
This commit is contained in:
parent
bacf2c6054
commit
2291ff2f2a
@ -3,6 +3,7 @@
|
|||||||
* VGICv3 MMIO handling functions
|
* VGICv3 MMIO handling functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
#include <linux/irqchip/arm-gic-v3.h>
|
#include <linux/irqchip/arm-gic-v3.h>
|
||||||
#include <linux/kvm.h>
|
#include <linux/kvm.h>
|
||||||
#include <linux/kvm_host.h>
|
#include <linux/kvm_host.h>
|
||||||
@ -70,6 +71,8 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
|
|||||||
if (vgic->enabled)
|
if (vgic->enabled)
|
||||||
value |= GICD_CTLR_ENABLE_SS_G1;
|
value |= GICD_CTLR_ENABLE_SS_G1;
|
||||||
value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
|
value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
|
||||||
|
if (vgic->nassgireq)
|
||||||
|
value |= GICD_CTLR_nASSGIreq;
|
||||||
break;
|
break;
|
||||||
case GICD_TYPER:
|
case GICD_TYPER:
|
||||||
value = vgic->nr_spis + VGIC_NR_PRIVATE_IRQS;
|
value = vgic->nr_spis + VGIC_NR_PRIVATE_IRQS;
|
||||||
@ -81,6 +84,10 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
|
|||||||
value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
|
value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case GICD_TYPER2:
|
||||||
|
if (kvm_vgic_global_state.has_gicv4_1)
|
||||||
|
value = GICD_TYPER2_nASSGIcap;
|
||||||
|
break;
|
||||||
case GICD_IIDR:
|
case GICD_IIDR:
|
||||||
value = (PRODUCT_ID_KVM << GICD_IIDR_PRODUCT_ID_SHIFT) |
|
value = (PRODUCT_ID_KVM << GICD_IIDR_PRODUCT_ID_SHIFT) |
|
||||||
(vgic->implementation_rev << GICD_IIDR_REVISION_SHIFT) |
|
(vgic->implementation_rev << GICD_IIDR_REVISION_SHIFT) |
|
||||||
@ -98,17 +105,43 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
|
|||||||
unsigned long val)
|
unsigned long val)
|
||||||
{
|
{
|
||||||
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
|
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
|
||||||
bool was_enabled = dist->enabled;
|
|
||||||
|
|
||||||
switch (addr & 0x0c) {
|
switch (addr & 0x0c) {
|
||||||
case GICD_CTLR:
|
case GICD_CTLR: {
|
||||||
|
bool was_enabled, is_hwsgi;
|
||||||
|
|
||||||
|
mutex_lock(&vcpu->kvm->lock);
|
||||||
|
|
||||||
|
was_enabled = dist->enabled;
|
||||||
|
is_hwsgi = dist->nassgireq;
|
||||||
|
|
||||||
dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
|
dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
|
||||||
|
|
||||||
|
/* Not a GICv4.1? No HW SGIs */
|
||||||
|
if (!kvm_vgic_global_state.has_gicv4_1)
|
||||||
|
val &= ~GICD_CTLR_nASSGIreq;
|
||||||
|
|
||||||
|
/* Dist stays enabled? nASSGIreq is RO */
|
||||||
|
if (was_enabled && dist->enabled) {
|
||||||
|
val &= ~GICD_CTLR_nASSGIreq;
|
||||||
|
val |= FIELD_PREP(GICD_CTLR_nASSGIreq, is_hwsgi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Switching HW SGIs? */
|
||||||
|
dist->nassgireq = val & GICD_CTLR_nASSGIreq;
|
||||||
|
if (is_hwsgi != dist->nassgireq)
|
||||||
|
vgic_v4_configure_vsgis(vcpu->kvm);
|
||||||
|
|
||||||
if (!was_enabled && dist->enabled)
|
if (!was_enabled && dist->enabled)
|
||||||
vgic_kick_vcpus(vcpu->kvm);
|
vgic_kick_vcpus(vcpu->kvm);
|
||||||
|
|
||||||
|
mutex_unlock(&vcpu->kvm->lock);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GICD_TYPER:
|
case GICD_TYPER:
|
||||||
|
case GICD_TYPER2:
|
||||||
case GICD_IIDR:
|
case GICD_IIDR:
|
||||||
|
/* This is at best for documentation purposes... */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,10 +150,22 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
|
|||||||
gpa_t addr, unsigned int len,
|
gpa_t addr, unsigned int len,
|
||||||
unsigned long val)
|
unsigned long val)
|
||||||
{
|
{
|
||||||
|
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
|
||||||
|
|
||||||
switch (addr & 0x0c) {
|
switch (addr & 0x0c) {
|
||||||
|
case GICD_TYPER2:
|
||||||
case GICD_IIDR:
|
case GICD_IIDR:
|
||||||
if (val != vgic_mmio_read_v3_misc(vcpu, addr, len))
|
if (val != vgic_mmio_read_v3_misc(vcpu, addr, len))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
case GICD_CTLR:
|
||||||
|
/* Not a GICv4.1? No HW SGIs */
|
||||||
|
if (!kvm_vgic_global_state.has_gicv4_1)
|
||||||
|
val &= ~GICD_CTLR_nASSGIreq;
|
||||||
|
|
||||||
|
dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
|
||||||
|
dist->nassgireq = val & GICD_CTLR_nASSGIreq;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vgic_mmio_write_v3_misc(vcpu, addr, len, val);
|
vgic_mmio_write_v3_misc(vcpu, addr, len, val);
|
||||||
|
@ -540,6 +540,8 @@ int vgic_v3_map_resources(struct kvm *kvm)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kvm_vgic_global_state.has_gicv4_1)
|
||||||
|
vgic_v4_configure_vsgis(kvm);
|
||||||
dist->ready = true;
|
dist->ready = true;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
Loading…
Reference in New Issue
Block a user