~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/smp-tbsync.c

Version: ~ [ linux-5.12-rc1 ] ~ [ linux-5.11.2 ] ~ [ linux-5.10.19 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.101 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.177 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.222 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.258 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.258 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Smp timebase synchronization for ppc.
  3  *
  4  * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
  5  *
  6  */
  7 
  8 #include <linux/kernel.h>
  9 #include <linux/sched.h>
 10 #include <linux/smp.h>
 11 #include <linux/unistd.h>
 12 #include <linux/slab.h>
 13 #include <linux/atomic.h>
 14 #include <asm/smp.h>
 15 #include <asm/time.h>
 16 
 17 #define NUM_ITER                300
 18 
 19 enum {
 20         kExit=0, kSetAndTest, kTest
 21 };
 22 
 23 static struct {
 24         volatile u64            tb;
 25         volatile u64            mark;
 26         volatile int            cmd;
 27         volatile int            handshake;
 28         int                     filler[2];
 29 
 30         volatile int            ack;
 31         int                     filler2[7];
 32 
 33         volatile int            race_result;
 34 } *tbsync;
 35 
 36 static volatile int             running;
 37 
 38 static void enter_contest(u64 mark, long add)
 39 {
 40         while (get_tb() < mark)
 41                 tbsync->race_result = add;
 42 }
 43 
 44 void smp_generic_take_timebase(void)
 45 {
 46         int cmd;
 47         u64 tb;
 48         unsigned long flags;
 49 
 50         local_irq_save(flags);
 51         while (!running)
 52                 barrier();
 53         rmb();
 54 
 55         for (;;) {
 56                 tbsync->ack = 1;
 57                 while (!tbsync->handshake)
 58                         barrier();
 59                 rmb();
 60 
 61                 cmd = tbsync->cmd;
 62                 tb = tbsync->tb;
 63                 mb();
 64                 tbsync->ack = 0;
 65                 if (cmd == kExit)
 66                         break;
 67 
 68                 while (tbsync->handshake)
 69                         barrier();
 70                 if (cmd == kSetAndTest)
 71                         set_tb(tb >> 32, tb & 0xfffffffful);
 72                 enter_contest(tbsync->mark, -1);
 73         }
 74         local_irq_restore(flags);
 75 }
 76 
 77 static int start_contest(int cmd, long offset, int num)
 78 {
 79         int i, score=0;
 80         u64 tb;
 81         u64 mark;
 82 
 83         tbsync->cmd = cmd;
 84 
 85         local_irq_disable();
 86         for (i = -3; i < num; ) {
 87                 tb = get_tb() + 400;
 88                 tbsync->tb = tb + offset;
 89                 tbsync->mark = mark = tb + 400;
 90 
 91                 wmb();
 92 
 93                 tbsync->handshake = 1;
 94                 while (tbsync->ack)
 95                         barrier();
 96 
 97                 while (get_tb() <= tb)
 98                         barrier();
 99                 tbsync->handshake = 0;
100                 enter_contest(mark, 1);
101 
102                 while (!tbsync->ack)
103                         barrier();
104 
105                 if (i++ > 0)
106                         score += tbsync->race_result;
107         }
108         local_irq_enable();
109         return score;
110 }
111 
112 void smp_generic_give_timebase(void)
113 {
114         int i, score, score2, old, min=0, max=5000, offset=1000;
115 
116         pr_debug("Software timebase sync\n");
117 
118         /* if this fails then this kernel won't work anyway... */
119         tbsync = kzalloc( sizeof(*tbsync), GFP_KERNEL );
120         mb();
121         running = 1;
122 
123         while (!tbsync->ack)
124                 barrier();
125 
126         pr_debug("Got ack\n");
127 
128         /* binary search */
129         for (old = -1; old != offset ; offset = (min+max) / 2) {
130                 score = start_contest(kSetAndTest, offset, NUM_ITER);
131 
132                 pr_debug("score %d, offset %d\n", score, offset );
133 
134                 if( score > 0 )
135                         max = offset;
136                 else
137                         min = offset;
138                 old = offset;
139         }
140         score = start_contest(kSetAndTest, min, NUM_ITER);
141         score2 = start_contest(kSetAndTest, max, NUM_ITER);
142 
143         pr_debug("Min %d (score %d), Max %d (score %d)\n",
144                  min, score, max, score2);
145         score = abs(score);
146         score2 = abs(score2);
147         offset = (score < score2) ? min : max;
148 
149         /* guard against inaccurate mttb */
150         for (i = 0; i < 10; i++) {
151                 start_contest(kSetAndTest, offset, NUM_ITER/10);
152 
153                 if ((score2 = start_contest(kTest, offset, NUM_ITER)) < 0)
154                         score2 = -score2;
155                 if (score2 <= score || score2 < 20)
156                         break;
157         }
158         pr_debug("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
159 
160         /* exiting */
161         tbsync->cmd = kExit;
162         wmb();
163         tbsync->handshake = 1;
164         while (tbsync->ack)
165                 barrier();
166         tbsync->handshake = 0;
167         kfree(tbsync);
168         tbsync = NULL;
169         running = 0;
170 }
171 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp