[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] sparc32: fix per cpu counter/timer
From: |
Robert Reif |
Subject: |
[Qemu-devel] [PATCH] sparc32: fix per cpu counter/timer |
Date: |
Fri, 04 Jan 2008 20:08:34 -0500 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040308 |
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,
- [Qemu-devel] [PATCH] sparc32: fix per cpu counter/timer,
Robert Reif <=