diff -Naur linux-2.4.20/Documentation/Configure.help linux-2.4.20-rtai/Documentation/Configure.help --- linux-2.4.20/Documentation/Configure.help Fri Nov 29 19:01:31 2002 +++ linux-2.4.20-rtai/Documentation/Configure.help Mon Dec 2 16:11:55 2002 @@ -254,6 +254,13 @@ You will need a new lynxer.elf file to flash your firmware with - send email to Martin.Bligh@us.ibm.com +Real-Time Harware Abstraction +CONFIG_RTHAL + The Real-Time Hardware Abstraction Layer (RTHAL) is used by + the Real-Time Application Interface (RTAI) to provide a + hard real-time environment as part of Linux. This feature + cannot be turned off, so say Y. + Support for IBM Summit (EXA) systems CONFIG_X86_SUMMIT This option is needed for IBM systems that use the Summit/EXA chipset. diff -Naur linux-2.4.20/arch/i386/config.in linux-2.4.20-rtai/arch/i386/config.in --- linux-2.4.20/arch/i386/config.in Fri Nov 29 19:01:34 2002 +++ linux-2.4.20-rtai/arch/i386/config.in Mon Dec 2 16:11:55 2002 @@ -256,6 +256,8 @@ if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then define_bool CONFIG_HAVE_DEC_LOCK y fi +comment 'CONFIG_RTHAL must be yes' +bool 'Real-Time Hardware Abstraction Layer' CONFIG_RTHAL endmenu mainmenu_option next_comment diff -Naur linux-2.4.20/arch/i386/defconfig linux-2.4.20-rtai/arch/i386/defconfig --- linux-2.4.20/arch/i386/defconfig Fri Nov 29 19:01:34 2002 +++ linux-2.4.20-rtai/arch/i386/defconfig Mon Dec 2 16:11:55 2002 @@ -66,6 +66,7 @@ # CONFIG_MULTIQUAD is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_NR_CPUS=32 +CONFIG_RTHAL=y # # General setup diff -Naur linux-2.4.20/arch/i386/kernel/entry.S linux-2.4.20-rtai/arch/i386/kernel/entry.S --- linux-2.4.20/arch/i386/kernel/entry.S Fri Nov 29 19:01:34 2002 +++ linux-2.4.20-rtai/arch/i386/kernel/entry.S Mon Dec 2 16:11:55 2002 @@ -184,6 +184,7 @@ ENTRY(ret_from_fork) + sti pushl %ebx call SYMBOL_NAME(schedule_tail) addl $4, %esp @@ -210,17 +211,20 @@ call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value ENTRY(ret_from_sys_call) - cli # need_resched and signals atomic test + call *(SYMBOL_NAME(rthal) + 12) # cli cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) jne signal_return + sti + call *(SYMBOL_NAME(rthal) + 16) # sti restore_all: RESTORE_ALL ALIGN signal_return: - sti # we can get here from an interrupt handler + sti # we can get here from an interrupt handler + call *(SYMBOL_NAME(rthal) + 16) # sti testl $(VM_MASK),EFLAGS(%esp) movl %esp,%eax jne v86_signal_return diff -Naur linux-2.4.20/arch/i386/kernel/i386_ksyms.c linux-2.4.20-rtai/arch/i386/kernel/i386_ksyms.c --- linux-2.4.20/arch/i386/kernel/i386_ksyms.c Sat Aug 3 02:39:42 2002 +++ linux-2.4.20-rtai/arch/i386/kernel/i386_ksyms.c Mon Dec 2 16:11:55 2002 @@ -32,6 +32,18 @@ extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; +EXPORT_SYMBOL_NOVERS(rthal); + +#ifdef CONFIG_VT + #include + EXPORT_SYMBOL(kd_mksound); +#endif + +#include +EXPORT_SYMBOL(console_drivers); +extern unsigned long cpu_khz; +EXPORT_SYMBOL(cpu_khz); + #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) extern void machine_real_restart(unsigned char *, int); EXPORT_SYMBOL(machine_real_restart); @@ -172,6 +184,13 @@ #ifdef CONFIG_HAVE_DEC_LOCK EXPORT_SYMBOL(atomic_dec_and_lock); +#endif + +#ifdef CONFIG_X86_REMOTE_DEBUG +#include +EXPORT_SYMBOL(linux_debug_hook); +EXPORT_SYMBOL(gdb_irq); +EXPORT_SYMBOL(gdb_interrupt); #endif extern int is_sony_vaio_laptop; diff -Naur linux-2.4.20/arch/i386/kernel/i8259.c linux-2.4.20-rtai/arch/i386/kernel/i8259.c --- linux-2.4.20/arch/i386/kernel/i8259.c Tue Sep 18 08:03:09 2001 +++ linux-2.4.20-rtai/arch/i386/kernel/i8259.c Mon Dec 2 16:11:55 2002 @@ -290,12 +290,12 @@ handle_real_irq: if (irq & 8) { - inb(0xA1); /* DUMMY - (do we need this?) */ +// inb(0xA1); /* DUMMY - (do we need this?) */ outb(cached_A1,0xA1); outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */ outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ } else { - inb(0x21); /* DUMMY - (do we need this?) */ +// inb(0x21); /* DUMMY - (do we need this?) */ outb(cached_21,0x21); outb(0x60+irq,0x20); /* 'Specific EOI' to master */ } @@ -508,3 +508,17 @@ if (boot_cpu_data.hard_math && !cpu_has_fpu) setup_irq(13, &irq13); } + +void ack_8259_irq(unsigned int irq) +{ + spin_lock(&i8259A_lock); + if (irq & 8) { + outb(0x62,0x20); + outb(0x20,0xA0); + } else { + outb(0x20,0x20); + } + spin_unlock(&i8259A_lock); + return; +} + diff -Naur linux-2.4.20/arch/i386/kernel/io_apic.c linux-2.4.20-rtai/arch/i386/kernel/io_apic.c --- linux-2.4.20/arch/i386/kernel/io_apic.c Fri Nov 29 19:01:34 2002 +++ linux-2.4.20-rtai/arch/i386/kernel/io_apic.c Mon Dec 2 16:11:55 2002 @@ -38,7 +38,7 @@ #undef APIC_LOCKUP_DEBUG -#define APIC_LOCKUP_DEBUG +//#define APIC_LOCKUP_DEBUG static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; @@ -1282,11 +1282,10 @@ #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq +static unsigned long strange_level; + static void end_level_ioapic_irq (unsigned int irq) { - unsigned long v; - int i; - /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1306,12 +1305,8 @@ * operation to prevent an edge-triggered interrupt escaping meanwhile. * The idea is from Manfred Spraul. --macro */ - i = IO_APIC_VECTOR(irq); - v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); - - ack_APIC_irq(); - if (!(v & (1 << (i & 0x1f)))) { + if (test_and_clear_bit(irq, &strange_level)) { #ifdef APIC_LOCKUP_DEBUG struct irq_pin_list *entry; #endif @@ -1320,7 +1315,6 @@ atomic_inc(&irq_mis_count); #endif spin_lock(&ioapic_lock); - __mask_and_edge_IO_APIC_irq(irq); #ifdef APIC_LOCKUP_DEBUG for (entry = irq_2_pin + irq;;) { unsigned int reg; @@ -1338,10 +1332,30 @@ #endif __unmask_and_level_IO_APIC_irq(irq); spin_unlock(&ioapic_lock); + } else { + spin_lock(&ioapic_lock); + __unmask_IO_APIC_irq(irq); + spin_unlock(&ioapic_lock); } } -static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } +static void mask_and_ack_level_ioapic_irq (unsigned int irq) +{ + unsigned long i; + + i = IO_APIC_VECTOR(irq); + if (!(apic_read(APIC_TMR + ((i & ~0x1f) >> 1)) & (1 << (i & 0x1f)))) { + test_and_set_bit(irq, &strange_level); + spin_lock(&ioapic_lock); + __mask_and_edge_IO_APIC_irq(irq); + spin_unlock(&ioapic_lock); + } else { + spin_lock(&ioapic_lock); + __mask_IO_APIC_irq(irq); + spin_unlock(&ioapic_lock); + } + ack_APIC_irq(); +} #ifndef CONFIG_SMP diff -Naur linux-2.4.20/arch/i386/kernel/irq.c linux-2.4.20-rtai/arch/i386/kernel/irq.c --- linux-2.4.20/arch/i386/kernel/irq.c Fri Nov 29 19:01:34 2002 +++ linux-2.4.20-rtai/arch/i386/kernel/irq.c Mon Dec 2 16:11:55 2002 @@ -1212,3 +1212,71 @@ register_irq_proc(i); } +static void linux_cli(void) +{ + hard_cli(); +} + +static void linux_sti(void) +{ + hard_sti(); +} + +static unsigned int linux_save_flags(void) +{ + int flags; + hard_save_flags(flags); + return flags; +} + +static void linux_restore_flags(unsigned int flags) +{ + hard_restore_flags(flags); +} + +static unsigned int linux_save_flags_and_cli(void) +{ + int flags; + hard_save_flags_and_cli(flags); + return flags; +} + +#include + +#ifndef CONFIG_X86_IO_APIC +int irq_vector[]; +#endif +#ifndef CONFIG_SMP +void smp_invalidate_interrupt(void) { } +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +static volatile int physical_apicid_2_cpu[1]; +#endif + +extern void *ret_from_intr; +extern struct desc_struct idt_table[]; +extern void ack_8259_irq(unsigned int); +extern int idle_weight; +extern void smp_invalidate_interrupt(void); +extern void switch_mem(struct task_struct *, struct task_struct *, int); +extern volatile int physical_apicid_2_cpu[]; + +struct rt_hal rthal = { + ret_from_intr: &ret_from_intr, + __switch_to: __switch_to, + idt_table: idt_table, + disint: linux_cli, + enint: linux_sti, + getflags: linux_save_flags, + setflags: linux_restore_flags, + getflags_and_cli: linux_save_flags_and_cli, + irq_desc: irq_desc, + irq_vector: irq_vector, + irq_affinity: irq_affinity, + smp_invalidate_interrupt: smp_invalidate_interrupt, + ack_8259_irq: ack_8259_irq, + idle_weight: &idle_weight, + lxrt_global_cli: NULL, + switch_mem: switch_mem, + init_tasks: init_tasks, + apicmap: physical_apicid_2_cpu, +}; diff -Naur linux-2.4.20/arch/i386/kernel/smp.c linux-2.4.20-rtai/arch/i386/kernel/smp.c --- linux-2.4.20/arch/i386/kernel/smp.c Fri Nov 29 19:01:34 2002 +++ linux-2.4.20-rtai/arch/i386/kernel/smp.c Mon Dec 2 16:11:55 2002 @@ -160,8 +160,7 @@ unsigned long cfg; unsigned long flags; - __save_flags(flags); - __cli(); + hard_save_flags_and_cli(flags); /* @@ -185,7 +184,7 @@ */ apic_write_around(APIC_ICR, cfg); - __restore_flags(flags); + hard_restore_flags(flags); } static inline void send_IPI_mask_sequence(int mask, int vector) diff -Naur linux-2.4.20/arch/i386/kernel/time.c linux-2.4.20-rtai/arch/i386/kernel/time.c --- linux-2.4.20/arch/i386/kernel/time.c Fri Nov 29 19:01:34 2002 +++ linux-2.4.20-rtai/arch/i386/kernel/time.c Mon Dec 2 16:11:55 2002 @@ -673,6 +673,7 @@ rdtscl(last_tsc_low); +#if 0 spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -704,6 +705,7 @@ count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; +#endif } do_timer_interrupt(irq, NULL, regs); diff -Naur linux-2.4.20/arch/i386/mm/fault.c linux-2.4.20-rtai/arch/i386/mm/fault.c --- linux-2.4.20/arch/i386/mm/fault.c Fri Nov 29 19:01:34 2002 +++ linux-2.4.20-rtai/arch/i386/mm/fault.c Mon Dec 2 16:11:55 2002 @@ -153,7 +153,7 @@ /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & X86_EFLAGS_IF) - local_irq_enable(); + hard_sti(); tsk = current; diff -Naur linux-2.4.20/arch/i386/mm/ioremap.c linux-2.4.20-rtai/arch/i386/mm/ioremap.c --- linux-2.4.20/arch/i386/mm/ioremap.c Sat Aug 3 02:39:42 2002 +++ linux-2.4.20-rtai/arch/i386/mm/ioremap.c Mon Dec 2 16:11:55 2002 @@ -81,6 +81,7 @@ if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) break; + set_pgdir(address, *dir); error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; diff -Naur linux-2.4.20/arch/ppc/config.in linux-2.4.20-rtai/arch/ppc/config.in --- linux-2.4.20/arch/ppc/config.in Fri Nov 29 19:01:45 2002 +++ linux-2.4.20-rtai/arch/ppc/config.in Mon Dec 2 16:11:55 2002 @@ -125,6 +125,9 @@ bool ' Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS fi +#bool 'Real-Time Hardware Abstraction Layer' CONFIG_RTHAL +define_bool CONFIG_RTHAL y + if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then bool 'AltiVec Support' CONFIG_ALTIVEC bool 'Thermal Management Support' CONFIG_TAU diff -Naur linux-2.4.20/arch/ppc/kernel/entry.S linux-2.4.20-rtai/arch/ppc/kernel/entry.S --- linux-2.4.20/arch/ppc/kernel/entry.S Fri Nov 29 19:01:45 2002 +++ linux-2.4.20-rtai/arch/ppc/kernel/entry.S Mon Dec 2 16:11:55 2002 @@ -291,6 +291,7 @@ bl do_signal .globl do_signal_ret do_signal_ret: + bl do_soft_sti .globl ret_to_user_hook ret_to_user_hook: nop diff -Naur linux-2.4.20/arch/ppc/kernel/irq.c linux-2.4.20-rtai/arch/ppc/kernel/irq.c --- linux-2.4.20/arch/ppc/kernel/irq.c Fri Nov 29 19:01:45 2002 +++ linux-2.4.20-rtai/arch/ppc/kernel/irq.c Mon Dec 2 16:11:55 2002 @@ -510,6 +510,17 @@ spin_unlock(&desc->lock); } +void do_soft_cli(void) +{ +} + +void (*rtai_soft_sti)(void); + +void do_soft_sti(void) +{ + if(rtai_soft_sti)rtai_soft_sti(); +} + int do_IRQ(struct pt_regs *regs) { int cpu = smp_processor_id(); diff -Naur linux-2.4.20/arch/ppc/kernel/traps.c linux-2.4.20-rtai/arch/ppc/kernel/traps.c --- linux-2.4.20/arch/ppc/kernel/traps.c Sat Nov 3 02:43:54 2001 +++ linux-2.4.20-rtai/arch/ppc/kernel/traps.c Mon Dec 2 16:11:55 2002 @@ -320,9 +320,15 @@ return retval; } +int (*rtai_srq_bckdr)(struct pt_regs *regs) = NULL; + void ProgramCheckException(struct pt_regs *regs) { + if (rtai_srq_bckdr && !rtai_srq_bckdr(regs)) { + return; + } +{ unsigned int reason = get_reason(regs); extern int do_mathemu(struct pt_regs *regs); @@ -378,6 +384,7 @@ } _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); +} } void diff -Naur linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c linux-2.4.20-rtai/arch/ppc/kernel/ppc_ksyms.c --- linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c Fri Nov 29 19:01:46 2002 +++ linux-2.4.20-rtai/arch/ppc/kernel/ppc_ksyms.c Mon Dec 2 16:11:55 2002 @@ -220,6 +220,12 @@ EXPORT_SYMBOL(synchronize_irq); #endif +extern int (*rtai_srq_bckdr)(struct pt_regs *); +EXPORT_SYMBOL(rtai_srq_bckdr); + +extern void (*rtai_soft_sti)(void); +EXPORT_SYMBOL(rtai_soft_sti); + EXPORT_SYMBOL(ppc_md); #ifdef CONFIG_ADB diff -Naur linux-2.4.20/include/asm-i386/hw_irq.h linux-2.4.20-rtai/include/asm-i386/hw_irq.h --- linux-2.4.20/include/asm-i386/hw_irq.h Thu Nov 22 20:46:18 2001 +++ linux-2.4.20-rtai/include/asm-i386/hw_irq.h Mon Dec 2 16:16:00 2002 @@ -37,18 +37,31 @@ * * Vectors 0xf0-0xfa are free (reserved for future Linux use). */ +#ifdef CONFIG_RTHAL +/* the standard definitions conflict with LXRT */ +#define SPURIOUS_APIC_VECTOR 0xdf +#define ERROR_APIC_VECTOR 0xde +#define INVALIDATE_TLB_VECTOR 0xdd +#define RESCHEDULE_VECTOR 0xdc +#define CALL_FUNCTION_VECTOR 0xdb +#else #define SPURIOUS_APIC_VECTOR 0xff #define ERROR_APIC_VECTOR 0xfe #define INVALIDATE_TLB_VECTOR 0xfd #define RESCHEDULE_VECTOR 0xfc #define CALL_FUNCTION_VECTOR 0xfb +#endif /* * Local APIC timer IRQ vector is on a different priority level, * to work around the 'lost local interrupt if more than 2 IRQ * sources per level' errata. */ +#ifdef CONFIG_RTHAL +#define LOCAL_TIMER_VECTOR 0xcf +#else #define LOCAL_TIMER_VECTOR 0xef +#endif /* * First APIC vector available to drivers: (vectors 0x30-0xee) @@ -56,7 +69,11 @@ * levels. (0x80 is the syscall vector) */ #define FIRST_DEVICE_VECTOR 0x31 +#ifdef CONFIG_RTHAL +#define FIRST_SYSTEM_VECTOR 0xcf +#else #define FIRST_SYSTEM_VECTOR 0xef +#endif extern int irq_vector[NR_IRQS]; #define IO_APIC_VECTOR(irq) irq_vector[irq] diff -Naur linux-2.4.20/include/asm-i386/irq.h linux-2.4.20-rtai/include/asm-i386/irq.h --- linux-2.4.20/include/asm-i386/irq.h Sat Aug 3 02:39:45 2002 +++ linux-2.4.20-rtai/include/asm-i386/irq.h Mon Dec 2 16:11:55 2002 @@ -26,7 +26,7 @@ #ifdef CONFIG_X86_IO_APIC #define NR_IRQS 224 #else -#define NR_IRQS 16 +#define NR_IRQS 32 /* 2.4.19 vanilla has 16, this is rtai back compatibility */ #endif static __inline__ int irq_cannonicalize(int irq) diff -Naur linux-2.4.20/include/asm-i386/pgalloc.h linux-2.4.20-rtai/include/asm-i386/pgalloc.h --- linux-2.4.20/include/asm-i386/pgalloc.h Sat Aug 3 02:39:45 2002 +++ linux-2.4.20-rtai/include/asm-i386/pgalloc.h Mon Dec 2 16:16:00 2002 @@ -158,6 +158,33 @@ extern int do_check_pgt_cache(int, int); +extern inline void set_pgdir(unsigned long address, pgd_t entry) +{ + struct task_struct * p; + pgd_t *pgd; +#ifdef CONFIG_SMP + int i; +#endif + + read_lock(&tasklist_lock); + for_each_task(p) { + if (!p->mm) + continue; + *pgd_offset(p->mm,address) = entry; + } + read_unlock(&tasklist_lock); +#ifndef CONFIG_SMP + for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; +#else + /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can + modify pgd caches of other CPUs as well. -jj */ + for (i = 0; i < NR_CPUS; i++) + for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; +#endif +} + /* * TLB flushing: * diff -Naur linux-2.4.20/include/asm-i386/system.h linux-2.4.20-rtai/include/asm-i386/system.h --- linux-2.4.20/include/asm-i386/system.h Fri Nov 29 19:02:50 2002 +++ linux-2.4.20-rtai/include/asm-i386/system.h Mon Dec 2 16:16:00 2002 @@ -12,7 +12,12 @@ struct task_struct; /* one of the stranger aspects of C forward declarations.. */ extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); -#define prepare_to_switch() do { } while(0) +#define prepare_to_switch() do { \ + if (rthal.lxrt_global_cli) { \ + rthal.lxrt_global_cli(); \ + } \ +} while(0) + #define switch_to(prev,next,last) do { \ asm volatile("pushl %%esi\n\t" \ "pushl %%edi\n\t" \ @@ -23,6 +28,7 @@ "pushl %4\n\t" /* restore EIP */ \ "jmp __switch_to\n" \ "1:\t" \ + "sti\n\t" \ "popl %%ebp\n\t" \ "popl %%edi\n\t" \ "popl %%esi\n\t" \ @@ -315,29 +321,59 @@ #define set_wmb(var, value) do { var = value; wmb(); } while (0) +struct rt_hal { + void *ret_from_intr; + void *__switch_to; + struct desc_struct *idt_table; + void (*disint)(void); + void (*enint)(void); + unsigned int (*getflags)(void); + void (*setflags)(unsigned int flags); + unsigned int (*getflags_and_cli)(void); + void *irq_desc; + int *irq_vector; + unsigned long *irq_affinity; + void (*smp_invalidate_interrupt)(void); + void (*ack_8259_irq)(unsigned int); + int *idle_weight; + void (*lxrt_global_cli)(void); + void (*switch_mem)(struct task_struct *, struct task_struct *, int); + struct task_struct **init_tasks; + unsigned int *apicmap; +}; + +extern struct rt_hal rthal; + /* interrupt control.. */ -#define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) -#define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") -#define __cli() __asm__ __volatile__("cli": : :"memory") -#define __sti() __asm__ __volatile__("sti": : :"memory") -/* used in the idle loop; sti takes one instruction cycle to complete */ -#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory") +#define hard_save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) +#define hard_restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") +#define hard_cli() __asm__ __volatile__("cli": : :"memory") +#define hard_sti() __asm__ __volatile__("sti": : :"memory") +#define hard_save_flags_and_cli(x) __asm__ __volatile__("pushfl; popl %0; cli":"=g" (x): /* no input */) + +#define __cli() do { rthal.disint(); } while (0) +#define __sti() do { rthal.enint(); } while (0) +#define __save_flags(x) do { x = rthal.getflags(); } while (0) +#define __restore_flags(x) do { rthal.setflags(x); } while (0) + +#define __save_and_cli(x) do { x = rthal.getflags_and_cli(); } while (0) +#define __save_and_sti(x) do { x = rthal.getflags(); rthal.enint(); } while (0) -#define __save_and_cli(x) do { __save_flags(x); __cli(); } while(0); -#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0); +/* used in the idle loop; sti takes one instruction cycle to complete */ +#define safe_halt() __asm__ __volatile__("call *"SYMBOL_NAME_STR(rthal + 16)"; hlt": : :"memory") /* For spinlocks etc */ #if 0 #define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") #define local_irq_set(x) __asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory") #else -#define local_irq_save(x) __save_and_cli(x) -#define local_irq_set(x) __save_and_sti(x) +#define local_irq_save(x) do { x = rthal.getflags_and_cli(); } while (0) +#define local_irq_set(x) do { x = rthal.getflags(); rthal.enint(); } while (0) #endif -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() +#define local_irq_restore(x) do { rthal.setflags(x); } while (0) +#define local_irq_disable() do { rthal.disint(); } while (0) +#define local_irq_enable() do { rthal.enint(); } while (0) #ifdef CONFIG_SMP diff -Naur linux-2.4.20/include/asm-ppc/system.h linux-2.4.20-rtai/include/asm-ppc/system.h --- linux-2.4.20/include/asm-ppc/system.h Sat Aug 3 02:39:45 2002 +++ linux-2.4.20-rtai/include/asm-ppc/system.h Mon Dec 2 16:11:55 2002 @@ -82,6 +82,7 @@ struct task_struct; #define prepare_to_switch() do { } while(0) +#define end_switch() do { } while(0) #define switch_to(prev,next,last) _switch_to((prev),(next),&(last)) extern void _switch_to(struct task_struct *, struct task_struct *, struct task_struct **); diff -Naur linux-2.4.20/include/linux/sched.h linux-2.4.20-rtai/include/linux/sched.h --- linux-2.4.20/include/linux/sched.h Fri Nov 29 19:03:06 2002 +++ linux-2.4.20-rtai/include/linux/sched.h Mon Dec 2 16:16:00 2002 @@ -415,6 +415,8 @@ /* journalling filesystem info */ void *journal_info; + + void *this_rt_task[2]; }; /* @@ -509,6 +511,7 @@ blocked: {{0}}, \ alloc_lock: SPIN_LOCK_UNLOCKED, \ journal_info: NULL, \ + this_rt_task: {0,0}, \ } diff -Naur linux-2.4.20/kernel/exit.c linux-2.4.20-rtai/kernel/exit.c --- linux-2.4.20/kernel/exit.c Fri Nov 29 19:03:07 2002 +++ linux-2.4.20-rtai/kernel/exit.c Mon Dec 2 16:11:55 2002 @@ -422,6 +422,71 @@ write_unlock_irq(&tasklist_lock); } +// +// PGGC added these lines to callback rtai when a task dies. +// A list of functions allows different rt_modules to be informed. +// +static struct t_callback { + void (*rtai_callback)(struct task_struct *tsk); + struct t_callback *next; + } *rtai_callback_list; + +extern int set_rtai_callback( void (*fun)(struct task_struct *tsk)); +extern void remove_rtai_callback( void (*fun)(struct task_struct *tsk)); + +void inform_rtai(void) +{ + struct t_callback *pt; + + pt = rtai_callback_list; + while (pt) { + (*(pt->rtai_callback))(current); + pt = pt->next; + } +//printk( "Task pid %d going down\n", current->pid); +} + +int set_rtai_callback( void (*pt)(struct task_struct *tsk)) +{ + struct t_callback *ptn; + + ptn = kmalloc(sizeof(struct t_callback), GFP_KERNEL); + if (!ptn) { + return -ENOMEM; + } + ptn->rtai_callback = pt; + ptn->next = rtai_callback_list ? rtai_callback_list : 0; + rtai_callback_list = ptn; + return 0; +} + +void remove_rtai_callback(void (*pt)(struct task_struct *tsk)) +{ + struct t_callback *pto, *ptoo, *ptd; + + pto = rtai_callback_list; + ptoo = 0; + while (pto) { + if (pto->rtai_callback == pt) { + if (!ptoo) { + rtai_callback_list = pto->next; + } else { + ptoo->next = pto->next; + } + ptd = pto; + pto = pto->next; + kfree(ptd); + } else { + ptoo = pto; + pto = pto->next; + } + } +//printk("rtai_callback_list %X\n", rtai_callback_list); +} +// +// +// + NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; @@ -439,6 +504,18 @@ #ifdef CONFIG_BSD_PROCESS_ACCT acct_process(code); #endif + +/* + * PGGC added these lines to callback rtai when a task dies. + * This assumes that a LXRT task should/will always set its + * scheduling police to SCHED_FIFO or SCHED_RR. + * We may want to enforce this in rt_task_init(...). + * (For the moment it is not so, thus let's inform LXRT anyhow (Paolo)) + */ + if(tsk->this_rt_task[0]) { + inform_rtai(); + } + __exit_mm(tsk); lock_kernel(); diff -Naur linux-2.4.20/kernel/fork.c linux-2.4.20-rtai/kernel/fork.c --- linux-2.4.20/kernel/fork.c Fri Nov 29 19:03:07 2002 +++ linux-2.4.20-rtai/kernel/fork.c Mon Dec 2 16:11:55 2002 @@ -233,7 +233,9 @@ atomic_set(&mm->mm_count, 1); init_rwsem(&mm->mmap_sem); mm->page_table_lock = SPIN_LOCK_UNLOCKED; + lock_kernel(); mm->pgd = pgd_alloc(mm); + unlock_kernel(); mm->def_flags = 0; if (mm->pgd) return mm; @@ -265,7 +267,9 @@ inline void __mmdrop(struct mm_struct *mm) { BUG_ON(mm == &init_mm); + lock_kernel(); pgd_free(mm->pgd); + unlock_kernel(); check_pgt_cache(); destroy_context(mm); free_mm(mm); diff -Naur linux-2.4.20/kernel/ksyms.c linux-2.4.20-rtai/kernel/ksyms.c --- linux-2.4.20/kernel/ksyms.c Fri Nov 29 19:03:07 2002 +++ linux-2.4.20-rtai/kernel/ksyms.c Mon Dec 2 16:11:55 2002 @@ -600,3 +600,44 @@ /* To match ksyms with System.map */ extern const char _end[]; EXPORT_SYMBOL(_end); + +/* + * used to inform rtai a task is about to die. + */ +extern int set_rtai_callback( void (*fun)(struct task_struct *tsk)); +extern void remove_rtai_callback(void (*fun)(struct task_struct *tsk)); +extern NORET_TYPE void do_exit(long code); +EXPORT_SYMBOL(set_rtai_callback); +EXPORT_SYMBOL(remove_rtai_callback); +EXPORT_SYMBOL(do_exit); + +/* + * used to inform RTAI LXRT a task should deal with a Linux signal, and for rt_lxrt_fork() + */ +extern int (*rtai_signal_handler)(struct task_struct *lnxt, int sig); +EXPORT_SYMBOL(rtai_signal_handler); +extern int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size); +EXPORT_SYMBOL(do_fork); + +/* + * used to provide async io support (aio) to RTAI LXRT. + */ +extern ssize_t sys_read(unsigned int fd, char * buf, size_t count); +extern ssize_t sys_write(unsigned int fd, const char * buf, size_t count); +extern ssize_t sys_pread(unsigned int fd, char * buf, + size_t count, loff_t pos); +extern ssize_t sys_pwrite(unsigned int fd, const char * buf, + size_t count, loff_t pos); +extern long sys_fsync(unsigned int fd); +extern long sys_fdatasync(unsigned int fd); +extern long sys_open(const char * filename, int flags, int mode); +extern long sys_close(unsigned int fd); + +EXPORT_SYMBOL(sys_read); +EXPORT_SYMBOL(sys_write); +EXPORT_SYMBOL(sys_open); +//EXPORT_SYMBOL(sys_close); +EXPORT_SYMBOL(sys_pread); +EXPORT_SYMBOL(sys_pwrite); +EXPORT_SYMBOL(sys_fsync); +EXPORT_SYMBOL(sys_fdatasync); diff -Naur linux-2.4.20/kernel/sched.c linux-2.4.20-rtai/kernel/sched.c --- linux-2.4.20/kernel/sched.c Fri Nov 29 19:03:07 2002 +++ linux-2.4.20-rtai/kernel/sched.c Mon Dec 2 16:11:55 2002 @@ -544,6 +544,43 @@ * tasks can run. It can not be killed, and it cannot sleep. The 'state' * information in task[0] is never used. */ + +int idle_weight = -1000; +#define MAX_MM 1024 // How large should it be? +static struct smm_t { int in, out; struct mm_struct *mm[MAX_MM]; } smm[NR_CPUS]; +#define incpnd(x) do { x = (x + 1) & (MAX_MM - 1); } while(0) + +static inline void pend_mm(struct mm_struct *mm, int cpu) +{ + if (rthal.lxrt_global_cli) { + struct smm_t *p = smm + cpu; + p->mm[p->in] = mm; + incpnd(p->in); + } else { + mmdrop(mm); + } +} + +static inline void drop_mm(void) +{ + if (rthal.lxrt_global_cli) { + struct smm_t *p = smm + smp_processor_id(); + while (p->out != p->in) { + mmdrop(p->mm[p->out]); + incpnd(p->out); + } + } +} + +void switch_mem(struct task_struct *prevp, struct task_struct *nextp, int cpuid) +{ + struct mm_struct *oldmm = prevp->active_mm; + switch_mm(oldmm, nextp->active_mm, nextp, cpuid & 0x0FFFFFFF); + if (!nextp->mm) { + enter_lazy_tlb(oldmm, nextp, cpuid & 0x0FFFFFFF); + } +} + asmlinkage void schedule(void) { struct schedule_data * sched_data; @@ -602,7 +639,7 @@ * Default process to select.. */ next = idle_task(this_cpu); - c = -1000; + c = idle_weight; list_for_each(tmp, &runqueue_head) { p = list_entry(tmp, struct task_struct, run_list); if (can_schedule(p, this_cpu)) { @@ -684,7 +721,7 @@ if (!prev->mm) { prev->active_mm = NULL; - mmdrop(oldmm); + pend_mm(oldmm, this_cpu); } } @@ -693,6 +730,7 @@ * stack. */ switch_to(prev, next, prev); + drop_mm(); __schedule_tail(prev); same_process: diff -Naur linux-2.4.20/kernel/signal.c linux-2.4.20-rtai/kernel/signal.c --- linux-2.4.20/kernel/signal.c Fri Nov 29 19:03:07 2002 +++ linux-2.4.20-rtai/kernel/signal.c Mon Dec 2 16:11:55 2002 @@ -1010,9 +1010,30 @@ return ret; } +// +// Add this pointer to the RTAI signal handler. +// +int (*rtai_signal_handler)(struct task_struct *lnxt, int sig); + asmlinkage long sys_kill(int pid, int sig) { +// Add this section to call the RTAI signal handler. +// + { + struct task_struct *p; + int ret; + + if (rtai_signal_handler) { + p = find_task_by_pid(pid); + if(p && (p->policy == SCHED_FIFO || p->policy == SCHED_RR) && p->this_rt_task[0]) { + ret = rtai_signal_handler(p, sig); + if(!ret) return 0; //let Linux deal with it. + } + } + } + + { struct siginfo info; info.si_signo = sig; @@ -1022,6 +1043,7 @@ info.si_uid = current->uid; return kill_something_info(sig, &info, pid); + } } /* diff -Naur linux-2.4.20/mm/vmalloc.c linux-2.4.20-rtai/mm/vmalloc.c --- linux-2.4.20/mm/vmalloc.c Fri Nov 29 19:03:09 2002 +++ linux-2.4.20-rtai/mm/vmalloc.c Mon Dec 2 16:11:55 2002 @@ -166,6 +166,9 @@ spin_lock(&init_mm.page_table_lock); do { pmd_t *pmd; +#ifdef CONFIG_X86 + pgd_t olddir = *dir; +#endif pmd = pmd_alloc(&init_mm, dir, address); ret = -ENOMEM; @@ -175,6 +178,10 @@ ret = -ENOMEM; if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot, pages)) break; +#ifdef CONFIG_X86 + if (pgd_val(olddir) != pgd_val(*dir)) + set_pgdir(address, *dir); +#endif address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++;