base/arch/i386/hal/hal.c

Go to the documentation of this file.
00001 /**
00002  *   @ingroup hal
00003  *   @file
00004  *
00005  *   ARTI -- RTAI-compatible Adeos-based Real-Time Interface. Based on
00006  *   the original RTAI layer for x86.
00007  *
00008  *   Original RTAI/x86 layer implementation: \n
00009  *   Copyright © 2000-2008 Paolo Mantegazza, \n
00010  *   Copyright © 2000      Steve Papacharalambous, \n
00011  *   Copyright © 2000      Stuart Hughes, \n
00012  *   and others.
00013  *
00014  *   RTAI/x86 rewrite over Adeos: \n
00015  *   Copyright &copy 2002 Philippe Gerum.
00016  *
00017  *   This program is free software; you can redistribute it and/or modify
00018  *   it under the terms of the GNU General Public License as published by
00019  *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
00020  *   USA; either version 2 of the License, or (at your option) any later
00021  *   version.
00022  *
00023  *   This program is distributed in the hope that it will be useful,
00024  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00025  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00026  *   GNU General Public License for more details.
00027  *
00028  *   You should have received a copy of the GNU General Public License
00029  *   along with this program; if not, write to the Free Software
00030  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00031  */
00032 
00033 /**
00034  * @defgroup hal RTAI services functions.
00035  *
00036  * This module defines some functions that can be used by RTAI tasks, for
00037  * managing interrupts and communication services with Linux processes.
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     Hacked from arch/ia64/kernel/smpboot.c.
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 //      printk(KERN_ERR "sync_tsc: slave CPU %u failed to get attention from master CPU %u!\n", slave, master);
00163         return;
00164     }
00165     while (go[MASTER]) {
00166         cpu_relax();    /* wait for master to be ready */
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 //  printk(KERN_INFO "# %d - CPU %u: synced its TSC with CPU %u (master time stamp %llu cycles, < - OFFSET %lld cycles - > , max double tsc read span %llu cycles)\n", ++sync_cnt[slave], slave, master, master_time_stamp, delta, rt);
00173 }
00174 
00175 //#define CONFIG_RTAI_MASTER_TSC_CPU  0
00176 #define SLEEP0  500 // ms
00177 #define DSLEEP  500 // ms
00178 static volatile int end;
00179 
00180 // see: Computing Practices, ACM, vol. 31, n. 10, 1988, pgs 1192-1201.
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 /* defined(CONFIG_SMP) && defined(CONFIG_RTAI_DIAG_TSC_SYNC) */
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"

Generated on Tue Feb 2 17:46:04 2010 for RTAI API by  doxygen 1.4.7