aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuc Michel <luc.michel@greensocs.com>2018-08-14 17:17:19 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-08-14 17:17:19 +0100
commit3bb0b03897abb634231366ce4e6651b56f16aa26 (patch)
tree3add5315c37b2029e5dae5b33783e4f8b27ca40c
parent67ce697ac84bd7f44348830df43f05195d5987e6 (diff)
downloadqemu-3bb0b03897abb634231366ce4e6651b56f16aa26.zip
qemu-3bb0b03897abb634231366ce4e6651b56f16aa26.tar.gz
qemu-3bb0b03897abb634231366ce4e6651b56f16aa26.tar.bz2
intc/arm_gic: Implement GICD_ISACTIVERn and GICD_ICACTIVERn registers
Implement GICD_ISACTIVERn and GICD_ICACTIVERn registers in the GICv2. Those registers allow to set or clear the active state of an IRQ in the distributor. Signed-off-by: Luc Michel <luc.michel@greensocs.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20180727095421.386-3-luc.michel@greensocs.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/intc/arm_gic.c61
1 files changed, 57 insertions, 4 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 9286236..53b749d 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -725,8 +725,16 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
}
}
} else if (offset < 0x400) {
- /* Interrupt Active. */
- irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
+ /* Interrupt Set/Clear Active. */
+ if (offset < 0x380) {
+ irq = (offset - 0x300) * 8;
+ } else if (s->revision == 2) {
+ irq = (offset - 0x380) * 8;
+ } else {
+ goto bad_reg;
+ }
+
+ irq += GIC_BASE_IRQ;
if (irq >= s->num_irq)
goto bad_reg;
res = 0;
@@ -1007,9 +1015,54 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
GIC_DIST_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
}
}
+ } else if (offset < 0x380) {
+ /* Interrupt Set Active. */
+ if (s->revision != 2) {
+ goto bad_reg;
+ }
+
+ irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
+ if (irq >= s->num_irq) {
+ goto bad_reg;
+ }
+
+ /* This register is banked per-cpu for PPIs */
+ int cm = irq < GIC_INTERNAL ? (1 << cpu) : ALL_CPU_MASK;
+
+ for (i = 0; i < 8; i++) {
+ if (s->security_extn && !attrs.secure &&
+ !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) {
+ continue; /* Ignore Non-secure access of Group0 IRQ */
+ }
+
+ if (value & (1 << i)) {
+ GIC_DIST_SET_ACTIVE(irq + i, cm);
+ }
+ }
} else if (offset < 0x400) {
- /* Interrupt Active. */
- goto bad_reg;
+ /* Interrupt Clear Active. */
+ if (s->revision != 2) {
+ goto bad_reg;
+ }
+
+ irq = (offset - 0x380) * 8 + GIC_BASE_IRQ;
+ if (irq >= s->num_irq) {
+ goto bad_reg;
+ }
+
+ /* This register is banked per-cpu for PPIs */
+ int cm = irq < GIC_INTERNAL ? (1 << cpu) : ALL_CPU_MASK;
+
+ for (i = 0; i < 8; i++) {
+ if (s->security_extn && !attrs.secure &&
+ !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) {
+ continue; /* Ignore Non-secure access of Group0 IRQ */
+ }
+
+ if (value & (1 << i)) {
+ GIC_DIST_CLEAR_ACTIVE(irq + i, cm);
+ }
+ }
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = (offset - 0x400) + GIC_BASE_IRQ;