00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <linux/module.h>
00043 #include <linux/delay.h>
00044
00045 MODULE_LICENSE("GPL");
00046
00047 #include <asm/rtai_hal.h>
00048
00049 #if defined(CONFIG_SMP) && defined(CONFIG_RTAI_DIAG_TSC_SYNC)
00050
00051
00052
00053
00054
00055 static int sync_cnt[RTAI_NR_CPUS];
00056
00057 volatile long rtai_tsc_ofst[RTAI_NR_CPUS];
00058
00059 static inline long long readtsc(void)
00060 {
00061 long long t;
00062 __asm__ __volatile__("rdtsc" : "=A" (t));
00063 return t;
00064 }
00065
00066 #define MASTER (0)
00067 #define SLAVE (SMP_CACHE_BYTES/8)
00068
00069 #define NUM_ITERS 10
00070
00071 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
00072 static spinlock_t tsc_sync_lock = SPIN_LOCK_UNLOCKED;
00073 static spinlock_t tsclock = SPIN_LOCK_UNLOCKED;
00074 #else
00075 static DEFINE_SPINLOCK(tsc_sync_lock);
00076 static DEFINE_SPINLOCK(tsclock);
00077 #endif
00078
00079 static volatile long long go[SLAVE + 1];
00080
00081 static void sync_master(void *arg)
00082 {
00083 unsigned long flags, lflags, i;
00084
00085 if ((unsigned long)arg != hard_smp_processor_id()) {
00086 return;
00087 }
00088
00089 go[MASTER] = 0;
00090 local_irq_save(flags);
00091 for (i = 0; i < NUM_ITERS; ++i) {
00092 while (!go[MASTER]) {
00093 cpu_relax();
00094 }
00095 go[MASTER] = 0;
00096 spin_lock_irqsave(&tsclock, lflags);
00097 go[SLAVE] = readtsc();
00098 spin_unlock_irqrestore(&tsclock, lflags);
00099 }
00100 local_irq_restore(flags);
00101 }
00102
00103 static int first_sync_loop_done;
00104 static unsigned long worst_tsc_round_trip[RTAI_NR_CPUS];
00105
00106 static inline long long get_delta(long long *rt, long long *master, unsigned int slave)
00107 {
00108 unsigned long long best_t0 = 0, best_t1 = ~0ULL, best_tm = 0;
00109 unsigned long long tcenter = 0, t0, t1, tm, dt;
00110 unsigned long lflags;
00111 long i, done;
00112
00113 for (done = i = 0; i < NUM_ITERS; ++i) {
00114 t0 = readtsc();
00115 go[MASTER] = 1;
00116 spin_lock_irqsave(&tsclock, lflags);
00117 while (!(tm = go[SLAVE])) {
00118 spin_unlock_irqrestore(&tsclock, lflags);
00119 cpu_relax();
00120 spin_lock_irqsave(&tsclock, lflags);
00121 }
00122 spin_unlock_irqrestore(&tsclock, lflags);
00123 go[SLAVE] = 0;
00124 t1 = readtsc();
00125 dt = t1 - t0;
00126 if (!first_sync_loop_done && dt > worst_tsc_round_trip[slave]) {
00127 worst_tsc_round_trip[slave] = dt;
00128 }
00129 if (dt < (best_t1 - best_t0) && (dt <= worst_tsc_round_trip[slave] || !first_sync_loop_done)) {
00130 done = 1;
00131 best_t0 = t0, best_t1 = t1, best_tm = tm;
00132 }
00133 }
00134
00135 if (done) {
00136 *rt = best_t1 - best_t0;
00137 *master = best_tm - best_t0;
00138 tcenter = best_t0/2 + best_t1/2;
00139 if (best_t0 % 2 + best_t1 % 2 == 2) {
00140 ++tcenter;
00141 }
00142 }
00143 if (!first_sync_loop_done) {
00144 worst_tsc_round_trip[slave] = (worst_tsc_round_trip[slave]*120)/100;
00145 first_sync_loop_done = 1;
00146 return done ? rtai_tsc_ofst[slave] = tcenter - best_tm : 0;
00147 }
00148 return done ? rtai_tsc_ofst[slave] = (8*rtai_tsc_ofst[slave] + 2*((long)(tcenter - best_tm)))/10 : 0;
00149 }
00150
00151 static void sync_tsc(unsigned int master, unsigned int slave)
00152 {
00153 unsigned long flags;
00154 long long delta, rt = 0, master_time_stamp = 0;
00155
00156 go[MASTER] = 1;
00157 if (smp_call_function(sync_master, (void *)master,
00158 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
00159 1,
00160 #endif
00161 0) < 0) {
00162
00163 return;
00164 }
00165 while (go[MASTER]) {
00166 cpu_relax();
00167 }
00168 spin_lock_irqsave(&tsc_sync_lock, flags);
00169 delta = get_delta(&rt, &master_time_stamp, slave);
00170 spin_unlock_irqrestore(&tsc_sync_lock, flags);
00171
00172
00173 }
00174
00175
00176 #define SLEEP0 500 // ms
00177 #define DSLEEP 500 // ms
00178 static volatile int end;
00179
00180
00181
00182 #define TWOPWR31M1 2147483647 // 2^31 - 1
00183
00184 static inline long next_rand(long rand)
00185 {
00186 const long a = 16807;
00187 const long m = TWOPWR31M1;
00188 const long q = 127773;
00189 const long r = 2836;
00190
00191 long lo, hi;
00192
00193 hi = rand/q;
00194 lo = rand - hi*q;
00195 rand = a*lo - r*hi;
00196 if (rand <= 0) {
00197 rand += m;
00198 }
00199 return rand;
00200 }
00201
00202 static inline long irandu(unsigned long range)
00203 {
00204 static long seed = 783637;
00205 const long m = TWOPWR31M1;
00206
00207 seed = next_rand(seed);
00208 return rtai_imuldiv(seed, range, m);
00209 }
00210 static void kthread_fun(void *null)
00211 {
00212 int i;
00213 while (!end) {
00214 for (i = 0; i < num_online_cpus(); i++) {
00215 if (i != CONFIG_RTAI_MASTER_TSC_CPU) {
00216 set_cpus_allowed(current, cpumask_of_cpu(i));
00217 sync_tsc(CONFIG_RTAI_MASTER_TSC_CPU, i);
00218 }
00219 }
00220 msleep(SLEEP0 + irandu(DSLEEP));
00221 }
00222 end = 0;
00223 }
00224
00225 void init_tsc_sync(void)
00226 {
00227 if (num_online_cpus() > 1) {
00228 kernel_thread((void *)kthread_fun, NULL, 0);
00229 while(!first_sync_loop_done) {
00230 msleep(100);
00231 }
00232 }
00233 }
00234
00235 void cleanup_tsc_sync(void)
00236 {
00237 if (num_online_cpus() > 1) {
00238 end = 1;
00239 while(end) {
00240 msleep(100);
00241 }
00242 }
00243 }
00244
00245 EXPORT_SYMBOL(rtai_tsc_ofst);
00246
00247 #endif
00248
00249 #undef INCLUDED_BY_HAL_C
00250 #define INCLUDED_BY_HAL_C
00251 #ifdef RTAI_DUOSS
00252 #include "hal.immed"
00253 #else
00254 #include "hal.piped"
00255 #endif
00256 #include "rtc.c"