From patchwork Thu Dec 29 16:19:56 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Langsdorf X-Patchwork-Id: 133572 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 3AFFFB6FB7 for ; Fri, 30 Dec 2011 03:20:37 +1100 (EST) Received: from localhost ([::1]:57706 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RgIiY-0005VJ-9y for incoming@patchwork.ozlabs.org; Thu, 29 Dec 2011 11:20:34 -0500 Received: from eggs.gnu.org ([140.186.70.92]:49841) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RgIi7-0005L3-Sc for qemu-devel@nongnu.org; Thu, 29 Dec 2011 11:20:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RgIi4-0007nX-7W for qemu-devel@nongnu.org; Thu, 29 Dec 2011 11:20:07 -0500 Received: from smtp151.dfw.emailsrvr.com ([67.192.241.151]:43701) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RgIi3-0007mU-L7 for qemu-devel@nongnu.org; Thu, 29 Dec 2011 11:20:03 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp5.relay.dfw1a.emailsrvr.com (SMTP Server) with ESMTP id 44567581DD; Thu, 29 Dec 2011 11:20:01 -0500 (EST) X-Virus-Scanned: OK Received: by smtp5.relay.dfw1a.emailsrvr.com (Authenticated sender: mark.langsdorf-AT-calxeda.com) with ESMTPSA id 0B45C5835C; Thu, 29 Dec 2011 11:20:01 -0500 (EST) From: Mark Langsdorf To: qemu-devel@nongnu.org Date: Thu, 29 Dec 2011 10:19:56 -0600 Message-Id: <1325175596-5807-8-git-send-email-mark.langsdorf@calxeda.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1325175596-5807-1-git-send-email-mark.langsdorf@calxeda.com> References: <1325175596-5807-1-git-send-email-mark.langsdorf@calxeda.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 67.192.241.151 Cc: peter.maydell@linaro.org, Mark Langsdorf , afaerber@suse.de, rob.herring@calxeda.com Subject: [Qemu-devel] [PATCH v5 7/7] arm: make the number of GIC interrupts configurable X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Increase the maximum number of GIC interrupts for a9mp and a11mp to 256, and create a configurable property for each defaulting to 96 and 64 (respectively) so that device modelers can set the value appropriately for their SoC. Other ARM processors also set their maximum number of used IRQs appropriately. Set the maximum theoretically number of GIC interrupts to 1020 and update the save/restore code to only use the appropriate number for each SoC. Signed-off-by: Mark Langsdorf --- Changes from v4 None Changes from v3 Increase maximum number of GIC interrupts to 1020 Remove SoC/implementation specific GIC_NIRQ #defs Added properties code to arm11mp Changed error handling for too many interrupts Redid save/load handling Changes from v2 Skipped Changes from v1 Increase the number of a9mp interrupts to 192 Add a property defaulting to 96 Add a num_irq member in the gic state structure Use the num_irq value as appropriate Add num_irq argument to gic_init() Add num_irq to various CPU calls to gic_init hw/a9mpcore.c | 7 +++-- hw/arm11mpcore.c | 14 +++++++----- hw/arm_gic.c | 57 +++++++++++++++++++++++++++++----------------------- hw/armv7m_nvic.c | 7 ++--- hw/realview_gic.c | 3 +- 5 files changed, 48 insertions(+), 40 deletions(-) diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 3ef0e13..8c8b72b 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -11,9 +11,8 @@ #include "sysbus.h" /* Configuration for arm_gic.c: - * number of external IRQ lines, max number of CPUs, how to ID current CPU + * max number of CPUs, how to ID current CPU */ -#define GIC_NIRQ 96 #define NCPU 4 static inline int @@ -37,6 +36,7 @@ typedef struct a9mp_priv_state { MemoryRegion ptimer_iomem; MemoryRegion container; DeviceState *mptimer; + uint32_t num_irq; } a9mp_priv_state; static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset, @@ -153,7 +153,7 @@ static int a9mp_priv_init(SysBusDevice *dev) hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU); } - gic_init(&s->gic, s->num_cpu); + gic_init(&s->gic, s->num_cpu, s->num_irq); s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); @@ -216,6 +216,7 @@ static SysBusDeviceInfo a9mp_priv_info = { .qdev.reset = a9mp_priv_reset, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1), + DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 256), DEFINE_PROP_END_OF_LIST(), } }; diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index bc0457e..e4e4bb3 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -10,11 +10,6 @@ #include "sysbus.h" #include "qemu-timer.h" -/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines - (+ 32 internal). However my test chip only exposes/reports 32. - More importantly Linux falls over if more than 32 are present! */ -#define GIC_NIRQ 64 - #define NCPU 4 static inline int @@ -37,6 +32,7 @@ typedef struct mpcore_priv_state { MemoryRegion iomem; MemoryRegion container; DeviceState *mptimer; + uint32_t num_irq; } mpcore_priv_state; /* Per-CPU private memory mapped IO. */ @@ -132,7 +128,7 @@ static int mpcore_priv_init(SysBusDevice *dev) { mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); - gic_init(&s->gic, s->num_cpu); + gic_init(&s->gic, s->num_cpu, GIC_NIRQ); s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); qdev_init_nofail(s->mptimer); @@ -221,6 +217,12 @@ static SysBusDeviceInfo mpcore_priv_info = { .qdev.size = sizeof(mpcore_priv_state), .qdev.props = (Property[]) { DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), + /* The MPCore TRM says the on-chip controller has 224 external + * IRQ lines (+ 32 internal). Some test chips only + * expose/report 32. More importantly Linux falls over if more + * than 32 are present! Set the default to 64 and let chips + * with more working lines set it higher */ + DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64), DEFINE_PROP_END_OF_LIST(), } }; diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 0339cf5..5bfb01f 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -11,6 +11,7 @@ controller, MPCore distributed interrupt controller and ARMv7-M Nested Vectored Interrupt Controller. */ +#define GIC_NIRQ 1020 //#define DEBUG_GIC #ifdef DEBUG_GIC @@ -111,6 +112,7 @@ typedef struct gic_state struct gic_state *backref[NCPU]; MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */ #endif + int num_irq; } gic_state; /* TODO: Many places that call this routine could be optimized. */ @@ -133,7 +135,7 @@ static void gic_update(gic_state *s) } best_prio = 0x100; best_irq = 1023; - for (irq = 0; irq < GIC_NIRQ; irq++) { + for (irq = 0; irq < s->num_irq; irq++) { if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) { if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { best_prio = GIC_GET_PRIORITY(irq, cpu); @@ -222,7 +224,7 @@ static void gic_complete_irq(gic_state * s, int cpu, int irq) int update = 0; int cm = 1 << cpu; DPRINTF("EOI %d\n", irq); - if (irq >= GIC_NIRQ) { + if (irq >= s->num_irq) { /* This handles two cases: * 1. If software writes the ID of a spurious interrupt [ie 1023] * to the GICC_EOIR, the GIC ignores that write. @@ -279,7 +281,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) if (offset == 0) return s->enabled; if (offset == 4) - return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5); + return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5); if (offset < 0x08) return 0; if (offset >= 0x80) { @@ -295,7 +297,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) else irq = (offset - 0x180) * 8; irq += GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = 0; for (i = 0; i < 8; i++) { @@ -310,7 +312,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) else irq = (offset - 0x280) * 8; irq += GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = 0; mask = (irq < 32) ? cm : ALL_CPU_MASK; @@ -322,7 +324,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) } else if (offset < 0x400) { /* Interrupt Active. */ irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = 0; mask = (irq < 32) ? cm : ALL_CPU_MASK; @@ -334,14 +336,14 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) } else if (offset < 0x800) { /* Interrupt Priority. */ irq = (offset - 0x400) + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = GIC_GET_PRIORITY(irq, cpu); #ifndef NVIC } else if (offset < 0xc00) { /* Interrupt CPU Target. */ irq = (offset - 0x800) + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq >= 29 && irq <= 31) { res = cm; @@ -351,7 +353,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) } else if (offset < 0xf00) { /* Interrupt Configuration. */ irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = 0; for (i = 0; i < 4; i++) { @@ -426,7 +428,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x180) { /* Interrupt Set Enable. */ irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 16) value = 0xff; @@ -451,7 +453,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x200) { /* Interrupt Clear Enable. */ irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 16) value = 0; @@ -468,7 +470,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x280) { /* Interrupt Set Pending. */ irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 16) irq = 0; @@ -481,7 +483,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x300) { /* Interrupt Clear Pending. */ irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; for (i = 0; i < 8; i++) { /* ??? This currently clears the pending bit for all CPUs, even @@ -497,7 +499,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x800) { /* Interrupt Priority. */ irq = (offset - 0x400) + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 32) { s->priority1[irq][cpu] = value; @@ -508,7 +510,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0xc00) { /* Interrupt CPU Target. */ irq = (offset - 0x800) + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 29) value = 0; @@ -518,7 +520,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0xf00) { /* Interrupt Configuration. */ irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 32) value |= 0xaa; @@ -735,17 +737,17 @@ static void gic_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->cpu_enabled[i]); for (j = 0; j < 32; j++) qemu_put_be32(f, s->priority1[j][i]); - for (j = 0; j < GIC_NIRQ; j++) + for (j = 0; j < s->num_irq; j++) qemu_put_be32(f, s->last_active[j][i]); qemu_put_be32(f, s->priority_mask[i]); qemu_put_be32(f, s->running_irq[i]); qemu_put_be32(f, s->running_priority[i]); qemu_put_be32(f, s->current_pending[i]); } - for (i = 0; i < GIC_NIRQ - 32; i++) { + for (i = 0; i < s->num_irq - 32; i++) { qemu_put_be32(f, s->priority2[i]); } - for (i = 0; i < GIC_NIRQ; i++) { + for (i = 0; i < s->num_irq; i++) { #ifndef NVIC qemu_put_be32(f, s->irq_target[i]); #endif @@ -772,17 +774,17 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) s->cpu_enabled[i] = qemu_get_be32(f); for (j = 0; j < 32; j++) s->priority1[j][i] = qemu_get_be32(f); - for (j = 0; j < GIC_NIRQ; j++) + for (j = 0; j < s->num_irq; j++) s->last_active[j][i] = qemu_get_be32(f); s->priority_mask[i] = qemu_get_be32(f); s->running_irq[i] = qemu_get_be32(f); s->running_priority[i] = qemu_get_be32(f); s->current_pending[i] = qemu_get_be32(f); } - for (i = 0; i < GIC_NIRQ - 32; i++) { + for (i = 0; i < s->num_irq - 32; i++) { s->priority2[i] = qemu_get_be32(f); } - for (i = 0; i < GIC_NIRQ; i++) { + for (i = 0; i < s->num_irq; i++) { #ifndef NVIC s->irq_target[i] = qemu_get_be32(f); #endif @@ -798,9 +800,9 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) } #if NCPU > 1 -static void gic_init(gic_state *s, int num_cpu) +static void gic_init(gic_state *s, int num_cpu, int num_irq) #else -static void gic_init(gic_state *s) +static void gic_init(gic_state *s, int num_irq) #endif { int i; @@ -808,7 +810,12 @@ static void gic_init(gic_state *s) #if NCPU > 1 s->num_cpu = num_cpu; #endif - qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32); + s->num_irq = num_irq; + if (s->num_irq > GIC_NIRQ) { + hw_error("device requested %u out of %u interrupt lines, failing\n", + num_irq, GIC_NIRQ); + } + qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - 32); for (i = 0; i < NUM_CPU(s); i++) { sysbus_init_irq(&s->busdev, &s->parent_irq[i]); } diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index bf8c3c5..0de51f4 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -15,9 +15,6 @@ #include "arm-misc.h" #include "exec-memory.h" -/* 32 internal lines (16 used for system exceptions) plus 64 external - interrupt lines. */ -#define GIC_NIRQ 96 #define NCPU 1 #define NVIC 1 @@ -384,7 +381,9 @@ static int armv7m_nvic_init(SysBusDevice *dev) { nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev); - gic_init(&s->gic); + /* 32 internal lines (16 used for system exceptions) plus 64 external + * interrupt lines. */ + gic_init(&s->gic, 96); memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem); s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s); vmstate_register(&dev->qdev, -1, &vmstate_nvic, s); diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 8c4d509..cd7e53d 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -9,7 +9,6 @@ #include "sysbus.h" -#define GIC_NIRQ 96 #define NCPU 1 /* Only a single "CPU" interface is present. */ @@ -37,7 +36,7 @@ static int realview_gic_init(SysBusDevice *dev) { RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev); - gic_init(&s->gic); + gic_init(&s->gic, 96); realview_gic_map_setup(s); sysbus_init_mmio(dev, &s->container); return 0;