powerpc: Merge smp-tbsync.c (the generic timebase sync routine)
authorPaul Mackerras <paulus@samba.org>
Fri, 4 Nov 2005 02:28:58 +0000 (13:28 +1100)
committerPaul Mackerras <paulus@samba.org>
Fri, 4 Nov 2005 02:28:58 +0000 (13:28 +1100)
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/Kconfig
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/smp-tbsync.c [new file with mode: 0644]
arch/ppc64/Kconfig
arch/ppc64/kernel/Makefile
arch/ppc64/kernel/smp-tbsync.c [deleted file]

index 3cf03ab461132075e84815f3bd2d0f344ece85fe..f4e25c648fbbb977ed53d36489a8086bb474ecd9 100644 (file)
@@ -300,6 +300,7 @@ config PPC_PMAC64
        bool
        depends on PPC_PMAC && POWER4
        select U3_DART
+       select GENERIC_TBSYNC
        default y
 
 config PPC_PREP
@@ -314,6 +315,7 @@ config PPC_MAPLE
        bool "  Maple 970FX Evaluation Board"
        select U3_DART
        select MPIC_BROKEN_U3
+       select GENERIC_TBSYNC
        default n
        help
           This option enables support for the Maple 970FX Evaluation Board.
@@ -386,6 +388,11 @@ config PPC_MPC106
        bool
        default n
 
+config GENERIC_TBSYNC
+       bool
+       default y if CONFIG_PPC32 && CONFIG_SMP
+       default n
+
 source "drivers/cpufreq/Kconfig"
 
 config CPU_FREQ_PMAC
index 7a3e1155ac9a7bffb1ee73fb7ff747131f01d278..631149ea93db6dd76828f6012fa0686932ef6731 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_PPC_RTAS)                += rtas.o
 obj-$(CONFIG_RTAS_FLASH)       += rtas_flash.o
 obj-$(CONFIG_RTAS_PROC)                += rtas-proc.o
 obj-$(CONFIG_IBMVIO)           += vio.o
+obj-$(CONFIG_GENERIC_TBSYNC)   += smp-tbsync.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 
diff --git a/arch/powerpc/kernel/smp-tbsync.c b/arch/powerpc/kernel/smp-tbsync.c
new file mode 100644 (file)
index 0000000..9adef3b
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Smp timebase synchronization for ppc.
+ *
+ * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/unistd.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/time.h>
+
+#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;
+}
index 42677cc965082b09454d596c83632563a72e7d07..b987164fca4cb714f7a68476e82d9ae27c0d863d 100644 (file)
@@ -89,12 +89,14 @@ config PPC_PMAC
        bool "  Apple G5 based machines"
        default y
        select U3_DART
+       select GENERIC_TBSYNC
 
 config PPC_MAPLE
        depends on PPC_MULTIPLATFORM
        bool "  Maple 970FX Evaluation Board"
        select U3_DART
        select MPIC_BROKEN_U3
+       select GENERIC_TBSYNC
        default n
        help
           This option enables support for the Maple 970FX Evaluation Board.
@@ -182,6 +184,9 @@ config MPIC_BROKEN_U3
        depends on PPC_MAPLE
        default y
 
+config GENERIC_TBSYNC
+       def_bool n
+
 config PPC_PMAC64
        bool
        depends on PPC_PMAC
index 430cb3900a072eb56909f8f00d84e6803af63d16..f597c2954b719b8f2f454697a0c8c1ddda876424 100644 (file)
@@ -51,11 +51,6 @@ obj-$(CONFIG_PPC_PMAC)               += udbg_scc.o
 
 obj-$(CONFIG_PPC_MAPLE)                += udbg_16550.o
 
-ifdef CONFIG_SMP
-obj-$(CONFIG_PPC_PMAC)         += smp-tbsync.o
-obj-$(CONFIG_PPC_MAPLE)                += smp-tbsync.o
-endif
-
 obj-$(CONFIG_KPROBES)          += kprobes.o
 
 CFLAGS_ioctl32.o += -Ifs/
diff --git a/arch/ppc64/kernel/smp-tbsync.c b/arch/ppc64/kernel/smp-tbsync.c
deleted file mode 100644 (file)
index 7d8ec99..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Smp timebase synchronization for ppc.
- *
- * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/unistd.h>
-#include <linux/init.h>
-#include <asm/atomic.h>
-#include <asm/smp.h>
-#include <asm/time.h>
-
-#define NUM_ITER               300
-
-enum {
-       kExit=0, kSetAndTest, kTest
-};
-
-static struct {
-       volatile long           tb;
-       volatile long           mark;
-       volatile int            cmd;
-       volatile int            handshake;
-       int                     filler[3];
-
-       volatile int            ack;
-       int                     filler2[7];
-
-       volatile int            race_result;
-} *tbsync;
-
-static volatile int            running;
-
-static void __devinit
-enter_contest( long mark, long add )
-{
-       while( (long)(mftb() - mark) < 0 )
-               tbsync->race_result = add;
-}
-
-void __devinit
-smp_generic_take_timebase( void )
-{
-       int cmd;
-       long tb;
-
-       local_irq_disable();
-       while( !running )
-               ;
-       rmb();
-
-       for( ;; ) {
-               tbsync->ack = 1;
-               while( !tbsync->handshake )
-                       ;
-               rmb();
-
-               cmd = tbsync->cmd;
-               tb = tbsync->tb;
-               tbsync->ack = 0;
-               if( cmd == kExit )
-                       return;
-
-               if( cmd == kSetAndTest ) {
-                       while( tbsync->handshake )
-                               ;
-                       asm volatile ("mttbl %0" :: "r" (tb & 0xfffffffful) );
-                       asm volatile ("mttbu %0" :: "r" (tb >> 32) );
-               } else {
-                       while( tbsync->handshake )
-                               ;
-               }
-               enter_contest( tbsync->mark, -1 );
-       }
-       local_irq_enable();
-}
-
-static int __devinit
-start_contest( int cmd, long offset, long num )
-{
-       int i, score=0;
-       long tb, mark;
-
-       tbsync->cmd = cmd;
-
-       local_irq_disable();
-       for( i=-3; i<num; ) {
-               tb = (long)mftb() + 400;
-               tbsync->tb = tb + offset;
-               tbsync->mark = mark = tb + 400;
-
-               wmb();
-
-               tbsync->handshake = 1;
-               while( tbsync->ack )
-                       ;
-
-               while( (long)(mftb() - tb) <= 0 )
-                       ;
-               tbsync->handshake = 0;
-               enter_contest( mark, 1 );
-
-               while( !tbsync->ack )
-                       ;
-
-               if ((tbsync->tb ^ (long)mftb()) & 0x8000000000000000ul)
-                       continue;
-               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 )
-               ;
-
-       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 )
-               ;
-       tbsync->handshake = 0;
-       kfree( tbsync );
-       tbsync = NULL;
-       running = 0;
-}