diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 279254f7f8..d89f863156 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -44,6 +44,7 @@ do { printf("IRQ: " fmt , ##args); } while (0) */ #define MAX_CPUS 16 +#define MAX_PILS 16 typedef struct SLAVIO_INTCTLState { uint32_t intreg_pending[MAX_CPUS]; @@ -53,9 +54,10 @@ typedef struct SLAVIO_INTCTLState { #ifdef DEBUG_IRQ_COUNT uint64_t irq_count[32]; #endif - CPUState *cpu_envs[MAX_CPUS]; + qemu_irq *cpu_irqs[MAX_CPUS]; const uint32_t *intbit_to_level; uint32_t cputimer_bit; + uint32_t pil_out[MAX_CPUS]; } SLAVIO_INTCTLState; #define INTCTL_MAXADDR 0xf @@ -213,67 +215,53 @@ 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) { - CPUState *env; SLAVIO_INTCTLState *s = opaque; uint32_t pending = s->intregm_pending; unsigned int i, j, max = 0; pending &= ~s->intregm_disabled; - if (pending && !(s->intregm_disabled & 0x80000000)) { - for (i = 0; i < 32; i++) { - if (pending & (1 << i)) { - if (max < s->intbit_to_level[i]) - max = s->intbit_to_level[i]; - } - } - 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]++; -#endif - 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), disabled %x\n", pending, s->intregm_disabled); - + DPRINTF("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; + 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]; + } + } + } 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); - } - } + raise_pil(s, max, i); } } @@ -284,22 +272,20 @@ static void slavio_check_interrupts(void *opaque) static void slavio_set_irq(void *opaque, int irq, int level) { SLAVIO_INTCTLState *s = opaque; + uint32_t mask = 1 << irq; + uint32_t pil = s->intbit_to_level[irq]; - 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 = s->intbit_to_level[irq]; - if (pil > 0) { - if (level) { - s->intregm_pending |= mask; - s->intreg_pending[s->target_cpu] |= 1 << pil; - slavio_check_interrupts(s); - } - else { - s->intregm_pending &= ~mask; - s->intreg_pending[s->target_cpu] &= ~(1 << pil); - } - } + DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil, + level); + if (pil > 0) { + if (level) { + s->intregm_pending |= mask; + s->intreg_pending[s->target_cpu] |= 1 << pil; + } else { + s->intregm_pending &= ~mask; + s->intreg_pending[s->target_cpu] &= ~(1 << pil); + } + slavio_check_interrupts(s); } } @@ -307,15 +293,12 @@ static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) { SLAVIO_INTCTLState *s = opaque; - DPRINTF("Set cpu %d local level %d\n", cpu, level); - if (!s->cpu_envs[cpu]) - return; + DPRINTF("Set cpu %d local timer level %d\n", cpu, level); - if (level) { + if (level) s->intreg_pending[cpu] |= s->cputimer_bit; - } else { + else s->intreg_pending[cpu] &= ~s->cputimer_bit; - } slavio_check_interrupts(s); } @@ -363,18 +346,10 @@ 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(target_phys_addr_t addr, target_phys_addr_t addrg, const uint32_t *intbit_to_level, qemu_irq **irq, qemu_irq **cpu_irq, - unsigned int cputimer) - + qemu_irq **parent_irq, unsigned int cputimer) { int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; SLAVIO_INTCTLState *s; @@ -388,6 +363,7 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, slavio_intctl_io_memory); + s->cpu_irqs[i] = parent_irq[i]; } slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); diff --git a/hw/sun4m.c b/hw/sun4m.c index ed3be4e1d0..c69d732f91 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +//#define DEBUG_IRQ /* * Sun4m architecture was used in the following machines: @@ -38,6 +39,13 @@ * See for example: http://www.sunhelp.org/faq/sunref1.html */ +#ifdef DEBUG_IRQ +#define DPRINTF(fmt, args...) \ + do { printf("CPUIRQ: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + #define KERNEL_LOAD_ADDR 0x00004000 #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 @@ -46,6 +54,7 @@ #define PROM_FILENAME "openbios-sparc32" #define MAX_CPUS 16 +#define MAX_PILS 16 struct hwdef { target_phys_addr_t iommu_base, slavio_base; @@ -233,6 +242,33 @@ void irq_info() slavio_irq_info(slavio_intctl); } +static void cpu_set_irq(void *opaque, int irq, int level) +{ + CPUState *env = opaque; + + if (level) { + DPRINTF("Raise CPU IRQ %d\n", irq); + + env->halted = 0; + + if (env->interrupt_index == 0 || + ((env->interrupt_index & ~15) == TT_EXTINT && + (env->interrupt_index & 15) < irq)) { + env->interrupt_index = TT_EXTINT | irq; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + DPRINTF("Not triggered, pending exception %d\n", + env->interrupt_index); + } + } else { + DPRINTF("Lower CPU IRQ %d\n", irq); + } +} + +static void dummy_cpu_set_irq(void *opaque, int irq, int level) +{ +} + static void *slavio_misc; void qemu_system_powerdown(void) @@ -264,7 +300,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, unsigned int i; void *iommu, *espdma, *ledma, *main_esp; const sparc_def_t *def; - qemu_irq *slavio_irq, *slavio_cpu_irq, + qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; /* init CPUs */ @@ -273,6 +309,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, fprintf(stderr, "Unable to find Sparc CPU definition\n"); exit(1); } + for(i = 0; i < smp_cpus; i++) { env = cpu_init(); cpu_sparc_register(env, def); @@ -284,7 +321,12 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, env->halted = 1; } register_savevm("cpu", i, 3, cpu_save, cpu_load, env); + cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS); } + + for (i = smp_cpus; i < MAX_CPUS; i++) + cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); + /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); @@ -293,10 +335,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, hwdef->intctl_base + 0x10000ULL, &hwdef->intbit_to_level[0], &slavio_irq, &slavio_cpu_irq, + cpu_irqs, hwdef->clock_irq); - for(i = 0; i < smp_cpus; i++) { - slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); - } + espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], iommu, &espdma_irq); ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, diff --git a/vl.h b/vl.h index d6a76f6c9e..e8caaf8df8 100644 --- a/vl.h +++ b/vl.h @@ -1233,8 +1233,7 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, const uint32_t *intbit_to_level, qemu_irq **irq, qemu_irq **cpu_irq, - unsigned int cputimer); -void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); + qemu_irq **parent_irq, unsigned int cputimer); void slavio_pic_info(void *opaque); void slavio_irq_info(void *opaque);