# rtai_legacy.h

    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
    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:
    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 #define DECLR_8254_TSC_EMULATION
    00429 #define TICK_8254_TSC_EMULATION
    00430 #define SETUP_8254_TSC_EMULATION
    00431 #define CLEAR_8254_TSC_EMULATION
    00432
    00433 static inline unsigned long long rdtsc(void)
    00434 {
    00435         unsigned long long ts;
    00436         unsigned long chk;
    00437 // The code below is as suggested in Motorola reference manual for 32 bits PPCs.
    00438         __asm__ __volatile__ ("1: mftbu %0; mftb %1; mftbu %2; cmpw %2,%0; bne 1b"
    00439         : "=r" (((unsigned long *)&ts)[0]), "=r" (((unsigned long *)&ts)[1]), "=r" (chk) );
    00440
    00441         return ts;
    00442 }
    00443
    00444 #define RT_BUG() do{hard_cli();BUG();}while(0)
    00445
    00446 static inline void rt_set_decrementer_count(int delay)
    00447 {
    00448 // NOTE: delay MUST be 0 if a periodic timer is being used.
    00449         if(!delay)delay = rt_times.intr_time - rdtsc();
    00450
    00451         if(delay<1){RT_BUG();}
    00452 #ifdef CONFIG_4xx
    00453         set_dec_4xx(delay);
    00454 #else
    00455         set_dec(delay);
    00456 #endif
    00457 }
    00458
    00459 // We like keeping it as for i386.
    00460 static inline int ffnz(long ul)
    00461 {
    00462         __asm__ __volatile__ ("cntlzw %0, %1" : "=r" (ul) : "r" (ul & (-ul)));
    00463
    00464         return 31 - ul;
    00465 }
    00466
    00467 #define rt_set_timer_delay(x)  rt_set_decrementer_count(x)
    00468
    00469 #endif /* __KERNEL__ */
    00470
    00471 #define RTAI_DEFAULT_TICK    200000
    00472 #define RTAI_DEFAULT_STACKSZ 2000
    00473
    00474 #endif /* !_RTAI_ASM_PPC_RTAI_H_ */