qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] sparc32 counter/timer issues
@ 2007-09-21 14:22 Robert Reif
  2007-09-21 20:19 ` Blue Swirl
  0 siblings, 1 reply; 4+ messages in thread
From: Robert Reif @ 2007-09-21 14:22 UTC (permalink / raw)
  To: qemu-devel

I'm trying to run a real ss10 openboot prom image rather than
the supplied prom image and found some issues with the way
counters and timers are implemented.  It appears that the processor
and system counter/timers are not independent.  The system
config register actually configures the processor counter/timers
and the config register is actually a bit mask of the counter/timer
to configure. 1, 2, 4, and 8 are used to as config values for each
processor counter/timer and 0xf is used for setting all of them. 
This isn't apparent in the slaveio documentation because it is
for a single cpu only.

Because the system config register configures the processor
timers, it needs access to all the processor timers (or the
processor timers need access to the system timer).  This isn't
how it's currently implemented.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] sparc32 counter/timer issues
  2007-09-21 14:22 [Qemu-devel] sparc32 counter/timer issues Robert Reif
@ 2007-09-21 20:19 ` Blue Swirl
  0 siblings, 0 replies; 4+ messages in thread
From: Blue Swirl @ 2007-09-21 20:19 UTC (permalink / raw)
  To: qemu-devel

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

On 9/21/07, Robert Reif <reif@earthlink.net> wrote:
> I'm trying to run a real ss10 openboot prom image rather than
> the supplied prom image and found some issues with the way
> counters and timers are implemented.  It appears that the processor
> and system counter/timers are not independent.  The system
> config register actually configures the processor counter/timers
> and the config register is actually a bit mask of the counter/timer
> to configure. 1, 2, 4, and 8 are used to as config values for each
> processor counter/timer and 0xf is used for setting all of them.
> This isn't apparent in the slaveio documentation because it is
> for a single cpu only.
>
> Because the system config register configures the processor
> timers, it needs access to all the processor timers (or the
> processor timers need access to the system timer).  This isn't
> how it's currently implemented.

Thanks for testing. This patch changes the config register to what you
described, everything seems to work like before. Do you see any
difference?

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: timer_fix.diff --]
[-- Type: text/x-diff; name="timer_fix.diff", Size: 5150 bytes --]

Index: qemu/hw/slavio_timer.c
===================================================================
--- qemu.orig/hw/slavio_timer.c	2007-09-21 19:30:43.000000000 +0000
+++ qemu/hw/slavio_timer.c	2007-09-21 20:08:51.000000000 +0000
@@ -47,6 +47,8 @@
  *
  */
 
+#define MAX_CPUS 16
+
 typedef struct SLAVIO_TIMERState {
     qemu_irq irq;
     ptimer_state *timer;
@@ -54,10 +56,13 @@
     uint64_t limit;
     int stopped;
     int mode; // 0 = processor, 1 = user, 2 = system
+    struct SLAVIO_TIMERState *slave[MAX_CPUS];
+    uint32_t slave_mode;
 } SLAVIO_TIMERState;
 
 #define TIMER_MAXADDR 0x1f
 #define TIMER_SIZE (TIMER_MAXADDR + 1)
+#define CPU_TIMER_SIZE 0x10
 
 // Update count, set irq, update expire_time
 // Convert from ptimer countdown units
@@ -120,7 +125,7 @@
         break;
     case 4:
 	// read user/system mode
-        ret = s->mode & 1;
+        ret = s->slave_mode;
         break;
     default:
         ret = 0;
@@ -167,13 +172,22 @@
 	break;
     case 4:
 	// bit 0: user (1) or system (0) counter mode
-	if (s->mode == 0 || s->mode == 1)
-	    s->mode = val & 1;
-        if (s->mode == 1) {
-            qemu_irq_lower(s->irq);
-            s->limit = -1ULL;
+        {
+            unsigned int i;
+
+            for (i = 0; i < MAX_CPUS; i++) {
+                if (val & (1 << i)) {
+                    qemu_irq_lower(s->slave[i]->irq);
+                    s->slave[i]->limit = -1ULL;
+                    s->slave[i]->mode = 1;
+                } else {
+                    s->slave[i]->mode = 0;
+                }
+                ptimer_set_limit(s->slave[i]->timer, s->slave[i]->limit >> 9,
+                                 1);
+            }
+            s->slave_mode = val & ((1 << MAX_CPUS) - 1);
         }
-        ptimer_set_limit(s->timer, s->limit >> 9, 1);
 	break;
     default:
 	break;
@@ -240,7 +254,8 @@
     qemu_irq_lower(s->irq);
 }
 
-void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode)
+static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr,
+                                            qemu_irq irq, int mode)
 {
     int slavio_timer_io_memory;
     SLAVIO_TIMERState *s;
@@ -248,7 +263,7 @@
 
     s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
     if (!s)
-        return;
+        return s;
     s->irq = irq;
     s->mode = mode;
     bh = qemu_bh_new(slavio_timer_irq, s);
@@ -257,8 +272,29 @@
 
     slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
 						    slavio_timer_mem_write, s);
-    cpu_register_physical_memory(addr, TIMER_SIZE, slavio_timer_io_memory);
+    if (mode < 2)
+        cpu_register_physical_memory(addr, CPU_TIMER_SIZE, slavio_timer_io_memory);
+    else
+        cpu_register_physical_memory(addr, TIMER_SIZE,
+                                     slavio_timer_io_memory);
     register_savevm("slavio_timer", addr, 2, 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)
+{
+    SLAVIO_TIMERState *master;
+    unsigned int i;
+
+    master = slavio_timer_init(base + 0x10000ULL, master_irq, 2);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        master->slave[i] = slavio_timer_init(base + (target_phys_addr_t)
+                                             (i * TARGET_PAGE_SIZE),
+                                             cpu_irqs[i], 0);
+    }
 }
Index: qemu/hw/sun4m.c
===================================================================
--- qemu.orig/hw/sun4m.c	2007-09-21 19:31:14.000000000 +0000
+++ qemu/hw/sun4m.c	2007-09-21 19:49:54.000000000 +0000
@@ -379,13 +379,10 @@
 
     nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
                         hwdef->nvram_size, 8);
-    for (i = 0; i < MAX_CPUS; i++) {
-        slavio_timer_init(hwdef->counter_base +
-                          (target_phys_addr_t)(i * TARGET_PAGE_SIZE),
-                           slavio_cpu_irq[i], 0);
-    }
-    slavio_timer_init(hwdef->counter_base + 0x10000ULL,
-                      slavio_irq[hwdef->clock1_irq], 2);
+
+    slavio_timer_init_all(hwdef->counter_base, slavio_irq[hwdef->clock1_irq],
+                          slavio_cpu_irq);
+
     slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]);
     // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
     // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
Index: qemu/vl.h
===================================================================
--- qemu.orig/vl.h	2007-09-21 19:47:54.000000000 +0000
+++ qemu/vl.h	2007-09-21 19:48:26.000000000 +0000
@@ -1275,7 +1275,8 @@
 int load_uboot(const char *filename, target_ulong *ep, int *is_linux);
 
 /* slavio_timer.c */
-void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode);
+void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq,
+                           qemu_irq *cpu_irqs);
 
 /* slavio_serial.c */
 SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq,

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] sparc32 counter/timer issues
@ 2007-09-21 23:10 Robert Reif
  2007-09-23 12:08 ` Blue Swirl
  0 siblings, 1 reply; 4+ messages in thread
From: Robert Reif @ 2007-09-21 23:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel

With the patch and ss10 boot prom I get:

TIMER: write 0000000ff130000c 00000000
TIMER: write 0000000ff1310010 00000001
TIMER: write 0000000ff1300000 00000000
TIMER: write 0000000ff1300004 00000000
TIMER: write 0000000ff130000c 00000001
TIMER: write 0000000ff1300000 00000000
TIMER: write 0000000ff1300004 00000000
TIMER: get_out: limit 7ffffe00 count 000000000
TIMER: read 0000000ff1300000 = 00000000

with the last two lines repeating forever.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] sparc32 counter/timer issues
  2007-09-21 23:10 Robert Reif
@ 2007-09-23 12:08 ` Blue Swirl
  0 siblings, 0 replies; 4+ messages in thread
From: Blue Swirl @ 2007-09-23 12:08 UTC (permalink / raw)
  To: Robert Reif; +Cc: qemu-devel

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

On 9/22/07, Robert Reif <reif@earthlink.net> wrote:
> With the patch and ss10 boot prom I get:
>
> TIMER: write 0000000ff130000c 00000000
> TIMER: write 0000000ff1310010 00000001
> TIMER: write 0000000ff1300000 00000000
> TIMER: write 0000000ff1300004 00000000
> TIMER: write 0000000ff130000c 00000001
> TIMER: write 0000000ff1300000 00000000
> TIMER: write 0000000ff1300004 00000000
> TIMER: get_out: limit 7ffffe00 count 000000000
> TIMER: read 0000000ff1300000 = 00000000
>
> with the last two lines repeating forever.

>From this I gather that the user timer mode is not very well
implemented. Can you try if this updated version of the patch changes
anything?

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: timer_fix.diff --]
[-- Type: text/x-diff; name="timer_fix.diff", Size: 6593 bytes --]

Index: qemu/hw/slavio_timer.c
===================================================================
--- qemu.orig/hw/slavio_timer.c	2007-09-23 07:37:38.000000000 +0000
+++ qemu/hw/slavio_timer.c	2007-09-23 12:03:07.000000000 +0000
@@ -47,6 +47,8 @@
  *
  */
 
+#define MAX_CPUS 16
+
 typedef struct SLAVIO_TIMERState {
     qemu_irq irq;
     ptimer_state *timer;
@@ -54,10 +56,13 @@
     uint64_t limit;
     int stopped;
     int mode; // 0 = processor, 1 = user, 2 = system
+    struct SLAVIO_TIMERState *slave[MAX_CPUS];
+    uint32_t slave_mode;
 } SLAVIO_TIMERState;
 
 #define TIMER_MAXADDR 0x1f
 #define TIMER_SIZE (TIMER_MAXADDR + 1)
+#define CPU_TIMER_SIZE 0x10
 
 // Update count, set irq, update expire_time
 // Convert from ptimer countdown units
@@ -120,7 +125,7 @@
         break;
     case 4:
 	// read user/system mode
-        ret = s->mode & 1;
+        ret = s->slave_mode;
         break;
     default:
         ret = 0;
@@ -141,10 +146,20 @@
     saddr = (addr & TIMER_MAXADDR) >> 2;
     switch (saddr) {
     case 0:
-	// set limit, reset counter
+        if (s->mode == 1) {
+            // set user counter limit MSW, reset counter
+            qemu_irq_lower(s->irq);
+            s->limit &= 0xfffffe00ULL;
+            s->limit |= (uint64_t)val << 32;
+            if (!s->limit)
+                s->limit = 0x7ffffffffffffe00ULL;
+            ptimer_set_limit(s->timer, s->limit >> 9, 1);
+            break;
+        }
+        // set limit, reset counter
         reload = 1;
-	qemu_irq_lower(s->irq);
-	// fall through
+        qemu_irq_lower(s->irq);
+        // fall through
     case 2:
 	// set limit without resetting counter
         s->limit = val & 0x7ffffe00ULL;
@@ -152,6 +167,17 @@
             s->limit = 0x7ffffe00ULL;
         ptimer_set_limit(s->timer, s->limit >> 9, reload);
 	break;
+    case 1:
+	// set user counter limit LSW, reset counter
+        if (s->mode == 1) {
+            qemu_irq_lower(s->irq);
+            s->limit &= 0x7fffffff00000000ULL;
+            s->limit |= val & 0xfffffe00ULL;
+            if (!s->limit)
+                s->limit = 0x7ffffffffffffe00ULL;
+            ptimer_set_limit(s->timer, s->limit >> 9, 1);
+        }
+        break;
     case 3:
 	// start/stop user counter
 	if (s->mode == 1) {
@@ -167,13 +193,24 @@
 	break;
     case 4:
 	// bit 0: user (1) or system (0) counter mode
-	if (s->mode == 0 || s->mode == 1)
-	    s->mode = val & 1;
-        if (s->mode == 1) {
-            qemu_irq_lower(s->irq);
-            s->limit = -1ULL;
+        {
+            unsigned int i;
+
+            for (i = 0; i < MAX_CPUS; i++) {
+                if (val & (1 << i)) {
+                    qemu_irq_lower(s->slave[i]->irq);
+                    s->slave[i]->limit = -1ULL;
+                    s->slave[i]->mode = 1;
+                } else {
+                    s->slave[i]->mode = 0;
+                }
+                ptimer_stop(s->slave[i]->timer);
+                ptimer_set_limit(s->slave[i]->timer, s->slave[i]->limit >> 9,
+                                 1);
+                ptimer_run(s->slave[i]->timer, 0);
+            }
+            s->slave_mode = val & ((1 << MAX_CPUS) - 1);
         }
-        ptimer_set_limit(s->timer, s->limit >> 9, 1);
 	break;
     default:
 	break;
@@ -240,7 +277,8 @@
     qemu_irq_lower(s->irq);
 }
 
-void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode)
+static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr,
+                                            qemu_irq irq, int mode)
 {
     int slavio_timer_io_memory;
     SLAVIO_TIMERState *s;
@@ -248,7 +286,7 @@
 
     s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
     if (!s)
-        return;
+        return s;
     s->irq = irq;
     s->mode = mode;
     bh = qemu_bh_new(slavio_timer_irq, s);
@@ -257,8 +295,29 @@
 
     slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
 						    slavio_timer_mem_write, s);
-    cpu_register_physical_memory(addr, TIMER_SIZE, slavio_timer_io_memory);
+    if (mode < 2)
+        cpu_register_physical_memory(addr, CPU_TIMER_SIZE, slavio_timer_io_memory);
+    else
+        cpu_register_physical_memory(addr, TIMER_SIZE,
+                                     slavio_timer_io_memory);
     register_savevm("slavio_timer", addr, 2, 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)
+{
+    SLAVIO_TIMERState *master;
+    unsigned int i;
+
+    master = slavio_timer_init(base + 0x10000ULL, master_irq, 2);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        master->slave[i] = slavio_timer_init(base + (target_phys_addr_t)
+                                             (i * TARGET_PAGE_SIZE),
+                                             cpu_irqs[i], 0);
+    }
 }
Index: qemu/hw/sun4m.c
===================================================================
--- qemu.orig/hw/sun4m.c	2007-09-23 07:37:38.000000000 +0000
+++ qemu/hw/sun4m.c	2007-09-23 12:03:07.000000000 +0000
@@ -379,13 +379,10 @@
 
     nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
                         hwdef->nvram_size, 8);
-    for (i = 0; i < MAX_CPUS; i++) {
-        slavio_timer_init(hwdef->counter_base +
-                          (target_phys_addr_t)(i * TARGET_PAGE_SIZE),
-                           slavio_cpu_irq[i], 0);
-    }
-    slavio_timer_init(hwdef->counter_base + 0x10000ULL,
-                      slavio_irq[hwdef->clock1_irq], 2);
+
+    slavio_timer_init_all(hwdef->counter_base, slavio_irq[hwdef->clock1_irq],
+                          slavio_cpu_irq);
+
     slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]);
     // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
     // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
Index: qemu/vl.h
===================================================================
--- qemu.orig/vl.h	2007-09-23 07:37:38.000000000 +0000
+++ qemu/vl.h	2007-09-23 12:03:07.000000000 +0000
@@ -1275,7 +1275,8 @@
 int load_uboot(const char *filename, target_ulong *ep, int *is_linux);
 
 /* slavio_timer.c */
-void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode);
+void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq,
+                           qemu_irq *cpu_irqs);
 
 /* slavio_serial.c */
 SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq,

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2007-09-23 12:08 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-09-21 14:22 [Qemu-devel] sparc32 counter/timer issues Robert Reif
2007-09-21 20:19 ` Blue Swirl
  -- strict thread matches above, loose matches on Subject: below --
2007-09-21 23:10 Robert Reif
2007-09-23 12:08 ` Blue Swirl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).