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 |