hal.h

Go to the documentation of this file.
00001 
00038 #ifndef _RTAI_ASM_I386_HAL_H
00039 #define _RTAI_ASM_I386_HAL_H
00040 
00041 #include <rtai_config.h>
00042 
00043 #define RTHAL_NR_CPUS  ADEOS_NR_CPUS
00044 
00045 typedef unsigned long long rthal_time_t;
00046 
00047 /* FIXME: temporary fix pasted from include/linux/compiler*.h, in order to have
00048    nucleus/lib/fusion.c. The proper fix is to implement llimd in user-space,
00049    since this is the only routine needed. */
00050 #ifndef __KERNEL__
00051 #if __GNUC__ == 2 && __GNUC_MINOR >= 96 || __GNUC__ >= 3
00052 #define __attribute_const__ __attribute__((__const__))
00053 #else
00054 #define __attribute_const__
00055 #endif
00056 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 1
00057 # define inline         inline          __attribute__((always_inline))
00058 #endif
00059 #endif
00060 
00061 #define __rthal_u64tou32(ull, h, l) ({          \
00062     (l) = ull & 0xffffffff;                     \
00063     (h) = ull >> 32;                            \
00064 })
00065 
00066 #define __rthal_u64fromu32(h, l) ({                     \
00067     union { unsigned long long _ull;                    \
00068         struct { unsigned long _sl, _sh; } _s; } _tmp;  \
00069     _tmp._s._sh=(h);                                    \
00070     _tmp._s._sl=(l);                                    \
00071     _tmp._ull;                                          \
00072 })
00073 
00074 /* Fast longs multiplication. */
00075 static inline __attribute_const__ unsigned long long
00076 rthal_ullmul(unsigned long m1, unsigned long m2) {
00077     /* Gcc (at least for versions 2.95 and higher) optimises correctly here. */
00078     return (unsigned long long) m1 * m2;
00079 }
00080 
00081 /* const helper for rthal_uldivrem, so that the compiler will eliminate
00082    multiple calls with same arguments, at no additionnal cost. */
00083 static inline __attribute_const__ unsigned long long
00084 __rthal_uldivrem(unsigned long long ull, unsigned long d) {
00085 
00086     __asm__ ("divl %1" : "=A,A"(ull) : "r,?m"(d), "A,A"(ull));
00087     /* Exception if quotient does not fit on unsigned long. */
00088     return ull;
00089 }
00090 
00091 /* Fast long long division: when the quotient and remainder fit on 32 bits.
00092    Eg.: conversion between POSIX struct timespec and nanoseconds count.
00093    Recent compilers remove redundant calls to this function. */
00094 static inline unsigned long
00095 rthal_uldivrem(unsigned long long ull, unsigned long d, unsigned long *rp) {
00096 
00097     unsigned long q, r;
00098     ull = __rthal_uldivrem(ull, d);
00099     __asm__ ( "": "=d"(r), "=a"(q) : "A"(ull));
00100     if(rp)
00101         *rp = r;
00102     return q;
00103 }
00104 
00105 /* Slow long long division. Uses rthal_uldivrem, hence has the same property:
00106    compiler removes redundant calls. It seems to inline quite well too. */
00107 static inline unsigned long long rthal_ulldiv (unsigned long long ull,
00108                                                unsigned long d,
00109                                                unsigned long *rp) {
00110 
00111     unsigned long h, l, qh, rh, ql;
00112     __rthal_u64tou32(ull, h, l);
00113 
00114     qh = rthal_uldivrem(h, d, &rh);
00115     __asm__ ( "": "=A"(ull) : "d"(rh), "a"(l));
00116     ql = rthal_uldivrem(ull, d, rp);
00117 
00118     return __rthal_u64fromu32(qh, ql);
00119 }
00120 
00121 /* Replaced the helper with rthal_ulldiv: rthal_ulldiv inlines better. */
00122 #define rthal_u64div32c rthal_ulldiv
00123 
00124 static inline __attribute_const__ int rthal_imuldiv (int i, int mult, int div) {
00125 
00126     /* Returns (unsigned)i = (unsigned)i*(unsigned)(mult)/(unsigned)div. */
00127     unsigned long ui = (unsigned long) i, um = (unsigned long) mult;
00128     return __rthal_uldivrem((unsigned long long) ui * um, div);
00129 }
00130 
00131 static inline __attribute_const__ long long rthal_llimd(long long ll,
00132                                                         int mult,
00133                                                         int div) {
00134 
00135     /* Returns (long long)ll = (int)ll*(int)(mult)/(int)div. */
00136 
00137     __asm__  ( \
00138         "movl %%edx,%%ecx\t\n" \
00139         "mull %%esi\t\n" \
00140         "movl %%eax,%%ebx\n\t" \
00141         "movl %%ecx,%%eax\t\n" \
00142         "movl %%edx,%%ecx\t\n" \
00143         "mull %%esi\n\t" \
00144         "addl %%ecx,%%eax\t\n" \
00145         "adcl $0,%%edx\t\n" \
00146         "divl %%edi\n\t" \
00147         "movl %%eax,%%ecx\t\n" \
00148         "movl %%ebx,%%eax\t\n" \
00149         "divl %%edi\n\t" \
00150         "sal $1,%%edx\t\n" \
00151         "cmpl %%edx,%%edi\t\n" \
00152         "movl %%ecx,%%edx\n\t" \
00153         "jge 1f\t\n" \
00154         "addl $1,%%eax\t\n" \
00155         "adcl $0,%%edx\t\n" \
00156         "1:\t\n" \
00157         : "=A" (ll) \
00158         : "A" (ll), "S" (mult), "D" (div) \
00159         : "%ebx", "%ecx");
00160 
00161     return ll;
00162 }
00163 
00164 
00165 static inline __attribute_const__ unsigned long ffnz (unsigned long word) {
00166     /* Derived from bitops.h's ffs() */
00167     __asm__("bsfl %1, %0"
00168             : "=r,r" (word)
00169             : "r,?m"  (word));
00170     return word;
00171 }
00172 
00173 #if defined(__KERNEL__) && !defined(__cplusplus)
00174 #include <linux/sched.h>
00175 #include <linux/interrupt.h>
00176 #include <asm/system.h>
00177 #include <asm/io.h>
00178 #include <asm/timex.h>
00179 #include <nucleus/asm/atomic.h>
00180 #include <asm/processor.h>
00181 #include <io_ports.h>
00182 #ifdef CONFIG_X86_LOCAL_APIC
00183 #include <asm/fixmap.h>
00184 #include <asm/apic.h>
00185 #endif /* CONFIG_X86_LOCAL_APIC */
00186 
00187 typedef void (*rthal_irq_handler_t)(unsigned irq,
00188                                     void *cookie);
00189 
00190 struct rthal_calibration_data {
00191 
00192     unsigned long cpu_freq;
00193     unsigned long timer_freq;
00194 };
00195 
00196 extern struct rthal_calibration_data rthal_tunables;
00197 
00198 extern volatile unsigned long rthal_cpu_realtime;
00199 
00200 extern adomain_t rthal_domain;
00201 
00202 #define RTHAL_DOMAIN_ID  0x52544149
00203 
00204 #define RTHAL_NR_SRQS    32
00205 
00206 #define RTHAL_TIMER_FREQ  (rthal_tunables.timer_freq)
00207 #define RTHAL_CPU_FREQ    (rthal_tunables.cpu_freq)
00208 #define RTHAL_8254_IRQ    0
00209 
00210 #ifdef CONFIG_X86_LOCAL_APIC
00211 #define RTHAL_APIC_TIMER_VECTOR    ADEOS_SERVICE_VECTOR3
00212 #define RTHAL_APIC_TIMER_IPI       ADEOS_SERVICE_IPI3
00213 #define RTHAL_APIC_ICOUNT          ((RTHAL_TIMER_FREQ + HZ/2)/HZ)
00214 #endif /* CONFIG_X86_LOCAL_APIC */
00215 
00216 #ifdef CONFIG_X86_TSC
00217 static inline unsigned long long rthal_rdtsc (void) {
00218     unsigned long long t;
00219     __asm__ __volatile__( "rdtsc" : "=A" (t));
00220     return t;
00221 }
00222 #else  /* !CONFIG_X86_TSC */
00223 #define RTHAL_8254_COUNT2LATCH  0xfffe
00224 void rthal_setup_8254_tsc(void);
00225 rthal_time_t rthal_get_8254_tsc(void);
00226 #define rthal_rdtsc() rthal_get_8254_tsc()
00227 #endif /* CONFIG_X86_TSC */
00228 
00229 #define rthal_cli()                     adeos_stall_pipeline_from(&rthal_domain)
00230 #define rthal_sti()                     adeos_unstall_pipeline_from(&rthal_domain)
00231 #define rthal_local_irq_save(x)         ((x) = !!adeos_test_and_stall_pipeline_from(&rthal_domain))
00232 #define rthal_local_irq_restore(x)      adeos_restore_pipeline_from(&rthal_domain,(x))
00233 #define rthal_local_irq_flags(x)        ((x) = !!adeos_test_pipeline_from(&rthal_domain))
00234 #define rthal_local_irq_test()          (!!adeos_test_pipeline_from(&rthal_domain))
00235 #define rthal_local_irq_sync(x)         ((x) = !!adeos_test_and_unstall_pipeline_from(&rthal_domain))
00236 
00237 #define rthal_hw_lock(flags)            adeos_hw_local_irq_save(flags)
00238 #define rthal_hw_unlock(flags)          adeos_hw_local_irq_restore(flags)
00239 #define rthal_hw_enable()               adeos_hw_sti()
00240 #define rthal_hw_disable()              adeos_hw_cli()
00241 
00242 #define rthal_linux_sti()                adeos_unstall_pipeline_from(adp_root)
00243 #define rthal_linux_cli()                adeos_stall_pipeline_from(adp_root)
00244 #define rthal_linux_local_irq_save(x)    ((x) = !!adeos_test_and_stall_pipeline_from(adp_root))
00245 #define rthal_linux_local_irq_restore(x) adeos_restore_pipeline_from(adp_root,x)
00246 #define rthal_linux_local_irq_restore_nosync(x,cpuid) adeos_restore_pipeline_nosync(adp_root,x,cpuid)
00247 
00248 #define rthal_spin_lock(lock)    adeos_spin_lock(lock)
00249 #define rthal_spin_unlock(lock)  adeos_spin_unlock(lock)
00250 
00251 static inline void rthal_spin_lock_irq(spinlock_t *lock) {
00252 
00253     rthal_cli();
00254     rthal_spin_lock(lock);
00255 }
00256 
00257 static inline void rthal_spin_unlock_irq(spinlock_t *lock) {
00258 
00259     rthal_spin_unlock(lock);
00260     rthal_sti();
00261 }
00262 
00263 static inline unsigned long rthal_spin_lock_irqsave(spinlock_t *lock) {
00264 
00265     unsigned long flags;
00266     rthal_local_irq_save(flags);
00267     rthal_spin_lock(lock);
00268     return flags;
00269 }
00270 
00271 static inline void rthal_spin_unlock_irqrestore(unsigned long flags,
00272                                                 spinlock_t *lock) {
00273     rthal_spin_unlock(lock);
00274     rthal_local_irq_restore(flags);
00275 }
00276 
00277 #ifdef CONFIG_SMP
00278 #define rthal_cpu_relax(x) \
00279 do { \
00280    int i = 0; \
00281    do \
00282      cpu_relax(); \
00283    while (++i < x); \
00284 } while(0)
00285 #endif /* CONFIG_SMP */
00286 
00287 #if !defined(CONFIG_ADEOS_NOTHREADS)
00288 
00289 /* Since real-time interrupt handlers are called on behalf of the RTAI
00290    domain stack, we cannot infere the "current" Linux task address
00291    using %esp. We must use the suspended Linux domain's stack pointer
00292    instead. */
00293 
00294 static inline struct task_struct *rthal_get_root_current (int cpuid) {
00295     return ((struct thread_info *)(((u_long)adp_root->esp[cpuid]) & (~8191UL)))->task;
00296 }
00297 
00298 static inline struct task_struct *rthal_get_current (int cpuid)
00299 
00300 {
00301     int *esp;
00302 
00303     __asm__ ("movl %%esp, %0" : "=r,?m" (esp));
00304 
00305     if (esp >= rthal_domain.estackbase[cpuid] && esp < rthal_domain.estackbase[cpuid] + 2048)
00306         return rthal_get_root_current(cpuid);
00307 
00308     return get_current();
00309 }
00310 
00311 #else /* CONFIG_ADEOS_NOTHREADS */
00312 
00313 static inline struct task_struct *rthal_get_root_current (int cpuid) {
00314     return current;
00315 }
00316 
00317 static inline struct task_struct *rthal_get_current (int cpuid) {
00318     return current;
00319 }
00320 
00321 #endif /* !CONFIG_ADEOS_NOTHREADS */
00322 
00323 static inline void rthal_set_timer_shot (unsigned long delay) {
00324 
00325     if (delay) {
00326         unsigned long flags;
00327         rthal_hw_lock(flags);
00328 #ifdef CONFIG_X86_LOCAL_APIC
00329         apic_read(APIC_LVTT);
00330         apic_write_around(APIC_LVTT,RTHAL_APIC_TIMER_VECTOR);
00331         apic_read(APIC_TMICT);
00332         apic_write_around(APIC_TMICT,delay);
00333 #else /* !CONFIG_X86_LOCAL_APIC */
00334         outb(delay & 0xff,0x40);
00335         outb(delay >> 8,0x40);
00336 #endif /* CONFIG_X86_LOCAL_APIC */
00337         rthal_hw_unlock(flags);
00338     }
00339 }
00340 
00341     /* Private interface -- Internal use only */
00342 
00343 unsigned long rthal_critical_enter(void (*synch)(void));
00344 
00345 void rthal_critical_exit(unsigned long flags);
00346 
00347 void rthal_set_linux_task_priority(struct task_struct *task,
00348                                    int policy,
00349                                    int prio);
00350 
00351 #endif /* __KERNEL__ && !__cplusplus */
00352 
00353     /* Public interface */
00354 
00355 #ifdef __KERNEL__
00356 
00357 #include <linux/kernel.h>
00358 
00359 typedef int (*rthal_trap_handler_t)(adevinfo_t *evinfo);
00360 
00361 #define rthal_printk    printk /* This is safe over Adeos */
00362 
00363 #ifdef __cplusplus
00364 extern "C" {
00365 #endif /* __cplusplus */
00366 
00367 int rthal_request_irq(unsigned irq,
00368                       void (*handler)(unsigned irq, void *cookie),
00369                       void *cookie);
00370 
00371 int rthal_release_irq(unsigned irq);
00372 
00378 int rthal_enable_irq(unsigned irq);
00379 
00380 int rthal_disable_irq(unsigned irq);
00381 
00384 int rthal_request_linux_irq(unsigned irq,
00385                             irqreturn_t (*handler)(int irq,
00386                                                    void *dev_id,
00387                                                    struct pt_regs *regs), 
00388                             char *name,
00389                             void *dev_id);
00390 
00391 int rthal_release_linux_irq(unsigned irq,
00392                             void *dev_id);
00393 
00394 int rthal_pend_linux_irq(unsigned irq);
00395 
00396 int rthal_pend_linux_srq(unsigned srq);
00397 
00398 int rthal_request_srq(unsigned label,
00399                       void (*handler)(void));
00400 
00401 int rthal_release_srq(unsigned srq);
00402 
00403 int rthal_set_irq_affinity(unsigned irq,
00404                            cpumask_t cpumask,
00405                            cpumask_t *oldmask);
00406 
00407 int rthal_request_timer(void (*handler)(void),
00408                         unsigned long nstick);
00409 
00410 void rthal_release_timer(void);
00411 
00412 rthal_trap_handler_t rthal_set_trap_handler(rthal_trap_handler_t handler);
00413 
00414 unsigned long rthal_calibrate_timer(void);
00415 
00416 #ifdef __cplusplus
00417 }
00418 #endif /* __cplusplus */
00419 
00420 #endif /* __KERNEL__ */
00421 
00424 #endif /* !_RTAI_ASM_I386_HAL_H */

Generated on Mon Dec 13 09:49:49 2004 for RTAI API by  doxygen 1.3.9.1