Sun4m SMP machines support a maximum of 4 CPUs. Linux knows this and uses fixed size arrays for per-cpu counter/timers and interrupt controllers. Sun4m uni-processor machines use the slaveio chip which has a single per-cpu counter/timer and interrupt controller. However it does not fully decode the address so the same counter/timer or interrupt controller can be accesses from multiple addresses.
This patch changes the per-cpu counter/timer to work the way the real hardware works: 4 per-cpu counter/timers for SMP and 1 counter/timer for UP mapped at multiple addresses. This patch also fixes a number of per-cpu user timer bugs: limit bit set when limit reached, count saved and used when written, limit bit reset on count write and system timer configuration register updated properly for per-cpu user timer mode. Sun4d currently uses the sun4m counter/timer code. They are simular but not the same. This patch will break the broken sun4d implementation further. The real fix is to create a proper sun4d counter/timer implementation. Since the sun4d implementation doesn't currently work anyway, this shouldn't be an issue.
Index: hw/sbi.c =================================================================== RCS file: /sources/qemu/qemu/hw/sbi.c,v retrieving revision 1.2 diff -p -u -r1.2 sbi.c --- hw/sbi.c 1 Jan 2008 17:06:38 -0000 1.2 +++ hw/sbi.c 5 Jan 2008 00:43:27 -0000 @@ -34,15 +34,13 @@ do { printf("IRQ: " fmt , ##args); } whi #define DPRINTF(fmt, args...) #endif -#define MAX_CPUS 16 - #define SBI_NREGS 16 typedef struct SBIState { uint32_t regs[SBI_NREGS]; - uint32_t intreg_pending[MAX_CPUS]; - qemu_irq *cpu_irqs[MAX_CPUS]; - uint32_t pil_out[MAX_CPUS]; + uint32_t intreg_pending[MAX_SUN4D_CPUS]; + qemu_irq *cpu_irqs[MAX_SUN4D_CPUS]; + uint32_t pil_out[MAX_SUN4D_CPUS]; } SBIState; #define SBI_SIZE (SBI_NREGS * 4) @@ -107,7 +105,7 @@ static void sbi_save(QEMUFile *f, void * SBIState *s = opaque; unsigned int i; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4D_CPUS; i++) { qemu_put_be32s(f, &s->intreg_pending[i]); } } @@ -120,7 +118,7 @@ static int sbi_load(QEMUFile *f, void *o if (version_id != 1) return -EINVAL; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4D_CPUS; i++) { qemu_get_be32s(f, &s->intreg_pending[i]); } sbi_check_interrupts(s); @@ -133,7 +131,7 @@ static void sbi_reset(void *opaque) SBIState *s = opaque; unsigned int i; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4D_CPUS; i++) { s->intreg_pending[i] = 0; } sbi_check_interrupts(s); @@ -150,7 +148,7 @@ void *sbi_init(target_phys_addr_t addr, if (!s) return NULL; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4D_CPUS; i++) { s->cpu_irqs[i] = parent_irq[i]; } @@ -160,7 +158,7 @@ void *sbi_init(target_phys_addr_t addr, register_savevm("sbi", addr, 1, sbi_save, sbi_load, s); qemu_register_reset(sbi_reset, s); *irq = qemu_allocate_irqs(sbi_set_irq, s, 32); - *cpu_irq = qemu_allocate_irqs(sbi_set_timer_irq_cpu, s, MAX_CPUS); + *cpu_irq = qemu_allocate_irqs(sbi_set_timer_irq_cpu, s, MAX_SUN4D_CPUS); sbi_reset(s); return s; Index: hw/slavio_intctl.c =================================================================== RCS file: /sources/qemu/qemu/hw/slavio_intctl.c,v retrieving revision 1.29 diff -p -u -r1.29 slavio_intctl.c --- hw/slavio_intctl.c 1 Jan 2008 20:57:25 -0000 1.29 +++ hw/slavio_intctl.c 5 Jan 2008 00:43:27 -0000 @@ -46,21 +46,20 @@ do { printf("IRQ: " fmt , ##args); } whi * */ -#define MAX_CPUS 16 #define MAX_PILS 16 typedef struct SLAVIO_INTCTLState { - uint32_t intreg_pending[MAX_CPUS]; + uint32_t intreg_pending[MAX_SUN4M_CPUS]; uint32_t intregm_pending; uint32_t intregm_disabled; uint32_t target_cpu; #ifdef DEBUG_IRQ_COUNT uint64_t irq_count[32]; #endif - qemu_irq *cpu_irqs[MAX_CPUS]; + qemu_irq *cpu_irqs[MAX_SUN4M_CPUS]; const uint32_t *intbit_to_level; uint32_t cputimer_lbit, cputimer_mbit; - uint32_t pil_out[MAX_CPUS]; + uint32_t pil_out[MAX_SUN4M_CPUS]; } SLAVIO_INTCTLState; #define INTCTL_MAXADDR 0xf @@ -84,7 +83,7 @@ static uint32_t slavio_intctl_mem_readl( uint32_t saddr, ret; int cpu; - cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; + cpu = (addr & (MAX_SUN4M_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; saddr = (addr & INTCTL_MAXADDR) >> 2; switch (saddr) { case 0: @@ -105,7 +104,7 @@ static void slavio_intctl_mem_writel(voi uint32_t saddr; int cpu; - cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; + cpu = (addr & (MAX_SUN4M_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; saddr = (addr & INTCTL_MAXADDR) >> 2; DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, val); switch (saddr) { @@ -190,7 +189,7 @@ static void slavio_intctlm_mem_writel(vo DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); break; case 4: - s->target_cpu = val & (MAX_CPUS - 1); + s->target_cpu = val & (MAX_SUN4M_CPUS - 1); slavio_check_interrupts(s); DPRINTF("Set master irq cpu %d\n", s->target_cpu); break; @@ -216,7 +215,7 @@ void slavio_pic_info(void *opaque) SLAVIO_INTCTLState *s = opaque; int i; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4M_CPUS; i++) { term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); } term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled); @@ -249,7 +248,7 @@ static void slavio_check_interrupts(void pending &= ~s->intregm_disabled; DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4M_CPUS; i++) { pil_pending = 0; if (pending && !(s->intregm_disabled & MASTER_DISABLE) && (i == s->target_cpu)) { @@ -322,7 +321,7 @@ static void slavio_intctl_save(QEMUFile SLAVIO_INTCTLState *s = opaque; int i; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4M_CPUS; i++) { qemu_put_be32s(f, &s->intreg_pending[i]); } qemu_put_be32s(f, &s->intregm_pending); @@ -335,10 +334,10 @@ static int slavio_intctl_load(QEMUFile * SLAVIO_INTCTLState *s = opaque; int i; - if (version_id != 1) + if (version_id != 2) return -EINVAL; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4M_CPUS; i++) { qemu_get_be32s(f, &s->intreg_pending[i]); } qemu_get_be32s(f, &s->intregm_pending); @@ -353,7 +352,7 @@ static void slavio_intctl_reset(void *op SLAVIO_INTCTLState *s = opaque; int i; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4M_CPUS; i++) { s->intreg_pending[i] = 0; } s->intregm_disabled = ~MASTER_IRQ_MASK; @@ -375,7 +374,7 @@ void *slavio_intctl_init(target_phys_add return NULL; s->intbit_to_level = intbit_to_level; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4M_CPUS; i++) { slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, slavio_intctl_io_memory); @@ -385,11 +384,11 @@ void *slavio_intctl_init(target_phys_add slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); cpu_register_physical_memory(addrg, INTCTLM_SIZE, slavio_intctlm_io_memory); - register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); + register_savevm("slavio_intctl", addr, 2, slavio_intctl_save, slavio_intctl_load, s); qemu_register_reset(slavio_intctl_reset, s); *irq = qemu_allocate_irqs(slavio_set_irq, s, 32); - *cpu_irq = qemu_allocate_irqs(slavio_set_timer_irq_cpu, s, MAX_CPUS); + *cpu_irq = qemu_allocate_irqs(slavio_set_timer_irq_cpu, s, MAX_SUN4M_CPUS); s->cputimer_mbit = 1 << cputimer; s->cputimer_lbit = 1 << intbit_to_level[cputimer]; slavio_intctl_reset(s); Index: hw/slavio_timer.c =================================================================== RCS file: /sources/qemu/qemu/hw/slavio_timer.c,v retrieving revision 1.28 diff -p -u -r1.28 slavio_timer.c --- hw/slavio_timer.c 1 Jan 2008 17:06:38 -0000 1.28 +++ hw/slavio_timer.c 5 Jan 2008 00:43:27 -0000 @@ -47,10 +47,13 @@ do { printf("TIMER: " fmt , ##args); } w * Per-CPU timers interrupt local CPU, system timer uses normal * interrupt routing. * + * SMP systems (SS-10, SS-20, SS-600MP) have 4 processor counter/timers. + * UP systems (SS-5) have a single processor counter/timer mapped at multiple + * addresses. + * + * Counters are always running. User timers may be stopped and started. */ -#define MAX_CPUS 16 - typedef struct SLAVIO_TIMERState { qemu_irq irq; ptimer_state *timer; @@ -61,8 +64,8 @@ typedef struct SLAVIO_TIMERState { struct SLAVIO_TIMERState *master; int slave_index; // system only - unsigned int num_slaves; - struct SLAVIO_TIMERState *slave[MAX_CPUS]; + int smp; + struct SLAVIO_TIMERState *slave[MAX_SUN4M_CPUS]; uint32_t slave_mode; } SLAVIO_TIMERState; @@ -93,6 +96,11 @@ static int slavio_timer_is_user(SLAVIO_T return s->master && (s->master->slave_mode & (1 << s->slave_index)); } +static int slavio_timer_is_mapped(SLAVIO_TIMERState *s) +{ + return s->master && (!s->master->smp && s->slave_index > 1); +} + // Update count, set irq, update expire_time // Convert from ptimer countdown units static void slavio_timer_get_out(SLAVIO_TIMERState *s) @@ -104,10 +112,7 @@ static void slavio_timer_get_out(SLAVIO_ else limit = s->limit; - if (s->timer) - count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer)); - else - count = 0; + count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer)); DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit, s->counthigh, s->count); @@ -122,10 +127,9 @@ static void slavio_timer_irq(void *opaqu slavio_timer_get_out(s); DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); - if (!slavio_timer_is_user(s)) { - s->reached = TIMER_REACHED; + s->reached = TIMER_REACHED; + if (!slavio_timer_is_user(s)) qemu_irq_raise(s->irq); - } } static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) @@ -133,6 +137,9 @@ static uint32_t slavio_timer_mem_readl(v SLAVIO_TIMERState *s = opaque; uint32_t saddr, ret; + if (slavio_timer_is_mapped(s)) + s = s->master->slave[0]; + saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { case TIMER_LIMIT: @@ -141,7 +148,7 @@ static uint32_t slavio_timer_mem_readl(v if (slavio_timer_is_user(s)) { // read user timer MSW slavio_timer_get_out(s); - ret = s->counthigh; + ret = s->counthigh | s->reached; } else { // read limit // clear irq @@ -183,89 +190,112 @@ static void slavio_timer_mem_writel(void uint32_t val) { SLAVIO_TIMERState *s = opaque; +#ifdef DEBUG_TIMER + SLAVIO_TIMERState *original = opaque; +#endif uint32_t saddr; + if (slavio_timer_is_mapped(s)) + s = s->master->slave[0]; + DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val); saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { case TIMER_LIMIT: if (slavio_timer_is_user(s)) { + uint64_t count; // set user counter MSW, reset counter qemu_irq_lower(s->irq); - s->limit = TIMER_MAX_COUNT64; - DPRINTF("processor %d user timer reset\n", s->slave_index); - if (s->timer) - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); + s->reached = 0; + s->counthigh = val & (TIMER_MAX_COUNT64 >> 32); + count = s->count | (uint64_t)s->counthigh << 32; + DPRINTF("processor %d user timer set to %016llx\n", + original->slave_index, count); + ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count)); } else { // set limit, reset counter qemu_irq_lower(s->irq); s->limit = val & TIMER_MAX_COUNT32; - if (s->timer) { - if (s->limit == 0) /* free-run */ - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); - else - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); - } + if (s->limit == 0) /* free-run */ + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), + 1); + else + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); } break; case TIMER_COUNTER: if (slavio_timer_is_user(s)) { + uint64_t count; // set user counter LSW, reset counter qemu_irq_lower(s->irq); - s->limit = TIMER_MAX_COUNT64; - DPRINTF("processor %d user timer reset\n", s->slave_index); - if (s->timer) - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); + s->reached = 0; + s->count = val & TIMER_MAX_COUNT64; + count = s->count | (uint64_t)s->counthigh << 32; + DPRINTF("processor %d user timer set to %016llx\n", + original->slave_index, count); + ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count)); } else DPRINTF("not user timer\n"); break; case TIMER_COUNTER_NORST: // set limit without resetting counter s->limit = val & TIMER_MAX_COUNT32; - if (s->timer) { - if (s->limit == 0) /* free-run */ - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); - else - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0); - } + if (s->limit == 0) /* free-run */ + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); + else + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0); break; case TIMER_STATUS: if (slavio_timer_is_user(s)) { // start/stop user counter if ((val & 1) && !s->running) { - DPRINTF("processor %d user timer started\n", s->slave_index); - if (s->timer) - ptimer_run(s->timer, 0); + DPRINTF("processor %d user timer started\n", original->slave_index); + ptimer_run(s->timer, 0); s->running = 1; } else if (!(val & 1) && s->running) { - DPRINTF("processor %d user timer stopped\n", s->slave_index); - if (s->timer) - ptimer_stop(s->timer); + DPRINTF("processor %d user timer stopped\n", original->slave_index); + ptimer_stop(s->timer); s->running = 0; } } break; case TIMER_MODE: if (s->master == NULL) { - unsigned int i; + unsigned int i, num_slaves = s->smp ? MAX_SUN4M_CPUS : 1; - for (i = 0; i < s->num_slaves; i++) { - if (val & (1 << i)) { - qemu_irq_lower(s->slave[i]->irq); - s->slave[i]->limit = -1ULL; - } else { - ptimer_stop(s->slave[i]->timer); - } - if ((val & (1 << i)) != (s->slave_mode & (1 << i))) { - ptimer_stop(s->slave[i]->timer); - ptimer_set_limit(s->slave[i]->timer, - LIMIT_TO_PERIODS(s->slave[i]->limit), 1); - DPRINTF("processor %d timer changed\n", - s->slave[i]->slave_index); - ptimer_run(s->slave[i]->timer, 0); + for (i = 0; i < num_slaves; i++) { + unsigned int processor = 1 << i; + // check for a change in timer mode for this processor + if ((val & processor) != (s->slave_mode & processor)) { + if (val & processor) { // counter -> user timer + qemu_irq_lower(s->slave[i]->irq); + // counters are always running + ptimer_stop(s->slave[i]->timer); + s->slave[i]->running = 0; + // user timer limit is always the same + s->slave[i]->limit = TIMER_MAX_COUNT64; + ptimer_set_limit(s->slave[i]->timer, + LIMIT_TO_PERIODS(s->slave[i]->limit), 1); + // set this processors user timer bit in config + // register + s->slave_mode |= processor; + DPRINTF("processor %d changed from counter to user " + "timer\n", s->slave[i]->slave_index); + } else { // user timer -> counter + // stop the user timer if it is running + if (s->slave[i]->running) + ptimer_stop(s->slave[i]->timer); + // start the counter + ptimer_run(s->slave[i]->timer, 0); + s->slave[i]->running = 1; + // clear this processors user timer bit in config + // register + s->slave_mode &= ~processor; + DPRINTF("processor %d changed from user timer to " + "counter\n", s->slave[i]->slave_index); + } } } - s->slave_mode = val & ((1 << s->num_slaves) - 1); } else DPRINTF("not system timer\n"); break; @@ -296,8 +326,7 @@ static void slavio_timer_save(QEMUFile * qemu_put_be32s(f, &s->counthigh); qemu_put_be32s(f, &s->reached); qemu_put_be32s(f, &s->running); - if (s->timer) - qemu_put_ptimer(f, s->timer); + qemu_put_ptimer(f, s->timer); } static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) @@ -312,8 +341,7 @@ static int slavio_timer_load(QEMUFile *f qemu_get_be32s(f, &s->counthigh); qemu_get_be32s(f, &s->reached); qemu_get_be32s(f, &s->running); - if (s->timer) - qemu_get_ptimer(f, s->timer); + qemu_get_ptimer(f, s->timer); return 0; } @@ -326,10 +354,8 @@ static void slavio_timer_reset(void *opa s->count = 0; s->reached = 0; s->slave_mode = 0; - if (!s->master || s->slave_index < s->master->num_slaves) { - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); - ptimer_run(s->timer, 0); - } + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); + ptimer_run(s->timer, 0); s->running = 1; qemu_irq_lower(s->irq); } @@ -337,7 +363,7 @@ static void slavio_timer_reset(void *opa static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, SLAVIO_TIMERState *master, - int slave_index) + int slave_index, int mapped) { int slavio_timer_io_memory; SLAVIO_TIMERState *s; @@ -349,7 +375,7 @@ static SLAVIO_TIMERState *slavio_timer_i s->irq = irq; s->master = master; s->slave_index = slave_index; - if (!master || slave_index < master->num_slaves) { + if (!mapped) { /* don't create a qemu timer for mapped devices */ bh = qemu_bh_new(slavio_timer_irq, s); s->timer = ptimer_init(bh); ptimer_set_period(s->timer, TIMER_PERIOD); @@ -363,27 +389,30 @@ static SLAVIO_TIMERState *slavio_timer_i else cpu_register_physical_memory(addr, SYS_TIMER_SIZE, slavio_timer_io_memory); - register_savevm("slavio_timer", addr, 3, slavio_timer_save, - slavio_timer_load, s); - qemu_register_reset(slavio_timer_reset, s); - slavio_timer_reset(s); + if (!mapped) { /* don't register mapped devices */ + register_savevm("slavio_timer", addr, 3, slavio_timer_save, + slavio_timer_load, s); + qemu_register_reset(slavio_timer_reset, s); + slavio_timer_reset(s); + } return s; } void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, - qemu_irq *cpu_irqs, unsigned int num_cpus) + qemu_irq *cpu_irqs, int smp) { SLAVIO_TIMERState *master; unsigned int i; - master = slavio_timer_init(base + SYS_TIMER_OFFSET, master_irq, NULL, 0); + master = slavio_timer_init(base + SYS_TIMER_OFFSET, master_irq, NULL, 0, 0); - master->num_slaves = num_cpus; + master->smp = smp; - for (i = 0; i < MAX_CPUS; i++) { + for (i = 0; i < MAX_SUN4M_CPUS; i++) { master->slave[i] = slavio_timer_init(base + (target_phys_addr_t) CPU_TIMER_OFFSET(i), - cpu_irqs[i], master, i); + cpu_irqs[i], master, i, + !smp && i != 0); } } Index: hw/sun4m.c =================================================================== RCS file: /sources/qemu/qemu/hw/sun4m.c,v retrieving revision 1.79 diff -p -u -r1.79 sun4m.c --- hw/sun4m.c 1 Jan 2008 20:57:25 -0000 1.79 +++ hw/sun4m.c 5 Jan 2008 00:43:28 -0000 @@ -75,7 +75,6 @@ #define PROM_VADDR 0xffd00000 #define PROM_FILENAME "openbios-sparc32" -#define MAX_CPUS 16 #define MAX_PILS 16 struct hwdef { @@ -366,10 +365,10 @@ static void sun4m_hw_init(const struct h const char *initrd_filename, const char *cpu_model) { - CPUState *env, *envs[MAX_CPUS]; + CPUState *env, *envs[MAX_SUN4M_CPUS]; unsigned int i; void *iommu, *espdma, *ledma, *main_esp, *nvram; - qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, + qemu_irq *cpu_irqs[MAX_SUN4M_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; qemu_irq *esp_reset, *le_reset; unsigned long prom_offset, kernel_size; @@ -378,6 +377,15 @@ static void sun4m_hw_init(const struct h BlockDriverState *fd[MAX_FD]; int index; + /* sun4m SMP systems support up to 4 CPUs */ + if ((hwdef->machine_id == 0x80 && smp_cpus > 1) || + (hwdef->machine_id != 0x80 && smp_cpus > MAX_SUN4M_CPUS)) { + fprintf(stderr, + "qemu: Too many CPUs for this machine: %d maiximum %d\n", + smp_cpus, hwdef->machine_id == 0x80 ? 1 : MAX_SUN4M_CPUS); + exit(1); + } + /* init CPUs */ if (!cpu_model) cpu_model = hwdef->default_cpu_model; @@ -385,7 +393,7 @@ static void sun4m_hw_init(const struct h for(i = 0; i < smp_cpus; i++) { env = cpu_init(cpu_model); if (!env) { - fprintf(stderr, "Unable to find Sparc CPU definition\n"); + fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); exit(1); } cpu_sparc_set_id(env, i); @@ -401,13 +409,14 @@ static void sun4m_hw_init(const struct h env->prom_addr = hwdef->slavio_base; } - for (i = smp_cpus; i < MAX_CPUS; i++) + for (i = smp_cpus; i < MAX_SUN4M_CPUS; i++) cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); /* allocate RAM */ if ((uint64_t)RAM_size > hwdef->max_mem) { - fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", + fprintf(stderr, + "qemu: Too much memory for this machine: %d, maximum %d\n", (unsigned int)RAM_size / (1024 * 1024), (unsigned int)(hwdef->max_mem / (1024 * 1024))); exit(1); @@ -481,7 +490,7 @@ static void sun4m_hw_init(const struct h hwdef->nvram_size, 8); slavio_timer_init_all(hwdef->counter_base, slavio_irq[hwdef->clock1_irq], - slavio_cpu_irq, smp_cpus); + slavio_cpu_irq, hwdef->machine_id != 0x80); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq], nographic); @@ -548,13 +557,20 @@ static void sun4c_hw_init(const struct h BlockDriverState *fd[MAX_FD]; int index; + /* sun4c is single processor only */ + if (smp_cpus != 1) { + fprintf(stderr, "qemu: Too many CPUs for this machine: %d maiximum 1\n", + smp_cpus); + exit(1); + } + /* init CPU */ if (!cpu_model) cpu_model = hwdef->default_cpu_model; env = cpu_init(cpu_model); if (!env) { - fprintf(stderr, "Unable to find Sparc CPU definition\n"); + fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); exit(1); } @@ -567,7 +583,8 @@ static void sun4c_hw_init(const struct h /* allocate RAM */ if ((uint64_t)RAM_size > hwdef->max_mem) { - fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", + fprintf(stderr, + "qemu: Too much memory for this machine: %d, maximum %d\n", (unsigned int)RAM_size / (1024 * 1024), (unsigned int)hwdef->max_mem / (1024 * 1024)); exit(1); @@ -1023,10 +1040,10 @@ static void sun4d_hw_init(const struct s const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUState *env, *envs[MAX_CPUS]; + CPUState *env, *envs[MAX_SUN4D_CPUS]; unsigned int i; void *iounits[MAX_IOUNITS], *espdma, *ledma, *main_esp, *nvram, *sbi; - qemu_irq *cpu_irqs[MAX_CPUS], *sbi_irq, *sbi_cpu_irq, + qemu_irq *cpu_irqs[MAX_SUN4D_CPUS], *sbi_irq, *sbi_cpu_irq, *espdma_irq, *ledma_irq; qemu_irq *esp_reset, *le_reset; unsigned long prom_offset, kernel_size; @@ -1034,6 +1051,13 @@ static void sun4d_hw_init(const struct s char buf[1024]; int index; + if (smp_cpus > MAX_SUN4D_CPUS) { + fprintf(stderr, + "qemu: Too many CPUs for this machine: %d maiximum %d\n", + smp_cpus, MAX_SUN4D_CPUS); + exit(1); + } + /* init CPUs */ if (!cpu_model) cpu_model = hwdef->default_cpu_model; @@ -1041,7 +1065,7 @@ static void sun4d_hw_init(const struct s for (i = 0; i < smp_cpus; i++) { env = cpu_init(cpu_model); if (!env) { - fprintf(stderr, "Unable to find Sparc CPU definition\n"); + fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); exit(1); } cpu_sparc_set_id(env, i); @@ -1057,12 +1081,13 @@ static void sun4d_hw_init(const struct s env->prom_addr = hwdef->slavio_base; } - for (i = smp_cpus; i < MAX_CPUS; i++) + for (i = smp_cpus; i < MAX_SUN4D_CPUS; i++) cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); /* allocate RAM */ if ((uint64_t)RAM_size > hwdef->max_mem) { - fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", + fprintf(stderr, + "qemu: Too much memory for this machine: %d, maximum %d\n", (unsigned int)RAM_size / (1024 * 1024), (unsigned int)(hwdef->max_mem / (1024 * 1024))); exit(1); @@ -1083,8 +1108,7 @@ static void sun4d_hw_init(const struct s if (ret < 0 || ret > PROM_SIZE_MAX) ret = load_image(buf, phys_ram_base + prom_offset); if (ret < 0 || ret > PROM_SIZE_MAX) { - fprintf(stderr, "qemu: could not load prom '%s'\n", - buf); + fprintf(stderr, "qemu: could not load prom '%s'\n", buf); exit(1); } @@ -1125,7 +1149,7 @@ static void sun4d_hw_init(const struct s hwdef->nvram_size, 8); slavio_timer_init_all(hwdef->counter_base, sbi_irq[hwdef->clock1_irq], - sbi_cpu_irq, smp_cpus); + sbi_cpu_irq, 1); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[hwdef->ms_kb_irq], nographic); Index: hw/sun4m.h =================================================================== RCS file: /sources/qemu/qemu/hw/sun4m.h,v retrieving revision 1.8 diff -p -u -r1.8 sun4m.h --- hw/sun4m.h 1 Jan 2008 17:04:45 -0000 1.8 +++ hw/sun4m.h 5 Jan 2008 00:43:28 -0000 @@ -1,6 +1,9 @@ #ifndef SUN4M_H #define SUN4M_H +#define MAX_SUN4M_CPUS 4 +#define MAX_SUN4D_CPUS 20 + /* Devices used by sparc32 system. */ /* iommu.c */ @@ -44,7 +47,7 @@ void *sun4c_intctl_init(target_phys_addr /* slavio_timer.c */ void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, - qemu_irq *cpu_irqs, unsigned int num_cpus); + qemu_irq *cpu_irqs, int smp); /* slavio_serial.c */ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq,