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