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 |