mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-29 21:33:53 -06:00
arm: make the number of GIC interrupts configurable
Increase the maximum number of GIC interrupts for a9mp and a11mp to 1020, 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 theoretical 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 <mark.langsdorf@calxeda.com> Reviewed-by: Andreas Färber <afaerber@suse.de> [Peter Maydell: fixed minor whitespace snafu] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
b09da0c335
commit
a32134aad8
5 changed files with 87 additions and 49 deletions
|
@ -11,9 +11,8 @@
|
||||||
#include "sysbus.h"
|
#include "sysbus.h"
|
||||||
|
|
||||||
/* Configuration for arm_gic.c:
|
/* 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
|
#define NCPU 4
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -37,6 +36,7 @@ typedef struct a9mp_priv_state {
|
||||||
MemoryRegion ptimer_iomem;
|
MemoryRegion ptimer_iomem;
|
||||||
MemoryRegion container;
|
MemoryRegion container;
|
||||||
DeviceState *mptimer;
|
DeviceState *mptimer;
|
||||||
|
uint32_t num_irq;
|
||||||
} a9mp_priv_state;
|
} a9mp_priv_state;
|
||||||
|
|
||||||
static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
|
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);
|
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");
|
s->mptimer = qdev_create(NULL, "arm_mptimer");
|
||||||
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
|
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
|
||||||
|
@ -216,6 +216,13 @@ static SysBusDeviceInfo a9mp_priv_info = {
|
||||||
.qdev.reset = a9mp_priv_reset,
|
.qdev.reset = a9mp_priv_reset,
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
|
DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
|
||||||
|
/* The Cortex-A9MP may have anything from 0 to 224 external interrupt
|
||||||
|
* IRQ lines (with another 32 internal). We default to 64+32, which
|
||||||
|
* is the number provided by the Cortex-A9MP test chip in the
|
||||||
|
* Realview PBX-A9 and Versatile Express A9 development boards.
|
||||||
|
* Other boards may differ and should set this property appropriately.
|
||||||
|
*/
|
||||||
|
DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,11 +10,6 @@
|
||||||
#include "sysbus.h"
|
#include "sysbus.h"
|
||||||
#include "qemu-timer.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
|
#define NCPU 4
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -37,6 +32,7 @@ typedef struct mpcore_priv_state {
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
MemoryRegion container;
|
MemoryRegion container;
|
||||||
DeviceState *mptimer;
|
DeviceState *mptimer;
|
||||||
|
uint32_t num_irq;
|
||||||
} mpcore_priv_state;
|
} mpcore_priv_state;
|
||||||
|
|
||||||
/* Per-CPU private memory mapped IO. */
|
/* 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);
|
mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
|
||||||
|
|
||||||
gic_init(&s->gic, s->num_cpu);
|
gic_init(&s->gic, s->num_cpu, s->num_irq);
|
||||||
s->mptimer = qdev_create(NULL, "arm_mptimer");
|
s->mptimer = qdev_create(NULL, "arm_mptimer");
|
||||||
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
|
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
|
||||||
qdev_init_nofail(s->mptimer);
|
qdev_init_nofail(s->mptimer);
|
||||||
|
@ -221,6 +217,15 @@ static SysBusDeviceInfo mpcore_priv_info = {
|
||||||
.qdev.size = sizeof(mpcore_priv_state),
|
.qdev.size = sizeof(mpcore_priv_state),
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
|
DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
|
||||||
|
/* The ARM11 MPCORE TRM says the on-chip controller may have
|
||||||
|
* anything from 0 to 224 external interrupt IRQ lines (with another
|
||||||
|
* 32 internal). We default to 32+32, which is the number provided by
|
||||||
|
* the ARM11 MPCore test chip in the Realview Versatile Express
|
||||||
|
* coretile. Other boards may differ and should set this property
|
||||||
|
* appropriately. Some Linux kernels may not boot if the hardware
|
||||||
|
* has more IRQ lines than the kernel expects.
|
||||||
|
*/
|
||||||
|
DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
68
hw/arm_gic.c
68
hw/arm_gic.c
|
@ -11,6 +11,8 @@
|
||||||
controller, MPCore distributed interrupt controller and ARMv7-M
|
controller, MPCore distributed interrupt controller and ARMv7-M
|
||||||
Nested Vectored Interrupt Controller. */
|
Nested Vectored Interrupt Controller. */
|
||||||
|
|
||||||
|
/* Maximum number of possible interrupts, determined by the GIC architecture */
|
||||||
|
#define GIC_MAXIRQ 1020
|
||||||
//#define DEBUG_GIC
|
//#define DEBUG_GIC
|
||||||
|
|
||||||
#ifdef DEBUG_GIC
|
#ifdef DEBUG_GIC
|
||||||
|
@ -86,13 +88,13 @@ typedef struct gic_state
|
||||||
int enabled;
|
int enabled;
|
||||||
int cpu_enabled[NCPU];
|
int cpu_enabled[NCPU];
|
||||||
|
|
||||||
gic_irq_state irq_state[GIC_NIRQ];
|
gic_irq_state irq_state[GIC_MAXIRQ];
|
||||||
#ifndef NVIC
|
#ifndef NVIC
|
||||||
int irq_target[GIC_NIRQ];
|
int irq_target[GIC_MAXIRQ];
|
||||||
#endif
|
#endif
|
||||||
int priority1[32][NCPU];
|
int priority1[32][NCPU];
|
||||||
int priority2[GIC_NIRQ - 32];
|
int priority2[GIC_MAXIRQ - 32];
|
||||||
int last_active[GIC_NIRQ][NCPU];
|
int last_active[GIC_MAXIRQ][NCPU];
|
||||||
|
|
||||||
int priority_mask[NCPU];
|
int priority_mask[NCPU];
|
||||||
int running_irq[NCPU];
|
int running_irq[NCPU];
|
||||||
|
@ -111,6 +113,7 @@ typedef struct gic_state
|
||||||
struct gic_state *backref[NCPU];
|
struct gic_state *backref[NCPU];
|
||||||
MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
|
MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
|
||||||
#endif
|
#endif
|
||||||
|
uint32_t num_irq;
|
||||||
} gic_state;
|
} gic_state;
|
||||||
|
|
||||||
/* TODO: Many places that call this routine could be optimized. */
|
/* TODO: Many places that call this routine could be optimized. */
|
||||||
|
@ -133,7 +136,7 @@ static void gic_update(gic_state *s)
|
||||||
}
|
}
|
||||||
best_prio = 0x100;
|
best_prio = 0x100;
|
||||||
best_irq = 1023;
|
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_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
|
||||||
if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
|
if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
|
||||||
best_prio = GIC_GET_PRIORITY(irq, cpu);
|
best_prio = GIC_GET_PRIORITY(irq, cpu);
|
||||||
|
@ -222,7 +225,7 @@ static void gic_complete_irq(gic_state * s, int cpu, int irq)
|
||||||
int update = 0;
|
int update = 0;
|
||||||
int cm = 1 << cpu;
|
int cm = 1 << cpu;
|
||||||
DPRINTF("EOI %d\n", irq);
|
DPRINTF("EOI %d\n", irq);
|
||||||
if (irq >= GIC_NIRQ) {
|
if (irq >= s->num_irq) {
|
||||||
/* This handles two cases:
|
/* This handles two cases:
|
||||||
* 1. If software writes the ID of a spurious interrupt [ie 1023]
|
* 1. If software writes the ID of a spurious interrupt [ie 1023]
|
||||||
* to the GICC_EOIR, the GIC ignores that write.
|
* to the GICC_EOIR, the GIC ignores that write.
|
||||||
|
@ -279,7 +282,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
|
||||||
if (offset == 0)
|
if (offset == 0)
|
||||||
return s->enabled;
|
return s->enabled;
|
||||||
if (offset == 4)
|
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)
|
if (offset < 0x08)
|
||||||
return 0;
|
return 0;
|
||||||
if (offset >= 0x80) {
|
if (offset >= 0x80) {
|
||||||
|
@ -295,7 +298,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
|
||||||
else
|
else
|
||||||
irq = (offset - 0x180) * 8;
|
irq = (offset - 0x180) * 8;
|
||||||
irq += GIC_BASE_IRQ;
|
irq += GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
res = 0;
|
res = 0;
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
|
@ -310,7 +313,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
|
||||||
else
|
else
|
||||||
irq = (offset - 0x280) * 8;
|
irq = (offset - 0x280) * 8;
|
||||||
irq += GIC_BASE_IRQ;
|
irq += GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
res = 0;
|
res = 0;
|
||||||
mask = (irq < 32) ? cm : ALL_CPU_MASK;
|
mask = (irq < 32) ? cm : ALL_CPU_MASK;
|
||||||
|
@ -322,7 +325,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
|
||||||
} else if (offset < 0x400) {
|
} else if (offset < 0x400) {
|
||||||
/* Interrupt Active. */
|
/* Interrupt Active. */
|
||||||
irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
|
irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
res = 0;
|
res = 0;
|
||||||
mask = (irq < 32) ? cm : ALL_CPU_MASK;
|
mask = (irq < 32) ? cm : ALL_CPU_MASK;
|
||||||
|
@ -334,14 +337,14 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
|
||||||
} else if (offset < 0x800) {
|
} else if (offset < 0x800) {
|
||||||
/* Interrupt Priority. */
|
/* Interrupt Priority. */
|
||||||
irq = (offset - 0x400) + GIC_BASE_IRQ;
|
irq = (offset - 0x400) + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
res = GIC_GET_PRIORITY(irq, cpu);
|
res = GIC_GET_PRIORITY(irq, cpu);
|
||||||
#ifndef NVIC
|
#ifndef NVIC
|
||||||
} else if (offset < 0xc00) {
|
} else if (offset < 0xc00) {
|
||||||
/* Interrupt CPU Target. */
|
/* Interrupt CPU Target. */
|
||||||
irq = (offset - 0x800) + GIC_BASE_IRQ;
|
irq = (offset - 0x800) + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
if (irq >= 29 && irq <= 31) {
|
if (irq >= 29 && irq <= 31) {
|
||||||
res = cm;
|
res = cm;
|
||||||
|
@ -351,7 +354,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
|
||||||
} else if (offset < 0xf00) {
|
} else if (offset < 0xf00) {
|
||||||
/* Interrupt Configuration. */
|
/* Interrupt Configuration. */
|
||||||
irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
|
irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
res = 0;
|
res = 0;
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
|
@ -426,7 +429,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
||||||
} else if (offset < 0x180) {
|
} else if (offset < 0x180) {
|
||||||
/* Interrupt Set Enable. */
|
/* Interrupt Set Enable. */
|
||||||
irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
|
irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
if (irq < 16)
|
if (irq < 16)
|
||||||
value = 0xff;
|
value = 0xff;
|
||||||
|
@ -451,7 +454,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
||||||
} else if (offset < 0x200) {
|
} else if (offset < 0x200) {
|
||||||
/* Interrupt Clear Enable. */
|
/* Interrupt Clear Enable. */
|
||||||
irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
|
irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
if (irq < 16)
|
if (irq < 16)
|
||||||
value = 0;
|
value = 0;
|
||||||
|
@ -468,7 +471,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
||||||
} else if (offset < 0x280) {
|
} else if (offset < 0x280) {
|
||||||
/* Interrupt Set Pending. */
|
/* Interrupt Set Pending. */
|
||||||
irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
|
irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
if (irq < 16)
|
if (irq < 16)
|
||||||
irq = 0;
|
irq = 0;
|
||||||
|
@ -481,7 +484,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
||||||
} else if (offset < 0x300) {
|
} else if (offset < 0x300) {
|
||||||
/* Interrupt Clear Pending. */
|
/* Interrupt Clear Pending. */
|
||||||
irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
|
irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
/* ??? This currently clears the pending bit for all CPUs, even
|
/* ??? This currently clears the pending bit for all CPUs, even
|
||||||
|
@ -497,7 +500,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
||||||
} else if (offset < 0x800) {
|
} else if (offset < 0x800) {
|
||||||
/* Interrupt Priority. */
|
/* Interrupt Priority. */
|
||||||
irq = (offset - 0x400) + GIC_BASE_IRQ;
|
irq = (offset - 0x400) + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
if (irq < 32) {
|
if (irq < 32) {
|
||||||
s->priority1[irq][cpu] = value;
|
s->priority1[irq][cpu] = value;
|
||||||
|
@ -508,7 +511,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
||||||
} else if (offset < 0xc00) {
|
} else if (offset < 0xc00) {
|
||||||
/* Interrupt CPU Target. */
|
/* Interrupt CPU Target. */
|
||||||
irq = (offset - 0x800) + GIC_BASE_IRQ;
|
irq = (offset - 0x800) + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
if (irq < 29)
|
if (irq < 29)
|
||||||
value = 0;
|
value = 0;
|
||||||
|
@ -518,7 +521,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
||||||
} else if (offset < 0xf00) {
|
} else if (offset < 0xf00) {
|
||||||
/* Interrupt Configuration. */
|
/* Interrupt Configuration. */
|
||||||
irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
|
irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
|
||||||
if (irq >= GIC_NIRQ)
|
if (irq >= s->num_irq)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
if (irq < 32)
|
if (irq < 32)
|
||||||
value |= 0xaa;
|
value |= 0xaa;
|
||||||
|
@ -699,7 +702,7 @@ static const MemoryRegionOps gic_cpu_ops = {
|
||||||
static void gic_reset(gic_state *s)
|
static void gic_reset(gic_state *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
|
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
|
||||||
for (i = 0 ; i < NUM_CPU(s); i++) {
|
for (i = 0 ; i < NUM_CPU(s); i++) {
|
||||||
s->priority_mask[i] = 0xf0;
|
s->priority_mask[i] = 0xf0;
|
||||||
s->current_pending[i] = 1023;
|
s->current_pending[i] = 1023;
|
||||||
|
@ -735,17 +738,17 @@ static void gic_save(QEMUFile *f, void *opaque)
|
||||||
qemu_put_be32(f, s->cpu_enabled[i]);
|
qemu_put_be32(f, s->cpu_enabled[i]);
|
||||||
for (j = 0; j < 32; j++)
|
for (j = 0; j < 32; j++)
|
||||||
qemu_put_be32(f, s->priority1[j][i]);
|
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->last_active[j][i]);
|
||||||
qemu_put_be32(f, s->priority_mask[i]);
|
qemu_put_be32(f, s->priority_mask[i]);
|
||||||
qemu_put_be32(f, s->running_irq[i]);
|
qemu_put_be32(f, s->running_irq[i]);
|
||||||
qemu_put_be32(f, s->running_priority[i]);
|
qemu_put_be32(f, s->running_priority[i]);
|
||||||
qemu_put_be32(f, s->current_pending[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]);
|
qemu_put_be32(f, s->priority2[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < GIC_NIRQ; i++) {
|
for (i = 0; i < s->num_irq; i++) {
|
||||||
#ifndef NVIC
|
#ifndef NVIC
|
||||||
qemu_put_be32(f, s->irq_target[i]);
|
qemu_put_be32(f, s->irq_target[i]);
|
||||||
#endif
|
#endif
|
||||||
|
@ -772,17 +775,17 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
s->cpu_enabled[i] = qemu_get_be32(f);
|
s->cpu_enabled[i] = qemu_get_be32(f);
|
||||||
for (j = 0; j < 32; j++)
|
for (j = 0; j < 32; j++)
|
||||||
s->priority1[j][i] = qemu_get_be32(f);
|
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->last_active[j][i] = qemu_get_be32(f);
|
||||||
s->priority_mask[i] = qemu_get_be32(f);
|
s->priority_mask[i] = qemu_get_be32(f);
|
||||||
s->running_irq[i] = qemu_get_be32(f);
|
s->running_irq[i] = qemu_get_be32(f);
|
||||||
s->running_priority[i] = qemu_get_be32(f);
|
s->running_priority[i] = qemu_get_be32(f);
|
||||||
s->current_pending[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);
|
s->priority2[i] = qemu_get_be32(f);
|
||||||
}
|
}
|
||||||
for (i = 0; i < GIC_NIRQ; i++) {
|
for (i = 0; i < s->num_irq; i++) {
|
||||||
#ifndef NVIC
|
#ifndef NVIC
|
||||||
s->irq_target[i] = qemu_get_be32(f);
|
s->irq_target[i] = qemu_get_be32(f);
|
||||||
#endif
|
#endif
|
||||||
|
@ -798,9 +801,9 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NCPU > 1
|
#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
|
#else
|
||||||
static void gic_init(gic_state *s)
|
static void gic_init(gic_state *s, int num_irq)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -808,7 +811,12 @@ static void gic_init(gic_state *s)
|
||||||
#if NCPU > 1
|
#if NCPU > 1
|
||||||
s->num_cpu = num_cpu;
|
s->num_cpu = num_cpu;
|
||||||
#endif
|
#endif
|
||||||
qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
|
s->num_irq = num_irq + GIC_BASE_IRQ;
|
||||||
|
if (s->num_irq > GIC_MAXIRQ) {
|
||||||
|
hw_error("requested %u interrupt lines exceeds GIC maximum %d\n",
|
||||||
|
num_irq, GIC_MAXIRQ);
|
||||||
|
}
|
||||||
|
qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - 32);
|
||||||
for (i = 0; i < NUM_CPU(s); i++) {
|
for (i = 0; i < NUM_CPU(s); i++) {
|
||||||
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
|
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,6 @@
|
||||||
#include "arm-misc.h"
|
#include "arm-misc.h"
|
||||||
#include "exec-memory.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 NCPU 1
|
||||||
#define NVIC 1
|
#define NVIC 1
|
||||||
|
|
||||||
|
@ -41,6 +38,7 @@ typedef struct {
|
||||||
int64_t tick;
|
int64_t tick;
|
||||||
QEMUTimer *timer;
|
QEMUTimer *timer;
|
||||||
} systick;
|
} systick;
|
||||||
|
uint32_t num_irq;
|
||||||
} nvic_state;
|
} nvic_state;
|
||||||
|
|
||||||
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
|
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
|
||||||
|
@ -125,7 +123,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 4: /* Interrupt Control Type. */
|
case 4: /* Interrupt Control Type. */
|
||||||
return (GIC_NIRQ / 32) - 1;
|
return (s->num_irq / 32) - 1;
|
||||||
case 0x10: /* SysTick Control and Status. */
|
case 0x10: /* SysTick Control and Status. */
|
||||||
val = s->systick.control;
|
val = s->systick.control;
|
||||||
s->systick.control &= ~SYSTICK_COUNTFLAG;
|
s->systick.control &= ~SYSTICK_COUNTFLAG;
|
||||||
|
@ -169,7 +167,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
||||||
if (s->gic.current_pending[0] != 1023)
|
if (s->gic.current_pending[0] != 1023)
|
||||||
val |= (s->gic.current_pending[0] << 12);
|
val |= (s->gic.current_pending[0] << 12);
|
||||||
/* ISRPENDING */
|
/* ISRPENDING */
|
||||||
for (irq = 32; irq < GIC_NIRQ; irq++) {
|
for (irq = 32; irq < s->num_irq; irq++) {
|
||||||
if (s->gic.irq_state[irq].pending) {
|
if (s->gic.irq_state[irq].pending) {
|
||||||
val |= (1 << 22);
|
val |= (1 << 22);
|
||||||
break;
|
break;
|
||||||
|
@ -384,16 +382,33 @@ static int armv7m_nvic_init(SysBusDevice *dev)
|
||||||
{
|
{
|
||||||
nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
|
nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
|
||||||
|
|
||||||
gic_init(&s->gic);
|
/* note that for the M profile gic_init() takes the number of external
|
||||||
|
* interrupt lines only.
|
||||||
|
*/
|
||||||
|
gic_init(&s->gic, s->num_irq);
|
||||||
memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
|
memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
|
||||||
s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
|
s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
|
||||||
vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SysBusDeviceInfo armv7m_nvic_priv_info = {
|
||||||
|
.init = armv7m_nvic_init,
|
||||||
|
.qdev.name = "armv7m_nvic",
|
||||||
|
.qdev.size = sizeof(nvic_state),
|
||||||
|
.qdev.vmsd = &vmstate_nvic,
|
||||||
|
.qdev.props = (Property[]) {
|
||||||
|
/* The ARM v7m may have anything from 0 to 496 external interrupt
|
||||||
|
* IRQ lines. We default to 64. Other boards may differ and should
|
||||||
|
* set this property appropriately.
|
||||||
|
*/
|
||||||
|
DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void armv7m_nvic_register_devices(void)
|
static void armv7m_nvic_register_devices(void)
|
||||||
{
|
{
|
||||||
sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
|
sysbus_register_withprop(&armv7m_nvic_priv_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
device_init(armv7m_nvic_register_devices)
|
device_init(armv7m_nvic_register_devices)
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include "sysbus.h"
|
#include "sysbus.h"
|
||||||
|
|
||||||
#define GIC_NIRQ 96
|
|
||||||
#define NCPU 1
|
#define NCPU 1
|
||||||
|
|
||||||
/* Only a single "CPU" interface is present. */
|
/* Only a single "CPU" interface is present. */
|
||||||
|
@ -37,7 +36,11 @@ static int realview_gic_init(SysBusDevice *dev)
|
||||||
{
|
{
|
||||||
RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
|
RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
|
||||||
|
|
||||||
gic_init(&s->gic);
|
/* The GICs on the RealView boards have a fixed nonconfigurable
|
||||||
|
* number of interrupt lines, so we don't need to expose this as
|
||||||
|
* a qdev property.
|
||||||
|
*/
|
||||||
|
gic_init(&s->gic, 96);
|
||||||
realview_gic_map_setup(s);
|
realview_gic_map_setup(s);
|
||||||
sysbus_init_mmio(dev, &s->container);
|
sysbus_init_mmio(dev, &s->container);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue