source: trunk/packages/xen-common/xen-common/xen/arch/powerpc/smp-tbsync.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 3.5 KB
Line 
1/*
2 * Smp timebase synchronization for ppc.
3 *
4 * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
5 *
6 */
7/* XXX Xen hacks ... */
8#define get_tb() get_timebase()
9#define set_tb(u,l) set_timebase(u,l)
10#define kmalloc(s,f) xmalloc_bytes(s);
11#define kfree(p) xfree(p)
12#define abs(x) ({                               \
13                int __x = (x);                  \
14                (__x < 0) ? -__x : __x;         \
15        })
16
17#include <xen/kernel.h>
18#include <xen/sched.h>
19#include <xen/smp.h>
20#ifndef __XEN__
21#include <linux/unistd.h>
22#endif
23#include <xen/init.h>
24#include <asm/atomic.h>
25#include <asm/smp.h>
26#include <asm/time.h>
27
28
29/* don't mess with IRQs */
30#define local_irq_enable()
31#define local_irq_disable()
32
33#define NUM_ITER                300
34
35#undef DEBUG
36#ifdef DEBUG
37#define DBG(fmt...) printk(fmt)
38#else
39#define DBG(fmt...)
40#endif
41
42enum {
43        kExit=0, kSetAndTest, kTest
44};
45
46static struct {
47        volatile u64            tb;
48        volatile u64            mark;
49        volatile int            cmd;
50        volatile int            handshake;
51        int                     filler[2];
52
53        volatile int            ack;
54        int                     filler2[7];
55
56        volatile int            race_result;
57} *tbsync;
58
59static volatile int             running;
60
61static void __devinit enter_contest(u64 mark, long add)
62{
63        while (get_tb() < mark)
64                tbsync->race_result = add;
65}
66
67void __devinit smp_generic_take_timebase(void)
68{
69        int cmd;
70        u64 tb;
71
72        local_irq_disable();
73        while (!running)
74                barrier();
75        rmb();
76
77        for (;;) {
78                tbsync->ack = 1;
79                while (!tbsync->handshake)
80                        barrier();
81                rmb();
82
83                cmd = tbsync->cmd;
84                tb = tbsync->tb;
85                mb();
86                tbsync->ack = 0;
87                if (cmd == kExit)
88                        break;
89
90                while (tbsync->handshake)
91                        barrier();
92                if (cmd == kSetAndTest)
93                        set_tb(tb >> 32, tb & 0xfffffffful);
94                enter_contest(tbsync->mark, -1);
95        }
96        local_irq_enable();
97}
98
99static int __devinit start_contest(int cmd, long offset, int num)
100{
101        int i, score=0;
102        u64 tb;
103        long mark;
104
105        tbsync->cmd = cmd;
106
107        local_irq_disable();
108        for (i = -3; i < num; ) {
109                tb = get_tb() + 400;
110                tbsync->tb = tb + offset;
111                tbsync->mark = mark = tb + 400;
112
113                wmb();
114
115                tbsync->handshake = 1;
116                while (tbsync->ack)
117                        barrier();
118
119                while (get_tb() <= tb)
120                        barrier();
121                tbsync->handshake = 0;
122                enter_contest(mark, 1);
123
124                while (!tbsync->ack)
125                        barrier();
126
127                if (i++ > 0)
128                        score += tbsync->race_result;
129        }
130        local_irq_enable();
131        return score;
132}
133
134void __devinit smp_generic_give_timebase(void)
135{
136        int i, score, score2, old, min=0, max=5000, offset=1000;
137
138        printk("Synchronizing timebase...\n");
139
140        /* if this fails then this kernel won't work anyway... */
141        tbsync = kmalloc( sizeof(*tbsync), GFP_KERNEL );
142        memset( tbsync, 0, sizeof(*tbsync) );
143        mb();
144        running = 1;
145
146        while (!tbsync->ack)
147                barrier();
148
149        DBG("Got ack\n");
150
151        /* binary search */
152        for (old = -1; old != offset ; offset = (min+max) / 2) {
153                score = start_contest(kSetAndTest, offset, NUM_ITER);
154
155                DBG("score %d, offset %d\n", score, offset );
156
157                if( score > 0 )
158                        max = offset;
159                else
160                        min = offset;
161                old = offset;
162        }
163        score = start_contest(kSetAndTest, min, NUM_ITER);
164        score2 = start_contest(kSetAndTest, max, NUM_ITER);
165
166        DBG("Min %d (score %d), Max %d (score %d)\n",
167               min, score, max, score2);
168        score = abs(score);
169        score2 = abs(score2);
170        offset = (score < score2) ? min : max;
171
172        /* guard against inaccurate mttb */
173        for (i = 0; i < 10; i++) {
174                start_contest(kSetAndTest, offset, NUM_ITER/10);
175
176                if ((score2 = start_contest(kTest, offset, NUM_ITER)) < 0)
177                        score2 = -score2;
178                if (score2 <= score || score2 < 20)
179                        break;
180        }
181        DBG("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
182
183        /* exiting */
184        tbsync->cmd = kExit;
185        wmb();
186        tbsync->handshake = 1;
187        while (tbsync->ack)
188                barrier();
189        tbsync->handshake = 0;
190        kfree(tbsync);
191        tbsync = NULL;
192        running = 0;
193}
Note: See TracBrowser for help on using the repository browser.