2 * Smp timebase synchronization for ppc.
4 * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
8 #include <linux/kernel.h>
9 #include <linux/sched.h>
10 #include <linux/smp.h>
11 #include <linux/unistd.h>
12 #include <linux/init.h>
13 #include <asm/atomic.h>
20 kExit
=0, kSetAndTest
, kTest
27 volatile int handshake
;
33 volatile int race_result
;
36 static volatile int running
;
38 static void __devinit
enter_contest(u64 mark
, long add
)
40 while (get_tb() < mark
)
41 tbsync
->race_result
= add
;
44 void __devinit
smp_generic_take_timebase(void)
50 local_irq_save(flags
);
57 while (!tbsync
->handshake
)
68 while (tbsync
->handshake
)
70 if (cmd
== kSetAndTest
)
71 set_tb(tb
>> 32, tb
& 0xfffffffful
);
72 enter_contest(tbsync
->mark
, -1);
74 local_irq_restore(flags
);
77 static int __devinit
start_contest(int cmd
, long offset
, int num
)
86 for (i
= -3; i
< num
; ) {
88 tbsync
->tb
= tb
+ offset
;
89 tbsync
->mark
= mark
= tb
+ 400;
93 tbsync
->handshake
= 1;
97 while (get_tb() <= tb
)
99 tbsync
->handshake
= 0;
100 enter_contest(mark
, 1);
106 score
+= tbsync
->race_result
;
112 void __devinit
smp_generic_give_timebase(void)
114 int i
, score
, score2
, old
, min
=0, max
=5000, offset
=1000;
116 pr_debug("Software timebase sync\n");
118 /* if this fails then this kernel won't work anyway... */
119 tbsync
= kzalloc( sizeof(*tbsync
), GFP_KERNEL
);
126 pr_debug("Got ack\n");
129 for (old
= -1; old
!= offset
; offset
= (min
+max
) / 2) {
130 score
= start_contest(kSetAndTest
, offset
, NUM_ITER
);
132 pr_debug("score %d, offset %d\n", score
, offset
);
140 score
= start_contest(kSetAndTest
, min
, NUM_ITER
);
141 score2
= start_contest(kSetAndTest
, max
, NUM_ITER
);
143 pr_debug("Min %d (score %d), Max %d (score %d)\n",
144 min
, score
, max
, score2
);
146 score2
= abs(score2
);
147 offset
= (score
< score2
) ? min
: max
;
149 /* guard against inaccurate mttb */
150 for (i
= 0; i
< 10; i
++) {
151 start_contest(kSetAndTest
, offset
, NUM_ITER
/10);
153 if ((score2
= start_contest(kTest
, offset
, NUM_ITER
)) < 0)
155 if (score2
<= score
|| score2
< 20)
158 pr_debug("Final offset: %d (%d/%d)\n", offset
, score2
, NUM_ITER
);
163 tbsync
->handshake
= 1;
166 tbsync
->handshake
= 0;