base/include/asm-ppc/rtai_legacy.h

Go to the documentation of this file.
00001 /*
00002 COPYRIGHT (C) 2000  Paolo Mantegazza (mantegazza@aero.polimi.it)
00003 
00004 This library is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU Lesser General Public
00006 License as published by the Free Software Foundation; either
00007 version 2 of the License, or (at your option) any later version.
00008 
00009 This library is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public
00015 License along with this library; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
00017 */
00018 
00019 
00020 #ifndef _RTAI_ASM_PPC_RTAI_H_
00021 #define _RTAI_ASM_PPC_RTAI_H_
00022 
00023 #include <rtai_types.h>
00024 
00025 // These are truly PPC specific.
00026 #define LATENCY_DECR 2500 
00027 #define SETUP_TIME_DECR 500 
00028 
00029 // CPU frequency calibration
00030 #define CPU_FREQ (tuned.cpu_freq)
00031 #define FREQ_DECR CPU_FREQ
00032 #define CALIBRATED_CPU_FREQ     0 // Use this if you know better than Linux!
00033 
00034 // Do not be messed up by macros names below, is a trick for keeping i386 code.
00035 #define FREQ_8254 FREQ_DECR
00036 #define FREQ_APIC FREQ_DECR
00037 #define LATENCY_8254 3000
00038 #define SETUP_TIME_8254 500
00039 #define TIMER_8254_IRQ 0xFFFFFFFF
00040 
00041 #define IFLAG 15
00042 
00043 #define RTAI_NR_TRAPS 32
00044 
00045 // These and the related vector are of no use, at the moment.
00046 #define RTAI_1_IPI  6
00047 #define RTAI_2_IPI  7
00048 #define RTAI_3_IPI  8
00049 #define RTAI_4_IPI  9
00050 
00051 #define RTAI_1_VECTOR  0xD9
00052 #define RTAI_2_VECTOR  0xE1
00053 #define RTAI_3_VECTOR  0xE9
00054 #define RTAI_4_VECTOR  0xF1
00055 
00056 #define RT_TIME_END 0x7FFFFFFFFFFFFFFFLL
00057 
00058 #ifdef INLINE_MATH
00059 unsigned long long ullmul(unsigned long m0, unsigned long m1);
00060 unsigned long long ulldiv(unsigned long long ull, unsigned long uld, unsigned long *r);
00061 int imuldiv(int i, int mult, int div);
00062 unsigned long long llimd(unsigned long long ull, unsigned long mult, unsigned long div);
00063 #else /* !INLINE_MATH */
00064 // One of the silly thing of 32 bits PPCs, no 64 bits result for 32 bits mul.
00065 static inline unsigned long long ullmul(unsigned long m0, unsigned long m1)
00066 {
00067     unsigned long long res;
00068 
00069     __asm__ __volatile__ ("mulhwu %0, %1, %2"
00070     : "=r" (((unsigned long *)&res)[0]) : "%r" (m0), "r" (m1));
00071     ((unsigned long *)&res)[1] = m0*m1;
00072 
00073     return res;
00074 
00075 }
00076 
00077 // One of the silly thing of 32 bits PPCs, no 64 by 32 bits divide.
00078 static inline unsigned long long ulldiv(unsigned long long ull, unsigned long uld, unsigned long *r)
00079 {
00080     unsigned long long q, rf;
00081     unsigned long qh, rh, ql, qf;
00082 
00083     q = 0;
00084     rf = (unsigned long long)(0xFFFFFFFF - (qf = 0xFFFFFFFF / uld) * uld) + 1ULL;
00085 
00086     while (ull >= uld) {
00087         ((unsigned long *)&q)[0] += (qh = ((unsigned long *)&ull)[0] / uld);
00088         rh = ((unsigned long *)&ull)[0] - qh * uld;
00089         q += rh * (unsigned long long)qf + (ql = ((unsigned long *)&ull)[1] / uld);
00090         ull = rh * rf + (((unsigned long *)&ull)[1] - ql * uld);
00091     }
00092 
00093     *r = ull;
00094     return q;
00095 }
00096 
00097 static inline int imuldiv(int i, int mult, int div)
00098 {
00099     unsigned long q, r;
00100 
00101     q = ulldiv(ullmul(i, mult), div, &r);
00102 
00103     return (r + r) > div ? q + 1 : q;
00104 }
00105 
00106 static inline unsigned long long llimd(unsigned long long ull, unsigned long mult, unsigned long div)
00107 {
00108     unsigned long long low;
00109     unsigned long q, r;
00110 
00111     low  = ullmul(((unsigned long *)&ull)[1], mult);    
00112     q = ulldiv( ullmul(((unsigned long *)&ull)[0], mult) + ((unsigned long *)&low)[0], div, (unsigned long *)&low);
00113     low = ulldiv(low, div, &r);
00114     ((unsigned long *)&low)[0] += q;
00115 
00116     return (r + r) > div ? low + 1 : low;
00117 }
00118 #endif /* INLINE_MATH */
00119 
00120 #ifdef __KERNEL__
00121 
00122 #ifndef __cplusplus
00123 #include <linux/types.h>
00124 #include <linux/rtc.h>          /* to avoid warnings in time.h */
00125 #include <asm/time.h>
00126 #include <linux/kernel.h>
00127 #include <linux/smp.h>
00128 #include <linux/irq.h>
00129 #include <asm/page.h>
00130 #include <asm/ptrace.h>
00131 #include <asm/hw_irq.h>
00132 #include <asm/processor.h>
00133 #include <asm/bitops.h>
00134 #include <asm/rtai_fpu.h>
00135 #include <asm/rtai_atomic.h>
00136 #endif /* !__cplusplus */
00137 
00138 // Write to parallel port if present
00139 #if defined(CONFIG_PPC)
00140 #define LPT_OUTB(v) do { } while (0)
00141 #else
00142 #define LPT_OUTB(v) do { outb(v,0x378); } while(0)
00143 #endif
00144 
00145 struct apic_timer_setup_data { int mode, count; };
00146 
00147 struct desc_struct { void *fun; };
00148 
00149 extern unsigned volatile int *locked_cpus;
00150 
00151 extern void send_ipi_shorthand(unsigned int shorthand, int irq);
00152 extern void send_ipi_logical(unsigned long dest, int irq);
00153 #define rt_assign_irq_to_cpu(irq, cpu)
00154 #define rt_reset_irq_to_sym_mode(irq)
00155 extern int  rt_request_global_irq(unsigned int irq, void (*handler)(unsigned int irq));
00156 extern int  rt_request_global_irq_arg(unsigned int irq,
00157         int (*handler)(int,void *,struct pt_regs *),
00158         unsigned long flags,const char *dev,void *dev_id);
00159 extern int rt_request_global_irq_ext(unsigned int irq, 
00160                      int (*handler)(unsigned int irq, unsigned long handler), 
00161                      unsigned long data);
00162 extern void rt_set_global_irq_ext(unsigned int irq, int ext, unsigned long data);
00163 extern int  rt_free_global_irq(unsigned int irq);
00164 extern void rt_ack_irq(unsigned int irq);
00165 extern void rt_mask_and_ack_irq(unsigned int irq);
00166 extern void rt_unmask_irq(unsigned int irq);
00167 extern unsigned int rt_startup_irq(unsigned int irq);
00168 extern void rt_shutdown_irq(unsigned int irq);
00169 extern void rt_enable_irq(unsigned int irq);
00170 extern void rt_disable_irq(unsigned int irq);
00171 extern int rt_request_linux_irq(unsigned int irq,
00172     void (*linux_handler)(int irq, void *dev_id, struct pt_regs *regs), 
00173     char *linux_handler_id, void *dev_id);
00174 extern int rt_free_linux_irq(unsigned int irq, void *dev_id);
00175 extern void rt_pend_linux_irq(unsigned int irq);
00176 extern void rt_tick_linux_timer(void);
00177 extern struct desc_struct rt_set_full_intr_vect(unsigned int vector, int type, int dpl, void *handler);
00178 extern void rt_reset_full_intr_vect(unsigned int vector, struct desc_struct idt_element);
00179 #define rt_set_intr_handler(vector, handler) ((void *)0)
00180 #define rt_reset_intr_handler(vector, handler)
00181 extern int rt_request_srq(unsigned int label, void (*rtai_handler)(void), long long (*user_handler)(unsigned int whatever));
00182 extern int rt_free_srq(unsigned int srq);
00183 extern void rt_pend_linux_srq(unsigned int srq);
00184 #define rt_request_cpu_own_irq(irq, handler) rt_request_global_irq((irq), (handler))
00185 #define rt_free_cpu_own_irq(irq) rt_free_global_irq((irq))
00186 extern void rt_request_timer(void (*handler)(void), unsigned int tick, int apic);
00187 extern void rt_free_timer(void);
00188 extern void rt_request_apic_timers(void (*handler)(void), struct apic_timer_setup_data *apic_timer_data);
00189 extern void rt_free_apic_timers(void);
00190 extern void rt_mount_rtai(void);
00191 extern void rt_umount_rtai(void);
00192 extern int rt_printk(const char *format, ...);
00193 extern int rtai_print_to_screen(const char *format, ...);
00194 extern void rt_switch_to_linux(int cpuid);
00195 extern void rt_switch_to_real_time(int cpuid);
00196 
00197 #ifndef DEBUG_FLAGS
00198 #define debug_flags_set(ptr,a)
00199 #define debug_flags_check(ptr)
00200 #else
00201 void debug_flags_set(void *ptr,unsigned long flags);
00202 void debug_flags_check(void *ptr);
00203 #endif
00204 
00205 static inline void hard_cli(void)
00206 {
00207     debug_flags_set(__builtin_return_address(0),0);
00208     __asm__ __volatile__ (
00209         "\tmfmsr    0\n"
00210         //"\trlwinm 3,0,16+1,32-1,31\n"
00211         "\trlwinm   0,0,0,17,15\n"
00212         "\tmtmsr    0\n"
00213         : : : "r0"
00214     );
00215 }
00216 
00217 
00218 static inline void hard_restore_flags(unsigned long flags)
00219 {
00220     debug_flags_set(__builtin_return_address(0),flags);
00221     __asm__ __volatile__ (
00222         "\tmfmsr    0\n"
00223         "\trlwimi   %0,0,0,17,15\n"
00224         "\tmtmsr    %0\n"
00225     : : "r" (flags) : "r0"
00226     );
00227 }
00228     
00229 static inline void hard_sti(void)
00230 {
00231     debug_flags_set(__builtin_return_address(0),MSR_EE);
00232     __asm__ __volatile__ (
00233         "\tmfmsr    0\n"
00234         "\tori      0,0,(1<<15)\n"
00235         "\tmtmsr    0\n"
00236         : : : "r0"
00237     );
00238 }
00239 
00240 static inline void __hard_save_flags(unsigned long *flags)
00241 {
00242     __asm__ __volatile__ (
00243         "\tmfmsr    %0\n"
00244         : "=r" (*flags)
00245     );
00246 }
00247 
00248 #define hard_save_flags(flags)         do { __hard_save_flags(&(flags)); } while (0)
00249 #define hard_save_flags_and_cli(flags) do { __hard_save_flags(&(flags)); hard_cli(); } while (0)
00250 
00251 #ifdef CONFIG_SMP
00252 
00253 #define rt_spin_lock(lock) spin_lock((lock))
00254 
00255 #define rt_spin_unlock(lock) spin_unlock((lock))
00256 
00257 #define hard_cpu_id()  hard_smp_processor_id() 
00258 
00259 static inline void rt_get_global_lock(void)
00260 {
00261     hard_cli();
00262     if (!test_and_set_bit(hard_cpu_id(), locked_cpus)) {
00263         while (test_and_set_bit(31, locked_cpus));
00264     }
00265 }
00266 
00267 static inline void rt_release_global_lock(void)
00268 {
00269     hard_cli();
00270     if (test_and_clear_bit(hard_cpu_id(), locked_cpus)) {
00271         clear_bit(31, locked_cpus);
00272     }
00273 }
00274 
00275 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00276 // If NR_RT_CPUS > 8 RTAI must be changed as it cannot use APIC flat delivery
00277 // and the way processor[?].intr_flag is used must be changed (right now it
00278 // exploits the fact that the IF flags is at bit 16 so that bits 0-7 are used
00279 // to mark a cpu as Linux soft irq enabled/disabled. Bad but comfortable, it 
00280 // will take a very very long time before I'll have available SMP with more
00281 // than 8 cpus. Right now they are only:
00282 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00283 #define NR_RT_CPUS  2
00284 
00285 #else  /* !CONFIG_SMP */
00286 
00287 #define rt_spin_lock(whatever)  
00288 #define rt_spin_unlock(whatever)
00289 
00290 #define rt_get_global_lock()  hard_cli()
00291 #define rt_release_global_lock()
00292 
00293 #define hard_cpu_id()  0
00294 
00295 #define NR_RT_CPUS  1
00296 
00297 #endif  /* CONFIG_SMP */
00298 
00299 static inline void rt_spin_lock_irq(spinlock_t *lock)          
00300 {
00301     hard_cli(); 
00302     rt_spin_lock(lock);
00303 }
00304 
00305 static inline void rt_spin_unlock_irq(spinlock_t *lock)
00306 {
00307     rt_spin_unlock(lock);
00308     hard_sti();
00309 }
00310 
00311 // Note that the spinlock calling convention below for irqsave/restore is 
00312 // sligtly different from the one used in Linux. Done on purpose to get an 
00313 // error if you use Linux spinlocks in real time applications as they do not
00314 // guaranty any protection because of the soft irq disable. Be careful and 
00315 // sure to call the other spinlocks the right way, as they are compatible 
00316 // with Linux.
00317 
00318 static inline unsigned int rt_spin_lock_irqsave(spinlock_t *lock)          
00319 {
00320     unsigned long flags;
00321     hard_save_flags_and_cli(flags);
00322     rt_spin_lock(lock);
00323     return flags;
00324 }
00325 
00326 static inline void rt_spin_unlock_irqrestore(unsigned long flags, spinlock_t *lock)
00327 {
00328     rt_spin_unlock(lock);
00329     hard_restore_flags(flags);
00330 }
00331 
00332 /* Global interrupts and flags control (simplified, and modified, version of */
00333 /* similar global stuff in Linux irq.c).                                     */
00334 
00335 static inline void rt_global_cli(void)
00336 {
00337     rt_get_global_lock();
00338 }
00339 
00340 static inline void rt_global_sti(void)
00341 {
00342     rt_release_global_lock();
00343     hard_sti();
00344 }
00345 
00346 static inline int rt_global_save_flags_and_cli(void)
00347 {
00348     unsigned long flags;
00349 
00350     hard_save_flags_and_cli(flags);
00351     if (!test_and_set_bit(hard_cpu_id(), locked_cpus)) {
00352         while (test_and_set_bit(31, locked_cpus));
00353         return ((flags & (1 << IFLAG)) + 1);
00354     } else {
00355         return (flags & (1 << IFLAG));
00356     }
00357 }
00358 
00359 static inline void rt_global_save_flags(unsigned long *flags)
00360 {
00361     unsigned long hflags, rflags;
00362 
00363     hard_save_flags_and_cli(hflags);
00364     hflags = hflags & (1 << IFLAG);
00365     rflags = hflags | !test_bit(hard_cpu_id(), locked_cpus);
00366     if (hflags) {
00367         hard_sti();
00368     }
00369     *flags = rflags;
00370 }
00371 
00372 static inline void rt_global_restore_flags(unsigned long flags)
00373 {
00374     switch (flags) {
00375         case (1 << IFLAG) | 1:  rt_release_global_lock();
00376                         hard_sti();
00377                     break;
00378         case (1 << IFLAG) | 0:  rt_get_global_lock();
00379                     hard_sti();
00380                     break;
00381         case (0 << IFLAG) | 1:  rt_release_global_lock();
00382                     break;
00383         case (0 << IFLAG) | 0:  rt_get_global_lock();
00384                     break;
00385     }
00386 }
00387 
00388 static inline RT_TRAP_HANDLER rt_set_rtai_trap_handler(RT_TRAP_HANDLER handler)
00389 {
00390     return (RT_TRAP_HANDLER) 0;
00391 }
00392 
00393 struct calibration_data {
00394     unsigned int cpu_freq;
00395     int latency;
00396     int setup_time_TIMER_CPUNIT;
00397     int setup_time_TIMER_UNIT;
00398     int timers_tol[NR_RT_CPUS];
00399 };
00400 
00401 extern struct rt_times rt_times;
00402 extern struct rt_times rt_smp_times[NR_RT_CPUS];
00403 extern struct calibration_data tuned;
00404 
00405 #if 0
00406 static inline unsigned int get_dec(void)
00407 {
00408         return (mfspr(SPRN_DEC));
00409 }
00410 
00411 static inline void set_dec(unsigned int val)
00412 {
00413     mtspr(SPRN_DEC, val);
00414 }
00415 #endif
00416 #ifdef CONFIG_4xx
00417 static inline unsigned int get_dec_4xx(void)
00418 {
00419     return (mfspr(SPRN_PIT));
00420 }
00421 
00422 static inline void set_dec_4xx(unsigned int val)
00423 {
00424     mtspr(SPRN_PIT, val);
00425 }
00426 #endif
00427 
00428 #if 0
00429 #define DECLR_8254_TSC_EMULATION
00430 #define TICK_8254_TSC_EMULATION
00431 #define SETUP_8254_TSC_EMULATION
00432 #define CLEAR_8254_TSC_EMULATION
00433 #endif
00434 
00435 static inline unsigned long long rdtsc(void)
00436 {
00437     unsigned long long ts;
00438     unsigned long chk;
00439 // The code below is as suggested in Motorola reference manual for 32 bits PPCs.
00440     __asm__ __volatile__ ("1: mftbu %0; mftb %1; mftbu %2; cmpw %2,%0; bne 1b"
00441     : "=r" (((unsigned long *)&ts)[0]), "=r" (((unsigned long *)&ts)[1]), "=r" (chk) );
00442 
00443     return ts;
00444 }
00445 
00446 #define RT_BUG() do{hard_cli();BUG();}while(0)
00447 
00448 static inline void rt_set_decrementer_count(int delay)
00449 {
00450 // NOTE: delay MUST be 0 if a periodic timer is being used.
00451     if(!delay)delay = rt_times.intr_time - rdtsc();
00452 
00453     if(delay<1){RT_BUG();}
00454 #ifdef CONFIG_4xx
00455     set_dec_4xx(delay);
00456 #else
00457         set_dec(delay);
00458 #endif
00459 }
00460 
00461 // We like keeping it as for i386.
00462 static inline int ffnz(long ul)
00463 {
00464     __asm__ __volatile__ ("cntlzw %0, %1" : "=r" (ul) : "r" (ul & (-ul)));
00465 
00466     return 31 - ul;
00467 }
00468 
00469 #define rt_set_timer_delay(x)  rt_set_decrementer_count(x)
00470 
00471 #endif /* __KERNEL__ */
00472 
00473 #define RTAI_DEFAULT_TICK    200000
00474 #define RTAI_DEFAULT_STACKSZ 2000
00475 
00476 #endif /* !_RTAI_ASM_PPC_RTAI_H_ */

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