📄 rtai.c
字号:
}static unsigned long linux_save_flags_and_cli(void){ unsigned long linux_flags; linux_flags = cpu.intr_flag; cpu.intr_flag = 0; return linux_flags;}unsigned long linux_save_flags_and_cli_cpuid(int cpuid){ return linux_save_flags_and_cli();}void rtai_just_copy_back(unsigned long flags, int cpuid){ cpu.intr_flag = flags;}/* * hard_sti() is asm-defined as "ei" in system.h. This function * is used at rthal.ei_if_rtai when RTAI has been mounted. */ static void do_hard_sti(void){ hard_sti();}/* * Special fast version of rdtsc called from dispatch_timer_irq * with interrupts disabled. * When arriving here we _KNOW_ hat a timer interrupt has occured */static inline void rdtsc_special(void){#ifdef CONFIG_ETRAX_DISABLE_CASCADED_TIMERS_IN_RTAI unsigned int count = *R_TIMER0_DATA; #else unsigned int count = *R_TIMER01_DATA;#endif /* We know there was a timer interrupt when this function was called */ rtai_tsc += rtai_delay - rtai_lastcount + count; rtai_lastcount = count;}/* * This function is called as interrupt handler for most of the * interrupts when RTAI is mounted. See also dispatch_timer_irq. */asmlinkage void dispatch_irq(int irq, struct pt_regs *regs){ if (irq < 0 || irq >= NR_IRQS) return; /* Is there an RT-handler installed? */ if (global_irq_handlers[irq]) { /* The handler should: * ACK the interrupt properly and immediately. * Pend it to Linux if necessary. */ ((void (*)(int))global_irq_handlers[irq])(irq); /* Unmask ASAP since this is a RT interrupt. */ unmask_irq(irq); } else { /* There is no RT-handler; pend the interrupt to Linux. */ set_bit_non_atomic(irq, (int*) &global.pending_irqs); } /* Are interrupts enabled for Linux? */ if (cpu.intr_flag) { /* Dispatch any pending interrupts to Linux. */ linux_sti(); }} /* * This function is called as interrupt handler for the timer * interrupt when RTAI is mounted. */asmlinkage void dispatch_timer_irq(int irq, struct pt_regs *regs){ /* A minimum rdtsc (updates data used in scheduler) */ rdtsc_special(); /* ACK the timer interrupt */ *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i0, clr); /* The timer irq is not masked and should not be so either. */ /* The watchdog should preferably be disabled when running RTAI. */#ifdef CONFIG_ETRAX_WATCHDOG reset_watchdog();#endif /* Is there a RT-handler installed on the timer irq? */ if (global_irq_handlers[TIMER_IRQ]) { /* The handler pends the interrupt to Linux if necessary. */ ((void (*)(int))global_irq_handlers[TIMER_IRQ])(TIMER_IRQ); } else { /* There is no RT-handler so pend the interrupt to Linux */ set_bit_non_atomic(TIMER_IRQ, (int*) &global.pending_irqs); } /* Are interrupts enabled for Linux? */ if (cpu.intr_flag) { /* Dispatch any pending interrupts to Linux */ linux_sti(); } /* For speed (ei_if_rtai is done a little later anyway) */ hard_sti();} /* * This function is a way to enter the kernel in our own way from user-space. * * FIX: This function is never called. A kernel patch has to be added in future * versions. A file rtai_srq.h has to be added to the CRIS port before this * will work. Perhaps the break function could be used in a clever way. */asmlinkage long long dispatch_srq(int srq, unsigned long whatever){ if (srq > 1 && srq < NR_SYSRQS && sysrq[srq].user_handler) { return sysrq[srq].user_handler(whatever); } for (srq = 2; srq < NR_SYSRQS; srq++) { if (sysrq[srq].label == whatever) { return (long long) srq; } } return 0;}/* --------------------------------------------------------------------------*//* Used by the scheduler */int rt_is_linux(void){ return global.used_by_linux;}void rt_switch_to_linux(int cpuid){ global.used_by_linux = 1; cpu.intr_flag = cpu.linux_intr_flag; /* Restore */}void rt_switch_to_real_time(int cpuid){ if (global.used_by_linux) cpu.linux_intr_flag = cpu.intr_flag; /* Save */ cpu.intr_flag = 0; global.used_by_linux = 0;}/* --------------------------------------------------------------------------*//* * rt_request_timer set's the new timer latch value and * free's + requests the global timer irq as a realtime interrupt. */void rt_request_timer(void (*handler)(void), unsigned int tick, int unused){ unsigned long flags; flags = hard_lock_all(); /* Wait for a timer underflow and clear the int. bit. Needs to wait since we pend the irq for Linux later. Otherwise we could be 10ms off. */ do { ; } while ( !( *R_VECT_READ & IO_STATE(R_VECT_READ, timer0, active)) ); *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i0, clr); /* set up rt_times structure */ rt_times.linux_tick = LATCH; rt_times.periodic_tick = (tick > 0) ? tick : rt_times.linux_tick; rt_times.tick_time = rdtsc(); rt_times.intr_time = rt_times.tick_time + rt_times.periodic_tick; rt_times.linux_time = rt_times.tick_time + (RTIME) rt_times.linux_tick; /* Set the new timer divide factor */ rt_set_timer_delay(rt_times.periodic_tick); rt_free_global_irq(TIMER_IRQ); rt_request_global_irq(TIMER_IRQ, handler); /* pend linux timer irq to handle the current jiffie */ rt_pend_linux_irq(TIMER_IRQ); hard_unlock_all(flags);}void rt_free_timer(void){ unsigned long flags; flags = hard_lock_all();#ifdef CONFIG_ETRAX_DISABLE_CASCADED_TIMERS_IN_RTAI /* Clear the corresponding fields of the shadow. */ r_timer_ctrl_shadow = r_timer_ctrl_shadow & ( ~IO_FIELD(R_TIMER_CTRL, timerdiv0, 255) & ~IO_STATE(R_TIMER_CTRL, tm0, reserved)); /* Stop the timer and load the original timerdiv0 */ *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | IO_STATE(R_TIMER_CTRL, tm0, stop_ld); /* Restart the timer and save the changes to r_timer_ctrl_shadow */ *R_TIMER_CTRL = r_timer_ctrl_shadow = r_timer_ctrl_shadow | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | IO_STATE(R_TIMER_CTRL, tm0, run);#else /* Configure the timers to operate in cascading mode. */ *R_TIMER_CTRL = IO_FIELD( R_TIMER_CTRL, timerdiv1, RTAI_CASCADED_TIMER1_DIV) | IO_FIELD( R_TIMER_CTRL, timerdiv0, RTAI_CASCADED_TIMER0_DIV) | IO_STATE( R_TIMER_CTRL, i1, nop) | IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | IO_STATE( R_TIMER_CTRL, i0, nop) | IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | IO_STATE( R_TIMER_CTRL, clksel0, flexible); *R_TIMER_CTRL = r_timer_ctrl_shadow = IO_FIELD( R_TIMER_CTRL, timerdiv1, RTAI_CASCADED_TIMER1_DIV) | IO_FIELD( R_TIMER_CTRL, timerdiv0, RTAI_CASCADED_TIMER0_DIV) | IO_STATE( R_TIMER_CTRL, i1, nop) | IO_STATE( R_TIMER_CTRL, tm1, run) | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | IO_STATE( R_TIMER_CTRL, i0, nop) | IO_STATE( R_TIMER_CTRL, tm0, run) | IO_STATE( R_TIMER_CTRL, clksel0, flexible); *R_TIMER_PRESCALE = RTAI_CASCADED_TIMER_PRESCALE;#endif rt_free_global_irq(TIMER_IRQ); hard_unlock_all(flags);}/* --------------------------------------------------------------------------*/extern void soft_timer_interrupt(int, void*, struct pt_regs*);void __rt_mount_rtai(void){ unsigned long flags; flags = hard_lock_all(); /* Save the old rthal struct */ linux_rthal = rthal; rthal.do_IRQ = dispatch_irq; rthal.do_timer_IRQ = dispatch_timer_irq; rthal.do_SRQ = do_nothing; /* Set later upon request */ rthal.disint = linux_cli; rthal.enint = linux_sti; rthal.getflags = linux_save_flags; rthal.setflags = linux_restore_flags; rthal.getflags_and_cli = linux_save_flags_and_cli; rthal.ei_if_rtai = do_hard_sti; rthal.unmask_if_not_rtai = do_nothing_uint; /* Save the timer handler */ saved_timer_action_handler = irq_action[TIMER_IRQ]->handler; irq_action[TIMER_IRQ]->handler = soft_timer_interrupt; hard_unlock_all(flags); printk("\n***** RTAI MOUNTED *****\n\n");}extern void rt_printk_cleanup(void);extern void rt_printk_init(void);void __rt_umount_rtai(void){ unsigned long flags; flags = hard_lock_all(); /* Restore the old rthal struct */ rthal = linux_rthal; /* Restore timer-interrupt handler */ irq_action[TIMER_IRQ]->handler = saved_timer_action_handler; /* Remove SRQ for rt_printk etc. */ rt_printk_cleanup(); hard_unlock_all(flags); printk("\n***** RTAI UNMOUNTED *****\n\n");}static int init_rtai_cris(void){ int i; global.pending_irqs = 0; cpu.intr_flag = 1; cpu.linux_intr_flag = 1; for (i = 0; i < NR_IRQS; i++) { global_irq_handlers[i] = 0; chained_to_linux[i] = 0; } for (i = 0; i < NR_SYSRQS; i++) { sysrq[i].rtai_handler = 0; sysrq[i].user_handler = 0; sysrq[i].label = 0; } rt_printk_init();#ifdef CONFIG_ETRAX_DISABLE_CASCADED_TIMERS_IN_RTAI /* Keep timers as they are but save the * old timer control shadow. */ saved_r_timer_ctrl_shadow = r_timer_ctrl_shadow;#else /* Configure the timers to operate in cascading mode. */ *R_TIMER_CTRL = IO_FIELD( R_TIMER_CTRL, timerdiv1, RTAI_CASCADED_TIMER1_DIV) | IO_FIELD( R_TIMER_CTRL, timerdiv0, RTAI_CASCADED_TIMER0_DIV) | IO_STATE( R_TIMER_CTRL, i1, nop) | IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | IO_STATE( R_TIMER_CTRL, i0, nop) | IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | IO_STATE( R_TIMER_CTRL, clksel0, flexible); *R_TIMER_CTRL = r_timer_ctrl_shadow = IO_FIELD( R_TIMER_CTRL, timerdiv1, RTAI_CASCADED_TIMER1_DIV) | IO_FIELD( R_TIMER_CTRL, timerdiv0, RTAI_CASCADED_TIMER0_DIV) | IO_STATE( R_TIMER_CTRL, i1, nop) | IO_STATE( R_TIMER_CTRL, tm1, run) | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | IO_STATE( R_TIMER_CTRL, i0, nop) | IO_STATE( R_TIMER_CTRL, tm0, run) | IO_STATE( R_TIMER_CTRL, clksel0, flexible); *R_TIMER_PRESCALE = RTAI_CASCADED_TIMER_PRESCALE;#endif #ifdef CONFIG_PROC_FS rtai_proc_register();#endif return 0;}static void cleanup_rtai_cris(void){#ifdef CONFIG_PROC_FS rtai_proc_unregister();#endif /* Release any timer-interrupt handler */ rt_free_timer(); #ifdef CONFIG_ETRAX_DISABLE_CASCADED_TIMERS_IN_RTAI /* Restore timer control shadow */ r_timer_ctrl_shadow = saved_r_timer_ctrl_shadow;#endif }void rt_mount_rtai(void){ if ( !(rtai_mounted++) ){ init_rtai_cris(); __rt_mount_rtai(); }}void rt_umount_rtai(void){ if ( !(--rtai_mounted) ) { __rt_umount_rtai(); cleanup_rtai_cris(); }}module_init(init_rtai_cris);module_exit(cleanup_rtai_cris);/* --------------------------------------------------------------------------*//* Mostly copied from i386 */#ifdef CONFIG_PROC_FSstruct proc_dir_entry *rtai_proc_root = NULL;static int rtai_read_rtai(char *page, char **start, off_t off, int count, int *eof, void *data){ PROC_PRINT_VARS; int i; PROC_PRINT("\nRTAI Real Time Kernel, Version: %s\n\n", RTAI_RELEASE); PROC_PRINT(" RTAI mount count: %d\n", rtai_mounted); PROC_PRINT(" TIMER Frequency: %d\n", FREQ_8254); PROC_PRINT(" TIMER Latency: %d ns\n", LATENCY_8254); PROC_PRINT(" TIMER Setup: %d ns\n", SETUP_TIME_8254);#ifndef CONFIG_ETRAX_DISABLE_CASCADED_TIMERS_IN_RTAI PROC_PRINT("\n Using timers in cascade-mode.\n");#endif PROC_PRINT("\nirqs used by RTAI: \n"); for (i = 0; i < NR_GLOBAL_IRQS; i++) { if (global_irq_handlers[i]) { PROC_PRINT("%d ", i); } } PROC_PRINT("\nRTAI sysreqs in use: \n"); for (i = 0; i < NR_GLOBAL_IRQS; i++) { if (sysrq[i].rtai_handler || sysrq[i].user_handler) { PROC_PRINT("%d ", i); } } PROC_PRINT("\n\n"); PROC_PRINT_DONE;} /* End function - rtai_read_rtai */static int rtai_proc_register(void){ struct proc_dir_entry *ent; rtai_proc_root = create_proc_entry("rtai", S_IFDIR, 0); if (!rtai_proc_root) { printk("Unable to initialize /proc/rtai\n"); return(-1); } /* rtai.o is compiled into the kernel */ /* rtai_proc_root->owner = THIS_MODULE; */ ent = create_proc_entry("rtai", S_IFREG|S_IRUGO|S_IWUSR, rtai_proc_root); if (!ent) { printk("Unable to initialize /proc/rtai/rtai\n"); return(-1); } ent->read_proc = rtai_read_rtai; return(0);} /* End function - rtai_proc_register */static void rtai_proc_unregister(void){ remove_proc_entry("rtai", rtai_proc_root); remove_proc_entry("rtai", 0);} /* End function - rtai_proc_unregister */#endif /* CONFIG_PROC_FS *//* --------------------------------------------------------------------------*/EXPORT_SYMBOL(rt_mask_and_ack_irq);EXPORT_SYMBOL(rt_mask_irq);EXPORT_SYMBOL(rt_unmask_irq);EXPORT_SYMBOL(rt_disable_irq);EXPORT_SYMBOL(rt_enable_irq);EXPORT_SYMBOL(rt_request_global_irq);EXPORT_SYMBOL(rt_free_global_irq);EXPORT_SYMBOL(rt_free_linux_irq);EXPORT_SYMBOL(rt_free_srq);EXPORT_SYMBOL(rt_free_timer);EXPORT_SYMBOL(rt_mount_rtai); EXPORT_SYMBOL(rt_umount_rtai);EXPORT_SYMBOL(rt_pend_linux_irq);EXPORT_SYMBOL(rt_pend_linux_srq); EXPORT_SYMBOL(rt_printk);EXPORT_SYMBOL(rt_request_linux_irq);EXPORT_SYMBOL(rt_request_srq);EXPORT_SYMBOL(rt_request_timer);EXPORT_SYMBOL(rt_shutdown_irq);EXPORT_SYMBOL(rt_startup_irq);EXPORT_SYMBOL(rt_switch_to_linux);EXPORT_SYMBOL(rt_switch_to_real_time);EXPORT_SYMBOL(rt_is_linux);EXPORT_SYMBOL(rt_times);EXPORT_SYMBOL(tuned);EXPORT_SYMBOL(dispatch_irq);EXPORT_SYMBOL(dispatch_timer_irq);EXPORT_SYMBOL(dispatch_srq);EXPORT_SYMBOL(rtai_just_copy_back);EXPORT_SYMBOL(rtai_delay);EXPORT_SYMBOL(rtai_tsc);EXPORT_SYMBOL(rtai_lastcount);EXPORT_SYMBOL(rtai_proc_root);EXPORT_SYMBOL(linux_save_flags_and_cli_cpuid);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -