2 * Smp timebase synchronization for ppc.
4 * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
8 #include <linux/config.h>
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/smp.h>
12 #include <linux/unistd.h>
13 #include <linux/init.h>
14 #include <asm/atomic.h>
21 kExit
=0, kSetAndTest
, kTest
28 volatile int handshake
;
34 volatile int race_result
;
37 static volatile int running
;
40 enter_contest( long mark
, long add
)
42 while( (long)(mftb() - mark
) < 0 )
43 tbsync
->race_result
= add
;
47 smp_generic_take_timebase( void )
59 while( !tbsync
->handshake
)
69 if( cmd
== kSetAndTest
) {
70 while( tbsync
->handshake
)
72 asm volatile ("mttbl %0" :: "r" (tb
& 0xfffffffful
) );
73 asm volatile ("mttbu %0" :: "r" (tb
>> 32) );
75 while( tbsync
->handshake
)
78 enter_contest( tbsync
->mark
, -1 );
84 start_contest( int cmd
, long offset
, long num
)
93 tb
= (long)mftb() + 400;
94 tbsync
->tb
= tb
+ offset
;
95 tbsync
->mark
= mark
= tb
+ 400;
99 tbsync
->handshake
= 1;
103 while( (long)(mftb() - tb
) <= 0 )
105 tbsync
->handshake
= 0;
106 enter_contest( mark
, 1 );
108 while( !tbsync
->ack
)
111 if ((tbsync
->tb
^ (long)mftb()) & 0x8000000000000000ul
)
114 score
+= tbsync
->race_result
;
121 smp_generic_give_timebase( void )
123 int i
, score
, score2
, old
, min
=0, max
=5000, offset
=1000;
125 printk("Synchronizing timebase\n");
127 /* if this fails then this kernel won't work anyway... */
128 tbsync
= kmalloc( sizeof(*tbsync
), GFP_KERNEL
);
129 memset( tbsync
, 0, sizeof(*tbsync
) );
133 while( !tbsync
->ack
)
139 for( old
=-1 ; old
!= offset
; offset
=(min
+max
)/2 ) {
140 score
= start_contest( kSetAndTest
, offset
, NUM_ITER
);
142 printk("score %d, offset %d\n", score
, offset
);
150 score
= start_contest( kSetAndTest
, min
, NUM_ITER
);
151 score2
= start_contest( kSetAndTest
, max
, NUM_ITER
);
153 printk( "Min %d (score %d), Max %d (score %d)\n", min
, score
, max
, score2
);
154 score
= abs( score
);
155 score2
= abs( score2
);
156 offset
= (score
< score2
) ? min
: max
;
158 /* guard against inaccurate mttb */
159 for( i
=0; i
<10; i
++ ) {
160 start_contest( kSetAndTest
, offset
, NUM_ITER
/10 );
162 if( (score2
=start_contest(kTest
, offset
, NUM_ITER
)) < 0 )
164 if( score2
<= score
|| score2
< 20 )
167 printk("Final offset: %d (%d/%d)\n", offset
, score2
, NUM_ITER
);
172 tbsync
->handshake
= 1;
175 tbsync
->handshake
= 0;