diff options
author | Andre Przywara <andre.przywara@arm.com> | 2015-12-01 15:41:31 +0300 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2016-05-20 16:39:53 +0300 |
commit | 79717e4ac09c7c0c1414a3338fec457d982e9dd8 (patch) | |
tree | 352d0155516eac5ca0d5b00de3f6ee1feb8c3245 /virt/kvm | |
parent | 055658bf48fcc6afdf90810e7e8f4e98f486c0d2 (diff) | |
download | linux-79717e4ac09c7c0c1414a3338fec457d982e9dd8.tar.xz |
KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
The config register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Diffstat (limited to 'virt/kvm')
-rw-r--r-- | virt/kvm/arm/vgic/vgic-mmio-v2.c | 2 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-mmio.c | 47 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-mmio.h | 7 |
3 files changed, 55 insertions, 1 deletions
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c index d564a3068fcd..bb7389edadd3 100644 --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c @@ -96,7 +96,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = { vgic_mmio_read_raz, vgic_mmio_write_wi, 8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit), REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG, - vgic_mmio_read_raz, vgic_mmio_write_wi, 2, + vgic_mmio_read_config, vgic_mmio_write_config, 2, VGIC_ACCESS_32bit), REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT, vgic_mmio_read_raz, vgic_mmio_write_wi, 4, diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c index 6f4e05bada17..9de80be4d607 100644 --- a/virt/kvm/arm/vgic/vgic-mmio.c +++ b/virt/kvm/arm/vgic/vgic-mmio.c @@ -276,6 +276,53 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu, } } +unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu, + gpa_t addr, unsigned int len) +{ + u32 intid = VGIC_ADDR_TO_INTID(addr, 2); + u32 value = 0; + int i; + + for (i = 0; i < len * 4; i++) { + struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + + if (irq->config == VGIC_CONFIG_EDGE) + value |= (2U << (i * 2)); + } + + return value; +} + +void vgic_mmio_write_config(struct kvm_vcpu *vcpu, + gpa_t addr, unsigned int len, + unsigned long val) +{ + u32 intid = VGIC_ADDR_TO_INTID(addr, 2); + int i; + + for (i = 0; i < len * 4; i++) { + struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + + /* + * The configuration cannot be changed for SGIs in general, + * for PPIs this is IMPLEMENTATION DEFINED. The arch timer + * code relies on PPIs being level triggered, so we also + * make them read-only here. + */ + if (intid + i < VGIC_NR_PRIVATE_IRQS) + continue; + + spin_lock(&irq->irq_lock); + if (test_bit(i * 2 + 1, &val)) { + irq->config = VGIC_CONFIG_EDGE; + } else { + irq->config = VGIC_CONFIG_LEVEL; + irq->pending = irq->line_level | irq->soft_pending; + } + spin_unlock(&irq->irq_lock); + } +} + static int match_region(const void *key, const void *elt) { const unsigned int offset = (unsigned long)key; diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h index 7e73f10bf646..d1348acc0e72 100644 --- a/virt/kvm/arm/vgic/vgic-mmio.h +++ b/virt/kvm/arm/vgic/vgic-mmio.h @@ -136,6 +136,13 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len, unsigned long val); +unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu, + gpa_t addr, unsigned int len); + +void vgic_mmio_write_config(struct kvm_vcpu *vcpu, + gpa_t addr, unsigned int len, + unsigned long val); + unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev); #endif |