[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [POWERPC][XEN] Synchronize Timebase on all CPUs
# HG changeset patch # User Jimi Xenidis <jimix@xxxxxxxxxxxxxx> # Node ID e20a469dabb42c8731171556f99e076a7981d2bf # Parent 464acece0dad70663f8658ec555db5564ba126c2 [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 (samuel@xxxxxxxxx) Signed-off-by: Jimi Xenidis <jimix@xxxxxxxxxxxxxx> Signed-off-by: Hollis Blanchard <hollisb@xxxxxxxxxx> --- 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 464acece0dad -r e20a469dabb4 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 464acece0dad -r e20a469dabb4 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 464acece0dad -r e20a469dabb4 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 <jimix@xxxxxxxxxxxxxx> + * Amos Waterland <apw@xxxxxxxxxx> + * Hollis Blanchard <hollisb@xxxxxxxxxx> */ #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 464acece0dad -r e20a469dabb4 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 464acece0dad -r e20a469dabb4 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 464acece0dad -r e20a469dabb4 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 464acece0dad -r e20a469dabb4 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 <hollisb@xxxxxxxxxx> - * Hollis Blanchard <jimix@xxxxxxxxxxxxxx> + * Jimi Xenidis <jimix@xxxxxxxxxxxxxx> */ #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 464acece0dad -r e20a469dabb4 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 (samuel@xxxxxxxxx) + * + */ +/* 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-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |