rtai-core/include/asm-mips/rtai.h

00001 /*
00002  * COPYRIGHT (C) 2001  Steve Papacharalambous (stevep@lineo.com)
00003  * COPYRIGHT (C) 2000  Paolo Mantegazza (mantegazza@aero.polimi.it)
00004  *  
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Lesser General Public
00007  *  License as published by the Free Software Foundation; either
00008  *  version 2 of the License, or (at your option) any later version.
00009  *   
00010  *   This library is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *   Lesser General Public License for more details.
00014  *    
00015  *    You should have received a copy of the GNU Lesser General Public
00016  *    License along with this library; if not, write to the Free Software
00017  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
00018  *
00019  */
00020 
00021 /*
00022  * Modifications for MIPS port - Steve Papacharalambous (stevep@lineo.com)
00023  * 19Jun01
00024  */
00025 
00026 /*
00027  * More MIPS stuff by Steven Seeger (sseeger@stellartec.com)
00028  * 
00029  */
00030 
00031 #ifndef _RTAI_ASM_MIPS_RTAI_H_
00032 #define _RTAI_ASM_MIPS_RTAI_H_
00033 
00034 #include <rtai_types.h>
00035 
00036 static inline unsigned long long ullmul(unsigned long m0, unsigned long m1)
00037 {
00038 
00039         unsigned long long __res;
00040 
00041         __asm__ __volatile__ (
00042                         "multu\t%2,%3\n\t"
00043                         "mflo\t%0\n\t"
00044                         "mfhi\t%1\n\t"
00045                         : "=r" (((unsigned long *)&__res)[0]),
00046                           "=r" (((unsigned long *)&__res)[1])
00047                         : "r" (m0), "r" (m1));
00048 
00049         return(__res);
00050 
00051 } /* End function - ullmul */
00052 
00053 // One of the silly thing of 32 bits MIPS, no 64 by 32 bits divide.
00054 static inline unsigned long long ulldiv(unsigned long long ull,
00055                                 unsigned long uld, unsigned long *r)
00056 {
00057         unsigned long long q, rf;
00058         unsigned long qh, rh, ql, qf;
00059 
00060         q = 0;
00061         rf = (unsigned long long)(0xFFFFFFFF - (qf = 0xFFFFFFFF / uld) * uld)
00062                                                                         + 1ULL;
00063 
00064         while (ull >= uld) {
00065                 ((unsigned long *)&q)[1] +=
00066                         (qh = ((unsigned long *)&ull)[1] / uld);
00067 
00068                 rh = ((unsigned long *)&ull)[1] - qh * uld;
00069                 q += rh * (unsigned long long)qf +
00070                         (ql = ((unsigned long *)&ull)[0] / uld);
00071 
00072                 ull = rh * rf + (((unsigned long *)&ull)[0] - ql * uld);
00073         }
00074 
00075         *r = ull;
00076         return(q);
00077 }  /* End function - ulldiv */
00078 
00079 static inline int imuldiv(int i, int mult, int div)
00080 {
00081         unsigned long q, r;
00082 
00083         q = ulldiv(ullmul(i, mult), div, &r);
00084 
00085         return (r + r) > div ? q + 1 : q;
00086 }  /* End function - imuldiv */
00087 
00088 static inline unsigned long long llimd(unsigned long long ull,
00089                                 unsigned long mult, unsigned long div)
00090 {
00091         unsigned long long low;
00092         unsigned long q, r;
00093 
00094         low  = ullmul(((unsigned long *)&ull)[0], mult);        
00095         q = ulldiv( ullmul(((unsigned long *)&ull)[1], mult) +
00096                 ((unsigned long *)&low)[1], div, (unsigned long *)&low);
00097         low = ulldiv(low, div, &r);
00098         ((unsigned long *)&low)[1] += q;
00099 
00100         return (r + r) > div ? low + 1 : low;
00101 }  /* End function - llimd */
00102 
00103 
00104 #ifdef __KERNEL__
00105 
00106 #ifndef __cplusplus
00107 #include <linux/smp.h>
00108 #include <linux/spinlock.h>
00109 #include <linux/irq.h>
00110 #include <asm/system.h>
00111 #include <asm/bitops.h>
00112 #include <asm/mipsregs.h>
00113 #include <asm/rtai_atomic.h>
00114 #endif /* !__cplusplus */
00115 
00116 /*
00117  * Pending IRQ bit definitions.
00118  */
00119 #define IRQ_s334 3
00120 #define IRQ_EIC 5
00121 #define IRQ_TIMER 7
00122 
00123 /*
00124  * This needs to be fixed for the specific arch
00125  */
00126 #define RTAI_NR_TRAPS 16
00127 
00128 /*
00129  * CPU frequency calibration.
00130  */
00131 #define CPU_FREQ (tuned.cpu_freq)
00132 #define FREQ_DECR CPU_FREQ
00133 #define CALIBRATED_CPU_FREQ     0 /* Use this if you know better than Linux! */
00134 
00135 /*
00136  * Do not be messed up by macros names below, is a trick for keeping i386 code.
00137  */
00138 #define FREQ_8254 CPU_FREQ
00139 #define FREQ_APIC CPU_FREQ
00140 #define LATENCY_8254 3000
00141 #define SETUP_TIME_8254 500
00142 #define TIMER_8254_IRQ IRQ_TIMER
00143 
00144 #define IFLAG 9
00145 
00146 #ifndef CLOCK_TICK_RATE
00147 #define CLOCK_TICK_RATE 1193180 /* Ok, this makes no sense on MIPS */
00148 #endif /* CLOCK_TICK_RATE */
00149 
00150 /*
00151  * IE Bit position for MIPS is cp0 status register bit 0
00152  */
00153 #define IFLAG_POS 0
00154 
00155 #define NR_RT_CPUS 1
00156 
00157 #define rt_write_timer_count(cnt)  do { \
00158                 write_c0_count(cnt); } while(0)
00159 
00160 #define rt_read_timer_countg() read_c0_count();
00161 
00162 #define rt_write_timer_comp(cnt)  do { \
00163                 write_c0_compare(cnt); } while(0)
00164 
00165 #define rt_read_timer_comp()      do { \
00166                 read_c0_compare(); } while(0)
00167 
00168 #define rt_set_timer_incr(x)    do { \
00169                 write_c0_compare((x)); } while(0)
00170 
00171 #define hard_cpu_id() hard_smp_processor_id()
00172 
00173 #define rt_spin_lock(lock)
00174 #define rt_spin_unlock(lock)
00175 
00176 #define rt_get_global_lock() hard_cli()
00177 #define rt_release_global_lock()
00178 
00179 #define save_fpenv(x)
00180 #define restore_fpenv(x)
00181 
00182 #define RT_TIME_END 0x7fffffffffffffffLL
00183 
00184 struct apic_timer_setup_data;
00185 
00186 struct global_rt_status {
00187         volatile unsigned int pending_irqs_l;
00188         volatile unsigned int pending_irqs_h;
00189         volatile unsigned int activ_irqs;
00190         volatile unsigned int pending_srqs;
00191         volatile unsigned int activ_srqs;
00192         volatile unsigned int cpu_in_sti;
00193         volatile unsigned int used_by_linux;
00194         volatile unsigned int locked_cpus;
00195         volatile unsigned int hard_nesting;
00196         volatile unsigned int hard_lock_all_service;
00197 #ifdef CONFIG_X86_REMOTE_DEBUG
00198         volatile unsigned int used_by_gdbstub;
00199 #endif
00200         spinlock_t hard_lock;
00201         spinlock_t data_lock;
00202 };
00203 
00204 /* grrr - this should have a arch-independent name */
00205 struct apic_timer_setup_data {
00206         int mode;
00207         int count;
00208 };
00209 
00210 
00211 
00212 struct calibration_data {
00213         unsigned int cpu_freq;
00214         unsigned int apic_freq;
00215         int latency;
00216         int setup_time_TIMER_CPUNIT;
00217         int setup_time_TIMER_UNIT;
00218         int timers_tol[NR_RT_CPUS];
00219 };
00220 
00221 
00222 typedef struct mips_fpu_env { unsigned long fpu_reg[32]; } FPU_ENV;
00223 
00224 /* unknown stuff */
00225 #define save_cr0_and_clts(x)
00226 #define restore_cr0(x)
00227 #define enable_fpu()
00228 #define DECLR_8254_TSC_EMULATION
00229 #define TICK_8254_TSC_EMULATION
00230 #define SETUP_8254_TSC_EMULATION
00231 #define CLEAR_8254_TSC_EMULATION
00232 
00233 
00234 extern unsigned volatile int *locked_cpus;
00235 
00236 static inline void rt_spin_lock_irq(spinlock_t *lock)
00237 {
00238         hard_cli();
00239         rt_spin_lock(lock);
00240 }  /* End function - rt_spin_lock_irq */
00241 
00242 static inline void rt_spin_unlock_irq(spinlock_t *lock)
00243 {
00244         rt_spin_unlock(lock);
00245         hard_sti();
00246 }  /* End function - rt_spin_unlock_irq */
00247 
00248 
00249 /*
00250  * Note that the spinlock calling convention below for irqsave/restore is
00251  * slightly different from the one used in Linux. Done on purpose to get an
00252  * error if you use Linux spinlocks in real time applications as they do not
00253  * guarantee any protection because of the soft irq disable. Be careful and
00254  * sure to call the other spinlocks the right way, as they are compatible
00255  * with Linux.
00256  */
00257 
00258 static inline unsigned int rt_spin_lock_irqsave(spinlock_t *lock)
00259 {
00260         unsigned long flags;
00261         hard_save_flags_and_cli(flags);
00262         rt_spin_lock(lock);
00263         return flags;
00264 } /* End function - rt_spin_lock_irqsave */
00265 
00266 static inline void rt_spin_unlock_irqrestore(unsigned long flags,
00267                                                         spinlock_t *lock)
00268 {
00269         rt_spin_unlock(lock);
00270         hard_restore_flags(flags);
00271 } /* End function - rt_spin_unlock_irqrestore */
00272 
00273 
00274 /*
00275  * Global interrupts and flags control (simplified, and modified, version of
00276  * similar global stuff in Linux irq.c).
00277  */
00278  
00279 static inline void rt_global_cli(void)
00280 {
00281         rt_get_global_lock();
00282 } /* End function - rt_global_cli */
00283  
00284 static inline void rt_global_sti(void)
00285 {
00286         rt_release_global_lock();
00287         hard_sti();
00288 } /* End function - rt_global_sti */
00289 
00290  
00291 static inline int rt_global_save_flags_and_cli(void)
00292 {
00293         unsigned long flags;
00294 
00295         hard_save_flags_and_cli(flags);
00296         if (!test_and_set_bit(hard_cpu_id(), locked_cpus)) {
00297                 while (test_and_set_bit(31, locked_cpus));
00298                 return ((flags & (1 << IFLAG)) + 1);
00299         } else {
00300                 return (flags & (1 << IFLAG));
00301         }
00302 } /* End function - rt_global_save_flags_and_cli */
00303 
00304 
00305 static inline void rt_global_save_flags(unsigned long *flags)
00306 {
00307         unsigned long hflags, rflags;
00308 
00309         hard_save_flags_and_cli(hflags);
00310         hflags = hflags & (1 << IFLAG);
00311         rflags = hflags | !test_bit(hard_cpu_id(), locked_cpus);
00312         if (hflags) {
00313                 hard_sti();
00314         }
00315         *flags = rflags;
00316 } /* End function - rt_global_save_flags */
00317 
00318 
00319 static inline void rt_global_restore_flags(unsigned long flags)
00320 {
00321         switch (flags) {
00322         case (1 << IFLAG) | 1:  rt_release_global_lock();
00323                 hard_sti();
00324                 break;
00325         case (1 << IFLAG) | 0:  rt_get_global_lock();
00326                 hard_sti();
00327                 break;
00328         case (0 << IFLAG) | 1:  rt_release_global_lock();
00329                 break;
00330         case (0 << IFLAG) | 0:  rt_get_global_lock();
00331                 break;
00332         }
00333 } /* End function - rt_global_restore_flags */
00334 
00335 
00336 extern struct rt_times rt_times;
00337 extern struct rt_times rt_smp_times[NR_RT_CPUS];
00338 extern struct calibration_data tuned;
00339 
00340 
00341 /*
00342  * This has been copied from the Linux kernel source for ffz and modified
00343  * to return the position of the first non zero bit. - Stevep
00344  *
00345  * ffnz = Find First Non Zero in word. Undefined if no one exists,
00346  * so code should check against ~0xffffffffUL first..
00347  *
00348  */
00349 extern __inline__ unsigned long ffnz(unsigned long word)
00350 {
00351         unsigned int    __res;
00352         unsigned int    __mask = 1;
00353 
00354         __asm__ (
00355                 ".set\tnoreorder\n\t"
00356                 ".set\tnoat\n\t"
00357                 "move\t%0,$0\n"
00358                 "1:\tand\t$1,%2,%1\n\t"
00359                 "bnez\t$1,2f\n\t"
00360                 "sll\t%1,1\n\t"
00361                 "bnez\t%1,1b\n\t"
00362                 "addiu\t%0,1\n\t"
00363                 ".set\tat\n\t"
00364                 ".set\treorder\n"
00365                 "2:\n\t"
00366                 : "=&r" (__res), "=r" (__mask)
00367                 : "r" (word), "1" (__mask)
00368                 : "$1");
00369 
00370         return __res;
00371 } /* End function - ffnz */
00372 
00373 
00374 static inline unsigned long long rdtsc(void)
00375 {
00376         extern struct rt_hal rthal;
00377         unsigned long count;
00378         long flags;
00379 
00380         count = read_c0_count();
00381         hard_save_flags_and_cli(flags);
00382         rthal.tsc.hltsc[1] += (count < rthal.tsc.hltsc[0]);
00383         rthal.tsc.hltsc[0] = count;
00384         hard_restore_flags(flags);
00385         return rthal.tsc.tsc;
00386 
00387 }  /* End function - rdtsc */
00388 
00389 /*
00390  * Temporary section as include asm-generic/rtai.h causes building problems.
00391  * Stevep - 7Jan02
00392  */
00393 
00394 int rt_request_global_irq(unsigned int irq, void (*handler)(void));
00395 int rt_free_global_irq(unsigned int irq);
00396 void rt_ack_irq(unsigned int irq);
00397 void rt_mask_and_ack_irq(unsigned int irq);
00398 void rt_unmask_irq(unsigned int irq);
00399 unsigned int rt_startup_irq(unsigned int irq);
00400 void rt_shutdown_irq(unsigned int irq);
00401 void rt_enable_irq(unsigned int irq);
00402 void rt_disable_irq(unsigned int irq);
00403 int rt_request_linux_irq(unsigned int irq,
00404         void (*linux_handler)(int irq, void *dev_id, struct pt_regs *regs), 
00405         char *linux_handler_id, void *dev_id);
00406 int rt_free_linux_irq(unsigned int irq, void *dev_id);
00407 void rt_pend_linux_irq(unsigned int irq);
00408 int rt_request_srq(unsigned int label, void (*rtai_handler)(void),
00409         long long (*user_handler)(unsigned int whatever));
00410 int rt_free_srq(unsigned int srq);
00411 void rt_pend_linux_srq(unsigned int srq);
00412 int rt_request_cpu_own_irq(unsigned int irq, void (*handler)(void));
00413 int rt_free_cpu_own_irq(unsigned int irq);
00414 int rt_request_timer(void (*handler)(void), unsigned int tick, int apic);
00415 int rt_free_timer(void);
00416 void rt_request_apic_timers(void (*handler)(void),
00417                         struct apic_timer_setup_data *apic_timer_data);
00418 void rt_free_apic_timers(void);
00419 void rt_mount_rtai(void);
00420 void rt_umount_rtai(void);
00421 int rt_printk(const char *format, ...);
00422 int rtai_print_to_screen(const char *format, ...);
00423 extern void rt_switch_to_linux(int cpuid);
00424 extern void rt_switch_to_real_time(int cpuid);
00425 
00426 #define rt_assign_irq_to_cpu(irq, cpu)
00427 #define rt_reset_irq_to_sym_mode(irq)
00428 
00429 /*
00430  * NOTE: delay MUST be 0 if a periodic timer is being used.
00431  *       This must go below the inclusion of the generic rtai.h header
00432  *       file as it need the prototye for rt_enable_irq.
00433  */
00434 static inline void rt_set_timer_delay(int delay)
00435 {
00436         unsigned long flags;
00437 
00438         hard_save_flags_and_cli(flags);
00439         write_c0_compare(read_c0_count() +
00440                         (delay ? delay : rt_times.periodic_tick));
00441         hard_restore_flags(flags);
00442         rt_enable_irq(TIMER_8254_IRQ);
00443 
00444 }  /* End function - rt_set_timer_delay */
00445 
00446 #endif /* __KERNEL__ */
00447 
00448 #define RTAI_DEFAULT_TICK    200000
00449 #define RTAI_DEFAULT_STACKSZ 1000
00450 
00451 #endif // _RTAI_ASM_MIPS_RTAI_H_

Generated on Sat Jul 24 19:36:02 2004 for RTAI API by doxygen 1.3.4