From: Hollis B. <ho...@us...> - 2008-04-30 21:03:55
|
This fixes the following race condition: 1. target handles an interrupt and begins to EOI 2. device raises an interrupt, setting UIC SR 3. target finishes EOI by clearing SR bit On hardware, a device with a level-triggered interrupt would instantly re-assert SR after step 3, so we need to do the same. Signed-off-by: Hollis Blanchard <ho...@us...> diff --git a/qemu/hw/ppc4xx_devs.c b/qemu/hw/ppc4xx_devs.c --- a/qemu/hw/ppc4xx_devs.c +++ b/qemu/hw/ppc4xx_devs.c @@ -278,6 +278,7 @@ struct ppcuic_t { struct ppcuic_t { uint32_t dcr_base; int use_vectors; + uint32_t level; /* Remembers the state of level-triggered interrupts. */ uint32_t uicsr; /* Status register */ uint32_t uicer; /* Enable register */ uint32_t uiccr; /* Critical register */ @@ -385,10 +386,13 @@ static void ppcuic_set_irq (void *opaque uic->uicsr |= mask; } else { /* Level sensitive interrupt */ - if (level == 1) + if (level == 1) { uic->uicsr |= mask; - else + uic->level |= mask; + } else { uic->uicsr &= ~mask; + uic->level &= ~mask; + } } #ifdef DEBUG_UIC if (loglevel & CPU_LOG_INT) { @@ -460,6 +464,7 @@ static void dcr_write_uic (void *opaque, switch (dcrn) { case DCR_UICSR: uic->uicsr &= ~val; + uic->uicsr |= uic->level; ppcuic_trigger_irq(uic); break; case DCR_UICSRS: |