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
29 volatile int handshake
;
35 volatile int race_result
;
38 static volatile int running
;
41 enter_contest( int mark
, int add
)
43 while( (int)(get_tbl() - mark
) < 0 )
44 tbsync
->race_result
= add
;
48 smp_generic_take_timebase( void )
59 while( !tbsync
->handshake
)
70 if( cmd
== kSetAndTest
) {
71 while( tbsync
->handshake
)
73 asm volatile ("mttbl %0" :: "r" (tbl
) );
74 asm volatile ("mttbu %0" :: "r" (tbu
) );
76 while( tbsync
->handshake
)
79 enter_contest( tbsync
->mark
, -1 );
85 start_contest( int cmd
, int offset
, int num
)
87 int i
, tbu
, tbl
, mark
, score
=0;
93 tbl
= get_tbl() + 400;
94 tbsync
->tbu
= tbu
= get_tbu();
95 tbsync
->tbl
= tbl
+ offset
;
96 tbsync
->mark
= mark
= tbl
+ 400;
100 tbsync
->handshake
= 1;
104 while( (int)(get_tbl() - tbl
) <= 0 )
106 tbsync
->handshake
= 0;
107 enter_contest( mark
, 1 );
109 while( !tbsync
->ack
)
112 if( tbsync
->tbu
!= get_tbu() || ((tbsync
->tbl
^ get_tbl()) & 0x80000000) )
115 score
+= tbsync
->race_result
;
122 smp_generic_give_timebase( void )
124 int i
, score
, score2
, old
, min
=0, max
=5000, offset
=1000;
126 printk("Synchronizing timebase\n");
128 /* if this fails then this kernel won't work anyway... */
129 tbsync
= kmalloc( sizeof(*tbsync
), GFP_KERNEL
);
130 memset( tbsync
, 0, sizeof(*tbsync
) );
134 while( !tbsync
->ack
)
138 for( old
=-1 ; old
!= offset
; offset
=(min
+max
)/2 ) {
139 score
= start_contest( kSetAndTest
, offset
, NUM_ITER
);
141 printk("score %d, offset %d\n", score
, offset
);
149 score
= start_contest( kSetAndTest
, min
, NUM_ITER
);
150 score2
= start_contest( kSetAndTest
, max
, NUM_ITER
);
152 printk( "Min %d (score %d), Max %d (score %d)\n", min
, score
, max
, score2
);
153 score
= abs( score
);
154 score2
= abs( score2
);
155 offset
= (score
< score2
) ? min
: max
;
157 /* guard against inaccurate mttb */
158 for( i
=0; i
<10; i
++ ) {
159 start_contest( kSetAndTest
, offset
, NUM_ITER
/10 );
161 if( (score2
=start_contest(kTest
, offset
, NUM_ITER
)) < 0 )
163 if( score2
<= score
|| score2
< 20 )
166 printk("Final offset: %d (%d/%d)\n", offset
, score2
, NUM_ITER
);
171 tbsync
->handshake
= 1;
174 tbsync
->handshake
= 0;
180 smp_tb_synchronized
= 1;