📄 rtai.c
字号:
/* * MIPS Port - Steve Papacharalambous (stevep@lineo.com) - 7 June 2001 * COPYRIGHT (C) 2001 Steve Papacharalambous. * COPYRIGHT (C) 2001 Paolo Mantegazza (mantegazza@aero.polimi.it) * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* * ACKNOWLEDGMENTS: * - Steve Papacharalambous (stevep@zentropix.com) has contributed an * informative proc filesystem procedure. * Stuart Hughes (sehughes@zentropix.com) has helped a lot in debugging the * porting of this module to 2.4.xx. *//* * Module to hook plain Linux up to do real time the way you like, hardware, * hopefully, fully trapped; the machine is in your hand, do what you want! *//* * Modified for 2.4.18 and other various things by Steven Seeger * sseeger@stellartec.com 07/08/2002 */#include <linux/module.h>#include <linux/version.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/init.h>#include <linux/string.h>#include <asm/system.h>#include <asm/hw_irq.h>#include <asm/io.h>#ifdef CONFIG_PROC_FS#include <linux/stat.h>#include <linux/proc_fs.h>#include "rtai_proc_fs.h"#endif#include <asm/rtai.h>#include <asm/rtai_srq.h>#include <rtai_version.h>MODULE_LICENSE("GPL");/* proc filesystem additions. */static int rtai_proc_register(void);static void rtai_proc_unregister(void);/* End of proc filesystem additions. *//* Some defines. */#undef CONFIG_RTAI_MOUNT_ON_LOAD#define CONFIG_RTAI_MOUNT_ON_LOAD 1#define NR_GLOBAL_IRQS 64#define NR_RTAI_IRQS 64#define NR_SYSRQS 32#define LAST_GLOBAL_RTAI_IRQ 63#define IRQ_DESC ((irq_desc_t *)rthal.irq_desc)#define HINT_DIAG_LSTI#define HINT_DIAG_ECHO#define HINT_DIAG_LRSTF#ifdef HINT_DIAG_ECHO#define HINT_DIAG_MSG(x) x#else#define HINT_DIAG_MSG(x)#endif/* External definitions. */extern void *set_except_vector(int n, void *addr);extern unsigned char debug_pport;/* Function prototypes. */unsigned long linux_save_flags_and_cli(void);void rtai_just_copy_back(unsigned long flags, int cpuid);/* Data declarations. */static void (*global_irq_handler[NR_GLOBAL_IRQS])(void);static unsigned long linux_hz = 0;static unsigned long rtai_hz = 0;static unsigned int rt_timer_active;extern unsigned long cycles_per_jiffy; //new to 2.4.18static struct sysrq_t { unsigned int label; void (*rtai_handler)(void); long long (*user_handler)(unsigned int whatever);} sysrq[NR_SYSRQS];struct rt_hal linux_rthal;static unsigned int (*linux_isr[NR_IRQS])(int irq, struct pt_regs *) = {0};/* * Array of pointers to pt_regs structures. This is used by the * dispatch_xxxx functions to save the pt_regs structure pointers * until the linux ISR is invoked. * * This is a horrible temporary hack. - Stevep :-( */struct pt_regs *rtai_regs[NR_IRQS];static struct hw_interrupt_type *linux_irq_desc_handler[NR_IRQS];static struct global_rt_status global;volatile unsigned int *locked_cpus = &global.locked_cpus;static struct cpu_own_status { volatile unsigned int intr_flag; volatile unsigned int linux_intr_flag; volatile unsigned int pending_irqs_l; volatile unsigned int pending_irqs_h; volatile unsigned int activ_irqs; volatile int irqs[NR_GLOBAL_IRQS];} processor[NR_RT_CPUS];static inline unsigned long hard_lock_all(void){ unsigned long flags; hard_save_flags_and_cli(flags); return(flags);} /* End function - hard_lock_all */#define hard_unlock_all(flags) hard_restore_flags((flags))/* * This is used in place of the standard Linux kernel function as the * standard Linux assembler version doesn't work properly with the IDT * CPU (causes adel exceptions out of the wazoo) and the c version uses * cli which becomes a soft cli when rtai is mounted. - Stevep */static inline unsigned long rtai_xchg_u32(volatile int *m, unsigned long val){ unsigned long flags, retval; hard_save_flags_and_cli(flags); retval = *m; *m = val; hard_restore_flags(flags); return(retval);} /* End function - rtai_xchg_u32 *//* * Functions to control Advanced-Programmable Interrupt Controllers (A-PIC). */ /* * Now Linux has a per PIC spinlock, as it has always been in RTAI. So there * is more a need to duplicate them here. Note however that they are not * safe since interrupts has just soft disabled, so we have to provide the * hard cli/sti. Moreover we do not want to run Linux_sti uselessly so we * clear also the soft flag. */static void (*internal_ic_ack_irq[NR_GLOBAL_IRQS]) (unsigned int irq);static void (*ic_ack_irq[NR_GLOBAL_IRQS]) (unsigned int irq);static void (*ic_end_irq[NR_GLOBAL_IRQS]) (unsigned int irq);static void (*linux_end_irq[NR_GLOBAL_IRQS]) (unsigned int irq);static void do_nothing_picfun(unsigned int irq) { }unsigned int rt_startup_irq(unsigned int irq){ unsigned long flags, lflags; volatile int *lflagp; int retval; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_save_flags_and_cli(flags); retval = linux_irq_desc_handler[irq]->startup(irq); hard_restore_flags(flags); *lflagp = lflags; return(retval);} /* End function - rt_startup_irq */void rt_shutdown_irq(unsigned int irq){ unsigned long flags, lflags; volatile int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_save_flags_and_cli(flags); linux_irq_desc_handler[irq]->shutdown(irq); hard_restore_flags(flags); *lflagp = lflags;} /* End function - rt_shutdown_irq */void rt_enable_irq(unsigned int irq){ unsigned long flags, lflags; volatile int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_save_flags_and_cli(flags); linux_irq_desc_handler[irq]->enable(irq); hard_restore_flags(flags); *lflagp = lflags;} /* End function - rt_enable_irq */void rt_disable_irq(unsigned int irq){ unsigned long flags, lflags; volatile int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_save_flags_and_cli(flags); linux_irq_desc_handler[irq]->disable(irq); hard_restore_flags(flags); *lflagp = lflags;} /* End function - rt_disable_irq */void rt_mask_and_ack_irq(unsigned int irq){ unsigned long flags, lflags; volatile int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_save_flags_and_cli(flags); ic_ack_irq[irq](irq); hard_restore_flags(flags); *lflagp = lflags;} /* End function - rt_mask_and_ack_irq */void rt_ack_irq(unsigned int irq){ unsigned long flags, lflags; volatile int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_save_flags_and_cli(flags); internal_ic_ack_irq[irq](irq); hard_restore_flags(flags); *lflagp = lflags;} /* End function - rt_ack_irq */void rt_unmask_irq(unsigned int irq){ unsigned long flags, lflags; volatile int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_save_flags_and_cli(flags); ic_end_irq[irq](irq); hard_restore_flags(flags); *lflagp = lflags;} /* End function - rt_unmask_irq *//* * The functions below are the same as those above, except that we do not need * to save the hard flags as they have the interrupt bit set for sure. */unsigned int trpd_startup_irq(unsigned int irq){ unsigned int lflags; volatile unsigned int *lflagp; int retval; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_cli(); retval = linux_irq_desc_handler[irq]->startup(irq); hard_sti(); *lflagp = lflags; return(retval);} /* End function - trpd_startup_irq */void trpd_shutdown_irq(unsigned int irq){ unsigned int lflags; volatile unsigned int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_cli(); linux_irq_desc_handler[irq]->shutdown(irq); hard_sti(); *lflagp = lflags;} /* End function - trpd_shutdown_irq */void trpd_enable_irq(unsigned int irq){ unsigned int lflags; volatile unsigned int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_cli(); linux_irq_desc_handler[irq]->enable(irq); hard_sti(); *lflagp = lflags;} /* End function - trpd_enable_irq */void trpd_disable_irq(unsigned int irq){ unsigned int lflags; volatile unsigned int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_cli(); linux_irq_desc_handler[irq]->disable(irq); hard_sti(); *lflagp = lflags;} /* End function - trpd_disable_irq */void trpd_end_irq(unsigned int irq){ unsigned int lflags; volatile unsigned int *lflagp; lflags = rtai_xchg_u32(lflagp = &processor[hard_cpu_id()].intr_flag, 0); hard_cli(); linux_end_irq[irq](irq); hard_sti(); *lflagp = lflags;} /* End function - trpd_end_irq */void trpd_set_affinity(unsigned int irq, unsigned long mask){ unsigned int lflags; volatile unsigned int *lflagp; lflags = rtai_xchg_u32(lflagp = (int *)&processor[hard_cpu_id()].intr_flag, 0); hard_cli(); linux_irq_desc_handler[irq]->set_affinity(irq, mask); hard_sti(); *lflagp = lflags;} /* End function - trpd_set_affinity */static struct hw_interrupt_type trapped_linux_irq_type = { "RT SPVISD", trpd_startup_irq, trpd_shutdown_irq, trpd_enable_irq, trpd_disable_irq, do_nothing_picfun, trpd_end_irq, trpd_set_affinity };static struct hw_interrupt_type real_time_irq_type = { "REAL TIME", (unsigned int (*)(unsigned int))do_nothing_picfun, do_nothing_picfun, do_nothing_picfun, do_nothing_picfun, do_nothing_picfun, do_nothing_picfun, (void (*)(unsigned int, unsigned long)) do_nothing_picfun };void rt_switch_to_linux(int cpuid){ set_bit(cpuid, &global.used_by_linux); processor[cpuid].intr_flag = processor[cpuid].linux_intr_flag;} /* End function - rt_switch_to_linux */void rt_switch_to_real_time(int cpuid){ processor[cpuid].linux_intr_flag = xchg(&(processor[cpuid].intr_flag), 0); clear_bit(cpuid, &global.used_by_linux);} /* End function - rt_switch_to_linux *//* * Request and free interrupts, system requests and interprocessors messages * Request for regular Linux irqs also included. They are nicely chained to * Linux, forcing sharing with any already installed handler, so that we can * have an echo from Linux for global handlers. We found that usefull during * debug, but can be nice for a lot of other things, e.g. see the jiffies * recovery in rtai_sched.c, and the global broadcast to local apic timers. */static unsigned long irq_action_flags[NR_GLOBAL_IRQS];static int chained_to_linux[NR_GLOBAL_IRQS];int rt_request_global_irq(unsigned int irq, void (*handler)(void)){ unsigned long flags; if(irq >= NR_GLOBAL_IRQS || !handler) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -