[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH RFC V5 4/9] hw/intc: arm_gicv3_dist
From: |
Shlomo Pongratz |
Subject: |
[Qemu-devel] [PATCH RFC V5 4/9] hw/intc: arm_gicv3_dist |
Date: |
Tue, 20 Oct 2015 20:22:07 +0300 |
From: Shlomo Pongratz <address@hidden>
Signed-off-by: Shlomo Pongratz <address@hidden>
---
hw/intc/Makefile.objs | 1 +
hw/intc/arm_gicv3_dist.c | 655 +++++++++++++++++++++++++++++++++++++++++++++++
hw/intc/arm_gicv3_dist.h | 9 +
hw/intc/gicv3_internal.h | 8 +
4 files changed, 673 insertions(+)
create mode 100644 hw/intc/arm_gicv3_dist.c
create mode 100644 hw/intc/arm_gicv3_dist.h
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index fb6494f..cdfb877 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -15,6 +15,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_interrupts.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpu_interface.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
common-obj-$(CONFIG_OPENPIC) += openpic.o
obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
new file mode 100644
index 0000000..973a1b3
--- /dev/null
+++ b/hw/intc/arm_gicv3_dist.c
@@ -0,0 +1,655 @@
+#include "gicv3_internal.h"
+#include "qom/cpu.h"
+#include "arm_gicv3_dist.h"
+#include "arm_gicv3_interrupts.h"
+
+static const uint8_t gic_dist_ids[] = {
+ 0x44, 0x00, 0x00, 0x00, 0x092, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1
+};
+
+static uint64_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
+{
+ GICv3State *s = (GICv3State *)opaque;
+ uint64_t res;
+ int irq;
+ int i;
+ int cpu;
+ int cm;
+
+ cpu = gic_get_current_cpu(s);
+ if (offset < 0x100) {
+ if (offset == 0) {/* GICD_CTLR */
+ /* GICv3 5.3.20 without GICV2 backwards compatibility */
+ if (s->security_levels > 1) {
+ /* Support TWO security states */
+ if (attrs.secure) {
+ return s->ctlr;
+ } else {
+ /* For non secure access bits [30:5] are reserved and
ARE_NS
+ * is RAO/WI note that ARE_NS in this case is bit [4] same
+ * as ARE_S in the prvious secure case. Now since it is
+ * RAO/WI than bit [0] EnableGrp1 is reserved and we can
+ * only use Bit [1] EnableGrp1A to enable Non-secure Group1
+ * interrupts
+ */
+ return s->ctlr & (GICD_CTLR_ARE_NS |
+ GICD_CTLR_EN_GRP1NS |
+ GICD_CTLR_RWP);
+ }
+ } else {
+ /* Support ONE security state without ARE is RAO/WI*/
+ return s->ctlr & (GICD_CTLR_ARE |
+ GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1NS |
+ GICD_CTLR_RWP);
+ }
+ }
+ if (offset == 4) { /* GICD_TYPER */
+ uint64_t num = NUM_CPU(s);
+ /* the number of cores in the system, saturated to 8 minus one. */
+ if (num > 8)
+ num = 8;
+ /* The num_irqs as given from virt machine via "num-irq"
+ * includes the internal irqs, so subtract them
+ */
+ res = (s->num_irq - GICV3_INTERNAL) / 32;
+ res |= (num - 1) << 5;
+ res |= 0xF << 19;
+ return res;
+ }
+ if (offset == 0x08)
+ return 0x43B; /* GIC_IIDR */
+ if (offset >= 0x80) {
+ /* Interrupt Group Registers: these RAZ/WI if this is an NS
+ * access to a GIC with the security extensions, or if the GIC
+ * doesn't have groups at all.
+ */
+ res = 0;
+ if (!attrs.secure) {
+ /* GIC-500 comment 'f' */
+ goto bad_reg;
+ }
+ /* Every byte offset holds 8 group status bits */
+ irq = (offset - 0x080) * 8 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq) {
+ goto bad_reg;
+ }
+ for (i = 0; i < 8; i++) {
+ if (GIC_TEST_GROUP(irq + i, cpu)) {
+ res |= (1 << i);
+ }
+ }
+ return res;
+ }
+ goto bad_reg;
+ } else if (offset < 0x200) {
+ /* Interrupt Set/Clear Enable. */
+ if (offset < 0x180)
+ irq = (offset - 0x100) * 8;
+ else
+ irq = (offset - 0x180) * 8;
+ irq += GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ res = 0;
+ for (i = 0; i < 8; i++) {
+ if (GIC_TEST_ENABLED(irq + i, cpu)) {
+ res |= (1 << i);
+ }
+ }
+ } else if (offset < 0x300) {
+ /* Interrupt Set/Clear Pending. */
+ if (offset < 0x280)
+ irq = (offset - 0x200) * 8;
+ else
+ irq = (offset - 0x280) * 8;
+ irq += GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ /* Comment 'o' GICv2 backwards competability support is not set...*/
+ if (irq < GICV3_INTERNAL && gicv3_no_gicv2_bc)
+ goto bad_reg;
+ res = 0;
+ cm = (irq < GICV3_INTERNAL) ? cpu : ALL_CPU_MASK;
+ for (i = 0; i < 8; i++) {
+ if (gic_test_pending(s, irq + i, cm)) {
+ res |= (1 << i);
+ }
+ }
+ } else if (offset < 0x400) {
+ /* Interrupt Set/Clear Active. */
+ if (offset < 0x380)
+ irq = (offset - 0x300) * 8 + GICV3_BASE_IRQ;
+ else
+ irq = (offset - 0x380) * 8 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ /* Comment 'o' GICv2 backwards competability support is not set...*/
+ if (irq < GICV3_INTERNAL && gicv3_no_gicv2_bc)
+ goto bad_reg;
+ res = 0;
+ cm = (irq < GICV3_INTERNAL) ? cpu : ALL_CPU_MASK;
+ for (i = 0; i < 8; i++) {
+ if (GIC_TEST_ACTIVE(irq + i, cm)) {
+ res |= (1 << i);
+ }
+ }
+ } else if (offset < 0x800) {
+ /* Interrupt Priority. */
+ irq = (offset - 0x400) + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ /* Comment 'p' GICv2 backwards competability support is not set...*/
+ if (irq < GICV3_INTERNAL * 8 && gicv3_no_gicv2_bc)
+ goto bad_reg;
+ res = GIC_GET_PRIORITY(irq, cpu);
+ } else if (offset < 0xc00) {
+ /* Interrupt CPU Target. */
+ if (s->num_cpu == 1) {
+ /* For uniprocessor GICs these RAZ/WI */
+ res = 0;
+ } else {
+ irq = (offset - 0x800) + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq) {
+ goto bad_reg;
+ }
+ /* Comment 'p' GICv2 backwards competability support is not
set...*/
+ if (irq < GICV3_INTERNAL * 8 && gicv3_no_gicv2_bc)
+ goto bad_reg;
+ if (irq >= 29 && irq <= 31) {
+ res = 1 << cpu;
+ } else {
+ /* Value is a small bitmap can do it directly */
+ res = *GIC_TARGET(irq);
+ }
+ }
+ } else if (offset < 0xd00) {
+ /* Interrupt Configuration. */
+ irq = (offset - 0xc00) * 4 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ /* Comment 'l' GICv2 backwards competability support is not set...*/
+ if (irq < GICV3_INTERNAL && gicv3_no_gicv2_bc)
+ goto bad_reg;
+ res = 0;
+ for (i = 0; i < 4; i++) {
+ /* Even bits are reserved */
+ if (GIC_TEST_EDGE_TRIGGER(irq + i))
+ res |= (2 << (i * 2));
+ }
+ } else if (offset < 0xf10) {
+ goto bad_reg;
+ } else if (offset < 0xf30) {
+ /* Comments 'e' & 't' GICv2 backwards competability support is not
set...*/
+ if (gicv3_no_gicv2_bc)
+ goto bad_reg;
+ /* These are 32 bit registers, should not be used with 128 cores. */
+ if (offset < 0xf20) {
+ /* GICD_CPENDSGIRn */
+ irq = (offset - 0xf10);
+ } else {
+ irq = (offset - 0xf20);
+ /* GICD_SPENDSGIRn */
+ }
+ /* Small bitmap */
+ res = *s->sgi[irq].state[cpu].pending;
+ } else if (offset < 0xffd0) {
+ goto bad_reg;
+ } else /* offset >= 0xffd0 */ {
+ if (offset & 3) {
+ res = 0;
+ } else {
+ res = gic_dist_ids[(offset - 0xffd0) >> 2];
+ }
+ }
+ return res;
+bad_reg:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset %x\n", __func__, (int)offset);
+ return 0;
+}
+
+static uint64_t gic_dist_readll(void *opaque, hwaddr offset,
+ MemTxAttrs attrs)
+{
+ GICv3State *s = (GICv3State *)opaque;
+ uint64_t value;
+
+ if (offset >= 0x6100 && offset <= 0x7EF8) {
+ int irq = (offset - 0x6100) / 8;
+ /* GCID_IROUTERn [affinity-3:X:affinity-2:affinity-1:affininty-0]
+ * See kernel code for fields
+ * GIC 500 currently supports 32 clusters with 8 cores each,
+ * but virtv2 fills the Aff0 before filling Aff1 so
+ * 16 = 2 * 8 but not 4 x 4 nor 8 x 2 not 16 x 1
+ * Note Linux kernel doesn't set bit 31 thus send to all is not needed
+ */
+ uint32_t cpu, Aff1, Aff0;
+ cpu = find_first_bit(s->irq_state[irq].target, s->num_cpu);
+ Aff1 = cpu / 8;
+ Aff0 = cpu % 8;
+ value = (Aff1 << 8) | Aff0;
+ return value;
+ }
+
+ value = gic_dist_readb(opaque, offset, attrs);
+ value |= gic_dist_readb(opaque, offset + 1, attrs) << 8;
+ value |= gic_dist_readb(opaque, offset + 2, attrs) << 16;
+ value |= gic_dist_readb(opaque, offset + 3, attrs) << 24;
+ value |= gic_dist_readb(opaque, offset + 4, attrs) << 32;
+ value |= gic_dist_readb(opaque, offset + 5, attrs) << 40;
+ value |= gic_dist_readb(opaque, offset + 6, attrs) << 48;
+ value |= gic_dist_readb(opaque, offset + 7, attrs) << 56;
+
+ return value;
+}
+
+MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
+{
+ switch (size) {
+ case 1:
+ *data = gic_dist_readb(opaque, offset, attrs);
+ return MEMTX_OK;
+ case 2:
+ *data = gic_dist_readb(opaque, offset, attrs);
+ *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8;
+ return MEMTX_OK;
+ case 4:
+ *data = gic_dist_readb(opaque, offset, attrs);
+ *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8;
+ *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16;
+ *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24;
+ return MEMTX_OK;
+ case 8:
+ *data = gic_dist_readll(opaque, offset, attrs);
+ return MEMTX_OK;
+ default:
+ return MEMTX_ERROR;
+ }
+}
+
+static void gic_dist_writeb(void *opaque, hwaddr offset,
+ uint64_t value, MemTxAttrs attrs)
+{
+ GICv3State *s = (GICv3State *)opaque;
+ int irq;
+ int i;
+ int cpu;
+
+ cpu = gic_get_current_cpu(s);
+
+ if (offset < 0x100) {
+ if (offset < 0x80) {
+ /* Error! should be handeld in writel. */
+ DPRINTF("Distributor: error should be handled in dist_writel \n");
+ goto bad_reg;
+ } else if (offset >= 0x80) {
+ DPRINTF("Distributor: GICD_IGROUPRn\n");
+ /* Interrupt Group Registers: RAZ/WI for NS access to secure
+ * GIC, or for GICs without groups.
+ */
+ if (!attrs.secure) {
+ /* GIC-500 comment 'f' */
+ goto bad_reg;
+ }
+ /* Every byte offset holds 8 group status bits */
+ irq = (offset - 0x80) * 8 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq) {
+ goto bad_reg;
+ }
+ for (i = 0; i < 8; i++) {
+ /* Group bits are banked for private interrupts */
+ int cm = (irq < GICV3_INTERNAL) ? cpu : ALL_CPU_MASK;
+ if (value & (1 << i)) {
+ /* Group1 (Non-secure) */
+ GIC_SET_GROUP(irq + i, cm);
+ } else {
+ /* Group0 (Secure) */
+ GIC_CLEAR_GROUP(irq + i, cm);
+ }
+ }
+ } else {
+ goto bad_reg;
+ }
+ } else if (offset < 0x180) {
+ /* Interrupt Set Enable. */
+ irq = (offset - 0x100) * 8 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ if (irq < GICV3_NR_SGIS) {
+ DPRINTF("ISENABLERn SGI should be only in redistributer %d\n",
irq);
+ /* Ignored according to comment 'g' in GIC-500 document.
+ * The comment doen't say that the whole register is reservd
+ */
+ return;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (value & (1 << i)) {
+ int cm = (irq < GICV3_INTERNAL) ? cpu : ALL_CPU_MASK;
+
+ if (!GIC_TEST_ENABLED(irq + i, cm)) {
+ DPRINTF("Enabled IRQ %d\n", irq + i);
+ }
+ GIC_SET_ENABLED(irq + i, cm);
+ /* If a raised level triggered IRQ enabled then mark
+ is as pending. */
+ if (irq < GICV3_INTERNAL) {
+ if (GIC_TEST_LEVEL(irq + i, cpu)
+ && !GIC_TEST_EDGE_TRIGGER(irq + i)) {
+ DPRINTF("Set %d pending cpu %d\n", irq + i, cpu);
+ GIC_SET_PENDING(irq + i, cpu);
+ }
+ } else {
+ unsigned long *mask = GIC_TARGET(irq + i);
+ if (GIC_TEST_LEVEL_MASK(irq + i, mask)
+ && !GIC_TEST_EDGE_TRIGGER(irq + i)) {
+ DPRINTF("Set %d pending target\n", irq + i);
+ GIC_SET_PENDING_MASK(irq + i, mask);
+ }
+ }
+ }
+ }
+ } else if (offset < 0x200) {
+ /* Interrupt Clear Enable. */
+ irq = (offset - 0x180) * 8 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ if (irq < GICV3_NR_SGIS) {
+ DPRINTF("ICENABLERn SGI should be only in redistributer %d\n",
irq);
+ /* Ignored according to comment 'g' in GIC-500 document.
+ * The comment doen't say that the whole register is reservd
+ */
+ return;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (value & (1 << i)) {
+ int cm = (irq < GICV3_INTERNAL) ? cpu : ALL_CPU_MASK;
+
+ if (GIC_TEST_ENABLED(irq + i, cm)) {
+ DPRINTF("Disabled IRQ %d\n", irq + i);
+ }
+ GIC_CLEAR_ENABLED(irq + i, cm);
+ }
+ }
+ } else if (offset < 0x280) {
+ /* Interrupt Set Pending. */
+ irq = (offset - 0x200) * 8 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ /* Comment 'o' GICv2 backwards competability support is not set...*/
+ if (irq < GICV3_INTERNAL && gicv3_no_gicv2_bc)
+ goto bad_reg;
+
+ for (i = 0; i < 8; i++) {
+ if (value & (1 << i)) {
+ GIC_SET_PENDING_MASK(irq + i, GIC_TARGET(irq + i));
+ }
+ }
+ } else if (offset < 0x300) {
+ /* Interrupt Clear Pending. */
+ irq = (offset - 0x280) * 8 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ /* Comment 'o' GICv2 backwards competability support is not set...*/
+ if (irq < GICV3_INTERNAL && gicv3_no_gicv2_bc)
+ goto bad_reg;
+
+ for (i = 0; i < 8; i++) {
+ /* ??? This currently clears the pending bit for all CPUs, even
+ for per-CPU interrupts. It's unclear whether this is the
+ correct behavior. */
+ if (value & (1 << i)) {
+ GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
+ }
+ }
+ } else if (offset < 0x400) {
+ /* Interrupt Active. */
+ goto bad_reg;
+ } else if (offset < 0x800) {
+ /* Interrupt Priority. */
+ irq = (offset - 0x400) + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ /* Comment 'p' GICv2 backwards competability support is not set...*/
+ if (irq < GICV3_INTERNAL * 8 && gicv3_no_gicv2_bc)
+ goto bad_reg;
+ gicv3_set_priority(s, cpu, irq, value, attrs);
+ } else if (offset < 0xc00) {
+ /* Interrupt CPU Target. RAZ/WI on uni-processor GICs */
+ if (s->num_cpu != 1) {
+ irq = (offset - 0x800) + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq) {
+ goto bad_reg;
+ }
+ /* Comment 'p' GICv2 backwards competability support is not
set...*/
+ if (irq < GICV3_INTERNAL * 8 && gicv3_no_gicv2_bc)
+ goto bad_reg;
+ if (irq < 29) {
+ value = 0;
+ } else if (irq < GICV3_INTERNAL) {
+ value = ALL_CPU_MASK_COMPAT;
+ }
+ /* Small bitmap */
+ *s->irq_state[irq].target = value & ALL_CPU_MASK_COMPAT;
+ }
+ } else if (offset < 0xd00) {
+ /* Interrupt Configuration. */
+ irq = (offset - 0xc00) * 4 + GICV3_BASE_IRQ;
+ if (irq >= s->num_irq)
+ goto bad_reg;
+ /* Comment 'l' GICv2 backwards competability support is not set...*/
+ if (irq < GICV3_INTERNAL && gicv3_no_gicv2_bc)
+ goto bad_reg;
+ if (irq < GICV3_NR_SGIS)
+ value |= 0xaa; /* 10101010 */
+ /* Even bits are reserved */
+ for (i = 0; i < 4; i++) {
+ if (value & (2 << (i * 2))) {
+ GIC_SET_EDGE_TRIGGER(irq + i);
+ } else {
+ GIC_CLEAR_EDGE_TRIGGER(irq + i);
+ }
+ }
+ } else if (offset < 0xf30) {
+ /* Comments 'e' & 't' GICv2 backwards competability support is not set
*/
+ if (gicv3_no_gicv2_bc)
+ goto bad_reg;
+ /* These are 32 bit registers, should not be used with 128 cores. */
+ if (offset < 0xf20) {
+ /* GICD_CPENDSGIRn */
+ irq = (offset - 0xf10);
+ DPRINTF("GICD_CPENDSGIRn irq(%d) %lu\n", irq, value);
+ /* Value is a small bitmap can do it directly */
+ *s->sgi[irq].state[cpu].pending &= ~value;
+ if (*s->sgi[irq].state[cpu].pending == 0) {
+ GIC_CLEAR_PENDING(irq, cpu);
+ }
+ } else {
+ irq = (offset - 0xf20);
+ /* GICD_SPENDSGIRn */
+ DPRINTF("GICD_SPENDSGIRn irq(%d) %lu\n", irq, value);
+ GIC_SET_PENDING(irq, cpu);
+ /* Value is a small bitmap can do it directly */
+ *s->sgi[irq].state[cpu].pending |= value;
+ }
+ }
+ gicv3_update(s);
+ return;
+bad_reg:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset %x\n", __func__, (int)offset);
+}
+
+static void gic_dist_writew(void *opaque, hwaddr offset,
+ uint64_t value, MemTxAttrs attrs)
+{
+ gic_dist_writeb(opaque, offset, value & 0xff, attrs);
+ gic_dist_writeb(opaque, offset + 1, value >> 8, attrs);
+}
+
+static void gic_dist_writel(void *opaque, hwaddr offset,
+ uint64_t value, MemTxAttrs attrs)
+{
+ if (offset < 0x80) {
+ if (offset == 0) {
+ GICv3State *s = (GICv3State *)opaque;
+ uint32_t ctlr;
+ /* One day we may have MT QEMU */
+ s->ctlr |= GICD_CTLR_RWP;
+ /* GICv3 5.3.20 */
+ if (s->security_levels > 1) {
+ /* support TWO security states */
+ if (attrs.secure) {
+ /* for secure access DS is RAZ/WI ARE_NS is RAO/WI and
+ * ARE_S is RAO/WI
+ * for non secure access bits [30:5] are reserved and
ARE_NS is
+ * RAO/WI
+ *
+ * Can modify bits[2:0] Groups 0 & 1 NS & 1 S
+ */
+ ctlr = s->ctlr & ~(GICD_CTLR_EN_GRP0 |
GICD_CTLR_EN_GRP1_ALL);
+ value &= (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1_ALL);
+ value |= GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS;
+ } else {
+ /* For non secure access bits [30:5] are reserved and
ARE_NS is
+ * RAO/WI note that ARE_NS in this case is bit [4] same as
+ * ARE_S in the prvious secure case. Now since it is RAO/WI
+ * thane bit [0] EnableGrp1 is reserved and we can only use
+ * Bit [1] EnableGrp1A to enable Non-secure Group1
interrupts
+ */
+ ctlr = s->ctlr & ~GICD_CTLR_EN_GRP1NS;
+ value &= GICD_CTLR_EN_GRP1NS;
+ value |= GICD_CTLR_ARE_NS;
+ }
+ } else {
+ /* support ONE security state */
+ /* if GICv2 backwards cimpatibility is not implemented than ARE
+ * is RAO/WI
+ */
+ ctlr = s->ctlr & ~(GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1NS);
+ value &= (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1NS);
+ value |= GICD_CTLR_ARE;
+ }
+ s->ctlr = (ctlr | value) & ~GICD_CTLR_RWP;
+ DPRINTF("Distributor: Group0 %sabled; Group 1S %sabled Group 1NS
%sabled\n",
+ s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis",
+ s->ctlr & GICD_CTLR_EN_GRP1S ? "En" : "Dis",
+ s->ctlr & GICD_CTLR_EN_GRP1NS ? "En" : "Dis");
+ return;
+ }
+ if (offset < 0x40) {
+ /* RO or reserved < 0x40 */
+ return;
+ }
+ if (offset < 0x80) {
+ /* SPI not supported < 0x80 */
+ return;
+ }
+ return;
+ }
+ if (offset == 0xf00) {
+ /* GICD_SGIR Software generated Interrupt register
+ * This register should not be used if GICv2 backwards computability
+ * support is not included. (comment t page 3-8 on GIC-500 document)
+ * Or table 6 on GICv3 documment
+ */
+ int cpu;
+ int irq;
+ uint32_t mask, cpu_mask;
+ int target_cpu;
+ GICv3State *s = (GICv3State *)opaque;
+
+ if (gicv3_no_gicv2_bc) {
+ DPRINTF("GICv2 backwards computability is not supported\n");
+ return;
+ }
+ /* GICv2 competabiltu code only 8 CPU */
+ cpu = gic_get_current_cpu(s);
+ irq = value & 0x3ff;
+ switch ((value >> 24) & 3) {
+ case 0:
+ mask = (value >> 16) & ALL_CPU_MASK_COMPAT;
+ break;
+ case 1:
+ /* All cpus excpet this one (up to 7) */
+ mask = ALL_CPU_MASK_COMPAT ^ (1ll << cpu);
+ break;
+ case 2:
+ mask = 1ll << cpu;
+ break;
+ default:
+ DPRINTF("Bad Soft Int target filter\n");
+ /* All CPUs */
+ mask = 0xff;
+ break;
+ }
+ cpu_mask = (1ll << cpu);
+ DPRINTF("irq(%d) mask(0x%x)\n", irq, mask);
+ target_cpu = ctz32(mask);
+ while (target_cpu < s->num_cpu) {
+ GIC_SET_PENDING(irq, target_cpu);
+ /* Small mask, can do direct assignment */
+ *s->sgi[irq].state[target_cpu].pending |= cpu_mask;
+ mask &= ~(1ll << target_cpu);
+ target_cpu = ctz32(mask);
+ }
+ gicv3_update(s);
+ return;
+ }
+ gic_dist_writew(opaque, offset, value & 0xffff, attrs);
+ gic_dist_writew(opaque, offset + 2, value >> 16, attrs);
+}
+
+static void gic_dist_writell(void *opaque, hwaddr offset,
+ uint64_t value, MemTxAttrs attrs)
+{
+ GICv3State *s = (GICv3State *)opaque;
+
+ if (offset >= 0x6100 && offset <= 0x7EF8) {
+ int irq = (offset - 0x6100) / 8;
+ /* GCID_IROUTERn [affinity-3:X:affinity-2:affinity-1:affininty-0]
+ * See kernel code for fields
+ * GIC 500 currently supports 32 clusters with 8 cores each,
+ * but virtv2 fills the Aff0 before filling Aff1 so
+ * 16 = 2 * 8 but not 4 x 4 nor 8 x 2 not 16 x 1
+ * Note Linux kernel doesn't set bit 31 thus send to all is not needed
+ */
+ uint32_t cpu, Aff1, Aff0;
+ Aff1 = (value & 0xf00) >> (8 - 3); /* Shift by 8 multiply by 8 */
+ Aff0 = value & 0x7;
+ cpu = Aff1 + Aff0;
+ GIC_SET_TARGET(irq, cpu);
+ gicv3_update(s);
+ DPRINTF("irq(%d) cpu(%d)\n", irq, cpu);
+ return;
+ }
+
+ gic_dist_writel(opaque, offset, value & 0xffffffff, attrs);
+ gic_dist_writel(opaque, offset + 4, value >> 32, attrs);
+}
+
+MemTxResult gic_dist_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned size, MemTxAttrs attrs)
+{
+ DPRINTF("offset %p data %p secure(%d)\n", (void *) addr, (void *) data,
attrs.secure);
+ switch (size) {
+ case 1:
+ gic_dist_writeb(opaque, addr, data, attrs);
+ return MEMTX_OK;
+ case 2:
+ gic_dist_writew(opaque, addr, data, attrs);
+ return MEMTX_OK;
+ case 4:
+ gic_dist_writel(opaque, addr, data, attrs);
+ return MEMTX_OK;
+ case 8:
+ gic_dist_writell(opaque, addr, data, attrs);
+ return MEMTX_OK;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: size %u\n", __func__, size);
+ return MEMTX_ERROR;
+ }
+}
diff --git a/hw/intc/arm_gicv3_dist.h b/hw/intc/arm_gicv3_dist.h
new file mode 100644
index 0000000..7f38fa1
--- /dev/null
+++ b/hw/intc/arm_gicv3_dist.h
@@ -0,0 +1,9 @@
+#ifndef QEMU_ARM_GICV3_DIST_H
+#define QEMU_ARM_GICV3_DIST_H
+
+MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data,
+ unsigned size, MemTxAttrs attrs);
+MemTxResult gic_dist_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned size, MemTxAttrs attrs);
+
+#endif /* !QEMU_ARM_GIC_DIST_H */
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 14915e0..c438289 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -209,6 +209,14 @@ static inline bool gic_test_pending(GICv3State *s, int
irq, int cm)
#define NUM_CPU(s) ((s)->num_cpu)
+static inline int gic_get_current_cpu(GICv3State *s)
+{
+ if (s->num_cpu > 1) {
+ return current_cpu->cpu_index;
+ }
+ return 0;
+}
+
/* Return true if this GIC config has interrupt groups, which is
* true if we're a GICv3. Keep just
*/
--
1.9.1
- Re: [Qemu-devel] [PATCH RFC V5 6/9] hw/intc: arm_gicv3_spi_its, (continued)
- [Qemu-devel] [PATCH RFC V5 3/9] hw/intc: arm_gicv3_cpu_interface, Shlomo Pongratz, 2015/10/20
- [Qemu-devel] [PATCH RFC V5 5/9] hw/intc arm_gicv3_redist, Shlomo Pongratz, 2015/10/20
- [Qemu-devel] [PATCH RFC V5 8/9] target-arm/cpu64 GICv3 system instructions support, Shlomo Pongratz, 2015/10/20
- Re: [Qemu-devel] [PATCH RFC V5 8/9] target-arm/cpu64 GICv3 system instructions support, Pavel Fedin, 2015/10/22
- Re: [Qemu-devel] [PATCH RFC V5 8/9] target-arm/cpu64 GICv3 system instructions support, Shlomo Pongratz, 2015/10/22
- Re: [Qemu-devel] [PATCH RFC V5 8/9] target-arm/cpu64 GICv3 system instructions support, Pavel Fedin, 2015/10/22
- Re: [Qemu-devel] [PATCH RFC V5 8/9] target-arm/cpu64 GICv3 system instructions support, Shlomo Pongratz, 2015/10/22
- Re: [Qemu-devel] [PATCH RFC V5 8/9] target-arm/cpu64 GICv3 system instructions support, Pavel Fedin, 2015/10/22
- Re: [Qemu-devel] [PATCH RFC V5 8/9] target-arm/cpu64 GICv3 system instructions support, Shlomo Pongratz, 2015/10/22
[Qemu-devel] [PATCH RFC V5 4/9] hw/intc: arm_gicv3_dist,
Shlomo Pongratz <=
[Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Shlomo Pongratz, 2015/10/20
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Pavel Fedin, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Shlomo Pongratz, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Pavel Fedin, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Shlomo Pongratz, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Peter Maydell, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Shlomo Pongratz, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Peter Maydell, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Pavel Fedin, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500, Shlomo Pongratz, 2015/10/21