# HG changeset patch
# User Jimi Xenidis <[EMAIL PROTECTED]>
# Node ID c0034f57ead75782d958363bb61938cee59f0db9
# Parent  14ce119a001a5ec4a243e9462fa24ea09322550f
[POWERPC][XEN] Synchronize Timebase on all CPUs

This patch add the necessary support to use
  arch/powerpc/kernel/smp-tbsync.c
from Linux.
Original copyright and author are:
  Copyright (C) 2003 Samuel Rydh ([EMAIL PROTECTED])

Signed-off-by: Jimi Xenidis <[EMAIL PROTECTED]>
---
 xen/arch/powerpc/Makefile                     |    1 
 xen/arch/powerpc/exceptions.h                 |    1 
 xen/arch/powerpc/setup.c                      |   10 +
 xen/arch/powerpc/smp-tbsync.c                 |  186 ++++++++++++++++++++++++++
 xen/include/asm-powerpc/powerpc64/processor.h |   11 +
 xen/include/asm-powerpc/reg_defs.h            |    4 
 xen/include/asm-powerpc/smp.h                 |    4 
 xen/include/asm-powerpc/time.h                |    9 +
 8 files changed, 223 insertions(+), 3 deletions(-)

diff -r 14ce119a001a -r c0034f57ead7 xen/arch/powerpc/Makefile
--- a/xen/arch/powerpc/Makefile Thu Sep 07 02:21:17 2006 -0400
+++ b/xen/arch/powerpc/Makefile Thu Sep 07 02:50:06 2006 -0400
@@ -36,6 +36,7 @@ obj-y += setup.o
 obj-y += setup.o
 obj-y += shadow.o
 obj-y += smp.o
+obj-y += smp-tbsync.o
 obj-y += time.o
 obj-y += usercopy.o
 
diff -r 14ce119a001a -r c0034f57ead7 xen/arch/powerpc/exceptions.h
--- a/xen/arch/powerpc/exceptions.h     Thu Sep 07 02:21:17 2006 -0400
+++ b/xen/arch/powerpc/exceptions.h     Thu Sep 07 02:50:06 2006 -0400
@@ -51,4 +51,5 @@ extern char exception_vectors[];
 extern char exception_vectors[];
 extern char exception_vectors_end[];
 extern int spin_start[];
+extern int secondary_cpu_init(int cpuid, unsigned long r4);
 #endif
diff -r 14ce119a001a -r c0034f57ead7 xen/arch/powerpc/setup.c
--- a/xen/arch/powerpc/setup.c  Thu Sep 07 02:21:17 2006 -0400
+++ b/xen/arch/powerpc/setup.c  Thu Sep 07 02:50:06 2006 -0400
@@ -16,6 +16,8 @@
  * Copyright (C) IBM Corp. 2005, 2006
  *
  * Authors: Jimi Xenidis <[EMAIL PROTECTED]>
+ *          Amos Waterland <[EMAIL PROTECTED]>
+ *          Hollis Blanchard <[EMAIL PROTECTED]>
  */
 
 #include <xen/config.h>
@@ -242,16 +244,22 @@ static int kick_secondary_cpus(int maxcp
             break;
         init_parea(cpuid);
         cpu_set(cpuid, cpu_online_map);
+        smp_generic_give_timebase();
+
+        /* wait for it */
+        while (!cpu_online(cpuid))
+            cpu_relax();
     }
 
     return 0;
 }
 
 /* This is the first C code that secondary processors invoke.  */
-int secondary_cpu_init(int cpuid, unsigned long r4);
 int secondary_cpu_init(int cpuid, unsigned long r4)
 {
     cpu_initialize(cpuid);
+    smp_generic_take_timebase();
+    cpu_set(cpuid, cpu_online_map);
     while(1);
 }
 
diff -r 14ce119a001a -r c0034f57ead7 
xen/include/asm-powerpc/powerpc64/processor.h
--- a/xen/include/asm-powerpc/powerpc64/processor.h     Thu Sep 07 02:21:17 
2006 -0400
+++ b/xen/include/asm-powerpc/powerpc64/processor.h     Thu Sep 07 02:50:06 
2006 -0400
@@ -91,10 +91,21 @@ static inline unsigned long mftb(void)
     return tb;
 }
 
+static inline void mttbl(unsigned low)
+{
+    __asm__ __volatile__ ("mtspr %0, %1" : : "i"(SPRN_TBWL), "r" (low));
+}
+
+static inline void mttbu(unsigned upper)
+{
+    __asm__ __volatile__ ("mtspr %0, %1" : : "i"(SPRN_TBWU), "r" (upper));
+}
+
 static inline void mthdec(unsigned ticks)
 {
     __asm__ __volatile__ ("mtspr %0, %1" : : "i"(SPRN_HDEC), "r" (ticks));
 }
+
 static inline unsigned int mfhdec(void)
 {
     unsigned int val;
diff -r 14ce119a001a -r c0034f57ead7 xen/include/asm-powerpc/reg_defs.h
--- a/xen/include/asm-powerpc/reg_defs.h        Thu Sep 07 02:21:17 2006 -0400
+++ b/xen/include/asm-powerpc/reg_defs.h        Thu Sep 07 02:50:06 2006 -0400
@@ -146,10 +146,14 @@
 #define SPRN_DEC    22
 #define SPRN_SRR0   26
 #define SPRN_SRR1   27
+#define SPRN_TBRL   268
+#define SPRN_TBRU   269
 #define SPRN_SPRG0  272
 #define SPRN_SPRG1  273
 #define SPRN_SPRG2  274
 #define SPRN_SPRG3  275
+#define SPRN_TBWL   284
+#define SPRN_TBWU   285
 
 #define SPRN_HSPRG0 304
 #define SPRN_HSPRG1 305
diff -r 14ce119a001a -r c0034f57ead7 xen/include/asm-powerpc/smp.h
--- a/xen/include/asm-powerpc/smp.h     Thu Sep 07 02:21:17 2006 -0400
+++ b/xen/include/asm-powerpc/smp.h     Thu Sep 07 02:50:06 2006 -0400
@@ -23,6 +23,7 @@
 
 #include <xen/types.h>
 #include <xen/cpumask.h>
+#include <xen/init.h>
 #include <asm/current.h>
 extern int smp_num_siblings;
 
@@ -32,5 +33,6 @@ extern int smp_num_siblings;
 #define hard_smp_processor_id() raw_smp_processor_id()
 extern cpumask_t cpu_sibling_map[];
 extern cpumask_t cpu_core_map[];
-
+extern void __devinit smp_generic_take_timebase(void);
+extern void __devinit smp_generic_give_timebase(void);
 #endif
diff -r 14ce119a001a -r c0034f57ead7 xen/include/asm-powerpc/time.h
--- a/xen/include/asm-powerpc/time.h    Thu Sep 07 02:21:17 2006 -0400
+++ b/xen/include/asm-powerpc/time.h    Thu Sep 07 02:50:06 2006 -0400
@@ -16,7 +16,7 @@
  * Copyright (C) IBM Corp. 2005, 2006
  *
  * Authors: Hollis Blanchard <[EMAIL PROTECTED]>
- *          Hollis Blanchard <[EMAIL PROTECTED]>
+ *          Jimi Xenidis <[EMAIL PROTECTED]>
  */
 
 #ifndef _ASM_TIME_H_
@@ -54,6 +54,13 @@ static inline u64 get_timebase(void)
     return s;
 }
 
+static inline void set_timebase(unsigned upper, unsigned lower)
+{
+    mttbl(0);
+    mttbu(upper);
+    mttbl(lower);
+}
+
 typedef u64 cycles_t;
 static inline cycles_t get_cycles(void)
 {
diff -r 14ce119a001a -r c0034f57ead7 xen/arch/powerpc/smp-tbsync.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/powerpc/smp-tbsync.c     Thu Sep 07 02:50:06 2006 -0400
@@ -0,0 +1,186 @@
+/*
+ * Smp timebase synchronization for ppc.
+ *
+ * Copyright (C) 2003 Samuel Rydh ([EMAIL PROTECTED])
+ *
+ */
+/* XXX Xen hacks ... */
+#define get_tb() get_timebase()
+#define set_tb(u,l) set_timebase(u,l)
+#define kmalloc(s,f) xmalloc_bytes(s);
+#define kfree(p) xfree(p)
+#define abs(x) ({                              \
+               int __x = (x);                  \
+               (__x < 0) ? -__x : __x;         \
+       })
+
+#include <xen/kernel.h>
+#include <xen/sched.h>
+#include <xen/smp.h>
+#ifndef __XEN__ 
+#include <linux/unistd.h>
+#endif
+#include <xen/init.h>
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/time.h>
+
+
+/* don't mess with IRQs */
+#define local_irq_enable()
+#define local_irq_disable()
+
+#define NUM_ITER               300
+
+enum {
+       kExit=0, kSetAndTest, kTest
+};
+
+static struct {
+       volatile u64            tb;
+       volatile u64            mark;
+       volatile int            cmd;
+       volatile int            handshake;
+       int                     filler[2];
+
+       volatile int            ack;
+       int                     filler2[7];
+
+       volatile int            race_result;
+} *tbsync;
+
+static volatile int            running;
+
+static void __devinit enter_contest(u64 mark, long add)
+{
+       while (get_tb() < mark)
+               tbsync->race_result = add;
+}
+
+void __devinit smp_generic_take_timebase(void)
+{
+       int cmd;
+       u64 tb;
+
+       local_irq_disable();
+       while (!running)
+               barrier();
+       rmb();
+
+       for (;;) {
+               tbsync->ack = 1;
+               while (!tbsync->handshake)
+                       barrier();
+               rmb();
+
+               cmd = tbsync->cmd;
+               tb = tbsync->tb;
+               mb();
+               tbsync->ack = 0;
+               if (cmd == kExit)
+                       break;
+
+               while (tbsync->handshake)
+                       barrier();
+               if (cmd == kSetAndTest)
+                       set_tb(tb >> 32, tb & 0xfffffffful);
+               enter_contest(tbsync->mark, -1);
+       }
+       local_irq_enable();
+}
+
+static int __devinit start_contest(int cmd, long offset, int num)
+{
+       int i, score=0;
+       u64 tb;
+       long mark;
+
+       tbsync->cmd = cmd;
+
+       local_irq_disable();
+       for (i = -3; i < num; ) {
+               tb = get_tb() + 400;
+               tbsync->tb = tb + offset;
+               tbsync->mark = mark = tb + 400;
+
+               wmb();
+
+               tbsync->handshake = 1;
+               while (tbsync->ack)
+                       barrier();
+
+               while (get_tb() <= tb)
+                       barrier();
+               tbsync->handshake = 0;
+               enter_contest(mark, 1);
+
+               while (!tbsync->ack)
+                       barrier();
+
+               if (i++ > 0)
+                       score += tbsync->race_result;
+       }
+       local_irq_enable();
+       return score;
+}
+
+void __devinit smp_generic_give_timebase(void)
+{
+       int i, score, score2, old, min=0, max=5000, offset=1000;
+
+       printk("Synchronizing timebase\n");
+
+       /* if this fails then this kernel won't work anyway... */
+       tbsync = kmalloc( sizeof(*tbsync), GFP_KERNEL );
+       memset( tbsync, 0, sizeof(*tbsync) );
+       mb();
+       running = 1;
+
+       while (!tbsync->ack)
+               barrier();
+
+       printk("Got ack\n");
+
+       /* binary search */
+       for (old = -1; old != offset ; offset = (min+max) / 2) {
+               score = start_contest(kSetAndTest, offset, NUM_ITER);
+
+               printk("score %d, offset %d\n", score, offset );
+
+               if( score > 0 )
+                       max = offset;
+               else
+                       min = offset;
+               old = offset;
+       }
+       score = start_contest(kSetAndTest, min, NUM_ITER);
+       score2 = start_contest(kSetAndTest, max, NUM_ITER);
+
+       printk("Min %d (score %d), Max %d (score %d)\n",
+              min, score, max, score2);
+       score = abs(score);
+       score2 = abs(score2);
+       offset = (score < score2) ? min : max;
+
+       /* guard against inaccurate mttb */
+       for (i = 0; i < 10; i++) {
+               start_contest(kSetAndTest, offset, NUM_ITER/10);
+
+               if ((score2 = start_contest(kTest, offset, NUM_ITER)) < 0)
+                       score2 = -score2;
+               if (score2 <= score || score2 < 20)
+                       break;
+       }
+       printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
+
+       /* exiting */
+       tbsync->cmd = kExit;
+       wmb();
+       tbsync->handshake = 1;
+       while (tbsync->ack)
+               barrier();
+       tbsync->handshake = 0;
+       kfree(tbsync);
+       tbsync = NULL;
+       running = 0;
+}

_______________________________________________
Xen-ppc-devel mailing list
Xen-ppc-devel@lists.xensource.com
http://lists.xensource.com/xen-ppc-devel

Reply via email to