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 <linux/slab.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
;
39 static void __devinit
enter_contest(u64 mark
, long add
)
41 while (get_tb() < mark
)
42 tbsync
->race_result
= add
;
45 void __devinit
smp_generic_take_timebase(void)
51 local_irq_save(flags
);
58 while (!tbsync
->handshake
)
69 while (tbsync
->handshake
)
71 if (cmd
== kSetAndTest
)
72 set_tb(tb
>> 32, tb
& 0xfffffffful
);
73 enter_contest(tbsync
->mark
, -1);
75 local_irq_restore(flags
);
78 static int __devinit
start_contest(int cmd
, long offset
, int num
)
87 for (i
= -3; i
< num
; ) {
89 tbsync
->tb
= tb
+ offset
;
90 tbsync
->mark
= mark
= tb
+ 400;
94 tbsync
->handshake
= 1;
98 while (get_tb() <= tb
)
100 tbsync
->handshake
= 0;
101 enter_contest(mark
, 1);
107 score
+= tbsync
->race_result
;
113 void __devinit
smp_generic_give_timebase(void)
115 int i
, score
, score2
, old
, min
=0, max
=5000, offset
=1000;
117 pr_debug("Software timebase sync\n");
119 /* if this fails then this kernel won't work anyway... */
120 tbsync
= kzalloc( sizeof(*tbsync
), GFP_KERNEL
);
127 pr_debug("Got ack\n");
130 for (old
= -1; old
!= offset
; offset
= (min
+max
) / 2) {
131 score
= start_contest(kSetAndTest
, offset
, NUM_ITER
);
133 pr_debug("score %d, offset %d\n", score
, offset
);
141 score
= start_contest(kSetAndTest
, min
, NUM_ITER
);
142 score2
= start_contest(kSetAndTest
, max
, NUM_ITER
);
144 pr_debug("Min %d (score %d), Max %d (score %d)\n",
145 min
, score
, max
, score2
);
147 score2
= abs(score2
);
148 offset
= (score
< score2
) ? min
: max
;
150 /* guard against inaccurate mttb */
151 for (i
= 0; i
< 10; i
++) {
152 start_contest(kSetAndTest
, offset
, NUM_ITER
/10);
154 if ((score2
= start_contest(kTest
, offset
, NUM_ITER
)) < 0)
156 if (score2
<= score
|| score2
< 20)
159 pr_debug("Final offset: %d (%d/%d)\n", offset
, score2
, NUM_ITER
);
164 tbsync
->handshake
= 1;
167 tbsync
->handshake
= 0;