aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio-v2.c4
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio.c56
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio.h11
3 files changed, 69 insertions, 2 deletions
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index d812c933708a..d5355b502f4a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -72,10 +72,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
72 vgic_mmio_read_rao, vgic_mmio_write_wi, 1, 72 vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
73 VGIC_ACCESS_32bit), 73 VGIC_ACCESS_32bit),
74 REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET, 74 REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
75 vgic_mmio_read_raz, vgic_mmio_write_wi, 1, 75 vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
76 VGIC_ACCESS_32bit), 76 VGIC_ACCESS_32bit),
77 REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR, 77 REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
78 vgic_mmio_read_raz, vgic_mmio_write_wi, 1, 78 vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
79 VGIC_ACCESS_32bit), 79 VGIC_ACCESS_32bit),
80 REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET, 80 REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
81 vgic_mmio_read_raz, vgic_mmio_write_wi, 1, 81 vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 1a977654681d..32ed8dbd93d6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -39,6 +39,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
39 /* Ignore */ 39 /* Ignore */
40} 40}
41 41
42/*
43 * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
44 * of the enabled bit, so there is only one function for both here.
45 */
46unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
47 gpa_t addr, unsigned int len)
48{
49 u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
50 u32 value = 0;
51 int i;
52
53 /* Loop over all IRQs affected by this read */
54 for (i = 0; i < len * 8; i++) {
55 struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
56
57 if (irq->enabled)
58 value |= (1U << i);
59 }
60
61 return value;
62}
63
64void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
65 gpa_t addr, unsigned int len,
66 unsigned long val)
67{
68 u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
69 int i;
70
71 for_each_set_bit(i, &val, len * 8) {
72 struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
73
74 spin_lock(&irq->irq_lock);
75 irq->enabled = true;
76 vgic_queue_irq_unlock(vcpu->kvm, irq);
77 }
78}
79
80void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
81 gpa_t addr, unsigned int len,
82 unsigned long val)
83{
84 u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
85 int i;
86
87 for_each_set_bit(i, &val, len * 8) {
88 struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
89
90 spin_lock(&irq->irq_lock);
91
92 irq->enabled = false;
93
94 spin_unlock(&irq->irq_lock);
95 }
96}
97
42static int match_region(const void *key, const void *elt) 98static int match_region(const void *key, const void *elt)
43{ 99{
44 const unsigned int offset = (unsigned long)key; 100 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 5b928d4b197e..57e19fe8df55 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -96,6 +96,17 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
96void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr, 96void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
97 unsigned int len, unsigned long val); 97 unsigned int len, unsigned long val);
98 98
99unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
100 gpa_t addr, unsigned int len);
101
102void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
103 gpa_t addr, unsigned int len,
104 unsigned long val);
105
106void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
107 gpa_t addr, unsigned int len,
108 unsigned long val);
109
99unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev); 110unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
100 111
101#endif 112#endif