All of lore.kernel.org
 help / color / mirror / Atom feed
From: Robert Reif <reif@earthlink.net>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] sparc32: fix per cpu counter/timer
Date: Fri, 04 Jan 2008 20:08:34 -0500	[thread overview]
Message-ID: <477ED892.8060400@earthlink.net> (raw)

[-- Attachment #1: Type: text/plain, Size: 1140 bytes --]

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.

[-- Attachment #2: maxcpus.diff.txt --]
[-- Type: text/plain, Size: 28739 bytes --]

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,

             reply	other threads:[~2008-01-05  1:08 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-01-05  1:08 Robert Reif [this message]
2008-01-05 11:30 ` [Qemu-devel] [PATCH] sparc32: fix per cpu counter/timer Blue Swirl
2008-01-05 15:07   ` Robert Reif

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=477ED892.8060400@earthlink.net \
    --to=reif@earthlink.net \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.