aboutsummaryrefslogtreecommitdiff
path: root/hw/slavio_intctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/slavio_intctl.c')
-rw-r--r--hw/slavio_intctl.c83
1 files changed, 73 insertions, 10 deletions
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index 9780785a47..e43151fad8 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -53,6 +53,7 @@ typedef struct SLAVIO_INTCTLState {
#ifdef DEBUG_IRQ_COUNT
uint64_t irq_count[32];
#endif
+ CPUState *cpu_envs[MAX_CPUS];
} SLAVIO_INTCTLState;
#define INTCTL_MAXADDR 0xf
@@ -96,6 +97,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint
case 2: // set softint
val &= 0xfffe0000;
s->intreg_pending[cpu] |= val;
+ slavio_check_interrupts(s);
DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
break;
default:
@@ -216,7 +218,7 @@ static void slavio_check_interrupts(void *opaque)
CPUState *env;
SLAVIO_INTCTLState *s = opaque;
uint32_t pending = s->intregm_pending;
- unsigned int i, max = 0;
+ unsigned int i, j, max = 0;
pending &= ~s->intregm_disabled;
@@ -227,20 +229,52 @@ static void slavio_check_interrupts(void *opaque)
max = intbit_to_level[i];
}
}
- env = first_cpu;
- if (env->interrupt_index == 0) {
- DPRINTF("Triggered pil %d\n", max);
+ env = s->cpu_envs[s->target_cpu];
+ if (!env) {
+ DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending);
+ }
+ else {
+ if (env->halted)
+ env->halted = 0;
+ if (env->interrupt_index == 0) {
+ DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max);
#ifdef DEBUG_IRQ_COUNT
- s->irq_count[max]++;
+ s->irq_count[max]++;
#endif
- env->interrupt_index = TT_EXTINT | max;
- cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ env->interrupt_index = TT_EXTINT | max;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+ else
+ DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
}
- else
- DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
}
else
DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
+
+ for (i = 0; i < MAX_CPUS; i++) {
+ max = 0;
+ env = s->cpu_envs[i];
+ if (!env)
+ continue;
+ for (j = 17; j < 32; j++) {
+ if (s->intreg_pending[i] & (1 << j)) {
+ if (max < j - 16)
+ max = j - 16;
+ }
+ }
+ if (max > 0) {
+ if (env->halted)
+ env->halted = 0;
+ if (env->interrupt_index == 0) {
+ DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending);
+#ifdef DEBUG_IRQ_COUNT
+ s->irq_count[max]++;
+#endif
+ env->interrupt_index = TT_EXTINT | max;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+ }
+ }
}
/*
@@ -251,7 +285,7 @@ void slavio_pic_set_irq(void *opaque, int irq, int level)
{
SLAVIO_INTCTLState *s = opaque;
- DPRINTF("Set irq %d level %d\n", irq, level);
+ DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level);
if (irq < 32) {
uint32_t mask = 1 << irq;
uint32_t pil = intbit_to_level[irq];
@@ -269,6 +303,29 @@ void slavio_pic_set_irq(void *opaque, int irq, int level)
slavio_check_interrupts(s);
}
+void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
+{
+ SLAVIO_INTCTLState *s = opaque;
+
+ DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level);
+ if (cpu == (unsigned int)-1) {
+ slavio_pic_set_irq(opaque, irq, level);
+ return;
+ }
+ if (irq < 32) {
+ uint32_t pil = intbit_to_level[irq];
+ if (pil > 0) {
+ if (level) {
+ s->intreg_pending[cpu] |= 1 << pil;
+ }
+ else {
+ s->intreg_pending[cpu] &= ~(1 << pil);
+ }
+ }
+ }
+ slavio_check_interrupts(s);
+}
+
static void slavio_intctl_save(QEMUFile *f, void *opaque)
{
SLAVIO_INTCTLState *s = opaque;
@@ -312,6 +369,12 @@ static void slavio_intctl_reset(void *opaque)
s->target_cpu = 0;
}
+void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ s->cpu_envs[cpu] = env;
+}
+
void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
{
int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;