Commit 327ac2e797ed57d7231d44c77a7473d62efe0989
1 parent
ccf1d14a
Fix Sparc32 interrupt handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3110 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
55 additions
and
44 deletions
cpu-exec.c
| @@ -461,6 +461,9 @@ int cpu_exec(CPUState *env1) | @@ -461,6 +461,9 @@ int cpu_exec(CPUState *env1) | ||
| 461 | env->interrupt_request &= ~CPU_INTERRUPT_HARD; | 461 | env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
| 462 | do_interrupt(env->interrupt_index); | 462 | do_interrupt(env->interrupt_index); |
| 463 | env->interrupt_index = 0; | 463 | env->interrupt_index = 0; |
| 464 | +#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) | ||
| 465 | + cpu_check_irqs(env); | ||
| 466 | +#endif | ||
| 464 | #if defined(__sparc__) && !defined(HOST_SOLARIS) | 467 | #if defined(__sparc__) && !defined(HOST_SOLARIS) |
| 465 | tmp_T0 = 0; | 468 | tmp_T0 = 0; |
| 466 | #else | 469 | #else |
hw/slavio_intctl.c
| @@ -104,6 +104,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint | @@ -104,6 +104,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint | ||
| 104 | val |= 80000000; | 104 | val |= 80000000; |
| 105 | val &= 0xfffe0000; | 105 | val &= 0xfffe0000; |
| 106 | s->intreg_pending[cpu] &= ~val; | 106 | s->intreg_pending[cpu] &= ~val; |
| 107 | + slavio_check_interrupts(s); | ||
| 107 | DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); | 108 | DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); |
| 108 | break; | 109 | break; |
| 109 | case 2: // set softint | 110 | case 2: // set softint |
| @@ -175,10 +176,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin | @@ -175,10 +176,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin | ||
| 175 | val &= ~0x4fb2007f; | 176 | val &= ~0x4fb2007f; |
| 176 | s->intregm_disabled |= val; | 177 | s->intregm_disabled |= val; |
| 177 | s->intregm_pending &= ~val; | 178 | s->intregm_pending &= ~val; |
| 179 | + slavio_check_interrupts(s); | ||
| 178 | DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); | 180 | DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); |
| 179 | break; | 181 | break; |
| 180 | case 4: | 182 | case 4: |
| 181 | s->target_cpu = val & (MAX_CPUS - 1); | 183 | s->target_cpu = val & (MAX_CPUS - 1); |
| 184 | + slavio_check_interrupts(s); | ||
| 182 | DPRINTF("Set master irq cpu %d\n", s->target_cpu); | 185 | DPRINTF("Set master irq cpu %d\n", s->target_cpu); |
| 183 | break; | 186 | break; |
| 184 | default: | 187 | default: |
| @@ -227,53 +230,36 @@ void slavio_irq_info(void *opaque) | @@ -227,53 +230,36 @@ void slavio_irq_info(void *opaque) | ||
| 227 | #endif | 230 | #endif |
| 228 | } | 231 | } |
| 229 | 232 | ||
| 230 | -static void raise_pil(SLAVIO_INTCTLState *s, unsigned int pil, | ||
| 231 | - unsigned int cpu) | ||
| 232 | -{ | ||
| 233 | - qemu_irq irq; | ||
| 234 | - unsigned int oldmax; | ||
| 235 | - | ||
| 236 | - irq = s->cpu_irqs[cpu][pil]; | ||
| 237 | - | ||
| 238 | -#ifdef DEBUG_IRQ_COUNT | ||
| 239 | - s->irq_count[pil]++; | ||
| 240 | -#endif | ||
| 241 | - oldmax = s->pil_out[cpu]; | ||
| 242 | - if (oldmax > 0 && oldmax != pil) | ||
| 243 | - qemu_irq_lower(s->cpu_irqs[cpu][oldmax]); | ||
| 244 | - s->pil_out[cpu] = pil; | ||
| 245 | - if (pil > 0) | ||
| 246 | - qemu_irq_raise(irq); | ||
| 247 | - DPRINTF("cpu %d pil %d\n", cpu, pil); | ||
| 248 | -} | ||
| 249 | - | ||
| 250 | static void slavio_check_interrupts(void *opaque) | 233 | static void slavio_check_interrupts(void *opaque) |
| 251 | { | 234 | { |
| 252 | SLAVIO_INTCTLState *s = opaque; | 235 | SLAVIO_INTCTLState *s = opaque; |
| 253 | - uint32_t pending = s->intregm_pending; | ||
| 254 | - unsigned int i, j, max = 0; | 236 | + uint32_t pending = s->intregm_pending, pil_pending; |
| 237 | + unsigned int i, j; | ||
| 255 | 238 | ||
| 256 | pending &= ~s->intregm_disabled; | 239 | pending &= ~s->intregm_disabled; |
| 257 | 240 | ||
| 258 | DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); | 241 | DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); |
| 259 | for (i = 0; i < MAX_CPUS; i++) { | 242 | for (i = 0; i < MAX_CPUS; i++) { |
| 260 | - max = 0; | 243 | + pil_pending = 0; |
| 261 | if (pending && !(s->intregm_disabled & 0x80000000) && | 244 | if (pending && !(s->intregm_disabled & 0x80000000) && |
| 262 | (i == s->target_cpu)) { | 245 | (i == s->target_cpu)) { |
| 263 | for (j = 0; j < 32; j++) { | 246 | for (j = 0; j < 32; j++) { |
| 264 | - if (pending & (1 << j)) { | ||
| 265 | - if (max < s->intbit_to_level[j]) | ||
| 266 | - max = s->intbit_to_level[j]; | ||
| 267 | - } | 247 | + if (pending & (1 << j)) |
| 248 | + pil_pending |= 1 << s->intbit_to_level[j]; | ||
| 268 | } | 249 | } |
| 269 | } | 250 | } |
| 270 | - for (j = 17; j < 32; j++) { | ||
| 271 | - if (s->intreg_pending[i] & (1 << j)) { | ||
| 272 | - if (max < j - 16) | ||
| 273 | - max = j - 16; | 251 | + pil_pending |= (s->intreg_pending[i] >> 16) & 0xfffe; |
| 252 | + | ||
| 253 | + for (j = 0; j < MAX_PILS; j++) { | ||
| 254 | + if (pil_pending & (1 << j)) { | ||
| 255 | + if (!(s->pil_out[i] & (1 << j))) | ||
| 256 | + qemu_irq_raise(s->cpu_irqs[i][j]); | ||
| 257 | + } else { | ||
| 258 | + if (s->pil_out[i] & (1 << j)) | ||
| 259 | + qemu_irq_lower(s->cpu_irqs[i][j]); | ||
| 274 | } | 260 | } |
| 275 | } | 261 | } |
| 276 | - raise_pil(s, max, i); | 262 | + s->pil_out[i] = pil_pending; |
| 277 | } | 263 | } |
| 278 | } | 264 | } |
| 279 | 265 | ||
| @@ -291,6 +277,9 @@ static void slavio_set_irq(void *opaque, int irq, int level) | @@ -291,6 +277,9 @@ static void slavio_set_irq(void *opaque, int irq, int level) | ||
| 291 | level); | 277 | level); |
| 292 | if (pil > 0) { | 278 | if (pil > 0) { |
| 293 | if (level) { | 279 | if (level) { |
| 280 | +#ifdef DEBUG_IRQ_COUNT | ||
| 281 | + s->irq_count[pil]++; | ||
| 282 | +#endif | ||
| 294 | s->intregm_pending |= mask; | 283 | s->intregm_pending |= mask; |
| 295 | s->intreg_pending[s->target_cpu] |= 1 << pil; | 284 | s->intreg_pending[s->target_cpu] |= 1 << pil; |
| 296 | } else { | 285 | } else { |
| @@ -342,6 +331,7 @@ static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) | @@ -342,6 +331,7 @@ static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) | ||
| 342 | qemu_get_be32s(f, &s->intregm_pending); | 331 | qemu_get_be32s(f, &s->intregm_pending); |
| 343 | qemu_get_be32s(f, &s->intregm_disabled); | 332 | qemu_get_be32s(f, &s->intregm_disabled); |
| 344 | qemu_get_be32s(f, &s->target_cpu); | 333 | qemu_get_be32s(f, &s->target_cpu); |
| 334 | + slavio_check_interrupts(s); | ||
| 345 | return 0; | 335 | return 0; |
| 346 | } | 336 | } |
| 347 | 337 | ||
| @@ -356,6 +346,7 @@ static void slavio_intctl_reset(void *opaque) | @@ -356,6 +346,7 @@ static void slavio_intctl_reset(void *opaque) | ||
| 356 | s->intregm_disabled = ~0xffb2007f; | 346 | s->intregm_disabled = ~0xffb2007f; |
| 357 | s->intregm_pending = 0; | 347 | s->intregm_pending = 0; |
| 358 | s->target_cpu = 0; | 348 | s->target_cpu = 0; |
| 349 | + slavio_check_interrupts(s); | ||
| 359 | } | 350 | } |
| 360 | 351 | ||
| 361 | void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, | 352 | void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, |
hw/sun4m.c
| @@ -240,26 +240,41 @@ void irq_info() | @@ -240,26 +240,41 @@ void irq_info() | ||
| 240 | slavio_irq_info(slavio_intctl); | 240 | slavio_irq_info(slavio_intctl); |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | +void cpu_check_irqs(CPUState *env) | ||
| 244 | +{ | ||
| 245 | + if (env->pil_in && (env->interrupt_index == 0 || | ||
| 246 | + (env->interrupt_index & ~15) == TT_EXTINT)) { | ||
| 247 | + unsigned int i; | ||
| 248 | + | ||
| 249 | + for (i = 15; i > 0; i--) { | ||
| 250 | + if (env->pil_in & (1 << i)) { | ||
| 251 | + int old_interrupt = env->interrupt_index; | ||
| 252 | + | ||
| 253 | + env->interrupt_index = TT_EXTINT | i; | ||
| 254 | + if (old_interrupt != env->interrupt_index) | ||
| 255 | + cpu_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 256 | + break; | ||
| 257 | + } | ||
| 258 | + } | ||
| 259 | + } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { | ||
| 260 | + env->interrupt_index = 0; | ||
| 261 | + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 262 | + } | ||
| 263 | +} | ||
| 264 | + | ||
| 243 | static void cpu_set_irq(void *opaque, int irq, int level) | 265 | static void cpu_set_irq(void *opaque, int irq, int level) |
| 244 | { | 266 | { |
| 245 | CPUState *env = opaque; | 267 | CPUState *env = opaque; |
| 246 | 268 | ||
| 247 | if (level) { | 269 | if (level) { |
| 248 | DPRINTF("Raise CPU IRQ %d\n", irq); | 270 | DPRINTF("Raise CPU IRQ %d\n", irq); |
| 249 | - | ||
| 250 | env->halted = 0; | 271 | env->halted = 0; |
| 251 | - | ||
| 252 | - if (env->interrupt_index == 0 || | ||
| 253 | - ((env->interrupt_index & ~15) == TT_EXTINT && | ||
| 254 | - (env->interrupt_index & 15) < irq)) { | ||
| 255 | - env->interrupt_index = TT_EXTINT | irq; | ||
| 256 | - cpu_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 257 | - } else { | ||
| 258 | - DPRINTF("Not triggered, pending exception %d\n", | ||
| 259 | - env->interrupt_index); | ||
| 260 | - } | 272 | + env->pil_in |= 1 << irq; |
| 273 | + cpu_check_irqs(env); | ||
| 261 | } else { | 274 | } else { |
| 262 | DPRINTF("Lower CPU IRQ %d\n", irq); | 275 | DPRINTF("Lower CPU IRQ %d\n", irq); |
| 276 | + env->pil_in &= ~(1 << irq); | ||
| 277 | + cpu_check_irqs(env); | ||
| 263 | } | 278 | } |
| 264 | } | 279 | } |
| 265 | 280 |
target-sparc/cpu.h
| @@ -181,7 +181,8 @@ typedef struct CPUSPARCState { | @@ -181,7 +181,8 @@ typedef struct CPUSPARCState { | ||
| 181 | int psrs; /* supervisor mode (extracted from PSR) */ | 181 | int psrs; /* supervisor mode (extracted from PSR) */ |
| 182 | int psrps; /* previous supervisor mode */ | 182 | int psrps; /* previous supervisor mode */ |
| 183 | int psret; /* enable traps */ | 183 | int psret; /* enable traps */ |
| 184 | - uint32_t psrpil; /* interrupt level */ | 184 | + uint32_t psrpil; /* interrupt blocking level */ |
| 185 | + uint32_t pil_in; /* incoming interrupt level bitmap */ | ||
| 185 | int psref; /* enable fpu */ | 186 | int psref; /* enable fpu */ |
| 186 | target_ulong version; | 187 | target_ulong version; |
| 187 | jmp_buf jmp_env; | 188 | jmp_buf jmp_env; |
| @@ -306,6 +307,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, | @@ -306,6 +307,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, | ||
| 306 | void do_tick_set_count(void *opaque, uint64_t count); | 307 | void do_tick_set_count(void *opaque, uint64_t count); |
| 307 | uint64_t do_tick_get_count(void *opaque); | 308 | uint64_t do_tick_get_count(void *opaque); |
| 308 | void do_tick_set_limit(void *opaque, uint64_t limit); | 309 | void do_tick_set_limit(void *opaque, uint64_t limit); |
| 310 | +void cpu_check_irqs(CPUSPARCState *env); | ||
| 309 | 311 | ||
| 310 | #define CPUState CPUSPARCState | 312 | #define CPUState CPUSPARCState |
| 311 | #define cpu_init cpu_sparc_init | 313 | #define cpu_init cpu_sparc_init |