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 | ... | ... |