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,6 +44,7 @@ do { printf("IRQ: " fmt , ##args); } while (0) | ||
44 | */ | 44 | */ |
45 | 45 | ||
46 | #define MAX_CPUS 16 | 46 | #define MAX_CPUS 16 |
47 | +#define MAX_PILS 16 | ||
47 | 48 | ||
48 | typedef struct SLAVIO_INTCTLState { | 49 | typedef struct SLAVIO_INTCTLState { |
49 | uint32_t intreg_pending[MAX_CPUS]; | 50 | uint32_t intreg_pending[MAX_CPUS]; |
@@ -53,9 +54,10 @@ typedef struct SLAVIO_INTCTLState { | @@ -53,9 +54,10 @@ typedef struct SLAVIO_INTCTLState { | ||
53 | #ifdef DEBUG_IRQ_COUNT | 54 | #ifdef DEBUG_IRQ_COUNT |
54 | uint64_t irq_count[32]; | 55 | uint64_t irq_count[32]; |
55 | #endif | 56 | #endif |
56 | - CPUState *cpu_envs[MAX_CPUS]; | 57 | + qemu_irq *cpu_irqs[MAX_CPUS]; |
57 | const uint32_t *intbit_to_level; | 58 | const uint32_t *intbit_to_level; |
58 | uint32_t cputimer_bit; | 59 | uint32_t cputimer_bit; |
60 | + uint32_t pil_out[MAX_CPUS]; | ||
59 | } SLAVIO_INTCTLState; | 61 | } SLAVIO_INTCTLState; |
60 | 62 | ||
61 | #define INTCTL_MAXADDR 0xf | 63 | #define INTCTL_MAXADDR 0xf |
@@ -213,67 +215,53 @@ void slavio_irq_info(void *opaque) | @@ -213,67 +215,53 @@ void slavio_irq_info(void *opaque) | ||
213 | #endif | 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 | static void slavio_check_interrupts(void *opaque) | 238 | static void slavio_check_interrupts(void *opaque) |
217 | { | 239 | { |
218 | - CPUState *env; | ||
219 | SLAVIO_INTCTLState *s = opaque; | 240 | SLAVIO_INTCTLState *s = opaque; |
220 | uint32_t pending = s->intregm_pending; | 241 | uint32_t pending = s->intregm_pending; |
221 | unsigned int i, j, max = 0; | 242 | unsigned int i, j, max = 0; |
222 | 243 | ||
223 | pending &= ~s->intregm_disabled; | 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 | for (i = 0; i < MAX_CPUS; i++) { | 247 | for (i = 0; i < MAX_CPUS; i++) { |
255 | max = 0; | 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 | for (j = 17; j < 32; j++) { | 258 | for (j = 17; j < 32; j++) { |
260 | if (s->intreg_pending[i] & (1 << j)) { | 259 | if (s->intreg_pending[i] & (1 << j)) { |
261 | if (max < j - 16) | 260 | if (max < j - 16) |
262 | max = j - 16; | 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,22 +272,20 @@ static void slavio_check_interrupts(void *opaque) | ||
284 | static void slavio_set_irq(void *opaque, int irq, int level) | 272 | static void slavio_set_irq(void *opaque, int irq, int level) |
285 | { | 273 | { |
286 | SLAVIO_INTCTLState *s = opaque; | 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,15 +293,12 @@ static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) | ||
307 | { | 293 | { |
308 | SLAVIO_INTCTLState *s = opaque; | 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 | s->intreg_pending[cpu] |= s->cputimer_bit; | 299 | s->intreg_pending[cpu] |= s->cputimer_bit; |
316 | - } else { | 300 | + else |
317 | s->intreg_pending[cpu] &= ~s->cputimer_bit; | 301 | s->intreg_pending[cpu] &= ~s->cputimer_bit; |
318 | - } | ||
319 | 302 | ||
320 | slavio_check_interrupts(s); | 303 | slavio_check_interrupts(s); |
321 | } | 304 | } |
@@ -363,18 +346,10 @@ static void slavio_intctl_reset(void *opaque) | @@ -363,18 +346,10 @@ static void slavio_intctl_reset(void *opaque) | ||
363 | s->target_cpu = 0; | 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 | void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, | 349 | void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, |
374 | const uint32_t *intbit_to_level, | 350 | const uint32_t *intbit_to_level, |
375 | qemu_irq **irq, qemu_irq **cpu_irq, | 351 | qemu_irq **irq, qemu_irq **cpu_irq, |
376 | - unsigned int cputimer) | ||
377 | - | 352 | + qemu_irq **parent_irq, unsigned int cputimer) |
378 | { | 353 | { |
379 | int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; | 354 | int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; |
380 | SLAVIO_INTCTLState *s; | 355 | SLAVIO_INTCTLState *s; |
@@ -388,6 +363,7 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, | @@ -388,6 +363,7 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, | ||
388 | slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); | 363 | slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); |
389 | cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, | 364 | cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, |
390 | slavio_intctl_io_memory); | 365 | slavio_intctl_io_memory); |
366 | + s->cpu_irqs[i] = parent_irq[i]; | ||
391 | } | 367 | } |
392 | 368 | ||
393 | slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); | 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,6 +22,7 @@ | ||
22 | * THE SOFTWARE. | 22 | * THE SOFTWARE. |
23 | */ | 23 | */ |
24 | #include "vl.h" | 24 | #include "vl.h" |
25 | +//#define DEBUG_IRQ | ||
25 | 26 | ||
26 | /* | 27 | /* |
27 | * Sun4m architecture was used in the following machines: | 28 | * Sun4m architecture was used in the following machines: |
@@ -38,6 +39,13 @@ | @@ -38,6 +39,13 @@ | ||
38 | * See for example: http://www.sunhelp.org/faq/sunref1.html | 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 | #define KERNEL_LOAD_ADDR 0x00004000 | 49 | #define KERNEL_LOAD_ADDR 0x00004000 |
42 | #define CMDLINE_ADDR 0x007ff000 | 50 | #define CMDLINE_ADDR 0x007ff000 |
43 | #define INITRD_LOAD_ADDR 0x00800000 | 51 | #define INITRD_LOAD_ADDR 0x00800000 |
@@ -46,6 +54,7 @@ | @@ -46,6 +54,7 @@ | ||
46 | #define PROM_FILENAME "openbios-sparc32" | 54 | #define PROM_FILENAME "openbios-sparc32" |
47 | 55 | ||
48 | #define MAX_CPUS 16 | 56 | #define MAX_CPUS 16 |
57 | +#define MAX_PILS 16 | ||
49 | 58 | ||
50 | struct hwdef { | 59 | struct hwdef { |
51 | target_phys_addr_t iommu_base, slavio_base; | 60 | target_phys_addr_t iommu_base, slavio_base; |
@@ -233,6 +242,33 @@ void irq_info() | @@ -233,6 +242,33 @@ void irq_info() | ||
233 | slavio_irq_info(slavio_intctl); | 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 | static void *slavio_misc; | 272 | static void *slavio_misc; |
237 | 273 | ||
238 | void qemu_system_powerdown(void) | 274 | void qemu_system_powerdown(void) |
@@ -264,7 +300,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, | @@ -264,7 +300,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, | ||
264 | unsigned int i; | 300 | unsigned int i; |
265 | void *iommu, *espdma, *ledma, *main_esp; | 301 | void *iommu, *espdma, *ledma, *main_esp; |
266 | const sparc_def_t *def; | 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 | *espdma_irq, *ledma_irq; | 304 | *espdma_irq, *ledma_irq; |
269 | 305 | ||
270 | /* init CPUs */ | 306 | /* init CPUs */ |
@@ -273,6 +309,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, | @@ -273,6 +309,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, | ||
273 | fprintf(stderr, "Unable to find Sparc CPU definition\n"); | 309 | fprintf(stderr, "Unable to find Sparc CPU definition\n"); |
274 | exit(1); | 310 | exit(1); |
275 | } | 311 | } |
312 | + | ||
276 | for(i = 0; i < smp_cpus; i++) { | 313 | for(i = 0; i < smp_cpus; i++) { |
277 | env = cpu_init(); | 314 | env = cpu_init(); |
278 | cpu_sparc_register(env, def); | 315 | cpu_sparc_register(env, def); |
@@ -284,7 +321,12 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, | @@ -284,7 +321,12 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, | ||
284 | env->halted = 1; | 321 | env->halted = 1; |
285 | } | 322 | } |
286 | register_savevm("cpu", i, 3, cpu_save, cpu_load, env); | 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 | /* allocate RAM */ | 330 | /* allocate RAM */ |
289 | cpu_register_physical_memory(0, ram_size, 0); | 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,10 +335,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, | ||
293 | hwdef->intctl_base + 0x10000ULL, | 335 | hwdef->intctl_base + 0x10000ULL, |
294 | &hwdef->intbit_to_level[0], | 336 | &hwdef->intbit_to_level[0], |
295 | &slavio_irq, &slavio_cpu_irq, | 337 | &slavio_irq, &slavio_cpu_irq, |
338 | + cpu_irqs, | ||
296 | hwdef->clock_irq); | 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 | espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], | 341 | espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], |
301 | iommu, &espdma_irq); | 342 | iommu, &espdma_irq); |
302 | ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, | 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,8 +1233,7 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, | ||
1233 | void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, | 1233 | void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, |
1234 | const uint32_t *intbit_to_level, | 1234 | const uint32_t *intbit_to_level, |
1235 | qemu_irq **irq, qemu_irq **cpu_irq, | 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 | void slavio_pic_info(void *opaque); | 1237 | void slavio_pic_info(void *opaque); |
1239 | void slavio_irq_info(void *opaque); | 1238 | void slavio_irq_info(void *opaque); |
1240 | 1239 |