hw/arm_gic: Make CPU target registers RAZ/WI on uniprocessor

The GIC spec says that the CPU target registers should RAZ/WI
for uniprocessor implementations. Implement this, which also
conveniently lets us drop an NVIC ifdef.

Annoyingly, the 11MPCore's GIC is the odd one out, since
it always has these registers, even in uniprocessor configs.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2012-05-02 16:49:40 +00:00
parent 306a571a2d
commit 6b9680bb58

View File

@ -86,11 +86,7 @@ typedef struct gic_irq_state
#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ? \ #define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ? \
s->priority1[irq][cpu] : \ s->priority1[irq][cpu] : \
s->priority2[(irq) - GIC_INTERNAL]) s->priority2[(irq) - GIC_INTERNAL])
#ifdef NVIC
#define GIC_TARGET(irq) 1
#else
#define GIC_TARGET(irq) s->irq_target[irq] #define GIC_TARGET(irq) s->irq_target[irq]
#endif
typedef struct gic_state typedef struct gic_state
{ {
@ -377,18 +373,22 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
if (irq >= s->num_irq) 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
} else if (offset < 0xc00) { } else if (offset < 0xc00) {
/* Interrupt CPU Target. */ /* Interrupt CPU Target. */
irq = (offset - 0x800) + GIC_BASE_IRQ; if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
if (irq >= s->num_irq) /* For uniprocessor GICs these RAZ/WI */
goto bad_reg; res = 0;
if (irq >= 29 && irq <= 31) {
res = cm;
} else { } else {
res = GIC_TARGET(irq); irq = (offset - 0x800) + GIC_BASE_IRQ;
if (irq >= s->num_irq) {
goto bad_reg;
}
if (irq >= 29 && irq <= 31) {
res = cm;
} else {
res = GIC_TARGET(irq);
}
} }
#endif
} 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;
@ -533,18 +533,22 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else { } else {
s->priority2[irq - GIC_INTERNAL] = value; s->priority2[irq - GIC_INTERNAL] = value;
} }
#ifndef NVIC
} else if (offset < 0xc00) { } else if (offset < 0xc00) {
/* Interrupt CPU Target. */ /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
irq = (offset - 0x800) + GIC_BASE_IRQ; * annoying exception of the 11MPCore's GIC.
if (irq >= s->num_irq) */
goto bad_reg; if (s->num_cpu != 1 || s->revision == REV_11MPCORE) {
if (irq < 29) irq = (offset - 0x800) + GIC_BASE_IRQ;
value = 0; if (irq >= s->num_irq) {
else if (irq < GIC_INTERNAL) goto bad_reg;
value = ALL_CPU_MASK; }
s->irq_target[irq] = value & ALL_CPU_MASK; if (irq < 29) {
#endif value = 0;
} else if (irq < GIC_INTERNAL) {
value = ALL_CPU_MASK;
}
s->irq_target[irq] = value & ALL_CPU_MASK;
}
} 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;
@ -733,6 +737,12 @@ static void gic_reset(DeviceState *dev)
GIC_SET_ENABLED(i, ALL_CPU_MASK); GIC_SET_ENABLED(i, ALL_CPU_MASK);
GIC_SET_TRIGGER(i); GIC_SET_TRIGGER(i);
} }
if (s->num_cpu == 1) {
/* For uniprocessor GICs all interrupts always target the sole CPU */
for (i = 0; i < GIC_MAXIRQ; i++) {
s->irq_target[i] = 1;
}
}
s->enabled = 0; s->enabled = 0;
} }