diff options
Diffstat (limited to 'hw/slavio_intctl.c')
-rw-r--r-- | hw/slavio_intctl.c | 55 |
1 files changed, 23 insertions, 32 deletions
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index acde370e5c..9550c0064f 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -104,6 +104,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint val |= 80000000; val &= 0xfffe0000; s->intreg_pending[cpu] &= ~val; + slavio_check_interrupts(s); DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); break; case 2: // set softint @@ -175,10 +176,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin val &= ~0x4fb2007f; s->intregm_disabled |= val; s->intregm_pending &= ~val; + slavio_check_interrupts(s); DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); break; case 4: s->target_cpu = val & (MAX_CPUS - 1); + slavio_check_interrupts(s); DPRINTF("Set master irq cpu %d\n", s->target_cpu); break; default: @@ -227,53 +230,36 @@ void slavio_irq_info(void *opaque) #endif } -static void raise_pil(SLAVIO_INTCTLState *s, unsigned int pil, - unsigned int cpu) -{ - qemu_irq irq; - unsigned int oldmax; - - irq = s->cpu_irqs[cpu][pil]; - -#ifdef DEBUG_IRQ_COUNT - s->irq_count[pil]++; -#endif - oldmax = s->pil_out[cpu]; - if (oldmax > 0 && oldmax != pil) - qemu_irq_lower(s->cpu_irqs[cpu][oldmax]); - s->pil_out[cpu] = pil; - if (pil > 0) - qemu_irq_raise(irq); - DPRINTF("cpu %d pil %d\n", cpu, pil); -} - static void slavio_check_interrupts(void *opaque) { SLAVIO_INTCTLState *s = opaque; - uint32_t pending = s->intregm_pending; - unsigned int i, j, max = 0; + uint32_t pending = s->intregm_pending, pil_pending; + unsigned int i, j; pending &= ~s->intregm_disabled; DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); for (i = 0; i < MAX_CPUS; i++) { - max = 0; + pil_pending = 0; if (pending && !(s->intregm_disabled & 0x80000000) && (i == s->target_cpu)) { for (j = 0; j < 32; j++) { - if (pending & (1 << j)) { - if (max < s->intbit_to_level[j]) - max = s->intbit_to_level[j]; - } + if (pending & (1 << j)) + pil_pending |= 1 << s->intbit_to_level[j]; } } - for (j = 17; j < 32; j++) { - if (s->intreg_pending[i] & (1 << j)) { - if (max < j - 16) - max = j - 16; + pil_pending |= (s->intreg_pending[i] >> 16) & 0xfffe; + + for (j = 0; j < MAX_PILS; j++) { + if (pil_pending & (1 << j)) { + if (!(s->pil_out[i] & (1 << j))) + qemu_irq_raise(s->cpu_irqs[i][j]); + } else { + if (s->pil_out[i] & (1 << j)) + qemu_irq_lower(s->cpu_irqs[i][j]); } } - raise_pil(s, max, i); + s->pil_out[i] = pil_pending; } } @@ -291,6 +277,9 @@ static void slavio_set_irq(void *opaque, int irq, int level) level); if (pil > 0) { if (level) { +#ifdef DEBUG_IRQ_COUNT + s->irq_count[pil]++; +#endif s->intregm_pending |= mask; s->intreg_pending[s->target_cpu] |= 1 << pil; } else { @@ -342,6 +331,7 @@ static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->intregm_pending); qemu_get_be32s(f, &s->intregm_disabled); qemu_get_be32s(f, &s->target_cpu); + slavio_check_interrupts(s); return 0; } @@ -356,6 +346,7 @@ static void slavio_intctl_reset(void *opaque) s->intregm_disabled = ~0xffb2007f; s->intregm_pending = 0; s->target_cpu = 0; + slavio_check_interrupts(s); } void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, |