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 | 461 | env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
| 462 | 462 | do_interrupt(env->interrupt_index); |
| 463 | 463 | env->interrupt_index = 0; |
| 464 | +#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) | |
| 465 | + cpu_check_irqs(env); | |
| 466 | +#endif | |
| 464 | 467 | #if defined(__sparc__) && !defined(HOST_SOLARIS) |
| 465 | 468 | tmp_T0 = 0; |
| 466 | 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 | 104 | val |= 80000000; |
| 105 | 105 | val &= 0xfffe0000; |
| 106 | 106 | s->intreg_pending[cpu] &= ~val; |
| 107 | + slavio_check_interrupts(s); | |
| 107 | 108 | DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); |
| 108 | 109 | break; |
| 109 | 110 | case 2: // set softint |
| ... | ... | @@ -175,10 +176,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin |
| 175 | 176 | val &= ~0x4fb2007f; |
| 176 | 177 | s->intregm_disabled |= val; |
| 177 | 178 | s->intregm_pending &= ~val; |
| 179 | + slavio_check_interrupts(s); | |
| 178 | 180 | DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); |
| 179 | 181 | break; |
| 180 | 182 | case 4: |
| 181 | 183 | s->target_cpu = val & (MAX_CPUS - 1); |
| 184 | + slavio_check_interrupts(s); | |
| 182 | 185 | DPRINTF("Set master irq cpu %d\n", s->target_cpu); |
| 183 | 186 | break; |
| 184 | 187 | default: |
| ... | ... | @@ -227,53 +230,36 @@ void slavio_irq_info(void *opaque) |
| 227 | 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 | 233 | static void slavio_check_interrupts(void *opaque) |
| 251 | 234 | { |
| 252 | 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 | 239 | pending &= ~s->intregm_disabled; |
| 257 | 240 | |
| 258 | 241 | DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); |
| 259 | 242 | for (i = 0; i < MAX_CPUS; i++) { |
| 260 | - max = 0; | |
| 243 | + pil_pending = 0; | |
| 261 | 244 | if (pending && !(s->intregm_disabled & 0x80000000) && |
| 262 | 245 | (i == s->target_cpu)) { |
| 263 | 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 | 277 | level); |
| 292 | 278 | if (pil > 0) { |
| 293 | 279 | if (level) { |
| 280 | +#ifdef DEBUG_IRQ_COUNT | |
| 281 | + s->irq_count[pil]++; | |
| 282 | +#endif | |
| 294 | 283 | s->intregm_pending |= mask; |
| 295 | 284 | s->intreg_pending[s->target_cpu] |= 1 << pil; |
| 296 | 285 | } else { |
| ... | ... | @@ -342,6 +331,7 @@ static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) |
| 342 | 331 | qemu_get_be32s(f, &s->intregm_pending); |
| 343 | 332 | qemu_get_be32s(f, &s->intregm_disabled); |
| 344 | 333 | qemu_get_be32s(f, &s->target_cpu); |
| 334 | + slavio_check_interrupts(s); | |
| 345 | 335 | return 0; |
| 346 | 336 | } |
| 347 | 337 | |
| ... | ... | @@ -356,6 +346,7 @@ static void slavio_intctl_reset(void *opaque) |
| 356 | 346 | s->intregm_disabled = ~0xffb2007f; |
| 357 | 347 | s->intregm_pending = 0; |
| 358 | 348 | s->target_cpu = 0; |
| 349 | + slavio_check_interrupts(s); | |
| 359 | 350 | } |
| 360 | 351 | |
| 361 | 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 | 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 | 265 | static void cpu_set_irq(void *opaque, int irq, int level) |
| 244 | 266 | { |
| 245 | 267 | CPUState *env = opaque; |
| 246 | 268 | |
| 247 | 269 | if (level) { |
| 248 | 270 | DPRINTF("Raise CPU IRQ %d\n", irq); |
| 249 | - | |
| 250 | 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 | 274 | } else { |
| 262 | 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 | 181 | int psrs; /* supervisor mode (extracted from PSR) */ |
| 182 | 182 | int psrps; /* previous supervisor mode */ |
| 183 | 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 | 186 | int psref; /* enable fpu */ |
| 186 | 187 | target_ulong version; |
| 187 | 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 | 307 | void do_tick_set_count(void *opaque, uint64_t count); |
| 307 | 308 | uint64_t do_tick_get_count(void *opaque); |
| 308 | 309 | void do_tick_set_limit(void *opaque, uint64_t limit); |
| 310 | +void cpu_check_irqs(CPUSPARCState *env); | |
| 309 | 311 | |
| 310 | 312 | #define CPUState CPUSPARCState |
| 311 | 313 | #define cpu_init cpu_sparc_init | ... | ... |