ia64/xen-unstable
changeset 11503:e20a469dabb4
[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@ibrium.se)
Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
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@ibrium.se)
Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
author | Jimi Xenidis <jimix@watson.ibm.com> |
---|---|
date | Thu Sep 07 02:50:06 2006 -0400 (2006-09-07) |
parents | 464acece0dad |
children | e7c55ba4de2e |
files | xen/arch/powerpc/Makefile xen/arch/powerpc/exceptions.h xen/arch/powerpc/setup.c xen/arch/powerpc/smp-tbsync.c xen/include/asm-powerpc/powerpc64/processor.h xen/include/asm-powerpc/reg_defs.h xen/include/asm-powerpc/smp.h xen/include/asm-powerpc/time.h |
line diff
1.1 --- a/xen/arch/powerpc/Makefile Thu Sep 07 02:21:17 2006 -0400 1.2 +++ b/xen/arch/powerpc/Makefile Thu Sep 07 02:50:06 2006 -0400 1.3 @@ -36,6 +36,7 @@ obj-y += rtas.o 1.4 obj-y += setup.o 1.5 obj-y += shadow.o 1.6 obj-y += smp.o 1.7 +obj-y += smp-tbsync.o 1.8 obj-y += time.o 1.9 obj-y += usercopy.o 1.10
2.1 --- a/xen/arch/powerpc/exceptions.h Thu Sep 07 02:21:17 2006 -0400 2.2 +++ b/xen/arch/powerpc/exceptions.h Thu Sep 07 02:50:06 2006 -0400 2.3 @@ -51,4 +51,5 @@ extern ulong *__hypercall_table[]; 2.4 extern char exception_vectors[]; 2.5 extern char exception_vectors_end[]; 2.6 extern int spin_start[]; 2.7 +extern int secondary_cpu_init(int cpuid, unsigned long r4); 2.8 #endif
3.1 --- a/xen/arch/powerpc/setup.c Thu Sep 07 02:21:17 2006 -0400 3.2 +++ b/xen/arch/powerpc/setup.c Thu Sep 07 02:50:06 2006 -0400 3.3 @@ -16,6 +16,8 @@ 3.4 * Copyright (C) IBM Corp. 2005, 2006 3.5 * 3.6 * Authors: Jimi Xenidis <jimix@watson.ibm.com> 3.7 + * Amos Waterland <apw@us.ibm.com> 3.8 + * Hollis Blanchard <hollisb@us.ibm.com> 3.9 */ 3.10 3.11 #include <xen/config.h> 3.12 @@ -242,16 +244,22 @@ static int kick_secondary_cpus(int maxcp 3.13 break; 3.14 init_parea(cpuid); 3.15 cpu_set(cpuid, cpu_online_map); 3.16 + smp_generic_give_timebase(); 3.17 + 3.18 + /* wait for it */ 3.19 + while (!cpu_online(cpuid)) 3.20 + cpu_relax(); 3.21 } 3.22 3.23 return 0; 3.24 } 3.25 3.26 /* This is the first C code that secondary processors invoke. */ 3.27 -int secondary_cpu_init(int cpuid, unsigned long r4); 3.28 int secondary_cpu_init(int cpuid, unsigned long r4) 3.29 { 3.30 cpu_initialize(cpuid); 3.31 + smp_generic_take_timebase(); 3.32 + cpu_set(cpuid, cpu_online_map); 3.33 while(1); 3.34 } 3.35
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/xen/arch/powerpc/smp-tbsync.c Thu Sep 07 02:50:06 2006 -0400 4.3 @@ -0,0 +1,186 @@ 4.4 +/* 4.5 + * Smp timebase synchronization for ppc. 4.6 + * 4.7 + * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) 4.8 + * 4.9 + */ 4.10 +/* XXX Xen hacks ... */ 4.11 +#define get_tb() get_timebase() 4.12 +#define set_tb(u,l) set_timebase(u,l) 4.13 +#define kmalloc(s,f) xmalloc_bytes(s); 4.14 +#define kfree(p) xfree(p) 4.15 +#define abs(x) ({ \ 4.16 + int __x = (x); \ 4.17 + (__x < 0) ? -__x : __x; \ 4.18 + }) 4.19 + 4.20 +#include <xen/kernel.h> 4.21 +#include <xen/sched.h> 4.22 +#include <xen/smp.h> 4.23 +#ifndef __XEN__ 4.24 +#include <linux/unistd.h> 4.25 +#endif 4.26 +#include <xen/init.h> 4.27 +#include <asm/atomic.h> 4.28 +#include <asm/smp.h> 4.29 +#include <asm/time.h> 4.30 + 4.31 + 4.32 +/* don't mess with IRQs */ 4.33 +#define local_irq_enable() 4.34 +#define local_irq_disable() 4.35 + 4.36 +#define NUM_ITER 300 4.37 + 4.38 +enum { 4.39 + kExit=0, kSetAndTest, kTest 4.40 +}; 4.41 + 4.42 +static struct { 4.43 + volatile u64 tb; 4.44 + volatile u64 mark; 4.45 + volatile int cmd; 4.46 + volatile int handshake; 4.47 + int filler[2]; 4.48 + 4.49 + volatile int ack; 4.50 + int filler2[7]; 4.51 + 4.52 + volatile int race_result; 4.53 +} *tbsync; 4.54 + 4.55 +static volatile int running; 4.56 + 4.57 +static void __devinit enter_contest(u64 mark, long add) 4.58 +{ 4.59 + while (get_tb() < mark) 4.60 + tbsync->race_result = add; 4.61 +} 4.62 + 4.63 +void __devinit smp_generic_take_timebase(void) 4.64 +{ 4.65 + int cmd; 4.66 + u64 tb; 4.67 + 4.68 + local_irq_disable(); 4.69 + while (!running) 4.70 + barrier(); 4.71 + rmb(); 4.72 + 4.73 + for (;;) { 4.74 + tbsync->ack = 1; 4.75 + while (!tbsync->handshake) 4.76 + barrier(); 4.77 + rmb(); 4.78 + 4.79 + cmd = tbsync->cmd; 4.80 + tb = tbsync->tb; 4.81 + mb(); 4.82 + tbsync->ack = 0; 4.83 + if (cmd == kExit) 4.84 + break; 4.85 + 4.86 + while (tbsync->handshake) 4.87 + barrier(); 4.88 + if (cmd == kSetAndTest) 4.89 + set_tb(tb >> 32, tb & 0xfffffffful); 4.90 + enter_contest(tbsync->mark, -1); 4.91 + } 4.92 + local_irq_enable(); 4.93 +} 4.94 + 4.95 +static int __devinit start_contest(int cmd, long offset, int num) 4.96 +{ 4.97 + int i, score=0; 4.98 + u64 tb; 4.99 + long mark; 4.100 + 4.101 + tbsync->cmd = cmd; 4.102 + 4.103 + local_irq_disable(); 4.104 + for (i = -3; i < num; ) { 4.105 + tb = get_tb() + 400; 4.106 + tbsync->tb = tb + offset; 4.107 + tbsync->mark = mark = tb + 400; 4.108 + 4.109 + wmb(); 4.110 + 4.111 + tbsync->handshake = 1; 4.112 + while (tbsync->ack) 4.113 + barrier(); 4.114 + 4.115 + while (get_tb() <= tb) 4.116 + barrier(); 4.117 + tbsync->handshake = 0; 4.118 + enter_contest(mark, 1); 4.119 + 4.120 + while (!tbsync->ack) 4.121 + barrier(); 4.122 + 4.123 + if (i++ > 0) 4.124 + score += tbsync->race_result; 4.125 + } 4.126 + local_irq_enable(); 4.127 + return score; 4.128 +} 4.129 + 4.130 +void __devinit smp_generic_give_timebase(void) 4.131 +{ 4.132 + int i, score, score2, old, min=0, max=5000, offset=1000; 4.133 + 4.134 + printk("Synchronizing timebase\n"); 4.135 + 4.136 + /* if this fails then this kernel won't work anyway... */ 4.137 + tbsync = kmalloc( sizeof(*tbsync), GFP_KERNEL ); 4.138 + memset( tbsync, 0, sizeof(*tbsync) ); 4.139 + mb(); 4.140 + running = 1; 4.141 + 4.142 + while (!tbsync->ack) 4.143 + barrier(); 4.144 + 4.145 + printk("Got ack\n"); 4.146 + 4.147 + /* binary search */ 4.148 + for (old = -1; old != offset ; offset = (min+max) / 2) { 4.149 + score = start_contest(kSetAndTest, offset, NUM_ITER); 4.150 + 4.151 + printk("score %d, offset %d\n", score, offset ); 4.152 + 4.153 + if( score > 0 ) 4.154 + max = offset; 4.155 + else 4.156 + min = offset; 4.157 + old = offset; 4.158 + } 4.159 + score = start_contest(kSetAndTest, min, NUM_ITER); 4.160 + score2 = start_contest(kSetAndTest, max, NUM_ITER); 4.161 + 4.162 + printk("Min %d (score %d), Max %d (score %d)\n", 4.163 + min, score, max, score2); 4.164 + score = abs(score); 4.165 + score2 = abs(score2); 4.166 + offset = (score < score2) ? min : max; 4.167 + 4.168 + /* guard against inaccurate mttb */ 4.169 + for (i = 0; i < 10; i++) { 4.170 + start_contest(kSetAndTest, offset, NUM_ITER/10); 4.171 + 4.172 + if ((score2 = start_contest(kTest, offset, NUM_ITER)) < 0) 4.173 + score2 = -score2; 4.174 + if (score2 <= score || score2 < 20) 4.175 + break; 4.176 + } 4.177 + printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER ); 4.178 + 4.179 + /* exiting */ 4.180 + tbsync->cmd = kExit; 4.181 + wmb(); 4.182 + tbsync->handshake = 1; 4.183 + while (tbsync->ack) 4.184 + barrier(); 4.185 + tbsync->handshake = 0; 4.186 + kfree(tbsync); 4.187 + tbsync = NULL; 4.188 + running = 0; 4.189 +}
5.1 --- a/xen/include/asm-powerpc/powerpc64/processor.h Thu Sep 07 02:21:17 2006 -0400 5.2 +++ b/xen/include/asm-powerpc/powerpc64/processor.h Thu Sep 07 02:50:06 2006 -0400 5.3 @@ -91,10 +91,21 @@ static inline unsigned long mftb(void) 5.4 return tb; 5.5 } 5.6 5.7 +static inline void mttbl(unsigned low) 5.8 +{ 5.9 + __asm__ __volatile__ ("mtspr %0, %1" : : "i"(SPRN_TBWL), "r" (low)); 5.10 +} 5.11 + 5.12 +static inline void mttbu(unsigned upper) 5.13 +{ 5.14 + __asm__ __volatile__ ("mtspr %0, %1" : : "i"(SPRN_TBWU), "r" (upper)); 5.15 +} 5.16 + 5.17 static inline void mthdec(unsigned ticks) 5.18 { 5.19 __asm__ __volatile__ ("mtspr %0, %1" : : "i"(SPRN_HDEC), "r" (ticks)); 5.20 } 5.21 + 5.22 static inline unsigned int mfhdec(void) 5.23 { 5.24 unsigned int val;
6.1 --- a/xen/include/asm-powerpc/reg_defs.h Thu Sep 07 02:21:17 2006 -0400 6.2 +++ b/xen/include/asm-powerpc/reg_defs.h Thu Sep 07 02:50:06 2006 -0400 6.3 @@ -146,10 +146,14 @@ 6.4 #define SPRN_DEC 22 6.5 #define SPRN_SRR0 26 6.6 #define SPRN_SRR1 27 6.7 +#define SPRN_TBRL 268 6.8 +#define SPRN_TBRU 269 6.9 #define SPRN_SPRG0 272 6.10 #define SPRN_SPRG1 273 6.11 #define SPRN_SPRG2 274 6.12 #define SPRN_SPRG3 275 6.13 +#define SPRN_TBWL 284 6.14 +#define SPRN_TBWU 285 6.15 6.16 #define SPRN_HSPRG0 304 6.17 #define SPRN_HSPRG1 305
7.1 --- a/xen/include/asm-powerpc/smp.h Thu Sep 07 02:21:17 2006 -0400 7.2 +++ b/xen/include/asm-powerpc/smp.h Thu Sep 07 02:50:06 2006 -0400 7.3 @@ -23,6 +23,7 @@ 7.4 7.5 #include <xen/types.h> 7.6 #include <xen/cpumask.h> 7.7 +#include <xen/init.h> 7.8 #include <asm/current.h> 7.9 extern int smp_num_siblings; 7.10 7.11 @@ -32,5 +33,6 @@ extern int smp_num_siblings; 7.12 #define hard_smp_processor_id() raw_smp_processor_id() 7.13 extern cpumask_t cpu_sibling_map[]; 7.14 extern cpumask_t cpu_core_map[]; 7.15 - 7.16 +extern void __devinit smp_generic_take_timebase(void); 7.17 +extern void __devinit smp_generic_give_timebase(void); 7.18 #endif
8.1 --- a/xen/include/asm-powerpc/time.h Thu Sep 07 02:21:17 2006 -0400 8.2 +++ b/xen/include/asm-powerpc/time.h Thu Sep 07 02:50:06 2006 -0400 8.3 @@ -16,7 +16,7 @@ 8.4 * Copyright (C) IBM Corp. 2005, 2006 8.5 * 8.6 * Authors: Hollis Blanchard <hollisb@us.ibm.com> 8.7 - * Hollis Blanchard <jimix@watson.ibm.com> 8.8 + * Jimi Xenidis <jimix@watson.ibm.com> 8.9 */ 8.10 8.11 #ifndef _ASM_TIME_H_ 8.12 @@ -54,6 +54,13 @@ static inline u64 get_timebase(void) 8.13 return s; 8.14 } 8.15 8.16 +static inline void set_timebase(unsigned upper, unsigned lower) 8.17 +{ 8.18 + mttbl(0); 8.19 + mttbu(upper); 8.20 + mttbl(lower); 8.21 +} 8.22 + 8.23 typedef u64 cycles_t; 8.24 static inline cycles_t get_cycles(void) 8.25 {