Commit b3a2319792ad5c0f0f8c3d2f4d02b95fd7efbc69
1 parent
d7edfd27
Use qemu_irqs between CPUs and interrupt controller
Fix interrupt priority handling which prevented SMP from working git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2875 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
99 additions
and
83 deletions
hw/slavio_intctl.c
... | ... | @@ -44,6 +44,7 @@ do { printf("IRQ: " fmt , ##args); } while (0) |
44 | 44 | */ |
45 | 45 | |
46 | 46 | #define MAX_CPUS 16 |
47 | +#define MAX_PILS 16 | |
47 | 48 | |
48 | 49 | typedef struct SLAVIO_INTCTLState { |
49 | 50 | uint32_t intreg_pending[MAX_CPUS]; |
... | ... | @@ -53,9 +54,10 @@ typedef struct SLAVIO_INTCTLState { |
53 | 54 | #ifdef DEBUG_IRQ_COUNT |
54 | 55 | uint64_t irq_count[32]; |
55 | 56 | #endif |
56 | - CPUState *cpu_envs[MAX_CPUS]; | |
57 | + qemu_irq *cpu_irqs[MAX_CPUS]; | |
57 | 58 | const uint32_t *intbit_to_level; |
58 | 59 | uint32_t cputimer_bit; |
60 | + uint32_t pil_out[MAX_CPUS]; | |
59 | 61 | } SLAVIO_INTCTLState; |
60 | 62 | |
61 | 63 | #define INTCTL_MAXADDR 0xf |
... | ... | @@ -213,67 +215,53 @@ void slavio_irq_info(void *opaque) |
213 | 215 | #endif |
214 | 216 | } |
215 | 217 | |
218 | +static void raise_pil(SLAVIO_INTCTLState *s, unsigned int pil, | |
219 | + unsigned int cpu) | |
220 | +{ | |
221 | + qemu_irq irq; | |
222 | + unsigned int oldmax; | |
223 | + | |
224 | + irq = s->cpu_irqs[cpu][pil]; | |
225 | + | |
226 | +#ifdef DEBUG_IRQ_COUNT | |
227 | + s->irq_count[pil]++; | |
228 | +#endif | |
229 | + oldmax = s->pil_out[cpu]; | |
230 | + if (oldmax > 0 && oldmax != pil) | |
231 | + qemu_irq_lower(s->cpu_irqs[cpu][oldmax]); | |
232 | + s->pil_out[cpu] = pil; | |
233 | + if (pil > 0) | |
234 | + qemu_irq_raise(irq); | |
235 | + DPRINTF("cpu %d pil %d\n", cpu, pil); | |
236 | +} | |
237 | + | |
216 | 238 | static void slavio_check_interrupts(void *opaque) |
217 | 239 | { |
218 | - CPUState *env; | |
219 | 240 | SLAVIO_INTCTLState *s = opaque; |
220 | 241 | uint32_t pending = s->intregm_pending; |
221 | 242 | unsigned int i, j, max = 0; |
222 | 243 | |
223 | 244 | pending &= ~s->intregm_disabled; |
224 | 245 | |
225 | - if (pending && !(s->intregm_disabled & 0x80000000)) { | |
226 | - for (i = 0; i < 32; i++) { | |
227 | - if (pending & (1 << i)) { | |
228 | - if (max < s->intbit_to_level[i]) | |
229 | - max = s->intbit_to_level[i]; | |
230 | - } | |
231 | - } | |
232 | - env = s->cpu_envs[s->target_cpu]; | |
233 | - if (!env) { | |
234 | - DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending); | |
235 | - } | |
236 | - else { | |
237 | - if (env->halted) | |
238 | - env->halted = 0; | |
239 | - if (env->interrupt_index == 0) { | |
240 | - DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max); | |
241 | -#ifdef DEBUG_IRQ_COUNT | |
242 | - s->irq_count[max]++; | |
243 | -#endif | |
244 | - env->interrupt_index = TT_EXTINT | max; | |
245 | - cpu_interrupt(env, CPU_INTERRUPT_HARD); | |
246 | - } | |
247 | - else | |
248 | - DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index); | |
249 | - } | |
250 | - } | |
251 | - else | |
252 | - DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled); | |
253 | - | |
246 | + DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); | |
254 | 247 | for (i = 0; i < MAX_CPUS; i++) { |
255 | 248 | max = 0; |
256 | - env = s->cpu_envs[i]; | |
257 | - if (!env) | |
258 | - continue; | |
249 | + if (pending && !(s->intregm_disabled & 0x80000000) && | |
250 | + (i == s->target_cpu)) { | |
251 | + for (j = 0; j < 32; j++) { | |
252 | + if (pending & (1 << j)) { | |
253 | + if (max < s->intbit_to_level[j]) | |
254 | + max = s->intbit_to_level[j]; | |
255 | + } | |
256 | + } | |
257 | + } | |
259 | 258 | for (j = 17; j < 32; j++) { |
260 | 259 | if (s->intreg_pending[i] & (1 << j)) { |
261 | 260 | if (max < j - 16) |
262 | 261 | max = j - 16; |
263 | 262 | } |
264 | 263 | } |
265 | - if (max > 0) { | |
266 | - if (env->halted) | |
267 | - env->halted = 0; | |
268 | - if (env->interrupt_index == 0) { | |
269 | - DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending); | |
270 | -#ifdef DEBUG_IRQ_COUNT | |
271 | - s->irq_count[max]++; | |
272 | -#endif | |
273 | - env->interrupt_index = TT_EXTINT | max; | |
274 | - cpu_interrupt(env, CPU_INTERRUPT_HARD); | |
275 | - } | |
276 | - } | |
264 | + raise_pil(s, max, i); | |
277 | 265 | } |
278 | 266 | } |
279 | 267 | |
... | ... | @@ -284,22 +272,20 @@ static void slavio_check_interrupts(void *opaque) |
284 | 272 | static void slavio_set_irq(void *opaque, int irq, int level) |
285 | 273 | { |
286 | 274 | SLAVIO_INTCTLState *s = opaque; |
287 | - | |
288 | - DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level); | |
289 | - if (irq < 32) { | |
290 | - uint32_t mask = 1 << irq; | |
291 | - uint32_t pil = s->intbit_to_level[irq]; | |
292 | - if (pil > 0) { | |
293 | - if (level) { | |
294 | - s->intregm_pending |= mask; | |
295 | - s->intreg_pending[s->target_cpu] |= 1 << pil; | |
296 | - slavio_check_interrupts(s); | |
297 | - } | |
298 | - else { | |
299 | - s->intregm_pending &= ~mask; | |
300 | - s->intreg_pending[s->target_cpu] &= ~(1 << pil); | |
301 | - } | |
302 | - } | |
275 | + uint32_t mask = 1 << irq; | |
276 | + uint32_t pil = s->intbit_to_level[irq]; | |
277 | + | |
278 | + DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil, | |
279 | + level); | |
280 | + if (pil > 0) { | |
281 | + if (level) { | |
282 | + s->intregm_pending |= mask; | |
283 | + s->intreg_pending[s->target_cpu] |= 1 << pil; | |
284 | + } else { | |
285 | + s->intregm_pending &= ~mask; | |
286 | + s->intreg_pending[s->target_cpu] &= ~(1 << pil); | |
287 | + } | |
288 | + slavio_check_interrupts(s); | |
303 | 289 | } |
304 | 290 | } |
305 | 291 | |
... | ... | @@ -307,15 +293,12 @@ static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) |
307 | 293 | { |
308 | 294 | SLAVIO_INTCTLState *s = opaque; |
309 | 295 | |
310 | - DPRINTF("Set cpu %d local level %d\n", cpu, level); | |
311 | - if (!s->cpu_envs[cpu]) | |
312 | - return; | |
296 | + DPRINTF("Set cpu %d local timer level %d\n", cpu, level); | |
313 | 297 | |
314 | - if (level) { | |
298 | + if (level) | |
315 | 299 | s->intreg_pending[cpu] |= s->cputimer_bit; |
316 | - } else { | |
300 | + else | |
317 | 301 | s->intreg_pending[cpu] &= ~s->cputimer_bit; |
318 | - } | |
319 | 302 | |
320 | 303 | slavio_check_interrupts(s); |
321 | 304 | } |
... | ... | @@ -363,18 +346,10 @@ static void slavio_intctl_reset(void *opaque) |
363 | 346 | s->target_cpu = 0; |
364 | 347 | } |
365 | 348 | |
366 | -void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env) | |
367 | -{ | |
368 | - SLAVIO_INTCTLState *s = opaque; | |
369 | - | |
370 | - s->cpu_envs[cpu] = env; | |
371 | -} | |
372 | - | |
373 | 349 | void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, |
374 | 350 | const uint32_t *intbit_to_level, |
375 | 351 | qemu_irq **irq, qemu_irq **cpu_irq, |
376 | - unsigned int cputimer) | |
377 | - | |
352 | + qemu_irq **parent_irq, unsigned int cputimer) | |
378 | 353 | { |
379 | 354 | int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; |
380 | 355 | SLAVIO_INTCTLState *s; |
... | ... | @@ -388,6 +363,7 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, |
388 | 363 | slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); |
389 | 364 | cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, |
390 | 365 | slavio_intctl_io_memory); |
366 | + s->cpu_irqs[i] = parent_irq[i]; | |
391 | 367 | } |
392 | 368 | |
393 | 369 | slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); | ... | ... |
hw/sun4m.c
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | * THE SOFTWARE. |
23 | 23 | */ |
24 | 24 | #include "vl.h" |
25 | +//#define DEBUG_IRQ | |
25 | 26 | |
26 | 27 | /* |
27 | 28 | * Sun4m architecture was used in the following machines: |
... | ... | @@ -38,6 +39,13 @@ |
38 | 39 | * See for example: http://www.sunhelp.org/faq/sunref1.html |
39 | 40 | */ |
40 | 41 | |
42 | +#ifdef DEBUG_IRQ | |
43 | +#define DPRINTF(fmt, args...) \ | |
44 | + do { printf("CPUIRQ: " fmt , ##args); } while (0) | |
45 | +#else | |
46 | +#define DPRINTF(fmt, args...) | |
47 | +#endif | |
48 | + | |
41 | 49 | #define KERNEL_LOAD_ADDR 0x00004000 |
42 | 50 | #define CMDLINE_ADDR 0x007ff000 |
43 | 51 | #define INITRD_LOAD_ADDR 0x00800000 |
... | ... | @@ -46,6 +54,7 @@ |
46 | 54 | #define PROM_FILENAME "openbios-sparc32" |
47 | 55 | |
48 | 56 | #define MAX_CPUS 16 |
57 | +#define MAX_PILS 16 | |
49 | 58 | |
50 | 59 | struct hwdef { |
51 | 60 | target_phys_addr_t iommu_base, slavio_base; |
... | ... | @@ -233,6 +242,33 @@ void irq_info() |
233 | 242 | slavio_irq_info(slavio_intctl); |
234 | 243 | } |
235 | 244 | |
245 | +static void cpu_set_irq(void *opaque, int irq, int level) | |
246 | +{ | |
247 | + CPUState *env = opaque; | |
248 | + | |
249 | + if (level) { | |
250 | + DPRINTF("Raise CPU IRQ %d\n", irq); | |
251 | + | |
252 | + env->halted = 0; | |
253 | + | |
254 | + if (env->interrupt_index == 0 || | |
255 | + ((env->interrupt_index & ~15) == TT_EXTINT && | |
256 | + (env->interrupt_index & 15) < irq)) { | |
257 | + env->interrupt_index = TT_EXTINT | irq; | |
258 | + cpu_interrupt(env, CPU_INTERRUPT_HARD); | |
259 | + } else { | |
260 | + DPRINTF("Not triggered, pending exception %d\n", | |
261 | + env->interrupt_index); | |
262 | + } | |
263 | + } else { | |
264 | + DPRINTF("Lower CPU IRQ %d\n", irq); | |
265 | + } | |
266 | +} | |
267 | + | |
268 | +static void dummy_cpu_set_irq(void *opaque, int irq, int level) | |
269 | +{ | |
270 | +} | |
271 | + | |
236 | 272 | static void *slavio_misc; |
237 | 273 | |
238 | 274 | void qemu_system_powerdown(void) |
... | ... | @@ -264,7 +300,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, |
264 | 300 | unsigned int i; |
265 | 301 | void *iommu, *espdma, *ledma, *main_esp; |
266 | 302 | const sparc_def_t *def; |
267 | - qemu_irq *slavio_irq, *slavio_cpu_irq, | |
303 | + qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, | |
268 | 304 | *espdma_irq, *ledma_irq; |
269 | 305 | |
270 | 306 | /* init CPUs */ |
... | ... | @@ -273,6 +309,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, |
273 | 309 | fprintf(stderr, "Unable to find Sparc CPU definition\n"); |
274 | 310 | exit(1); |
275 | 311 | } |
312 | + | |
276 | 313 | for(i = 0; i < smp_cpus; i++) { |
277 | 314 | env = cpu_init(); |
278 | 315 | cpu_sparc_register(env, def); |
... | ... | @@ -284,7 +321,12 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, |
284 | 321 | env->halted = 1; |
285 | 322 | } |
286 | 323 | register_savevm("cpu", i, 3, cpu_save, cpu_load, env); |
324 | + cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS); | |
287 | 325 | } |
326 | + | |
327 | + for (i = smp_cpus; i < MAX_CPUS; i++) | |
328 | + cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); | |
329 | + | |
288 | 330 | /* allocate RAM */ |
289 | 331 | cpu_register_physical_memory(0, ram_size, 0); |
290 | 332 | |
... | ... | @@ -293,10 +335,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, |
293 | 335 | hwdef->intctl_base + 0x10000ULL, |
294 | 336 | &hwdef->intbit_to_level[0], |
295 | 337 | &slavio_irq, &slavio_cpu_irq, |
338 | + cpu_irqs, | |
296 | 339 | hwdef->clock_irq); |
297 | - for(i = 0; i < smp_cpus; i++) { | |
298 | - slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); | |
299 | - } | |
340 | + | |
300 | 341 | espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], |
301 | 342 | iommu, &espdma_irq); |
302 | 343 | ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, | ... | ... |
vl.h
... | ... | @@ -1233,8 +1233,7 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, |
1233 | 1233 | void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, |
1234 | 1234 | const uint32_t *intbit_to_level, |
1235 | 1235 | qemu_irq **irq, qemu_irq **cpu_irq, |
1236 | - unsigned int cputimer); | |
1237 | -void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); | |
1236 | + qemu_irq **parent_irq, unsigned int cputimer); | |
1238 | 1237 | void slavio_pic_info(void *opaque); |
1239 | 1238 | void slavio_irq_info(void *opaque); |
1240 | 1239 | ... | ... |