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>
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  {