From mboxrd@z Thu Jan 1 00:00:00 1970 Subject: Re: [Xenomai-core] Xenomai on PXA From: Bart Jonkers In-Reply-To: <17595.49478.157044.654500@domain.hid> References: <200607071703.10700.vagninu@domain.hid> <17582.50372.830923.414981@domain.hid> <44B34343.9F56F13@domain.hid> <17595.47131.142881.132531@domain.hid> <1153153788.11603.2.camel@domain.hid> <17595.49478.157044.654500@domain.hid> Content-Type: text/plain Date: Mon, 31 Jul 2006 10:34:19 +0200 Message-Id: <1154334859.9569.12.camel@domain.hid> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit List-Id: "Xenomai life and development \(bug reports, patches, discussions\)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Gilles Chanteperdrix Cc: xenomai@xenomai.org On Mon, 2006-07-17 at 18:56 +0200, Gilles Chanteperdrix wrote: > Philippe Gerum wrote: > > On Mon, 2006-07-17 at 18:17 +0200, Gilles Chanteperdrix wrote: > > > replaced PSR_I_BIT with its value. I now wonder if it is the proper fix, > > > or if __xchg should be fixed to use local_irq_save_hw and > > > local_irq_restore_hw instead, as is the case for the atomic operations > > > defined in atomic.h and bitops.h. > > > > Definitely, it should be fixed to use hw masking ops. > > Attached a corrected patch for 2.6.16. Hey, I tried this patch together with your ipipe-sa1100-pxa patch on my pxa-255 based platform. There are two adaptions that I need to make in arch/arm/mach-pxa/time.c to compile the kernel properly: - include linux/module.h to remove warnings about EXPORT_SYMBOL - replace sa1100_timer_initialized with pxa_timer_initialized When I boot the kernel with ipipe enabled, linux receives no interrupts anymore. Any idea to solve this? thanks in advance, Bart > > plain text document attachment > (adeos-ipipe-2.6.16-arm-unofficial2.patch) > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/Kconfig linux-2.6.16.5-tcl1-ipipe/arch/arm/Kconfig > --- linux-2.6.16.5-tcl1/arch/arm/Kconfig 2006-07-15 20:06:02.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/Kconfig 2006-07-16 15:01:24.000000000 +0200 > @@ -401,6 +401,8 @@ config LOCAL_TIMERS > accounting to be spread across the timer interval, preventing a > "thundering herd" at every timer tick. > > +source "kernel/ipipe/Kconfig" > + > config PREEMPT > bool "Preemptible Kernel (EXPERIMENTAL)" > depends on EXPERIMENTAL > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/Makefile linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/Makefile > --- linux-2.6.16.5-tcl1/arch/arm/kernel/Makefile 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/Makefile 2006-07-16 15:19:02.000000000 +0200 > @@ -21,6 +21,7 @@ obj-$(CONFIG_ISA_DMA) += dma-isa.o > obj-$(CONFIG_PCI) += bios32.o > obj-$(CONFIG_SMP) += smp.o > obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o > +obj-$(CONFIG_IPIPE) += ipipe-core.o ipipe-root.o > > obj-$(CONFIG_IWMMXT) += iwmmxt.o > AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/entry-armv.S linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-armv.S > --- linux-2.6.16.5-tcl1/arch/arm/kernel/entry-armv.S 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-armv.S 2006-07-16 15:19:54.000000000 +0200 > @@ -4,6 +4,7 @@ > * Copyright (C) 1996,1997,1998 Russell King. > * ARM700 fix by Matthew Godbolt (linux-user@domain.hid) > * nommu support by Hyok S. Choi (hyok.choi@domain.hid) > + * Copyright (C) 2005 Stelian Pop. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License version 2 as > @@ -33,7 +34,11 @@ > @ routine called with r0 = irq number, r1 = struct pt_regs * > @ > adrne lr, 1b > +#ifdef CONFIG_IPIPE > + bne __ipipe_grab_irq > +#else > bne asm_do_IRQ > +#endif > > #ifdef CONFIG_SMP > /* > @@ -199,6 +204,11 @@ __irq_svc: > #endif > > irq_handler > +#ifdef CONFIG_IPIPE > + cmp r0, #0 > + beq __ipipe_fast_svc_irq_exit > +#endif > + > #ifdef CONFIG_PREEMPT > ldr r0, [tsk, #TI_FLAGS] @ get flags > tst r0, #_TIF_NEED_RESCHED > @@ -209,6 +219,9 @@ preempt_return: > teq r0, r7 > strne r0, [r0, -r0] @ bug() > #endif > +#ifdef CONFIG_IPIPE > +__ipipe_fast_svc_irq_exit: > +#endif > ldr r0, [sp, #S_PSR] @ irqs are already disabled > msr spsr_cxsf, r0 > ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr > @@ -237,6 +250,12 @@ svc_preempt: > __und_svc: > svc_entry > > +#ifdef CONFIG_IPIPE > + mov r1, sp @ r0 = trapno, r1 = ®s > + bl __ipipe_dispatch_event @ branch to trap handler > + cmp r0, #0 > + bne 1f > +#endif /* CONFIG_IPIPE */ > @ > @ call emulation code, which returns using r9 if it has emulated > @ the instruction, or the more conventional lr if we are to treat > @@ -406,6 +425,12 @@ __irq_usr: > #endif > > irq_handler > +#ifdef CONFIG_IPIPE > + cmp r0, #0 > + bne __ipipe_usr_irq_continue > + slow_restore_user_regs @ Fast exit path over non-root domains > +__ipipe_usr_irq_continue: > +#endif > #ifdef CONFIG_PREEMPT > ldr r0, [tsk, #TI_PREEMPT] > str r8, [tsk, #TI_PREEMPT] > @@ -499,8 +524,8 @@ call_fpe: > mov pc, lr @ CP#8 > mov pc, lr @ CP#9 > #ifdef CONFIG_VFP > - b do_vfp @ CP#10 (VFP) > - b do_vfp @ CP#11 (VFP) > + b _do_vfp @ CP#10 (VFP) > + b _do_vfp @ CP#11 (VFP) > #else > mov pc, lr @ CP#10 (VFP) > mov pc, lr @ CP#11 (VFP) > @@ -511,10 +536,34 @@ call_fpe: > mov pc, lr @ CP#15 (Control) > > do_fpe: > +#ifdef CONFIG_IPIPE > + mov r4, r0 > + mov r0, #5 @ == IPIPE_TRAP_FPU > + mov r1, sp @ r0 = trapno, r1 = ®s > + bl __ipipe_dispatch_event @ branch to trap handler > + cmp r0, #0 > + ldrne pc, [r9] > + mov r0, r4 > +#endif > ldr r4, .LCfp > add r10, r10, #TI_FPSTATE @ r10 = workspace > ldr pc, [r4] @ Call FP module USR entry point > > +#ifdef CONFIG_VFP > +_do_vfp: > +#ifdef CONFIG_IPIPE > + mov r4, r0 > + mov r0, #6 @ == IPIPE_TRAP_VFP > + mov r1, sp @ r0 = trapno, r1 = ®s > + bl __ipipe_dispatch_event @ branch to trap handler > + cmp r0, #0 > + ldrne pc, [r9] > + mov r0, r4 > +#endif > + b do_vfp > +#endif > + > + > /* > * The FP module is called with these registers set: > * r0 = instruction > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/entry-common.S linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-common.S > --- linux-2.6.16.5-tcl1/arch/arm/kernel/entry-common.S 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-common.S 2006-07-16 16:15:08.000000000 +0200 > @@ -2,6 +2,7 @@ > * linux/arch/arm/kernel/entry-common.S > * > * Copyright (C) 2000 Russell King > + * Copyright (C) 2005 Stelian Pop. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License version 2 as > @@ -20,13 +21,18 @@ > * possible here, and this includes saving r0 back into the SVC > * stack. > */ > +#ifdef CONFIG_IPIPE > +__ipipe_ret_fast_syscall: > + ldr r0, [sp, #S_R0+S_OFF] @ returned r0 > + /* fall through */ > +#endif > ret_fast_syscall: > disable_irq @ disable interrupts > ldr r1, [tsk, #TI_FLAGS] > tst r1, #_TIF_WORK_MASK > bne fast_work_pending > > - @ fast_restore_user_regs > +fast_restore_user_regs: > ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr > ldr lr, [sp, #S_OFF + S_PC]! @ get pc > msr spsr_cxsf, r1 @ save in spsr_svc > @@ -35,6 +41,13 @@ ret_fast_syscall: > add sp, sp, #S_FRAME_SIZE - S_PC > movs pc, lr @ return & move spsr_svc into cpsr > > +#ifdef CONFIG_IPIPE > +__ipipe_fast_exit_syscall: > + ldr r0, [sp, #S_R0+S_OFF] @ returned r0 > + disable_irq @ disable interrupts > + b fast_restore_user_regs > +#endif /* CONFIG_IPIPE */ > + > /* > * Ok, we need to do extra processing, enter the slow path. > */ > @@ -62,19 +75,15 @@ ret_slow_syscall: > tst r1, #_TIF_WORK_MASK > bne work_pending > no_work_pending: > - @ slow_restore_user_regs > - ldr r1, [sp, #S_PSR] @ get calling cpsr > - ldr lr, [sp, #S_PC]! @ get pc > - msr spsr_cxsf, r1 @ save in spsr_svc > - ldmdb sp, {r0 - lr}^ @ get calling r1 - lr > - mov r0, r0 > - add sp, sp, #S_FRAME_SIZE - S_PC > - movs pc, lr @ return & move spsr_svc into cpsr > + slow_restore_user_regs > > /* > * This is how we return from a fork. > */ > ENTRY(ret_from_fork) > +#ifdef CONFIG_IPIPE > + enable_irq > +#endif /* CONFIG_IPIPE */ > bl schedule_tail > get_thread_info tsk > ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing > @@ -197,8 +206,18 @@ ENTRY(vector_swi) > bic scno, scno, #0xff000000 @ mask off SWI op-code > eor scno, scno, #__NR_SYSCALL_BASE @ check OS number > #endif > - > stmdb sp!, {r4, r5} @ push fifth and sixth args > +#ifdef CONFIG_IPIPE > + stmfd sp!, {r0-r3, ip} > + add r1, sp, #S_OFF > + add r1, r1, #20 > + mov r0, scno > + bl __ipipe_syscall_root > + cmp r0, #0 > + ldmfd sp!, {r0-r3, ip} > + blt __ipipe_ret_fast_syscall > + bgt __ipipe_fast_exit_syscall > +#endif /* CONFIG_IPIPE */ > tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? > bne __sys_trace > > @@ -245,6 +264,9 @@ __sys_trace_return: > __cr_alignment: > .word cr_alignment > #endif > +#ifdef CONFIG_IPIPE > + .word __ipipe_syscall_root > +#endif > .ltorg > > /* > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/entry-header.S linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-header.S > --- linux-2.6.16.5-tcl1/arch/arm/kernel/entry-header.S 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-header.S 2006-07-16 15:01:24.000000000 +0200 > @@ -68,6 +68,15 @@ > #endif > .endm > > + .macro slow_restore_user_regs > + ldr r1, [sp, #S_PSR] @ get calling cpsr > + ldr lr, [sp, #S_PC]! @ get pc > + msr spsr_cxsf, r1 @ save in spsr_svc > + ldmdb sp, {r0 - lr}^ @ get calling r1 - lr > + mov r0, r0 > + add sp, sp, #S_FRAME_SIZE - S_PC > + movs pc, lr @ return & move spsr_svc into cpsr > + .endm > > /* > * These are the registers used in the syscall handler, and allow us to > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/ipipe-core.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ipipe-core.c > --- linux-2.6.16.5-tcl1/arch/arm/kernel/ipipe-core.c 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ipipe-core.c 2006-07-16 15:01:24.000000000 +0200 > @@ -0,0 +1,239 @@ > +/* -*- linux-c -*- > + * linux/arch/arm/kernel/ipipe-core.c > + * > + * Copyright (C) 2002-2005 Philippe Gerum. > + * Copyright (C) 2004 Wolfgang Grandegger (Adeos/arm port over 2.4). > + * Copyright (C) 2005 Heikki Lindholm (PowerPC 970 fixes). > + * Copyright (C) 2005 Stelian Pop. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, > + * USA; either version 2 of the License, or (at your option) any later > + * version. > + * > + * 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. > + * > + * Architecture-dependent I-PIPE core support for ARM. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* Current reload value for the decrementer. */ > +unsigned long __ipipe_decr_ticks; > + > +/* Next tick date (timebase value). */ > +unsigned long long __ipipe_decr_next[IPIPE_NR_CPUS]; > + > +struct pt_regs __ipipe_tick_regs[IPIPE_NR_CPUS]; > + > +#ifdef CONFIG_SMP > + > +static cpumask_t __ipipe_cpu_sync_map; > + > +static cpumask_t __ipipe_cpu_lock_map; > + > +static ipipe_spinlock_t __ipipe_cpu_barrier = IPIPE_SPIN_LOCK_UNLOCKED; > + > +static atomic_t __ipipe_critical_count = ATOMIC_INIT(0); > + > +static void (*__ipipe_cpu_sync) (void); > + > +/* Always called with hw interrupts off. */ > + > +void __ipipe_do_critical_sync(unsigned irq) > +{ > + ipipe_declare_cpuid; > + > + ipipe_load_cpuid(); > + > + cpu_set(cpuid, __ipipe_cpu_sync_map); > + > + /* > + * Now we are in sync with the lock requestor running on another > + * CPU. Enter a spinning wait until he releases the global > + * lock. > + */ > + spin_lock_hw(&__ipipe_cpu_barrier); > + > + /* Got it. Now get out. */ > + > + if (__ipipe_cpu_sync) > + /* Call the sync routine if any. */ > + __ipipe_cpu_sync(); > + > + spin_unlock_hw(&__ipipe_cpu_barrier); > + > + cpu_clear(cpuid, __ipipe_cpu_sync_map); > +} > + > +#endif /* CONFIG_SMP */ > + > +/* > + * ipipe_critical_enter() -- Grab the superlock excluding all CPUs > + * but the current one from a critical section. This lock is used when > + * we must enforce a global critical section for a single CPU in a > + * possibly SMP system whichever context the CPUs are running. > + */ > +unsigned long ipipe_critical_enter(void (*syncfn) (void)) > +{ > + unsigned long flags; > + > + local_irq_save_hw(flags); > + > +#ifdef CONFIG_SMP > + if (num_online_cpus() > 1) { /* We might be running a SMP-kernel on a UP box... */ > + ipipe_declare_cpuid; > + cpumask_t lock_map; > + > + ipipe_load_cpuid(); > + > + if (!cpu_test_and_set(cpuid, __ipipe_cpu_lock_map)) { > + while (cpu_test_and_set(BITS_PER_LONG - 1, > + __ipipe_cpu_lock_map)) { > + int n = 0; > + do { > + cpu_relax(); > + } while (++n < cpuid); > + } > + > + spin_lock_hw(&__ipipe_cpu_barrier); > + > + __ipipe_cpu_sync = syncfn; > + > + /* Send the sync IPI to all processors but the current one. */ > + send_IPI_allbutself(IPIPE_CRITICAL_VECTOR); > + > + cpus_andnot(lock_map, cpu_online_map, > + __ipipe_cpu_lock_map); > + > + while (!cpus_equal(__ipipe_cpu_sync_map, lock_map)) > + cpu_relax(); > + } > + > + atomic_inc(&__ipipe_critical_count); > + } > +#endif /* CONFIG_SMP */ > + > + return flags; > +} > + > +/* ipipe_critical_exit() -- Release the superlock. */ > + > +void ipipe_critical_exit(unsigned long flags) > +{ > +#ifdef CONFIG_SMP > + if (num_online_cpus() > 1) { /* We might be running a SMP-kernel on a UP box... */ > + ipipe_declare_cpuid; > + > + ipipe_load_cpuid(); > + > + if (atomic_dec_and_test(&__ipipe_critical_count)) { > + spin_unlock_hw(&__ipipe_cpu_barrier); > + > + while (!cpus_empty(__ipipe_cpu_sync_map)) > + cpu_relax(); > + > + cpu_clear(cpuid, __ipipe_cpu_lock_map); > + cpu_clear(BITS_PER_LONG - 1, __ipipe_cpu_lock_map); > + } > + } > +#endif /* CONFIG_SMP */ > + > + local_irq_restore_hw(flags); > +} > + > +void __ipipe_init_platform(void) > +{ > + __ipipe_decr_ticks = __ipipe_mach_ticks_per_jiffy; > +} > + > +int ipipe_get_sysinfo(struct ipipe_sysinfo *info) > +{ > + info->ncpus = num_online_cpus(); > + info->cpufreq = ipipe_cpu_freq(); > + info->archdep.tmirq = __ipipe_mach_timerint; > + info->archdep.tmfreq = info->cpufreq; > + > + return 0; > +} > + > +/* > + * ipipe_trigger_irq() -- Push the interrupt at front of the pipeline > + * just like if it has been actually received from a hw source. Also > + * works for virtual interrupts. > + */ > +int ipipe_trigger_irq(unsigned irq) > +{ > + unsigned long flags; > + > + if (irq >= IPIPE_NR_IRQS || > + (ipipe_virtual_irq_p(irq) > + && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map))) > + return -EINVAL; > + > + local_irq_save_hw(flags); > + > + __ipipe_handle_irq(irq, NULL); > + > + local_irq_restore_hw(flags); > + > + return 1; > +} > + > +static void __ipipe_set_decr(void) > +{ > + ipipe_declare_cpuid; > + > + ipipe_load_cpuid(); > + > + __ipipe_decr_next[cpuid] = __ipipe_read_timebase() + __ipipe_decr_ticks; > + __ipipe_mach_set_dec(__ipipe_decr_ticks); > +} > + > +int ipipe_tune_timer(unsigned long ns, int flags) > +{ > + unsigned long x, ticks; > + > + if (flags & IPIPE_RESET_TIMER) > + ticks = __ipipe_mach_ticks_per_jiffy; > + else { > + ticks = (ns / 1000) * (__ipipe_mach_ticks_per_jiffy) / (1000000 / HZ); > + > + if (ticks > __ipipe_mach_ticks_per_jiffy) > + return -EINVAL; > + } > + > + x = ipipe_critical_enter(&__ipipe_set_decr); /* Sync with all CPUs */ > + __ipipe_decr_ticks = ticks; > + __ipipe_set_decr(); > + ipipe_critical_exit(x); > + > + return 0; > +} > + > +EXPORT_SYMBOL(__ipipe_decr_ticks); > +EXPORT_SYMBOL(__ipipe_decr_next); > +EXPORT_SYMBOL(ipipe_critical_enter); > +EXPORT_SYMBOL(ipipe_critical_exit); > +EXPORT_SYMBOL(ipipe_trigger_irq); > +EXPORT_SYMBOL(ipipe_get_sysinfo); > +EXPORT_SYMBOL(ipipe_tune_timer); > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/ipipe-root.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ipipe-root.c > --- linux-2.6.16.5-tcl1/arch/arm/kernel/ipipe-root.c 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ipipe-root.c 2006-07-17 14:59:06.000000000 +0200 > @@ -0,0 +1,379 @@ > +/* -*- linux-c -*- > + * linux/arch/arm/kernel/ipipe-root.c > + * > + * Copyright (C) 2002-2005 Philippe Gerum (Adeos/ppc port over 2.6). > + * Copyright (C) 2004 Wolfgang Grandegger (Adeos/ppc port over 2.4). > + * Copyright (C) 2005 Stelian Pop. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, > + * USA; either version 2 of the License, or (at your option) any later > + * version. > + * > + * 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. > + * > + * Architecture-dependent I-pipe support for ARM. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +extern struct irqdesc irq_desc[]; > +extern spinlock_t irq_controller_lock; > +extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs); > + > +static struct irqchip __ipipe_std_irq_dtype[NR_IRQS]; > + > +static void __ipipe_override_irq_unmask(unsigned irq) > +{ > + unsigned long flags; > + > + local_irq_save_hw(flags); > + ipipe_irq_unlock(irq); > + __ipipe_std_irq_dtype[irq].unmask(irq); > + local_irq_restore_hw(flags); > +} > + > +static void __ipipe_override_irq_mask(unsigned irq) > +{ > + unsigned long flags; > + > + local_irq_save_hw(flags); > + ipipe_irq_lock(irq); > + __ipipe_std_irq_dtype[irq].mask(irq); > + local_irq_restore_hw(flags); > +} > + > +static void __ipipe_override_irq_mask_ack(unsigned irq) > +{ > + unsigned long flags; > + > + local_irq_save_hw(flags); > + ipipe_irq_lock(irq); > + __ipipe_std_irq_dtype[irq].ack(irq); > + local_irq_restore_hw(flags); > +} > + > + > +static void __ipipe_enable_sync(void) > +{ > + __ipipe_decr_next[ipipe_processor_id()] = > + __ipipe_read_timebase() + __ipipe_mach_get_dec(); > +} > + > +/* > + * __ipipe_enable_pipeline() -- We are running on the boot CPU, hw > + * interrupts are off, and secondary CPUs are still lost in space. > + */ > +void __ipipe_enable_pipeline(void) > +{ > + unsigned long flags; > + unsigned irq; > + > + flags = ipipe_critical_enter(&__ipipe_enable_sync); > + > + /* First, virtualize all interrupts from the root domain. */ > + > + for (irq = 0; irq < NR_IRQS; irq++) > + ipipe_virtualize_irq(ipipe_root_domain, > + irq, > + (ipipe_irq_handler_t)&asm_do_IRQ, NULL, > + (irq == __ipipe_mach_timerint) ? &__ipipe_ack_timerirq : &__ipipe_ack_irq, > + IPIPE_HANDLE_MASK | IPIPE_PASS_MASK); > + > + /* > + * Interpose on the IRQ control routines so we can make them > + * atomic using hw masking and prevent the interrupt log from > + * being untimely flushed. > + */ > + > + for (irq = 0; irq < NR_IRQS; irq++) > + __ipipe_std_irq_dtype[irq] = *irq_desc[irq].chip; > + > + /* > + * The original controller structs are often shared, so we first > + * save them all before changing any of them. Notice that we don't > + * override the ack() handler since we will enforce the necessary > + * setup in __ipipe_ack_irq(). > + */ > + > + for (irq = 0; irq < NR_IRQS; irq++) { > + if (irq_desc[irq].chip->mask != NULL) > + irq_desc[irq].chip->mask = __ipipe_override_irq_mask; > + > + if (irq_desc[irq].chip->unmask != NULL) > + irq_desc[irq].chip->unmask = __ipipe_override_irq_unmask; > + > + if (irq_desc[irq].chip->ack != NULL) > + irq_desc[irq].chip->ack = __ipipe_override_irq_mask_ack; > + } > + > + __ipipe_decr_next[ipipe_processor_id()] = > + __ipipe_read_timebase() + __ipipe_mach_get_dec(); > + > + ipipe_critical_exit(flags); > +} > + > +int __ipipe_ack_irq(unsigned irq) > +{ > + unsigned long flags; > + ipipe_declare_cpuid; > + > + /* > + * No need to mask IRQs at hw level: we are always called from > + * __ipipe_handle_irq(), so interrupts are already off. We > + * stall the pipeline so that spin_lock_irq*() ops won't > + * unintentionally flush it, since this could cause infinite > + * recursion. > + */ > + > + ipipe_load_cpuid(); > + flags = ipipe_test_and_stall_pipeline(); > + preempt_disable(); > + spin_lock_hw(&irq_controller_lock); > + __ipipe_std_irq_dtype[irq].ack(irq); > + spin_unlock_hw(&irq_controller_lock); > + preempt_enable_no_resched(); > + ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], flags, cpuid); > + > + return 1; > +} > + > +int __ipipe_ack_timerirq(unsigned irq) > +{ > + unsigned long flags; > + ipipe_declare_cpuid; > + > + ipipe_load_cpuid(); > + flags = ipipe_test_and_stall_pipeline(); > + preempt_disable(); > + spin_lock_hw(&irq_controller_lock); > + __ipipe_mach_acktimer(); > + __ipipe_std_irq_dtype[irq].ack(irq); > + __ipipe_std_irq_dtype[irq].unmask(irq); > + spin_unlock_hw(&irq_controller_lock); > + preempt_enable_no_resched(); > + ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], flags, cpuid); > + > + return 1; > +} > + > +/* > + * __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic > + * interrupt protection log is maintained here for each domain. Hw > + * interrupts are off on entry. > + */ > +void __ipipe_handle_irq(int irq, struct pt_regs *regs) > +{ > + struct ipipe_domain *this_domain, *next_domain; > + struct list_head *head, *pos; > + ipipe_declare_cpuid; > + int m_ack, s_ack; > + > + m_ack = (regs == NULL); > + > + if (irq >= IPIPE_NR_IRQS) { > + printk(KERN_ERR "I-pipe: spurious interrupt %d\n", irq); > + return; > + } > + > + ipipe_load_cpuid(); > + > + this_domain = ipipe_percpu_domain[cpuid]; > + > + if (test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control)) > + head = &this_domain->p_link; > + else { > + head = __ipipe_pipeline.next; > + next_domain = list_entry(head, struct ipipe_domain, p_link); > + if (likely(test_bit(IPIPE_WIRED_FLAG, &next_domain->irqs[irq].control))) { > + if (!m_ack && next_domain->irqs[irq].acknowledge != NULL) > + next_domain->irqs[irq].acknowledge(irq); > + if (likely(__ipipe_dispatch_wired(next_domain, irq))) > + goto finalize; > + return; > + } > + } > + > + /* Ack the interrupt. */ > + > + s_ack = m_ack; > + pos = head; > + > + while (pos != &__ipipe_pipeline) { > + next_domain = list_entry(pos, struct ipipe_domain, p_link); > + > + /* > + * For each domain handling the incoming IRQ, mark it as > + * pending in its log. > + */ > + if (test_bit(IPIPE_HANDLE_FLAG, > + &next_domain->irqs[irq].control)) { > + /* > + * Domains that handle this IRQ are polled for > + * acknowledging it by decreasing priority order. The > + * interrupt must be made pending _first_ in the > + * domain's status flags before the PIC is unlocked. > + */ > + > + next_domain->cpudata[cpuid].irq_counters[irq].total_hits++; > + next_domain->cpudata[cpuid].irq_counters[irq].pending_hits++; > + __ipipe_set_irq_bit(next_domain, cpuid, irq); > + > + /* > + * Always get the first master acknowledge available. > + * Once we've got it, allow slave acknowledge > + * handlers to run (until one of them stops us). > + */ > + if (next_domain->irqs[irq].acknowledge != NULL) { > + if (!m_ack) > + m_ack = next_domain->irqs[irq].acknowledge(irq); > + else if (test_bit > + (IPIPE_SHARED_FLAG, > + &next_domain->irqs[irq].control) && !s_ack) > + s_ack = next_domain->irqs[irq].acknowledge(irq); > + } > + } > + > + /* > + * If the domain does not want the IRQ to be passed down the > + * interrupt pipe, exit the loop now. > + */ > + > + if (!test_bit(IPIPE_PASS_FLAG, &next_domain->irqs[irq].control)) > + break; > + > + pos = next_domain->p_link.next; > + } > + > +finalize: > + /* > + * Now walk the pipeline, yielding control to the highest > + * priority domain that has pending interrupt(s) or > + * immediately to the current domain if the interrupt has been > + * marked as 'sticky'. This search does not go beyond the > + * current domain in the pipeline. > + */ > + > + __ipipe_walk_pipeline(head, cpuid); > +} > + > +asmlinkage int __ipipe_grab_irq(int irq, struct pt_regs *regs) > +{ > + ipipe_declare_cpuid; > + > + if (irq == __ipipe_mach_timerint) { > + > + __ipipe_tick_regs[cpuid].ARM_cpsr = regs->ARM_cpsr; > + __ipipe_tick_regs[cpuid].ARM_pc = regs->ARM_pc; > + > + if (__ipipe_decr_ticks != __ipipe_mach_ticks_per_jiffy) { > + unsigned long long next_date, now; > + > + next_date = __ipipe_decr_next[cpuid]; > + > + while ((now = __ipipe_read_timebase()) >= next_date) > + next_date += __ipipe_decr_ticks; > + > + __ipipe_mach_set_dec(next_date - now); > + > + __ipipe_decr_next[cpuid] = next_date; > + } > + } > + > + __ipipe_handle_irq(irq, regs); > + > + ipipe_load_cpuid(); > + > + return (ipipe_percpu_domain[cpuid] == ipipe_root_domain && > + !test_bit(IPIPE_STALL_FLAG, > + &ipipe_root_domain->cpudata[cpuid].status)); > +} > + > +asmlinkage int __ipipe_check_root(struct pt_regs *regs) > +{ > + ipipe_declare_cpuid; > + /* > + * This routine is called with hw interrupts off, so no migration > + * can occur while checking the identity of the current domain. > + */ > + ipipe_load_cpuid(); > + return (ipipe_percpu_domain[cpuid] == ipipe_root_domain && > + !test_bit(IPIPE_STALL_FLAG, > + &ipipe_root_domain->cpudata[cpuid].status)); > +} > + > +asmlinkage int __ipipe_syscall_root(unsigned long scno, struct pt_regs *regs) > +{ > + ipipe_declare_cpuid; > + unsigned long flags, origr7; > + > + /* We use r7 to pass the syscall number to the other domains */ > + origr7 = regs->ARM_r7; > + regs->ARM_r7 = __NR_SYSCALL_BASE + scno; > + > + /* > + * This routine either returns: > + * 0 -- if the syscall is to be passed to Linux; > + * >0 -- if the syscall should not be passed to Linux, and no > + * tail work should be performed; > + * <0 -- if the syscall should not be passed to Linux but the > + * tail work has to be performed (for handling signals etc). > + */ > + > + if (__ipipe_event_pipelined_p(IPIPE_EVENT_SYSCALL) && > + __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,regs) > 0) { > + /* > + * We might enter here over a non-root domain and exit > + * over the root one as a result of the syscall > + * (i.e. by recycling the register set of the current > + * context across the migration), so we need to fixup > + * the interrupt flag upon return too, so that > + * __ipipe_unstall_iret_root() resets the correct > + * stall bit on exit. > + */ > + if (ipipe_current_domain == ipipe_root_domain && !in_atomic()) { > + /* > + * Sync pending VIRQs before _TIF_NEED_RESCHED > + * is tested. > + */ > + ipipe_lock_cpu(flags); > + if ((ipipe_root_domain->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0) > + __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT); > + ipipe_unlock_cpu(flags); > + regs->ARM_r7 = origr7; > + return -1; > + } > + regs->ARM_r7 = origr7; > + return 1; > + } > + > + regs->ARM_r7 = origr7; > + return 0; > +} > + > +EXPORT_SYMBOL_GPL(show_stack); > +#ifndef MULTI_CPU > +EXPORT_SYMBOL_GPL(cpu_do_switch_mm); > +#endif /* MULTI_CPU */ > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/irq.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/irq.c > --- linux-2.6.16.5-tcl1/arch/arm/kernel/irq.c 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/irq.c 2006-07-16 15:01:24.000000000 +0200 > @@ -54,10 +54,11 @@ > > static int noirqdebug; > static volatile unsigned long irq_err_count; > -static DEFINE_SPINLOCK(irq_controller_lock); > +DEFINE_SPINLOCK(irq_controller_lock); > static LIST_HEAD(irq_pending); > > struct irqdesc irq_desc[NR_IRQS]; > +EXPORT_SYMBOL(irq_desc); > void (*init_arch_irq)(void) __initdata = NULL; > > /* > @@ -412,7 +413,9 @@ do_edge_IRQ(unsigned int irq, struct irq > /* > * Acknowledge and clear the IRQ, but don't mask it. > */ > +#ifndef CONFIG_IPIPE > desc->chip->ack(irq); > +#endif /* CONFIG_IPIPE */ > > /* > * Mark the IRQ currently in progress. > @@ -450,8 +453,10 @@ do_edge_IRQ(unsigned int irq, struct irq > * currently running. Delay it. > */ > desc->pending = 1; > +#ifndef CONFIG_IPIPE > desc->chip->mask(irq); > desc->chip->ack(irq); > +#endif /* CONFIG_IPIPE */ > } > > /* > @@ -468,7 +473,9 @@ do_level_IRQ(unsigned int irq, struct ir > /* > * Acknowledge, clear _AND_ disable the interrupt. > */ > +#ifndef CONFIG_IPIPE > desc->chip->ack(irq); > +#endif /* CONFIG_IPIPE */ > > if (likely(!desc->disable_depth)) { > kstat_cpu(cpu).irqs[irq]++; > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/process.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/process.c > --- linux-2.6.16.5-tcl1/arch/arm/kernel/process.c 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/process.c 2006-07-16 15:01:24.000000000 +0200 > @@ -89,12 +89,12 @@ static void default_idle(void) > if (hlt_counter) > cpu_relax(); > else { > - local_irq_disable(); > + local_irq_disable_hw(); > if (!need_resched()) { > timer_dyn_reprogram(); > arch_idle(); > } > - local_irq_enable(); > + local_irq_enable_hw(); > } > } > > @@ -120,6 +120,7 @@ void cpu_idle(void) > > if (!idle) > idle = default_idle; > + ipipe_suspend_domain(); > leds_event(led_idle_start); > while (!need_resched()) > idle(); > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/ptrace.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ptrace.c > --- linux-2.6.16.5-tcl1/arch/arm/kernel/ptrace.c 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ptrace.c 2006-07-16 15:01:24.000000000 +0200 > @@ -486,6 +486,10 @@ void ptrace_break(struct task_struct *ts > > static int break_trap(struct pt_regs *regs, unsigned int instr) > { > + > + if (ipipe_trap_notify(IPIPE_TRAP_BREAK,regs)) > + return 0; > + > ptrace_break(current, regs); > return 0; > } > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/traps.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/traps.c > --- linux-2.6.16.5-tcl1/arch/arm/kernel/traps.c 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/traps.c 2006-07-16 15:01:24.000000000 +0200 > @@ -310,6 +310,9 @@ asmlinkage void do_undefinstr(struct pt_ > } > spin_unlock_irq(&undef_lock); > > + if (ipipe_trap_notify(IPIPE_TRAP_UNDEFINSTR,regs)) > + return; > + > #ifdef CONFIG_DEBUG_USER > if (user_debug & UDBG_UNDEFINED) { > printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n", > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mach-integrator/core.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-integrator/core.c > --- linux-2.6.16.5-tcl1/arch/arm/mach-integrator/core.c 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-integrator/core.c 2006-07-16 15:01:24.000000000 +0200 > @@ -2,6 +2,7 @@ > * linux/arch/arm/mach-integrator/core.c > * > * Copyright (C) 2000-2003 Deep Blue Solutions Ltd > + * Copyright (C) 2005 Stelian Pop. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License version 2, as > @@ -148,53 +149,57 @@ EXPORT_SYMBOL(cm_control); > /* > * How long is the timer interval? > */ > -#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) > -#if TIMER_INTERVAL >= 0x100000 > -#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) > -#elif TIMER_INTERVAL >= 0x10000 > -#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) > -#else > #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) > -#endif > > static unsigned long timer_reload; > +static unsigned long timer_interval; > +static unsigned long timer_lxlost; > +static int tscok; > + > +#ifdef CONFIG_IPIPE > +int __ipipe_mach_timerint = IRQ_TIMERINT1; > +static unsigned long long __ipipe_mach_tsc; > +static DEFINE_SPINLOCK(timer_lock); > + > +int __ipipe_mach_timerstolen = 0; > +EXPORT_SYMBOL(__ipipe_mach_timerstolen); > +#endif > > /* > - * Returns number of ms since last clock interrupt. Note that interrupts > - * will have been disabled by do_gettimeoffset() > + * Called with IRQ disabled from do_gettimeofday(). > */ > -unsigned long integrator_gettimeoffset(void) > +static inline unsigned long integrator_getticksoffset(void) > { > - unsigned long ticks1, ticks2, status; > + unsigned long ticks; > > - /* > - * Get the current number of ticks. Note that there is a race > - * condition between us reading the timer and checking for > - * an interrupt. We get around this by ensuring that the > - * counter has not reloaded between our two reads. > - */ > - ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff; > - do { > - ticks1 = ticks2; > - status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS); > - ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff; > - } while (ticks2 > ticks1); > + if (!tscok) > + return 0; > > - /* > - * Number of ticks since last interrupt. > - */ > - ticks1 = timer_reload - ticks2; > + ticks = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff; > > - /* > - * Interrupt pending? If so, we've reloaded once already. > - */ > - if (status & (1 << IRQ_TIMERINT1)) > - ticks1 += timer_reload; > + if (ticks > timer_reload) > + ticks = 0xffff + timer_reload - ticks; > + else > + ticks = timer_reload - ticks; > > + if (timer_interval < 0x10000) > + return ticks; > + else if (timer_interval < 0x100000) > + return ticks * 16; > + else > + return ticks * 256; > +} > + > +/* > + * Returns number of ms since last clock interrupt. Note that interrupts > + * will have been disabled by do_gettimeoffset() > + */ > +unsigned long integrator_gettimeoffset(void) > +{ > /* > * Convert the ticks to usecs > */ > - return TICKS2USECS(ticks1); > + return TICKS2USECS(timer_lxlost + integrator_getticksoffset()); > } > > /* > @@ -205,10 +210,22 @@ integrator_timer_interrupt(int irq, void > { > write_seqlock(&xtime_lock); > > + timer_lxlost = 0; > + > +#ifdef CONFIG_IPIPE > /* > - * clear the interrupt > + * If Linux is the only domain, ack the timer and reprogram it > */ > - writel(1, TIMER1_VA_BASE + TIMER_INTCLR); > + if (!__ipipe_mach_timerstolen) { > + __ipipe_mach_tsc += integrator_getticksoffset(); > +#else > + writel(1, TIMER1_VA_BASE + TIMER_INTCLR); > +#endif > + > + writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD); > +#ifdef CONFIG_IPIPE > + } > +#endif > > /* > * the clock tick routines are only processed on the > @@ -239,24 +256,30 @@ static struct irqaction integrator_timer > .handler = integrator_timer_interrupt, > }; > > -/* > - * Set up timer interrupt, and return the current time in seconds. > - */ > -void __init integrator_time_init(unsigned long reload, unsigned int ctrl) > +static inline void set_dec(unsigned long reload) > { > - unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; > + unsigned int ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_IE; > > timer_reload = reload; > - timer_ctrl |= ctrl; > + timer_interval = reload; > > - if (timer_reload > 0x100000) { > + if (timer_reload >= 0x100000) { > timer_reload >>= 8; > - timer_ctrl |= TIMER_CTRL_DIV256; > - } else if (timer_reload > 0x010000) { > + ctrl |= TIMER_CTRL_DIV256; > + } else if (timer_reload >= 0x010000) { > timer_reload >>= 4; > - timer_ctrl |= TIMER_CTRL_DIV16; > + ctrl |= TIMER_CTRL_DIV16; > } > > + writel(ctrl, TIMER1_VA_BASE + TIMER_CTRL); > + writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD); > +} > + > +/* > + * Set up timer interrupt, and return the current time in seconds. > + */ > +void __init integrator_time_init(unsigned long reload, unsigned int ctrl) > +{ > /* > * Initialise to a known state (all timers off) > */ > @@ -264,12 +287,51 @@ void __init integrator_time_init(unsigne > writel(0, TIMER1_VA_BASE + TIMER_CTRL); > writel(0, TIMER2_VA_BASE + TIMER_CTRL); > > - writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD); > - writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE); > - writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL); > + set_dec(reload); > > /* > * Make irqs happen for the system timer > */ > setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); > + > + tscok = 1; > } > + > +#ifdef CONFIG_IPIPE > +void __ipipe_mach_acktimer(void) > +{ > + writel(1, TIMER1_VA_BASE + TIMER_INTCLR); > +} > + > +unsigned long long __ipipe_mach_get_tsc(void) > +{ > + unsigned long long result; > + unsigned long flags; > + > + spin_lock_irqsave_hw(&timer_lock, flags); > + result = __ipipe_mach_tsc + integrator_getticksoffset(); > + spin_unlock_irqrestore_hw(&timer_lock, flags); > + return result; > +} > +EXPORT_SYMBOL(__ipipe_mach_get_tsc); > + > +void __ipipe_mach_set_dec(unsigned long reload) > +{ > + unsigned long ticks; > + unsigned long flags; > + > + spin_lock_irqsave_hw(&timer_lock, flags); > + ticks = integrator_getticksoffset(); > + __ipipe_mach_tsc += ticks; > + timer_lxlost += ticks; > + > + set_dec(reload); > + spin_unlock_irqrestore_hw(&timer_lock, flags); > +} > +EXPORT_SYMBOL(__ipipe_mach_set_dec); > + > +unsigned long __ipipe_mach_get_dec(void) > +{ > + return readl(TIMER1_VA_BASE + TIMER_VALUE); > +} > +#endif /* CONFIG_IPIPE */ > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mach-integrator/integrator_cp.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-integrator/integrator_cp.c > --- linux-2.6.16.5-tcl1/arch/arm/mach-integrator/integrator_cp.c 2006-05-07 16:41:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-integrator/integrator_cp.c 2006-07-16 15:01:24.000000000 +0200 > @@ -2,6 +2,7 @@ > * linux/arch/arm/mach-integrator/integrator_cp.c > * > * Copyright (C) 2003 Deep Blue Solutions Ltd > + * Copyright (C) 2005 Stelian Pop. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -568,9 +569,14 @@ static void __init intcp_init(void) > > #define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ > > +#ifdef CONFIG_IPIPE > +unsigned int __ipipe_mach_ticks_per_jiffy = 1000000 * TICKS_PER_uSEC / HZ; > +EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy); > +#endif > + > static void __init intcp_timer_init(void) > { > - integrator_time_init(1000000 / HZ, TIMER_CTRL_IE); > + integrator_time_init(1000000 * TICKS_PER_uSEC / HZ, TIMER_CTRL_IE); > } > > static struct sys_timer cp_timer = { > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mach-pxa/time.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-pxa/time.c > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mach-sa1100/time.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-sa1100/time.c > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mm/fault.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mm/fault.c > --- linux-2.6.16.5-tcl1/arch/arm/mm/fault.c 2005-10-28 02:02:08.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/mm/fault.c 2006-07-16 15:01:24.000000000 +0200 > @@ -223,6 +223,9 @@ do_page_fault(unsigned long addr, unsign > struct mm_struct *mm; > int fault, sig, code; > > + if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs)) > + return 0; > + > tsk = current; > mm = tsk->mm; > > @@ -354,6 +357,9 @@ do_translation_fault(unsigned long addr, > bad_area: > tsk = current; > > + if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs)) > + return 0; > + > do_bad_area(tsk, tsk->active_mm, addr, fsr, regs); > return 0; > } > @@ -366,6 +372,10 @@ static int > do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) > { > struct task_struct *tsk = current; > + > + if (ipipe_trap_notify(IPIPE_TRAP_SECTION,regs)) > + return 0; > + > do_bad_area(tsk, tsk->active_mm, addr, fsr, regs); > return 0; > } > @@ -376,6 +386,9 @@ do_sect_fault(unsigned long addr, unsign > static int > do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) > { > + if (ipipe_trap_notify(IPIPE_TRAP_DABT,regs)) > + return 0; > + > return 1; > } > > @@ -451,6 +464,9 @@ do_DataAbort(unsigned long addr, unsigne > if (!inf->fn(addr, fsr, regs)) > return; > > + if (ipipe_trap_notify(IPIPE_TRAP_UNKNOWN,regs)) > + return; > + > printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", > inf->name, fsr, addr); > > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/drivers/pci/msi.c linux-2.6.16.5-tcl1-ipipe/drivers/pci/msi.c > --- linux-2.6.16.5-tcl1/drivers/pci/msi.c 2006-05-07 16:41:40.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/drivers/pci/msi.c 2006-07-16 15:01:24.000000000 +0200 > @@ -151,6 +151,21 @@ static void unmask_MSI_irq(unsigned int > msi_set_mask_bit(vector, 0); > } > > +#ifdef CONFIG_IPIPE > +static void ack_MSI_irq_w_maskbit(unsigned int vector) > +{ > + mask_MSI_irq(vector); > + __ack_APIC_irq(); > +} > +static void ack_MSI_irq_wo_maskbit(unsigned int vector) > +{ > + __ack_APIC_irq(); > +} > +#else /* !CONFIG_IPIPE */ > +#define ack_MSI_irq_wo_maskbit do_nothing > +#define ack_MSI_irq_w_maskbit mask_MSI_irq > +#endif /* CONFIG_IPIPE */ > + > static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector) > { > struct msi_desc *entry; > @@ -214,7 +229,7 @@ static struct hw_interrupt_type msix_irq > .shutdown = shutdown_msi_irq, > .enable = unmask_MSI_irq, > .disable = mask_MSI_irq, > - .ack = mask_MSI_irq, > + .ack = ack_MSI_irq_w_maskbit, > .end = end_msi_irq_w_maskbit, > .set_affinity = set_msi_affinity > }; > @@ -230,7 +245,7 @@ static struct hw_interrupt_type msi_irq_ > .shutdown = shutdown_msi_irq, > .enable = unmask_MSI_irq, > .disable = mask_MSI_irq, > - .ack = mask_MSI_irq, > + .ack = ack_MSI_irq_w_maskbit, > .end = end_msi_irq_w_maskbit, > .set_affinity = set_msi_affinity > }; > @@ -246,7 +261,7 @@ static struct hw_interrupt_type msi_irq_ > .shutdown = shutdown_msi_irq, > .enable = do_nothing, > .disable = do_nothing, > - .ack = do_nothing, > + .ack = ack_MSI_irq_wo_maskbit, > .end = end_msi_irq_wo_maskbit, > .set_affinity = set_msi_affinity > }; > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/entry-macro.S linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/entry-macro.S > --- linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/entry-macro.S 2006-05-07 16:42:04.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/entry-macro.S 2006-07-16 15:01:24.000000000 +0200 > @@ -22,7 +22,11 @@ > teq \irqstat, #0 > ldreq \irqstat, [\base, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)] > moveq \irqnr, #IRQ_CIC_START > - > +#ifdef CONFIG_IPIPE > + tst \irqstat, #0x00000040 @ check IRQ_TIMERINT1 first > + movne \irqnr, #6 > + bne 1003f > +#endif /* CONFIG_IPIPE */ > 1001: tst \irqstat, #15 > bne 1002f > add \irqnr, \irqnr, #4 > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/platform.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/platform.h > --- linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/platform.h 2005-10-28 02:02:08.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/platform.h 2006-07-16 15:01:24.000000000 +0200 > @@ -26,13 +26,15 @@ > * NOTE: This is a multi-hosted header file for use with uHAL and > * supported debuggers. > * > - * $Id: platform.s,v 1.32 2000/02/18 10:51:39 asims Exp $ > + * $Id: platform.h,v 1.2 2006/02/20 13:54:22 rpm Exp $ > * > * ***********************************************************************/ > > #ifndef __address_h > #define __address_h 1 > > +#include > + > /* ======================================================================== > * Integrator definitions > * ======================================================================== > @@ -436,7 +438,7 @@ > * Timer definitions > * > * Only use timer 1 & 2 > - * (both run at 24MHz and will need the clock divider set to 16). > + * (both run at 1MHZ on /CP and at 24MHz on /AP) > * > * Timer 0 runs at bus frequency and therefore could vary and currently > * uHAL can't handle that. > @@ -449,7 +451,12 @@ > > #define MAX_TIMER 2 > #define MAX_PERIOD 699050 > + > +#ifdef CONFIG_ARCH_INTEGRATOR_CP > +#define TICKS_PER_uSEC 1 > +#else > #define TICKS_PER_uSEC 24 > +#endif > > /* > * These are useconds NOT ticks. > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/timex.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/timex.h > --- linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/timex.h 2005-10-28 02:02:08.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/timex.h 2006-07-16 15:01:24.000000000 +0200 > @@ -21,6 +21,6 @@ > */ > > /* > - * ?? > + * Timer rate > */ > -#define CLOCK_TICK_RATE (50000000 / 16) > +#define CLOCK_TICK_RATE (1000000) > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/atomic.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/atomic.h > --- linux-2.6.16.5-tcl1/include/asm-arm/atomic.h 2006-05-07 16:42:05.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/atomic.h 2006-07-16 15:01:24.000000000 +0200 > @@ -129,10 +129,10 @@ static inline int atomic_add_return(int > unsigned long flags; > int val; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > val = v->counter; > v->counter = val += i; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > > return val; > } > @@ -142,10 +142,10 @@ static inline int atomic_sub_return(int > unsigned long flags; > int val; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > val = v->counter; > v->counter = val -= i; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > > return val; > } > @@ -155,11 +155,11 @@ static inline int atomic_cmpxchg(atomic_ > int ret; > unsigned long flags; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > ret = v->counter; > if (likely(ret == old)) > v->counter = new; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > > return ret; > } > @@ -168,9 +168,9 @@ static inline void atomic_clear_mask(uns > { > unsigned long flags; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > *addr &= ~mask; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > } > > #endif /* __LINUX_ARM_ARCH__ */ > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/bitops.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/bitops.h > --- linux-2.6.16.5-tcl1/include/asm-arm/bitops.h 2006-05-07 16:42:05.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/bitops.h 2006-07-16 15:01:24.000000000 +0200 > @@ -37,9 +37,9 @@ static inline void ____atomic_set_bit(un > > p += bit >> 5; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > *p |= mask; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > } > > static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p) > @@ -49,9 +49,9 @@ static inline void ____atomic_clear_bit( > > p += bit >> 5; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > *p &= ~mask; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > } > > static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p) > @@ -61,9 +61,9 @@ static inline void ____atomic_change_bit > > p += bit >> 5; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > *p ^= mask; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > } > > static inline int > @@ -75,10 +75,10 @@ ____atomic_test_and_set_bit(unsigned int > > p += bit >> 5; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > res = *p; > *p = res | mask; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > > return res & mask; > } > @@ -92,10 +92,10 @@ ____atomic_test_and_clear_bit(unsigned i > > p += bit >> 5; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > res = *p; > *p = res & ~mask; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > > return res & mask; > } > @@ -109,10 +109,10 @@ ____atomic_test_and_change_bit(unsigned > > p += bit >> 5; > > - local_irq_save(flags); > + local_irq_save_hw(flags); > res = *p; > *p = res ^ mask; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > > return res & mask; > } > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/ipipe.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/ipipe.h > --- linux-2.6.16.5-tcl1/include/asm-arm/ipipe.h 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/ipipe.h 2006-07-16 15:01:24.000000000 +0200 > @@ -0,0 +1,193 @@ > +/* -*- linux-c -*- > + * include/asm-arm/ipipe.h > + * > + * Copyright (C) 2002-2005 Philippe Gerum. > + * Copyright (C) 2005 Stelian Pop. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, > + * USA; either version 2 of the License, or (at your option) any later > + * version. > + * > + * 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. > + */ > + > +#ifndef __ARM_IPIPE_H > +#define __ARM_IPIPE_H > + > +#include > + > +#ifdef CONFIG_IPIPE > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define IPIPE_ARCH_STRING "1.3-04" > +#define IPIPE_MAJOR_NUMBER 1 > +#define IPIPE_MINOR_NUMBER 3 > +#define IPIPE_PATCH_NUMBER 4 > + > +#define IPIPE_NR_XIRQS NR_IRQS > +#define IPIPE_IRQ_ISHIFT 5 /* 25 for 32bits arch. */ > + > +#ifdef CONFIG_SMP > +#error "I-pipe/arm: SMP not yet implemented" > +#define ipipe_processor_id() (current_thread_info()->cpu) > +#else /* !CONFIG_SMP */ > +#define ipipe_processor_id() 0 > +#endif /* CONFIG_SMP */ > + > +/* Note that we disable the interrupts around context_switch, > + * or we'll get into severe problems when scheduling Xenoma > + * user space real time threads. > + * This can however cause high latencies, see for example: > + * http://www.ussg.iu.edu/hypermail/linux/kernel/0405.2/1388.html > + * This may need further optimization... > + */ > +#define prepare_arch_switch(next) \ > +do { \ > + __ipipe_dispatch_event(IPIPE_EVENT_SCHEDULE,next); \ > + local_irq_disable_hw(); \ > +} while(0) > + > +#define task_hijacked(p) \ > + ( { \ > + int x = ipipe_current_domain != ipipe_root_domain; \ > + __clear_bit(IPIPE_SYNC_FLAG, \ > + &ipipe_root_domain->cpudata[task_cpu(p)].status); \ > + local_irq_enable_hw(); \ > + x; \ > + } ) > + > +/* ARM traps */ > +#define IPIPE_TRAP_ACCESS 0 /* Data or instruction access exception */ > +#define IPIPE_TRAP_SECTION 1 /* Section fault */ > +#define IPIPE_TRAP_DABT 2 /* Generic data abort */ > +#define IPIPE_TRAP_UNKNOWN 3 /* Unknown exception */ > +#define IPIPE_TRAP_BREAK 4 /* Instruction breakpoint */ > +#define IPIPE_TRAP_FPU 5 /* Floating point exception */ > +#define IPIPE_TRAP_VFP 6 /* VFP floating point exception */ > +#define IPIPE_TRAP_UNDEFINSTR 7 /* Undefined instruction */ > +#define IPIPE_NR_FAULTS 8 > + > +/* Pseudo-vectors used for kernel events */ > +#define IPIPE_FIRST_EVENT IPIPE_NR_FAULTS > +#define IPIPE_EVENT_SYSCALL (IPIPE_FIRST_EVENT) > +#define IPIPE_EVENT_SCHEDULE (IPIPE_FIRST_EVENT + 1) > +#define IPIPE_EVENT_SIGWAKE (IPIPE_FIRST_EVENT + 2) > +#define IPIPE_EVENT_SETSCHED (IPIPE_FIRST_EVENT + 3) > +#define IPIPE_EVENT_EXIT (IPIPE_FIRST_EVENT + 4) > +#define IPIPE_EVENT_CLEANUP (IPIPE_FIRST_EVENT + 5) > +#define IPIPE_LAST_EVENT IPIPE_EVENT_CLEANUP > +#define IPIPE_NR_EVENTS (IPIPE_LAST_EVENT + 1) > + > +struct ipipe_domain; > + > +struct ipipe_sysinfo { > + > + int ncpus; /* Number of CPUs on board */ > + u64 cpufreq; /* CPU frequency (in Hz) */ > + > + /* Arch-dependent block */ > + > + struct { > + unsigned tmirq; /* Timer tick IRQ */ > + u64 tmfreq; /* Timer frequency */ > + } archdep; > +}; > + > +/* arch specific stuff */ > +extern int __ipipe_mach_timerint; > +extern int __ipipe_mach_timerstolen; > +extern unsigned int __ipipe_mach_ticks_per_jiffy; > +extern void __ipipe_mach_acktimer(void); > +extern unsigned long long __ipipe_mach_get_tsc(void); > +extern void __ipipe_mach_set_dec(unsigned long); > +extern unsigned long __ipipe_mach_get_dec(void); > + > +#define ipipe_read_tsc(t) do { t = __ipipe_mach_get_tsc(); } while (0) > +#define __ipipe_read_timebase() __ipipe_mach_get_tsc() > + > +#define ipipe_cpu_freq() (HZ * __ipipe_mach_ticks_per_jiffy) > +#define ipipe_tsc2ns(t) (((t) * 1000) / (ipipe_cpu_freq() / 1000000)) > + > +/* Private interface -- Internal use only */ > + > +#define __ipipe_check_platform() do { } while(0) > + > +#define __ipipe_enable_irq(irq) irq_desc[irq].chip->unmask(irq) > + > +#define __ipipe_disable_irq(irq) irq_desc[irq].chip->mask(irq) > + > +void __ipipe_init_platform(void); > + > +void __ipipe_enable_pipeline(void); > + > +int __ipipe_ack_irq(unsigned irq); > + > +int __ipipe_ack_timerirq(unsigned irq); > + > +void __ipipe_do_IRQ(int irq, > + struct pt_regs *regs); > + > +void __ipipe_do_timer(int irq, > + struct pt_regs *regs); > + > +void __ipipe_do_critical_sync(unsigned irq, > + void *cookie); > + > +extern unsigned long __ipipe_decr_ticks; > + > +extern unsigned long long __ipipe_decr_next[]; > + > +extern struct pt_regs __ipipe_tick_regs[]; > + > +void __ipipe_handle_irq(int irq, > + struct pt_regs *regs); > + > +#define __ipipe_tick_irq ipipe_timerint > + > +static inline unsigned long __ipipe_ffnz(unsigned long ul) > +{ > + return ffs(ul) - 1; > +} > + > +#define __ipipe_run_isr(ipd, irq, cpuid) \ > +do { \ > + if (ipd == ipipe_root_domain) { \ > + /* \ > + * Linux handlers are called w/ hw interrupts on so \ > + * that they could not defer interrupts for higher \ > + * priority domains. \ > + */ \ > + local_irq_enable_hw(); \ > + ((void (*)(unsigned, struct pt_regs *)) \ > + ipd->irqs[irq].handler) (irq, __ipipe_tick_regs + cpuid); \ > + local_irq_disable_hw(); \ > + } else { \ > + __clear_bit(IPIPE_SYNC_FLAG, &cpudata->status); \ > + ipd->irqs[irq].handler(irq,ipd->irqs[irq].cookie); \ > + __set_bit(IPIPE_SYNC_FLAG, &cpudata->status); \ > + } \ > +} while(0) > + > +#else /* !CONFIG_IPIPE */ > + > +#define task_hijacked(p) 0 > + > +#endif /* CONFIG_IPIPE */ > + > +#endif /* !__ARM_IPIPE_H */ > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/mmu_context.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/mmu_context.h > --- linux-2.6.16.5-tcl1/include/asm-arm/mmu_context.h 2006-05-07 15:36:58.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/mmu_context.h 2006-07-16 15:01:24.000000000 +0200 > @@ -82,14 +82,17 @@ static inline void > switch_mm(struct mm_struct *prev, struct mm_struct *next, > struct task_struct *tsk) > { > - unsigned int cpu = smp_processor_id(); > + unsigned int cpu = smp_processor_id_hw(); > > if (prev != next) { > + unsigned long flags; > + local_irq_save_hw_cond(flags); > cpu_set(cpu, next->cpu_vm_mask); > check_context(next); > cpu_switch_mm(next->pgd, next); > if (cache_is_vivt()) > cpu_clear(cpu, prev->cpu_vm_mask); > + local_irq_restore_hw_cond(flags); > } > } > > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/pgalloc.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/pgalloc.h > --- linux-2.6.16.5-tcl1/include/asm-arm/pgalloc.h 2005-10-28 02:02:08.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/pgalloc.h 2006-07-16 15:01:24.000000000 +0200 > @@ -29,6 +29,11 @@ extern void free_pgd_slow(pgd_t *pgd); > > #define check_pgt_cache() do { } while (0) > > +static inline void set_pgdir(unsigned long address, pgd_t entry) > +{ > + /* nop */ > +} > + > /* > * Allocate one PTE table. > * > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/system.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/system.h > --- linux-2.6.16.5-tcl1/include/asm-arm/system.h 2006-05-07 16:42:05.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/system.h 2006-07-17 18:40:59.000000000 +0200 > @@ -186,30 +186,30 @@ static inline void sched_cacheflush(void > */ > #if __LINUX_ARM_ARCH__ >= 6 > > -#define local_irq_save(x) \ > +#define local_irq_save_hw(x) \ > ({ \ > __asm__ __volatile__( \ > - "mrs %0, cpsr @ local_irq_save\n" \ > + "mrs %0, cpsr @ local_irq_save_hw\n" \ > "cpsid i" \ > : "=r" (x) : : "memory", "cc"); \ > }) > > -#define local_irq_enable() __asm__("cpsie i @ __sti" : : : "memory", "cc") > -#define local_irq_disable() __asm__("cpsid i @ __cli" : : : "memory", "cc") > -#define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc") > -#define local_fiq_disable() __asm__("cpsid f @ __clf" : : : "memory", "cc") > +#define local_irq_enable_hw() __asm__("cpsie i @ __sti" : : : "memory", "cc") > +#define local_irq_disable_hw() __asm__("cpsid i @ __cli" : : : "memory", "cc") > +#define local_fiq_enable_hw() __asm__("cpsie f @ __stf" : : : "memory", "cc") > +#define local_fiq_disable_hw() __asm__("cpsid f @ __clf" : : : "memory", "cc") > > #else > > /* > * Save the current interrupt enable state & disable IRQs > */ > -#define local_irq_save(x) \ > +#define local_irq_save_hw(x) \ > ({ \ > unsigned long temp; \ > (void) (&temp == &x); \ > __asm__ __volatile__( \ > - "mrs %0, cpsr @ local_irq_save\n" \ > + "mrs %0, cpsr @ local_irq_save_hw\n" \ > " orr %1, %0, #128\n" \ > " msr cpsr_c, %1" \ > : "=r" (x), "=r" (temp) \ > @@ -220,11 +220,11 @@ static inline void sched_cacheflush(void > /* > * Enable IRQs > */ > -#define local_irq_enable() \ > +#define local_irq_enable_hw() \ > ({ \ > unsigned long temp; \ > __asm__ __volatile__( \ > - "mrs %0, cpsr @ local_irq_enable\n" \ > + "mrs %0, cpsr @ local_irq_enable_hw\n"\ > " bic %0, %0, #128\n" \ > " msr cpsr_c, %0" \ > : "=r" (temp) \ > @@ -235,11 +235,11 @@ static inline void sched_cacheflush(void > /* > * Disable IRQs > */ > -#define local_irq_disable() \ > +#define local_irq_disable_hw() \ > ({ \ > unsigned long temp; \ > __asm__ __volatile__( \ > - "mrs %0, cpsr @ local_irq_disable\n" \ > + "mrs %0, cpsr @ local_irq_disable_hw\n"\ > " orr %0, %0, #128\n" \ > " msr cpsr_c, %0" \ > : "=r" (temp) \ > @@ -250,7 +250,7 @@ static inline void sched_cacheflush(void > /* > * Enable FIQs > */ > -#define local_fiq_enable() \ > +#define local_fiq_enable_hw() \ > ({ \ > unsigned long temp; \ > __asm__ __volatile__( \ > @@ -265,7 +265,7 @@ static inline void sched_cacheflush(void > /* > * Disable FIQs > */ > -#define local_fiq_disable() \ > +#define local_fiq_disable_hw() \ > ({ \ > unsigned long temp; \ > __asm__ __volatile__( \ > @@ -282,29 +282,63 @@ static inline void sched_cacheflush(void > /* > * Save the current interrupt enable state. > */ > -#define local_save_flags(x) \ > +#define local_save_flags_hw(x) \ > ({ \ > __asm__ __volatile__( \ > - "mrs %0, cpsr @ local_save_flags" \ > + "mrs %0, cpsr @ local_save_flags_hw" \ > : "=r" (x) : : "memory", "cc"); \ > }) > > /* > * restore saved IRQ & FIQ state > */ > -#define local_irq_restore(x) \ > +#define local_irq_restore_hw(x) \ > __asm__ __volatile__( \ > - "msr cpsr_c, %0 @ local_irq_restore\n" \ > + "msr cpsr_c, %0 @ local_irq_restore_hw\n"\ > : \ > : "r" (x) \ > : "memory", "cc") > > -#define irqs_disabled() \ > -({ \ > +#define irqs_disabled_hw() \ > + ({ \ > unsigned long flags; \ > - local_save_flags(flags); \ > + local_save_flags_hw(flags); \ > (int)(flags & PSR_I_BIT); \ > -}) > + }) > + > + > +#ifdef CONFIG_IPIPE > + > +void __ipipe_stall_root(void); > +void __ipipe_unstall_root(void); > +unsigned long __ipipe_test_root(void); > +unsigned long __ipipe_test_and_stall_root(void); > +void __ipipe_restore_root(unsigned long flags); > + > +/* PSR_I_BIT is bit no. 7 and is set if interrupts are _disabled_ */ > +#define local_irq_save(flags) ((flags) = __ipipe_test_and_stall_root() << 7) > +#define local_irq_enable() __ipipe_unstall_root() > +#define local_irq_disable() __ipipe_stall_root() > +#define local_fiq_enable() __ipipe_unstall_root() > +#define local_fiq_disable() __ipipe_stall_root() > +#define local_save_flags(flags) ((flags) = __ipipe_test_root() << 7) > +#define local_irq_restore(flags) __ipipe_restore_root(flags & (1 << 7)) > + > +#define irqs_disabled() __ipipe_test_root() > + > +#else /* !CONFIG_IPIPE */ > + > +#define local_irq_save(flags) local_irq_save_hw(flags) > +#define local_irq_enable() local_irq_enable_hw() > +#define local_irq_disable() local_irq_disable_hw() > +#define local_fiq_enable() local_fiq_enable_hw() > +#define local_fiq_disable() local_fiq_disable_hw() > +#define local_save_flags(flags) local_save_flags_hw(flags) > +#define local_irq_restore(flags) local_irq_restore_hw(flags) > + > +#define irqs_disabled() irqs_disabled_hw() > + > +#endif /* CONFIG_IPIPE */ > > #ifdef CONFIG_SMP > > @@ -379,17 +413,17 @@ static inline unsigned long __xchg(unsig > #error SMP is not supported on this platform > #endif > case 1: > - local_irq_save(flags); > + local_irq_save_hw(flags); > ret = *(volatile unsigned char *)ptr; > *(volatile unsigned char *)ptr = x; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > break; > > case 4: > - local_irq_save(flags); > + local_irq_save_hw(flags); > ret = *(volatile unsigned long *)ptr; > *(volatile unsigned long *)ptr = x; > - local_irq_restore(flags); > + local_irq_restore_hw(flags); > break; > #else > case 1: > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/hardirq.h linux-2.6.16.5-tcl1-ipipe/include/linux/hardirq.h > --- linux-2.6.16.5-tcl1/include/linux/hardirq.h 2006-05-07 16:42:11.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/linux/hardirq.h 2006-07-16 15:01:24.000000000 +0200 > @@ -87,8 +87,21 @@ extern void synchronize_irq(unsigned int > # define synchronize_irq(irq) barrier() > #endif > > +#ifdef CONFIG_IPIPE > +#define nmi_enter() \ > +do { \ > + if (ipipe_current_domain == ipipe_root_domain) \ > + irq_enter(); \ > +} while(0) > +#define nmi_exit() \ > +do { \ > + if (ipipe_current_domain == ipipe_root_domain) \ > + sub_preempt_count(HARDIRQ_OFFSET); \ > +} while(0) > +#else /* !CONFIG_IPIPE */ > #define nmi_enter() irq_enter() > #define nmi_exit() sub_preempt_count(HARDIRQ_OFFSET) > +#endif /* CONFIG_IPIPE */ > > struct task_struct; > > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/ipipe.h linux-2.6.16.5-tcl1-ipipe/include/linux/ipipe.h > --- linux-2.6.16.5-tcl1/include/linux/ipipe.h 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.5-tcl1-ipipe/include/linux/ipipe.h 2006-07-16 15:01:24.000000000 +0200 > @@ -0,0 +1,699 @@ > +/* -*- linux-c -*- > + * include/linux/ipipe.h > + * > + * Copyright (C) 2002-2005 Philippe Gerum. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, > + * USA; either version 2 of the License, or (at your option) any later > + * version. > + * > + * 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. > + */ > + > +#ifndef __LINUX_IPIPE_H > +#define __LINUX_IPIPE_H > + > +#include > +#include > +#include > +#include > + > +#ifdef CONFIG_IPIPE > + > +#define IPIPE_VERSION_STRING IPIPE_ARCH_STRING > +#define IPIPE_RELEASE_NUMBER ((IPIPE_MAJOR_NUMBER << 16) | \ > + (IPIPE_MINOR_NUMBER << 8) | \ > + (IPIPE_PATCH_NUMBER)) > + > +#ifndef BROKEN_BUILTIN_RETURN_ADDRESS > +#define __BUILTIN_RETURN_ADDRESS0 ((unsigned long)__builtin_return_address(0)) > +#define __BUILTIN_RETURN_ADDRESS1 ((unsigned long)__builtin_return_address(1)) > +#endif /* !BUILTIN_RETURN_ADDRESS */ > + > +#define IPIPE_ROOT_PRIO 100 > +#define IPIPE_ROOT_ID 0 > +#define IPIPE_ROOT_NPTDKEYS 4 /* Must be <= BITS_PER_LONG */ > + > +#define IPIPE_RESET_TIMER 0x1 > +#define IPIPE_GRAB_TIMER 0x2 > + > +/* Global domain flags */ > +#define IPIPE_SPRINTK_FLAG 0 /* Synchronous printk() allowed */ > +#define IPIPE_AHEAD_FLAG 1 /* Domain always heads the pipeline */ > + > +#define IPIPE_STALL_FLAG 0 /* Stalls a pipeline stage -- guaranteed at bit #0 */ > +#define IPIPE_SYNC_FLAG 1 /* The interrupt syncer is running for the domain */ > + > +#define IPIPE_SYNC_MASK (1 << IPIPE_SYNC_FLAG) > + > +#define IPIPE_HANDLE_FLAG 0 > +#define IPIPE_PASS_FLAG 1 > +#define IPIPE_ENABLE_FLAG 2 > +#define IPIPE_DYNAMIC_FLAG IPIPE_HANDLE_FLAG > +#define IPIPE_STICKY_FLAG 3 > +#define IPIPE_SYSTEM_FLAG 4 > +#define IPIPE_LOCK_FLAG 5 > +#define IPIPE_SHARED_FLAG 6 > +#define IPIPE_WIRED_FLAG 7 > +#define IPIPE_EXCLUSIVE_FLAG 8 > + > +#define IPIPE_HANDLE_MASK (1 << IPIPE_HANDLE_FLAG) > +#define IPIPE_PASS_MASK (1 << IPIPE_PASS_FLAG) > +#define IPIPE_ENABLE_MASK (1 << IPIPE_ENABLE_FLAG) > +#define IPIPE_DYNAMIC_MASK IPIPE_HANDLE_MASK > +#define IPIPE_STICKY_MASK (1 << IPIPE_STICKY_FLAG) > +#define IPIPE_SYSTEM_MASK (1 << IPIPE_SYSTEM_FLAG) > +#define IPIPE_LOCK_MASK (1 << IPIPE_LOCK_FLAG) > +#define IPIPE_SHARED_MASK (1 << IPIPE_SHARED_FLAG) > +#define IPIPE_WIRED_MASK (1 << IPIPE_WIRED_FLAG) > +#define IPIPE_EXCLUSIVE_MASK (1 << IPIPE_EXCLUSIVE_FLAG) > + > +#define IPIPE_DEFAULT_MASK (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK) > +#define IPIPE_STDROOT_MASK (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_SYSTEM_MASK) > + > +#define IPIPE_EVENT_SELF 0x80000000 > + > +/* Number of virtual IRQs */ > +#define IPIPE_NR_VIRQS BITS_PER_LONG > +/* First virtual IRQ # */ > +#define IPIPE_VIRQ_BASE (((IPIPE_NR_XIRQS + BITS_PER_LONG - 1) / BITS_PER_LONG) * BITS_PER_LONG) > +/* Total number of IRQ slots */ > +#define IPIPE_NR_IRQS (IPIPE_VIRQ_BASE + IPIPE_NR_VIRQS) > +/* Number of indirect words needed to map the whole IRQ space. */ > +#define IPIPE_IRQ_IWORDS ((IPIPE_NR_IRQS + BITS_PER_LONG - 1) / BITS_PER_LONG) > +#define IPIPE_IRQ_IMASK (BITS_PER_LONG - 1) > +#define IPIPE_IRQMASK_ANY (~0L) > +#define IPIPE_IRQMASK_VIRT (IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG)) > + > +#ifdef CONFIG_SMP > + > +#define IPIPE_NR_CPUS NR_CPUS > +#define ipipe_declare_cpuid int cpuid > +#define ipipe_load_cpuid() do { \ > + (cpuid) = ipipe_processor_id(); \ > + } while(0) > +#define ipipe_lock_cpu(flags) do { \ > + local_irq_save_hw(flags); \ > + (cpuid) = ipipe_processor_id(); \ > + } while(0) > +#define ipipe_unlock_cpu(flags) local_irq_restore_hw(flags) > +#define ipipe_get_cpu(flags) ipipe_lock_cpu(flags) > +#define ipipe_put_cpu(flags) ipipe_unlock_cpu(flags) > +#define ipipe_current_domain (ipipe_percpu_domain[ipipe_processor_id()]) > + > +#else /* !CONFIG_SMP */ > + > +#define IPIPE_NR_CPUS 1 > +#define ipipe_declare_cpuid const int cpuid = 0 > +#define ipipe_load_cpuid() do { } while(0) > +#define ipipe_lock_cpu(flags) local_irq_save_hw(flags) > +#define ipipe_unlock_cpu(flags) local_irq_restore_hw(flags) > +#define ipipe_get_cpu(flags) do { (void)(flags); } while(0) > +#define ipipe_put_cpu(flags) do { } while(0) > +#define ipipe_current_domain (ipipe_percpu_domain[0]) > + > +#endif /* CONFIG_SMP */ > + > +#define ipipe_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && \ > + (irq) < IPIPE_NR_IRQS) > + > +typedef void (*ipipe_irq_handler_t)(unsigned irq, > + void *cookie); > + > +#define IPIPE_SAME_HANDLER ((ipipe_irq_handler_t)(-1)) > + > +typedef int (*ipipe_irq_ackfn_t)(unsigned irq); > + > +typedef int (*ipipe_event_handler_t)(unsigned event, > + struct ipipe_domain *from, > + void *data); > +struct ipipe_domain { > + > + struct list_head p_link; /* Link in pipeline */ > + > + struct ipcpudata { > + unsigned long status; > + unsigned long irq_pending_hi; > + unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS]; > + struct ipirqcnt { > + unsigned long pending_hits; > + unsigned long total_hits; > + } irq_counters[IPIPE_NR_IRQS]; > + } ____cacheline_aligned_in_smp cpudata[IPIPE_NR_CPUS]; > + > + struct { > + unsigned long control; > + ipipe_irq_ackfn_t acknowledge; > + ipipe_irq_handler_t handler; > + void *cookie; > + } ____cacheline_aligned irqs[IPIPE_NR_IRQS]; > + > + ipipe_event_handler_t evhand[IPIPE_NR_EVENTS]; /* Event handlers. */ > + unsigned long long evself; /* Self-monitored event bits. */ > + unsigned long flags; > + unsigned domid; > + const char *name; > + int priority; > + void *pdd; > +}; > + > +#define IPIPE_HEAD_PRIORITY (-1) /* For domains always heading the pipeline */ > + > +struct ipipe_domain_attr { > + > + unsigned domid; /* Domain identifier -- Magic value set by caller */ > + const char *name; /* Domain name -- Warning: won't be dup'ed! */ > + int priority; /* Priority in interrupt pipeline */ > + void (*entry) (void); /* Domain entry point */ > + void *pdd; /* Per-domain (opaque) data pointer */ > +}; > + > +/* The following macros must be used hw interrupts off. */ > + > +#define __ipipe_irq_cookie(ipd,irq) (ipd)->irqs[irq].cookie > +#define __ipipe_irq_handler(ipd,irq) (ipd)->irqs[irq].handler > + > +#define __ipipe_cpudata_irq_hits(ipd,cpuid,irq) ((ipd)->cpudata[cpuid].irq_counters[irq].total_hits) > + > +#define __ipipe_set_irq_bit(ipd,cpuid,irq) \ > +do { \ > + if (!test_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) { \ > + __set_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ > + __set_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[cpuid].irq_pending_hi); \ > + } \ > +} while(0) > + > +#define __ipipe_clear_pend(ipd,cpuid,irq) \ > +do { \ > + __clear_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ > + if ((ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT] == 0) \ > + __clear_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[cpuid].irq_pending_hi); \ > +} while(0) > + > +#define __ipipe_lock_irq(ipd,cpuid,irq) \ > +do { \ > + if (!test_and_set_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) \ > + __ipipe_clear_pend(ipd,cpuid,irq); \ > +} while(0) > + > +#define __ipipe_unlock_irq(ipd,irq) \ > +do { \ > + int __cpuid, __nr_cpus = num_online_cpus(); \ > + if (test_and_clear_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) \ > + for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) \ > + if ((ipd)->cpudata[__cpuid].irq_counters[irq].pending_hits > 0) { /* We need atomic ops next. */ \ > + set_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[__cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ > + set_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[__cpuid].irq_pending_hi); \ > + } \ > +} while(0) > + > +#define __ipipe_clear_irq(ipd,irq) \ > +do { \ > + int __cpuid, __nr_cpus = num_online_cpus(); \ > + clear_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control); \ > + for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) { \ > + (ipd)->cpudata[__cpuid].irq_counters[irq].pending_hits = 0; \ > + __ipipe_clear_pend(ipd,__cpuid,irq); \ > + } \ > +} while(0) > + > +#ifdef __RAW_SPIN_LOCK_UNLOCKED > +#define spin_lock_hw(x) _raw_spin_lock(x) > +#define spin_trylock_hw(x) _raw_spin_trylock(x) > +#define spin_unlock_hw(x) _raw_spin_unlock(x) > +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) > +#define write_lock_hw(x) _raw_write_lock(x) > +#define write_trylock_hw(x) _raw_write_trylock(x) > +#define write_unlock_hw(x) _raw_write_unlock(x) > +#define read_lock_hw(x) _raw_read_lock(x) > +#define read_trylock_hw(x) _raw_read_trylock(x) > +#define read_unlock_hw(x) _raw_read_unlock(x) > +#else /* UP non-debug */ > +#define write_lock_hw(lock) do { (void)(lock); } while (0) > +#define write_trylock_hw(lock) ({ (void)(lock); 1; }) > +#define write_unlock_hw(lock) do { (void)(lock); } while (0) > +#define read_lock_hw(lock) do { (void)(lock); } while (0) > +#define read_trylock_hw(lock) ({ (void)(lock); 1; }) > +#define read_unlock_hw(lock) do { (void)(lock); } while (0) > +#endif /* CONFIG_SMP || CONFIG_DEBUG_SPINLOCK */ > +#else /* !__RAW_SPIN_LOCK_UNLOCKED */ > +#define spin_lock_hw(x) _spin_lock(x) > +#define spin_unlock_hw(x) _spin_unlock(x) > +#define spin_trylock_hw(x) _spin_trylock(x) > +#define write_lock_hw(x) _write_lock(x) > +#define write_unlock_hw(x) _write_unlock(x) > +#define write_trylock_hw(x) _write_trylock(x) > +#define read_lock_hw(x) _read_lock(x) > +#define read_unlock_hw(x) _read_unlock(x) > +#endif /* __RAW_SPIN_LOCK_UNLOCKED */ > + > +typedef spinlock_t ipipe_spinlock_t; > +typedef rwlock_t ipipe_rwlock_t; > +#define IPIPE_SPIN_LOCK_UNLOCKED SPIN_LOCK_UNLOCKED > +#define IPIPE_RW_LOCK_UNLOCKED RW_LOCK_UNLOCKED > + > +#define spin_lock_irqsave_hw(x,flags) \ > +do { \ > + local_irq_save_hw(flags); \ > + spin_lock_hw(x); \ > +} while (0) > + > +#define spin_unlock_irqrestore_hw(x,flags) \ > +do { \ > + spin_unlock_hw(x); \ > + local_irq_restore_hw(flags); \ > +} while (0) > + > +#define spin_lock_irq_hw(x) \ > +do { \ > + local_irq_disable_hw(); \ > + spin_lock_hw(x); \ > +} while (0) > + > +#define spin_unlock_irq_hw(x) \ > +do { \ > + spin_unlock_hw(x); \ > + local_irq_enable_hw(); \ > +} while (0) > + > +#define read_lock_irqsave_hw(lock, flags) \ > +do { \ > + local_irq_save_hw(flags); \ > + read_lock_hw(lock); \ > +} while (0) > + > +#define read_unlock_irqrestore_hw(lock, flags) \ > +do { \ > + read_unlock_hw(lock); \ > + local_irq_restore_hw(flags); \ > +} while (0) > + > +#define write_lock_irqsave_hw(lock, flags) \ > +do { \ > + local_irq_save_hw(flags); \ > + write_lock_hw(lock); \ > +} while (0) > + > +#define write_unlock_irqrestore_hw(lock, flags) \ > +do { \ > + write_unlock_hw(lock); \ > + local_irq_restore_hw(flags); \ > +} while (0) > + > +extern struct ipipe_domain *ipipe_percpu_domain[], *ipipe_root_domain; > + > +extern unsigned __ipipe_printk_virq; > + > +extern unsigned long __ipipe_virtual_irq_map; > + > +extern struct list_head __ipipe_pipeline; > + > +extern ipipe_spinlock_t __ipipe_pipelock; > + > +extern int __ipipe_event_monitors[]; > + > +/* Private interface */ > + > +void ipipe_init(void); > + > +#ifdef CONFIG_PROC_FS > +void ipipe_init_proc(void); > + > +#ifdef CONFIG_IPIPE_TRACE > +void __ipipe_init_trace_proc(void); > +#else /* !CONFIG_IPIPE_TRACE */ > +#define __ipipe_init_trace_proc() do { } while(0) > +#endif /* CONFIG_IPIPE_TRACE */ > + > +#else /* !CONFIG_PROC_FS */ > +#define ipipe_init_proc() do { } while(0) > +#endif /* CONFIG_PROC_FS */ > + > +void __ipipe_init_stage(struct ipipe_domain *ipd); > + > +void __ipipe_cleanup_domain(struct ipipe_domain *ipd); > + > +void __ipipe_add_domain_proc(struct ipipe_domain *ipd); > + > +void __ipipe_remove_domain_proc(struct ipipe_domain *ipd); > + > +void __ipipe_flush_printk(unsigned irq, void *cookie); > + > +void __ipipe_stall_root(void); > + > +void __ipipe_unstall_root(void); > + > +unsigned long __ipipe_test_root(void); > + > +unsigned long __ipipe_test_and_stall_root(void); > + > +void fastcall __ipipe_walk_pipeline(struct list_head *pos, int cpuid); > + > +void fastcall __ipipe_restore_root(unsigned long x); > + > +int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head); > + > +int fastcall __ipipe_dispatch_event(unsigned event, void *data); > + > +int fastcall __ipipe_dispatch_wired(struct ipipe_domain *head, unsigned irq); > + > +void fastcall __ipipe_sync_stage(unsigned long syncmask); > + > +#ifndef __ipipe_sync_pipeline > +#define __ipipe_sync_pipeline(syncmask) __ipipe_sync_stage(syncmask) > +#endif > + > +#ifndef __ipipe_run_irqtail > +#define __ipipe_run_irqtail() do { } while(0) > +#endif > + > +#define __ipipe_pipeline_head_p(ipd) (&(ipd)->p_link == __ipipe_pipeline.next) > + > +/* > + * Keep the following as a macro, so that client code could check for > + * the support of the invariant pipeline head optimization. > + */ > +#define __ipipe_pipeline_head() list_entry(__ipipe_pipeline.next,struct ipipe_domain,p_link) > + > +#define __ipipe_event_pipelined_p(ev) \ > + (__ipipe_event_monitors[ev] > 0 || (ipipe_current_domain->evself & (1LL << ev))) > + > +#ifdef CONFIG_SMP > + > +cpumask_t __ipipe_set_irq_affinity(unsigned irq, > + cpumask_t cpumask); > + > +int fastcall __ipipe_send_ipi(unsigned ipi, > + cpumask_t cpumask); > + > +#endif /* CONFIG_SMP */ > + > +/* Called with hw interrupts off. */ > +static inline void __ipipe_switch_to(struct ipipe_domain *out, > + struct ipipe_domain *in, int cpuid) > +{ > + void ipipe_suspend_domain(void); > + > + /* > + * "in" is guaranteed to be closer than "out" from the head of the > + * pipeline (and obviously different). > + */ > + > + ipipe_percpu_domain[cpuid] = in; > + > + ipipe_suspend_domain(); /* Sync stage and propagate interrupts. */ > + ipipe_load_cpuid(); /* Processor might have changed. */ > + > + if (ipipe_percpu_domain[cpuid] == in) > + /* > + * Otherwise, something has changed the current domain under > + * our feet recycling the register set; do not override. > + */ > + ipipe_percpu_domain[cpuid] = out; > +} > + > +static inline void ipipe_sigwake_notify(struct task_struct *p) > +{ > + if (__ipipe_event_pipelined_p(IPIPE_EVENT_SIGWAKE)) > + __ipipe_dispatch_event(IPIPE_EVENT_SIGWAKE,p); > +} > + > +static inline void ipipe_setsched_notify(struct task_struct *p) > +{ > + if (__ipipe_event_pipelined_p(IPIPE_EVENT_SETSCHED)) > + __ipipe_dispatch_event(IPIPE_EVENT_SETSCHED,p); > +} > + > +static inline void ipipe_exit_notify(struct task_struct *p) > +{ > + if (__ipipe_event_pipelined_p(IPIPE_EVENT_EXIT)) > + __ipipe_dispatch_event(IPIPE_EVENT_EXIT,p); > +} > + > +static inline int ipipe_trap_notify(int ex, struct pt_regs *regs) > +{ > + return __ipipe_event_pipelined_p(ex) ? __ipipe_dispatch_event(ex,regs) : 0; > +} > + > +struct mm_struct; > + > +static inline void ipipe_cleanup_notify(struct mm_struct *mm) > +{ > + if (__ipipe_event_pipelined_p(IPIPE_EVENT_CLEANUP)) > + __ipipe_dispatch_event(IPIPE_EVENT_CLEANUP,mm); > +} > + > +/* Public interface */ > + > +int ipipe_register_domain(struct ipipe_domain *ipd, > + struct ipipe_domain_attr *attr); > + > +int ipipe_unregister_domain(struct ipipe_domain *ipd); > + > +void ipipe_suspend_domain(void); > + > +int ipipe_virtualize_irq(struct ipipe_domain *ipd, > + unsigned irq, > + ipipe_irq_handler_t handler, > + void *cookie, > + ipipe_irq_ackfn_t acknowledge, > + unsigned modemask); > + > +static inline int ipipe_share_irq(unsigned irq, > + ipipe_irq_ackfn_t acknowledge) > +{ > + return ipipe_virtualize_irq(ipipe_current_domain, > + irq, > + IPIPE_SAME_HANDLER, > + NULL, > + acknowledge, > + IPIPE_SHARED_MASK | IPIPE_HANDLE_MASK | > + IPIPE_PASS_MASK); > +} > + > +int ipipe_control_irq(unsigned irq, > + unsigned clrmask, > + unsigned setmask); > + > +unsigned ipipe_alloc_virq(void); > + > +int ipipe_free_virq(unsigned virq); > + > +int fastcall ipipe_trigger_irq(unsigned irq); > + > +static inline int ipipe_propagate_irq(unsigned irq) > +{ > + return __ipipe_schedule_irq(irq, ipipe_current_domain->p_link.next); > +} > + > +static inline int ipipe_schedule_irq(unsigned irq) > +{ > + return __ipipe_schedule_irq(irq, &ipipe_current_domain->p_link); > +} > + > +void fastcall ipipe_stall_pipeline_from(struct ipipe_domain *ipd); > + > +unsigned long fastcall ipipe_test_and_stall_pipeline_from(struct ipipe_domain *ipd); > + > +void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd); > + > +unsigned long fastcall ipipe_test_and_unstall_pipeline_from(struct ipipe_domain *ipd); > + > +void fastcall ipipe_restore_pipeline_from(struct ipipe_domain *ipd, > + unsigned long x); > + > +static inline unsigned long ipipe_test_pipeline_from(struct ipipe_domain *ipd) > +{ > + unsigned long flags, x; > + ipipe_declare_cpuid; > + > + ipipe_get_cpu(flags); > + x = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > + ipipe_put_cpu(flags); > + > + return x; > +} > + > +static inline void ipipe_restore_pipeline_nosync(struct ipipe_domain *ipd, > + unsigned long x, int cpuid) > +{ > + /* > + * If cpuid is current, then it must be held on entry > + * (ipipe_get_cpu/local_irq_save_hw/local_irq_disable_hw). > + */ > + > + if (x) > + __set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > + else > + __clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > +} > + > +static inline void ipipe_stall_pipeline_head(void) > +{ > + ipipe_declare_cpuid; > + unsigned long flags; > + > + ipipe_lock_cpu(flags); > + __set_bit(IPIPE_STALL_FLAG, &__ipipe_pipeline_head()->cpudata[cpuid].status); > +} > + > +static inline unsigned long ipipe_test_and_stall_pipeline_head(void) > +{ > + unsigned long flags; > + ipipe_declare_cpuid; > + > + ipipe_lock_cpu(flags); > + return __test_and_set_bit(IPIPE_STALL_FLAG, &__ipipe_pipeline_head()->cpudata[cpuid].status); > +} > + > +void ipipe_unstall_pipeline_head(void); > + > +void fastcall __ipipe_restore_pipeline_head(struct ipipe_domain *head, > + unsigned long x); > + > +static inline void ipipe_restore_pipeline_head(unsigned long x) > +{ > + struct ipipe_domain *head = __ipipe_pipeline_head(); > + /* On some archs, __test_and_set_bit() might return different > + * truth value than test_bit(), so we test the exclusive OR of > + * both statuses, assuming that the lowest bit is always set in > + * the truth value (if this is wrong, the failed optimization will > + * be caught in __ipipe_restore_pipeline_head() if > + * CONFIG_DEBUG_KERNEL is set). */ > + if ((x ^ test_bit(IPIPE_STALL_FLAG, &head->cpudata[ipipe_processor_id()].status)) & 1) > + __ipipe_restore_pipeline_head(head,x); > +} > + > +#define ipipe_unstall_pipeline() \ > + ipipe_unstall_pipeline_from(ipipe_current_domain) > + > +#define ipipe_test_and_unstall_pipeline() \ > + ipipe_test_and_unstall_pipeline_from(ipipe_current_domain) > + > +#define ipipe_test_pipeline() \ > + ipipe_test_pipeline_from(ipipe_current_domain) > + > +#define ipipe_test_and_stall_pipeline() \ > + ipipe_test_and_stall_pipeline_from(ipipe_current_domain) > + > +#define ipipe_stall_pipeline() \ > + ipipe_stall_pipeline_from(ipipe_current_domain) > + > +#define ipipe_restore_pipeline(x) \ > + ipipe_restore_pipeline_from(ipipe_current_domain, (x)) > + > +void ipipe_init_attr(struct ipipe_domain_attr *attr); > + > +int ipipe_get_sysinfo(struct ipipe_sysinfo *sysinfo); > + > +int ipipe_tune_timer(unsigned long ns, > + int flags); > + > +unsigned long ipipe_critical_enter(void (*syncfn) (void)); > + > +void ipipe_critical_exit(unsigned long flags); > + > +static inline void ipipe_set_printk_sync(struct ipipe_domain *ipd) > +{ > + set_bit(IPIPE_SPRINTK_FLAG, &ipd->flags); > +} > + > +static inline void ipipe_set_printk_async(struct ipipe_domain *ipd) > +{ > + clear_bit(IPIPE_SPRINTK_FLAG, &ipd->flags); > +} > + > +ipipe_event_handler_t ipipe_catch_event(struct ipipe_domain *ipd, > + unsigned event, > + ipipe_event_handler_t handler); > + > +cpumask_t ipipe_set_irq_affinity(unsigned irq, > + cpumask_t cpumask); > + > +int fastcall ipipe_send_ipi(unsigned ipi, > + cpumask_t cpumask); > + > +int ipipe_setscheduler_root(struct task_struct *p, > + int policy, > + int prio); > + > +int ipipe_reenter_root(struct task_struct *prev, > + int policy, > + int prio); > + > +int ipipe_alloc_ptdkey(void); > + > +int ipipe_free_ptdkey(int key); > + > +int fastcall ipipe_set_ptd(int key, > + void *value); > + > +void fastcall *ipipe_get_ptd(int key); > + > +#define local_irq_enable_hw_cond() local_irq_enable_hw() > +#define local_irq_disable_hw_cond() local_irq_disable_hw() > +#define local_irq_save_hw_cond(flags) local_irq_save_hw(flags) > +#define local_irq_restore_hw_cond(flags) local_irq_restore_hw(flags) > +#define spin_lock_irqsave_hw_cond(lock,flags) spin_lock_irqsave_hw(lock,flags) > +#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock_irqrestore_hw(lock,flags) > +#define smp_processor_id_hw() ipipe_processor_id() > + > +#define ipipe_irq_lock(irq) \ > + do { \ > + ipipe_declare_cpuid; \ > + ipipe_load_cpuid(); \ > + __ipipe_lock_irq(ipipe_percpu_domain[cpuid], cpuid, irq);\ > + } while(0) > + > +#define ipipe_irq_unlock(irq) \ > + do { \ > + ipipe_declare_cpuid; \ > + ipipe_load_cpuid(); \ > + __ipipe_unlock_irq(ipipe_percpu_domain[cpuid], irq); \ > + } while(0) > + > +#define ipipe_root_domain_p (ipipe_current_domain == ipipe_root_domain) > + > +#else /* !CONFIG_IPIPE */ > + > +#define ipipe_init() do { } while(0) > +#define ipipe_suspend_domain() do { } while(0) > +#define ipipe_sigwake_notify(p) do { } while(0) > +#define ipipe_setsched_notify(p) do { } while(0) > +#define ipipe_exit_notify(p) do { } while(0) > +#define ipipe_init_proc() do { } while(0) > +#define ipipe_trap_notify(t,r) 0 > +#define ipipe_cleanup_notify(mm) do { } while(0) > + > +#define spin_lock_hw(lock) spin_lock(lock) > +#define spin_unlock_hw(lock) spin_unlock(lock) > +#define spin_lock_irq_hw(lock) spin_lock_irq(lock) > +#define spin_unlock_irq_hw(lock) spin_unlock_irq(lock) > +#define spin_lock_irqsave_hw(lock,flags) spin_lock_irqsave(lock, flags) > +#define spin_unlock_irqrestore_hw(lock,flags) spin_unlock_irqrestore(lock, flags) > + > +#define local_irq_enable_hw_cond() do { } while(0) > +#define local_irq_disable_hw_cond() do { } while(0) > +#define local_irq_save_hw_cond(flags) do { (void)(flags); } while(0) > +#define local_irq_restore_hw_cond(flags) do { } while(0) > +#define spin_lock_irqsave_hw_cond(lock,flags) do { (void)(flags); spin_lock(lock); } while(0) > +#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock(lock) > +#define smp_processor_id_hw() smp_processor_id() > + > +#define ipipe_irq_lock(irq) do { } while(0) > +#define ipipe_irq_unlock(irq) do { } while(0) > + > +#define ipipe_root_domain_p 1 > + > +#endif /* CONFIG_IPIPE */ > + > +#endif /* !__LINUX_IPIPE_H */ > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/linkage.h linux-2.6.16.5-tcl1-ipipe/include/linux/linkage.h > --- linux-2.6.16.5-tcl1/include/linux/linkage.h 2005-10-28 02:02:08.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/linux/linkage.h 2006-07-16 15:01:24.000000000 +0200 > @@ -51,4 +51,8 @@ > #define fastcall > #endif > > +#ifndef notrace > +#define notrace __attribute__((no_instrument_function)) > +#endif > + > #endif > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/preempt.h linux-2.6.16.5-tcl1-ipipe/include/linux/preempt.h > --- linux-2.6.16.5-tcl1/include/linux/preempt.h 2006-05-07 15:37:01.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/linux/preempt.h 2006-07-16 15:01:24.000000000 +0200 > @@ -27,29 +27,43 @@ > > asmlinkage void preempt_schedule(void); > > -#define preempt_disable() \ > -do { \ > - inc_preempt_count(); \ > - barrier(); \ > +#ifdef CONFIG_IPIPE > +#include > +extern struct ipipe_domain *ipipe_percpu_domain[], *ipipe_root_domain; > +#define ipipe_preempt_guard() (ipipe_percpu_domain[ipipe_processor_id()] == ipipe_root_domain) > +#else /* !CONFIG_IPIPE */ > +#define ipipe_preempt_guard() 1 > +#endif /* CONFIG_IPIPE */ > + > +#define preempt_disable() \ > +do { \ > + if (ipipe_preempt_guard()) { \ > + inc_preempt_count(); \ > + barrier(); \ > + } \ > } while (0) > > -#define preempt_enable_no_resched() \ > -do { \ > - barrier(); \ > - dec_preempt_count(); \ > +#define preempt_enable_no_resched() \ > +do { \ > + if (ipipe_preempt_guard()) { \ > + barrier(); \ > + dec_preempt_count(); \ > + } \ > } while (0) > > -#define preempt_check_resched() \ > -do { \ > - if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ > - preempt_schedule(); \ > +#define preempt_check_resched() \ > +do { \ > + if (ipipe_preempt_guard()) { \ > + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ > + preempt_schedule(); \ > + } \ > } while (0) > > -#define preempt_enable() \ > -do { \ > - preempt_enable_no_resched(); \ > +#define preempt_enable() \ > +do { \ > + preempt_enable_no_resched(); \ > barrier(); \ > - preempt_check_resched(); \ > + preempt_check_resched(); \ > } while (0) > > #else > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/sched.h linux-2.6.16.5-tcl1-ipipe/include/linux/sched.h > --- linux-2.6.16.5-tcl1/include/linux/sched.h 2006-05-07 16:42:13.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/include/linux/sched.h 2006-07-16 15:06:26.000000000 +0200 > @@ -4,6 +4,7 @@ > #include /* for HZ */ > > #include > +#include > #include > #include > #include > @@ -129,6 +130,11 @@ extern unsigned long nr_iowait(void); > #define EXIT_DEAD 32 > /* in tsk->state again */ > #define TASK_NONINTERACTIVE 64 > +#ifdef CONFIG_IPIPE > +#define TASK_ATOMICSWITCH 512 > +#else /* !CONFIG_IPIPE */ > +#define TASK_ATOMICSWITCH 0 > +#endif /* CONFIG_IPIPE */ > > #define __set_task_state(tsk, state_value) \ > do { (tsk)->state = (state_value); } while (0) > @@ -871,6 +877,9 @@ struct task_struct { > #endif > atomic_t fs_excl; /* holding fs exclusive resources */ > struct rcu_head rcu; > +#ifdef CONFIG_IPIPE > + void *ptd[IPIPE_ROOT_NPTDKEYS]; > +#endif > }; > > static inline pid_t process_group(struct task_struct *tsk) > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/init/Kconfig linux-2.6.16.5-tcl1-ipipe/init/Kconfig > --- linux-2.6.16.5-tcl1/init/Kconfig 2006-05-07 16:42:14.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/init/Kconfig 2006-07-16 15:01:24.000000000 +0200 > @@ -58,6 +58,7 @@ menu "General setup" > > config LOCALVERSION > string "Local version - append to kernel release" > + default "-ipipe" > help > Append an extra string to the end of your kernel version. > This will show up when you type uname, for example. > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/init/main.c linux-2.6.16.5-tcl1-ipipe/init/main.c > --- linux-2.6.16.5-tcl1/init/main.c 2006-07-15 20:06:03.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/init/main.c 2006-07-16 15:01:24.000000000 +0200 > @@ -488,6 +488,11 @@ asmlinkage void __init start_kernel(void > hrtimers_init(); > softirq_init(); > time_init(); > + /* > + * We need to wait for the interrupt and time subsystems to be > + * initialized before enabling the pipeline. > + */ > + ipipe_init(); > > /* > * HACK ALERT! This is early. We're enabling the console before > @@ -613,6 +618,7 @@ static void __init do_basic_setup(void) > #ifdef CONFIG_SYSCTL > sysctl_init(); > #endif > + ipipe_init_proc(); > > do_initcalls(); > } > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/Makefile linux-2.6.16.5-tcl1-ipipe/kernel/Makefile > --- linux-2.6.16.5-tcl1/kernel/Makefile 2006-05-07 16:42:15.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/Makefile 2006-07-16 15:01:24.000000000 +0200 > @@ -34,6 +34,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softl > obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ > obj-$(CONFIG_SECCOMP) += seccomp.o > obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o > +obj-$(CONFIG_IPIPE) += ipipe/ > > ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) > # According to Alan Modra , the -fno-omit-frame-pointer is > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/exit.c linux-2.6.16.5-tcl1-ipipe/kernel/exit.c > --- linux-2.6.16.5-tcl1/kernel/exit.c 2006-05-07 16:42:15.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/exit.c 2006-07-16 15:01:24.000000000 +0200 > @@ -852,6 +852,7 @@ fastcall NORET_TYPE void do_exit(long co > exit_itimers(tsk->signal); > acct_process(code); > } > + ipipe_exit_notify(tsk); > exit_mm(tsk); > > exit_sem(tsk); > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/fork.c linux-2.6.16.5-tcl1-ipipe/kernel/fork.c > --- linux-2.6.16.5-tcl1/kernel/fork.c 2006-07-13 15:49:59.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/fork.c 2006-07-16 15:15:30.000000000 +0200 > @@ -371,6 +371,7 @@ void fastcall __mmdrop(struct mm_struct > void mmput(struct mm_struct *mm) > { > if (atomic_dec_and_test(&mm->mm_users)) { > + ipipe_cleanup_notify(mm); > exit_aio(mm); > exit_mmap(mm); > if (!list_empty(&mm->mmlist)) { > @@ -1198,6 +1199,14 @@ static task_t *copy_process(unsigned lon > spin_unlock(¤t->sighand->siglock); > write_unlock_irq(&tasklist_lock); > proc_fork_connector(p); > +#ifdef CONFIG_IPIPE > + { > + int k; > + > + for (k = 0; k < IPIPE_ROOT_NPTDKEYS; k++) > + p->ptd[k] = NULL; > + } > +#endif /* CONFIG_IPIPE */ > return p; > > bad_fork_cleanup_namespace: > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/ipipe/Kconfig linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/Kconfig > --- linux-2.6.16.5-tcl1/kernel/ipipe/Kconfig 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/Kconfig 2006-07-16 15:01:24.000000000 +0200 > @@ -0,0 +1,6 @@ > +config IPIPE > + bool "Interrupt pipeline" > + default y > + ---help--- > + Activate this option if you want the interrupt pipeline to be > + compiled in. > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/ipipe/Makefile linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/Makefile > --- linux-2.6.16.5-tcl1/kernel/ipipe/Makefile 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/Makefile 2006-07-16 15:01:24.000000000 +0200 > @@ -0,0 +1,3 @@ > + > +obj-$(CONFIG_IPIPE) += core.o generic.o > +obj-$(CONFIG_IPIPE_TRACE) += tracer.o > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/ipipe/core.c linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/core.c > --- linux-2.6.16.5-tcl1/kernel/ipipe/core.c 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/core.c 2006-07-16 15:01:24.000000000 +0200 > @@ -0,0 +1,1044 @@ > +/* -*- linux-c -*- > + * linux/kernel/ipipe/core.c > + * > + * Copyright (C) 2002-2005 Philippe Gerum. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, > + * USA; either version 2 of the License, or (at your option) any later > + * version. > + * > + * 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. > + * > + * Architecture-independent I-PIPE core support. > + */ > + > +#include > +#include > +#include > +#include > +#ifdef CONFIG_PROC_FS > +#include > +#endif /* CONFIG_PROC_FS */ > + > +static struct ipipe_domain ipipe_root = > + { .cpudata = {[0 ... IPIPE_NR_CPUS-1] = > + { .status = (1< + > +struct ipipe_domain *ipipe_root_domain = &ipipe_root; > + > +struct ipipe_domain *ipipe_percpu_domain[IPIPE_NR_CPUS] = > + {[0 ... IPIPE_NR_CPUS - 1] = &ipipe_root }; > + > +ipipe_spinlock_t __ipipe_pipelock = IPIPE_SPIN_LOCK_UNLOCKED; > + > +LIST_HEAD(__ipipe_pipeline); > + > +unsigned long __ipipe_virtual_irq_map = 0; > + > +#ifdef CONFIG_PRINTK > +unsigned __ipipe_printk_virq; > +#endif /* CONFIG_PRINTK */ > + > +int __ipipe_event_monitors[IPIPE_NR_EVENTS]; > + > +/* > + * ipipe_init() -- Initialization routine of the IPIPE layer. Called > + * by the host kernel early during the boot procedure. > + */ > +void ipipe_init(void) > +{ > + struct ipipe_domain *ipd = &ipipe_root; > + > + __ipipe_check_platform(); /* Do platform dependent checks first. */ > + > + /* > + * A lightweight registration code for the root domain. We are > + * running on the boot CPU, hw interrupts are off, and > + * secondary CPUs are still lost in space. > + */ > + > + ipd->name = "Linux"; > + ipd->domid = IPIPE_ROOT_ID; > + ipd->priority = IPIPE_ROOT_PRIO; > + > + __ipipe_init_stage(ipd); > + > + INIT_LIST_HEAD(&ipd->p_link); > + list_add_tail(&ipd->p_link, &__ipipe_pipeline); > + > + __ipipe_init_platform(); > + > +#ifdef CONFIG_PRINTK > + __ipipe_printk_virq = ipipe_alloc_virq(); /* Cannot fail here. */ > + ipd->irqs[__ipipe_printk_virq].handler = &__ipipe_flush_printk; > + ipd->irqs[__ipipe_printk_virq].cookie = NULL; > + ipd->irqs[__ipipe_printk_virq].acknowledge = NULL; > + ipd->irqs[__ipipe_printk_virq].control = IPIPE_HANDLE_MASK; > +#endif /* CONFIG_PRINTK */ > + > + __ipipe_enable_pipeline(); > + > + printk(KERN_INFO "I-pipe %s: pipeline enabled.\n", > + IPIPE_VERSION_STRING); > +} > + > +void __ipipe_init_stage(struct ipipe_domain *ipd) > +{ > + int cpuid, n; > + > + for (cpuid = 0; cpuid < IPIPE_NR_CPUS; cpuid++) { > + ipd->cpudata[cpuid].irq_pending_hi = 0; > + > + for (n = 0; n < IPIPE_IRQ_IWORDS; n++) > + ipd->cpudata[cpuid].irq_pending_lo[n] = 0; > + > + for (n = 0; n < IPIPE_NR_IRQS; n++) { > + ipd->cpudata[cpuid].irq_counters[n].total_hits = 0; > + ipd->cpudata[cpuid].irq_counters[n].pending_hits = 0; > + } > + } > + > + for (n = 0; n < IPIPE_NR_IRQS; n++) { > + ipd->irqs[n].acknowledge = NULL; > + ipd->irqs[n].handler = NULL; > + ipd->irqs[n].control = IPIPE_PASS_MASK; /* Pass but don't handle */ > + } > + > + for (n = 0; n < IPIPE_NR_EVENTS; n++) > + ipd->evhand[n] = NULL; > + > + ipd->evself = 0; > + > +#ifdef CONFIG_SMP > + ipd->irqs[IPIPE_CRITICAL_IPI].acknowledge = &__ipipe_ack_system_irq; > + ipd->irqs[IPIPE_CRITICAL_IPI].handler = &__ipipe_do_critical_sync; > + ipd->irqs[IPIPE_CRITICAL_IPI].cookie = NULL; > + /* Immediately handle in the current domain but *never* pass */ > + ipd->irqs[IPIPE_CRITICAL_IPI].control = > + IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SYSTEM_MASK; > +#endif /* CONFIG_SMP */ > +} > + > +void __ipipe_stall_root(void) > +{ > + ipipe_declare_cpuid; > + unsigned long flags; > + > + ipipe_get_cpu(flags); /* Care for migration. */ > + > + set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status); > + > +#ifdef CONFIG_SMP > + if (!__ipipe_pipeline_head_p(ipipe_root_domain)) > + ipipe_put_cpu(flags); > +#else /* CONFIG_SMP */ > + if (__ipipe_pipeline_head_p(ipipe_root_domain)) > + local_irq_disable_hw(); > +#endif /* CONFIG_SMP */ > +} > + > +void __ipipe_cleanup_domain(struct ipipe_domain *ipd) > +{ > + ipipe_unstall_pipeline_from(ipd); > + > +#ifdef CONFIG_SMP > + { > + int cpu; > + > + for_each_online_cpu(cpu) { > + while (ipd->cpudata[cpu].irq_pending_hi != 0) > + cpu_relax(); > + } > + } > +#endif /* CONFIG_SMP */ > +} > + > +void __ipipe_unstall_root(void) > +{ > + ipipe_declare_cpuid; > + > + local_irq_disable_hw(); > + > + ipipe_load_cpuid(); > + > + __clear_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status); > + > + if (ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0) > + __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); > + > + local_irq_enable_hw(); > +} > + > +unsigned long __ipipe_test_root(void) > +{ > + unsigned long flags, x; > + ipipe_declare_cpuid; > + > + ipipe_get_cpu(flags); /* Care for migration. */ > + x = test_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status); > + ipipe_put_cpu(flags); > + > + return x; > +} > + > +unsigned long __ipipe_test_and_stall_root(void) > +{ > + unsigned long flags, x; > + ipipe_declare_cpuid; > + > + ipipe_get_cpu(flags); /* Care for migration. */ > + x = test_and_set_bit(IPIPE_STALL_FLAG, > + &ipipe_root_domain->cpudata[cpuid].status); > + ipipe_put_cpu(flags); > + > + return x; > +} > + > +void fastcall __ipipe_restore_root(unsigned long x) > +{ > + if (x) > + __ipipe_stall_root(); > + else > + __ipipe_unstall_root(); > +} > + > +void fastcall ipipe_stall_pipeline_from(struct ipipe_domain *ipd) > +{ > + ipipe_declare_cpuid; > +#ifdef CONFIG_SMP > + unsigned long flags; > + > + ipipe_lock_cpu(flags); /* Care for migration. */ > + > + __set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > + > + if (!__ipipe_pipeline_head_p(ipd)) > + ipipe_unlock_cpu(flags); > +#else /* CONFIG_SMP */ > + set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > + > + if (__ipipe_pipeline_head_p(ipd)) > + local_irq_disable_hw(); > +#endif /* CONFIG_SMP */ > +} > + > +unsigned long fastcall ipipe_test_and_stall_pipeline_from(struct ipipe_domain *ipd) > +{ > + ipipe_declare_cpuid; > + unsigned long s; > +#ifdef CONFIG_SMP > + unsigned long flags; > + > + ipipe_lock_cpu(flags); /* Care for migration. */ > + > + s = __test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > + > + if (!__ipipe_pipeline_head_p(ipd)) > + ipipe_unlock_cpu(flags); > +#else /* CONFIG_SMP */ > + s = test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > + > + if (__ipipe_pipeline_head_p(ipd)) > + local_irq_disable_hw(); > +#endif /* CONFIG_SMP */ > + > + return s; > +} > + > +/* > + * ipipe_unstall_pipeline_from() -- Unstall the pipeline and > + * synchronize pending interrupts for a given domain. See > + * __ipipe_walk_pipeline() for more information. > + */ > +void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd) > +{ > + struct list_head *pos; > + unsigned long flags; > + ipipe_declare_cpuid; > + > + ipipe_lock_cpu(flags); > + > + __clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > + > + if (ipd == ipipe_percpu_domain[cpuid]) > + pos = &ipd->p_link; > + else > + pos = __ipipe_pipeline.next; > + > + __ipipe_walk_pipeline(pos, cpuid); > + > + if (__ipipe_pipeline_head_p(ipd)) > + local_irq_enable_hw(); > + else > + ipipe_unlock_cpu(flags); > +} > + > +unsigned long fastcall ipipe_test_and_unstall_pipeline_from(struct ipipe_domain *ipd) > +{ > + unsigned long flags, x; > + ipipe_declare_cpuid; > + > + ipipe_get_cpu(flags); > + x = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status); > + ipipe_unstall_pipeline_from(ipd); > + ipipe_put_cpu(flags); > + > + return x; > +} > + > +void fastcall ipipe_restore_pipeline_from(struct ipipe_domain *ipd, > + unsigned long x) > +{ > + if (x) > + ipipe_stall_pipeline_from(ipd); > + else > + ipipe_unstall_pipeline_from(ipd); > +} > + > +void ipipe_unstall_pipeline_head(void) > +{ > + struct ipipe_domain *head; > + unsigned long flags; > + ipipe_declare_cpuid; > + > + ipipe_lock_cpu(flags); > + head = __ipipe_pipeline_head(); > + __clear_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status); > + > + if (unlikely(head->cpudata[cpuid].irq_pending_hi != 0)) { > + if (likely(head == ipipe_percpu_domain[cpuid])) > + __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); > + else > + __ipipe_walk_pipeline(&head->p_link, cpuid); > + } > + > + local_irq_enable_hw(); > +} > + > +void fastcall __ipipe_restore_pipeline_head(struct ipipe_domain *head, unsigned long x) > +{ > + ipipe_declare_cpuid; > + unsigned long flags; > + > + ipipe_lock_cpu(flags); > + > + if (x) { > +#ifdef CONFIG_DEBUG_KERNEL > + static int warned; > + if (!warned && test_and_set_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status)) { > + /* > + * Already stalled albeit ipipe_restore_pipeline_head() > + * should have detected it? Send a warning once.\n"); > + */ > + warned = 1; > + printk(KERN_WARNING > + "I-pipe: ipipe_restore_pipeline_head() optimization failed.\n"); > + dump_stack(); > + } > +#else /* !CONFIG_DEBUG_KERNEL */ > + set_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status); > +#endif /* CONFIG_DEBUG_KERNEL */ > + } > + else { > + __clear_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status); > + if (unlikely(head->cpudata[cpuid].irq_pending_hi != 0)) { > + if (likely(head == ipipe_percpu_domain[cpuid])) > + __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); > + else > + __ipipe_walk_pipeline(&head->p_link, cpuid); > + } > + local_irq_enable_hw(); > + } > +} > + > +/* __ipipe_walk_pipeline(): Plays interrupts pending in the log. Must > + be called with local hw interrupts disabled. */ > + > +void fastcall __ipipe_walk_pipeline(struct list_head *pos, int cpuid) > +{ > + struct ipipe_domain *this_domain = ipipe_percpu_domain[cpuid]; > + > + while (pos != &__ipipe_pipeline) { > + struct ipipe_domain *next_domain = > + list_entry(pos, struct ipipe_domain, p_link); > + > + if (test_bit > + (IPIPE_STALL_FLAG, &next_domain->cpudata[cpuid].status)) > + break; /* Stalled stage -- do not go further. */ > + > + if (next_domain->cpudata[cpuid].irq_pending_hi != 0) { > + > + if (next_domain == this_domain) > + __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); > + else { > + __ipipe_switch_to(this_domain, next_domain, > + cpuid); > + > + ipipe_load_cpuid(); /* Processor might have changed. */ > + > + if (this_domain->cpudata[cpuid]. > + irq_pending_hi != 0 > + && !test_bit(IPIPE_STALL_FLAG, > + &this_domain->cpudata[cpuid].status)) > + __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); > + } > + > + break; > + } else if (next_domain == this_domain) > + break; > + > + pos = next_domain->p_link.next; > + } > +} > + > +/* > + * ipipe_suspend_domain() -- Suspend the current domain, switching to > + * the next one which has pending work down the pipeline. > + */ > +void ipipe_suspend_domain(void) > +{ > + struct ipipe_domain *this_domain, *next_domain; > + struct list_head *ln; > + unsigned long flags; > + ipipe_declare_cpuid; > + > + ipipe_lock_cpu(flags); > + > + this_domain = next_domain = ipipe_percpu_domain[cpuid]; > + > + __clear_bit(IPIPE_STALL_FLAG, &this_domain->cpudata[cpuid].status); > + > + if (this_domain->cpudata[cpuid].irq_pending_hi != 0) > + goto sync_stage; > + > + for (;;) { > + ln = next_domain->p_link.next; > + > + if (ln == &__ipipe_pipeline) > + break; > + > + next_domain = list_entry(ln, struct ipipe_domain, p_link); > + > + if (test_bit(IPIPE_STALL_FLAG, > + &next_domain->cpudata[cpuid].status)) > + break; > + > + if (next_domain->cpudata[cpuid].irq_pending_hi == 0) > + continue; > + > + ipipe_percpu_domain[cpuid] = next_domain; > + > +sync_stage: > + __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); > + > + ipipe_load_cpuid(); /* Processor might have changed. */ > + > + if (ipipe_percpu_domain[cpuid] != next_domain) > + /* > + * Something has changed the current domain under our > + * feet, recycling the register set; take note. > + */ > + this_domain = ipipe_percpu_domain[cpuid]; > + } > + > + ipipe_percpu_domain[cpuid] = this_domain; > + > + ipipe_unlock_cpu(flags); > +} > + > +/* ipipe_alloc_virq() -- Allocate a pipelined virtual/soft interrupt. > + * Virtual interrupts are handled in exactly the same way than their > + * hw-generated counterparts wrt pipelining. > + */ > +unsigned ipipe_alloc_virq(void) > +{ > + unsigned long flags, irq = 0; > + int ipos; > + > + spin_lock_irqsave_hw(&__ipipe_pipelock, flags); > + > + if (__ipipe_virtual_irq_map != ~0) { > + ipos = ffz(__ipipe_virtual_irq_map); > + set_bit(ipos, &__ipipe_virtual_irq_map); > + irq = ipos + IPIPE_VIRQ_BASE; > + } > + > + spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags); > + > + return irq; > +} > + > +/* ipipe_virtualize_irq() -- Attach a handler (and optionally a hw > + acknowledge routine) to an interrupt for a given domain. */ > + > +int ipipe_virtualize_irq(struct ipipe_domain *ipd, > + unsigned irq, > + ipipe_irq_handler_t handler, > + void *cookie, > + ipipe_irq_ackfn_t acknowledge, > + unsigned modemask) > +{ > + unsigned long flags; > + int err; > + > + if (irq >= IPIPE_NR_IRQS) > + return -EINVAL; > + > + if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK) > + return -EPERM; > + > + if (!test_bit(IPIPE_AHEAD_FLAG, &ipd->flags)) > + /* Silently unwire interrupts for non-heading domains. */ > + modemask &= ~IPIPE_WIRED_MASK; > + > + spin_lock_irqsave_hw(&__ipipe_pipelock, flags); > + > + if (handler != NULL) { > + > + if (handler == IPIPE_SAME_HANDLER) { > + handler = ipd->irqs[irq].handler; > + cookie = ipd->irqs[irq].cookie; > + > + if (handler == NULL) { > + err = -EINVAL; > + goto unlock_and_exit; > + } > + } else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 && > + ipd->irqs[irq].handler != NULL) { > + err = -EBUSY; > + goto unlock_and_exit; > + } > + > + if ((modemask & (IPIPE_SHARED_MASK | IPIPE_PASS_MASK)) == > + IPIPE_SHARED_MASK) { > + err = -EINVAL; > + goto unlock_and_exit; > + } > + > + /* Wired interrupts can only be delivered to domains > + * always heading the pipeline. */ > + > + if ((modemask & IPIPE_WIRED_MASK) != 0) { > + if ((modemask & (IPIPE_SHARED_MASK | IPIPE_PASS_MASK | IPIPE_STICKY_MASK)) != 0) { > + err = -EINVAL; > + goto unlock_and_exit; > + } > + modemask |= (IPIPE_HANDLE_MASK); > + } > + > + if ((modemask & IPIPE_STICKY_MASK) != 0) > + modemask |= IPIPE_HANDLE_MASK; > + } else > + modemask &= > + ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK | > + IPIPE_SHARED_MASK | IPIPE_EXCLUSIVE_MASK | IPIPE_WIRED_MASK); > + > + if (acknowledge == NULL) { > + if ((modemask & IPIPE_SHARED_MASK) == 0) { > + if (!ipipe_virtual_irq_p(irq)) { > + /* Acknowledge handler unspecified for a hw > + interrupt -- this is ok in non-shared > + management mode, but we will force the use > + of the Linux-defined handler instead. */ > + acknowledge = ipipe_root_domain->irqs[irq].acknowledge; > + } > + } > + else { > + /* A valid acknowledge handler to be called in shared mode > + is required when declaring a shared IRQ. */ > + err = -EINVAL; > + goto unlock_and_exit; > + } > + } > + > + ipd->irqs[irq].handler = handler; > + ipd->irqs[irq].cookie = cookie; > + ipd->irqs[irq].acknowledge = acknowledge; > + ipd->irqs[irq].control = modemask; > + > + if (irq < NR_IRQS && > + handler != NULL && > + !ipipe_virtual_irq_p(irq) && (modemask & IPIPE_ENABLE_MASK) != 0) { > + if (ipd != ipipe_current_domain) { > + /* IRQ enable/disable state is domain-sensitive, so we may > + not change it for another domain. What is allowed > + however is forcing some domain to handle an interrupt > + source, by passing the proper 'ipd' descriptor which > + thus may be different from ipipe_current_domain. */ > + err = -EPERM; > + goto unlock_and_exit; > + } > + > + __ipipe_enable_irq(irq); > + } > + > + err = 0; > + > + unlock_and_exit: > + > + spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags); > + > + return err; > +} > + > +/* ipipe_control_irq() -- Change modes of a pipelined interrupt for > + * the current domain. */ > + > +int ipipe_control_irq(unsigned irq, unsigned clrmask, unsigned setmask) > +{ > + struct ipipe_domain *ipd; > + unsigned long flags; > + > + if (irq >= IPIPE_NR_IRQS) > + return -EINVAL; > + > + ipd = ipipe_current_domain; > + > + if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK) > + return -EPERM; > + > + if (((setmask | clrmask) & IPIPE_SHARED_MASK) != 0) > + return -EINVAL; > + > + if (ipd->irqs[irq].handler == NULL) > + setmask &= ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK); > + > + if ((setmask & IPIPE_STICKY_MASK) != 0) > + setmask |= IPIPE_HANDLE_MASK; > + > + if ((clrmask & (IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK)) != 0) /* If one goes, both go. */ > + clrmask |= (IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK); > + > + spin_lock_irqsave_hw(&__ipipe_pipelock, flags); > + > + ipd->irqs[irq].control &= ~clrmask; > + ipd->irqs[irq].control |= setmask; > + > + if ((setmask & IPIPE_ENABLE_MASK) != 0) > + __ipipe_enable_irq(irq); > + else if ((clrmask & IPIPE_ENABLE_MASK) != 0) > + __ipipe_disable_irq(irq); > + > + spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags); > + > + return 0; > +} > + > +/* __ipipe_dispatch_event() -- Low-level event dispatcher. */ > + > +int fastcall __ipipe_dispatch_event (unsigned event, void *data) > +{ > + struct ipipe_domain *start_domain, *this_domain, *next_domain; > + struct list_head *pos, *npos; > + unsigned long flags; > + ipipe_declare_cpuid; > + int propagate = 1; > + > + ipipe_lock_cpu(flags); > + > + start_domain = this_domain = ipipe_percpu_domain[cpuid]; > + > + list_for_each_safe(pos,npos,&__ipipe_pipeline) { > + > + next_domain = list_entry(pos,struct ipipe_domain,p_link); > + > + /* > + * Note: Domain migration may occur while running > + * event or interrupt handlers, in which case the > + * current register set is going to be recycled for a > + * different domain than the initiating one. We do > + * care for that, always tracking the current domain > + * descriptor upon return from those handlers. > + */ > + if (next_domain->evhand[event] != NULL) { > + ipipe_percpu_domain[cpuid] = next_domain; > + ipipe_unlock_cpu(flags); > + propagate = !next_domain->evhand[event](event,start_domain,data); > + ipipe_lock_cpu(flags); > + if (ipipe_percpu_domain[cpuid] != next_domain) > + this_domain = ipipe_percpu_domain[cpuid]; > + } > + > + if (next_domain != ipipe_root_domain && /* NEVER sync the root stage here. */ > + next_domain->cpudata[cpuid].irq_pending_hi != 0 && > + !test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status)) { > + ipipe_percpu_domain[cpuid] = next_domain; > + __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); > + ipipe_load_cpuid(); > + if (ipipe_percpu_domain[cpuid] != next_domain) > + this_domain = ipipe_percpu_domain[cpuid]; > + } > + > + ipipe_percpu_domain[cpuid] = this_domain; > + > + if (next_domain == this_domain || !propagate) > + break; > + } > + > + ipipe_unlock_cpu(flags); > + > + return !propagate; > +} > + > +/* > + * __ipipe_dispatch_wired -- Wired interrupt dispatcher. Wired > + * interrupts are immediately and unconditionally delivered to the > + * domain heading the pipeline upon receipt, and such domain must have > + * been registered as an invariant head for the system (priority == > + * IPIPE_HEAD_PRIORITY). The motivation for using wired interrupts is > + * to get an extra-fast dispatching path for those IRQs, by relying on > + * a straightforward logic based on assumptions that must always be > + * true for invariant head domains. The following assumptions are > + * made when dealing with such interrupts: > + * > + * 1- Wired interrupts are purely dynamic, i.e. the decision to > + * propagate them down the pipeline must be done from the head domain > + * ISR. > + * 2- Wired interrupts cannot be shared or sticky. > + * 3- The root domain cannot be an invariant pipeline head, in > + * consequence of what the root domain cannot handle wired > + * interrupts. > + * 4- Wired interrupts must have a valid acknowledge handler for the > + * head domain (if needed), and in any case, must not rely on handlers > + * provided by lower priority domains during the acknowledge cycle > + * (see __ipipe_handle_irq). > + * > + * Called with hw interrupts off. > + */ > + > +int fastcall __ipipe_dispatch_wired(struct ipipe_domain *head, unsigned irq) > +{ > + struct ipcpudata *cpudata; > + struct ipipe_domain *old; > + ipipe_declare_cpuid; > + > + ipipe_load_cpuid(); > + cpudata = &head->cpudata[cpuid]; > + cpudata->irq_counters[irq].total_hits++; > + > + if (test_bit(IPIPE_LOCK_FLAG, &head->irqs[irq].control)) { > + /* If we can't process this IRQ right now, we must > + * mark it as pending, so that it will get played > + * during normal log sync when the corresponding > + * interrupt source is eventually unlocked. */ > + cpudata->irq_counters[irq].pending_hits++; > + return 0; > + } > + > + if (test_bit(IPIPE_STALL_FLAG, &cpudata->status)) { > + cpudata->irq_counters[irq].pending_hits++; > + __ipipe_set_irq_bit(head, cpuid, irq); > + return 0; > + } > + > + old = ipipe_percpu_domain[cpuid]; > + ipipe_percpu_domain[cpuid] = head; /* Switch to the head domain. */ > + > + __set_bit(IPIPE_STALL_FLAG, &cpudata->status); > + head->irqs[irq].handler(irq,head->irqs[irq].cookie); /* Call the ISR. */ > + __ipipe_run_irqtail(); > + __clear_bit(IPIPE_STALL_FLAG, &cpudata->status); > + > + /* We expect the caller to start a complete pipeline walk upon > + * return, so that propagated interrupts will get played. */ > + > + if (ipipe_percpu_domain[cpuid] == head) > + ipipe_percpu_domain[cpuid] = old; /* Back to the preempted domain. */ > + > + return 1; > +} > + > +/* > + * __ipipe_sync_stage() -- Flush the pending IRQs for the current > + * domain (and processor). This routine flushes the interrupt log > + * (see "Optimistic interrupt protection" from D. Stodolsky et al. for > + * more on the deferred interrupt scheme). Every interrupt that > + * occurred while the pipeline was stalled gets played. WARNING: > + * callers on SMP boxen should always check for CPU migration on > + * return of this routine. One can control the kind of interrupts > + * which are going to be sync'ed using the syncmask > + * parameter. IPIPE_IRQMASK_ANY plays them all, IPIPE_IRQMASK_VIRT > + * plays virtual interrupts only. > + * > + * This routine must be called with hw interrupts off. > + */ > +void fastcall __ipipe_sync_stage(unsigned long syncmask) > +{ > + unsigned long mask, submask; > + struct ipcpudata *cpudata; > + struct ipipe_domain *ipd; > + ipipe_declare_cpuid; > + int level, rank; > + unsigned irq; > + > + ipipe_load_cpuid(); > + ipd = ipipe_percpu_domain[cpuid]; > + cpudata = &ipd->cpudata[cpuid]; > + > + if (__test_and_set_bit(IPIPE_SYNC_FLAG, &cpudata->status)) > + return; > + > + /* > + * The policy here is to keep the dispatching code interrupt-free > + * by stalling the current stage. If the upper domain handler > + * (which we call) wants to re-enable interrupts while in a safe > + * portion of the code (e.g. SA_INTERRUPT flag unset for Linux's > + * sigaction()), it will have to unstall (then stall again before > + * returning to us!) the stage when it sees fit. > + */ > + while ((mask = (cpudata->irq_pending_hi & syncmask)) != 0) { > + level = __ipipe_ffnz(mask); > + __clear_bit(level, &cpudata->irq_pending_hi); > + > + while ((submask = cpudata->irq_pending_lo[level]) != 0) { > + rank = __ipipe_ffnz(submask); > + irq = (level << IPIPE_IRQ_ISHIFT) + rank; > + > + if (test_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control)) { > + __clear_bit(rank, &cpudata->irq_pending_lo[level]); > + continue; > + } > + > + if (--cpudata->irq_counters[irq].pending_hits == 0) > + __clear_bit(rank, &cpudata->irq_pending_lo[level]); > + > + __set_bit(IPIPE_STALL_FLAG, &cpudata->status); > + __ipipe_run_isr(ipd, irq, cpuid); > +#ifdef CONFIG_SMP > + { > + int _cpuid = ipipe_processor_id(); > + > + if (_cpuid != cpuid) { /* Handle CPU migration. */ > + /* > + * We expect any domain to clear the SYNC bit each > + * time it switches in a new task, so that preemptions > + * and/or CPU migrations (in the SMP case) over the > + * ISR do not lock out the log syncer for some > + * indefinite amount of time. In the Linux case, > + * schedule() handles this (see kernel/sched.c). For > + * this reason, we don't bother clearing it here for > + * the source CPU in the migration handling case, > + * since it must have scheduled another task in by > + * now. > + */ > + cpuid = _cpuid; > + cpudata = &ipd->cpudata[cpuid]; > + __set_bit(IPIPE_SYNC_FLAG, &cpudata->status); > + } > + } > +#endif /* CONFIG_SMP */ > + > + __clear_bit(IPIPE_STALL_FLAG, &cpudata->status); > + } > + } > + > + __clear_bit(IPIPE_SYNC_FLAG, &cpudata->status); > +} > + > +#ifdef CONFIG_PROC_FS > + > +#include > + > +struct proc_dir_entry *ipipe_proc_root; > + > +static int __ipipe_version_info_proc(char *page, > + char **start, > + off_t off, int count, int *eof, void *data) > +{ > + int len = sprintf(page, "%s\n", IPIPE_VERSION_STRING); > + > + len -= off; > + > + if (len <= off + count) > + *eof = 1; > + > + *start = page + off; > + > + if(len > count) > + len = count; > + > + if(len < 0) > + len = 0; > + > + return len; > +} > + > +static int __ipipe_common_info_proc(char *page, > + char **start, > + off_t off, int count, int *eof, void *data) > +{ > + struct ipipe_domain *ipd = (struct ipipe_domain *)data; > + unsigned long ctlbits; > + unsigned irq, _irq; > + char *p = page; > + int len; > + > + spin_lock(&__ipipe_pipelock); > + > + if (test_bit(IPIPE_AHEAD_FLAG,&ipd->flags)) > + p += sprintf(p, "Invariant head"); > + else > + p += sprintf(p, "Priority=%d", ipd->priority); > + > + p += sprintf(p, ", Id=0x%.8x\n", ipd->domid); > + > + irq = 0; > + > + while (irq < IPIPE_NR_IRQS) { > + ctlbits = > + (ipd->irqs[irq]. > + control & (IPIPE_HANDLE_MASK | IPIPE_PASS_MASK | > + IPIPE_STICKY_MASK | IPIPE_WIRED_MASK)); > + if (irq >= IPIPE_NR_XIRQS && !ipipe_virtual_irq_p(irq)) { > + /* > + * There might be a hole between the last external > + * IRQ and the first virtual one; skip it. > + */ > + irq++; > + continue; > + } > + > + if (ipipe_virtual_irq_p(irq) > + && !test_bit(irq - IPIPE_VIRQ_BASE, > + &__ipipe_virtual_irq_map)) { > + /* Non-allocated virtual IRQ; skip it. */ > + irq++; > + continue; > + } > + > + /* > + * Attempt to group consecutive IRQ numbers having the > + * same virtualization settings in a single line. > + */ > + > + _irq = irq; > + > + while (++_irq < IPIPE_NR_IRQS) { > + if (ipipe_virtual_irq_p(_irq) != > + ipipe_virtual_irq_p(irq) > + || (ipipe_virtual_irq_p(_irq) > + && !test_bit(_irq - IPIPE_VIRQ_BASE, > + &__ipipe_virtual_irq_map)) > + || ctlbits != (ipd->irqs[_irq]. > + control & (IPIPE_HANDLE_MASK | > + IPIPE_PASS_MASK | > + IPIPE_STICKY_MASK))) > + break; > + } > + > + if (_irq == irq + 1) > + p += sprintf(p, "irq%u: ", irq); > + else > + p += sprintf(p, "irq%u-%u: ", irq, _irq - 1); > + > + /* > + * Statuses are as follows: > + * o "accepted" means handled _and_ passed down the pipeline. > + * o "grabbed" means handled, but the interrupt might be > + * terminated _or_ passed down the pipeline depending on > + * what the domain handler asks for to the I-pipe. > + * o "wired" is basically the same as "grabbed", except that > + * the interrupt is unconditionally delivered to an invariant > + * pipeline head domain. > + * o "passed" means unhandled by the domain but passed > + * down the pipeline. > + * o "discarded" means unhandled and _not_ passed down the > + * pipeline. The interrupt merely disappears from the > + * current domain down to the end of the pipeline. > + */ > + if (ctlbits & IPIPE_HANDLE_MASK) { > + if (ctlbits & IPIPE_PASS_MASK) > + p += sprintf(p, "accepted"); > + else if (ctlbits & IPIPE_WIRED_MASK) > + p += sprintf(p, "wired"); > + else > + p += sprintf(p, "grabbed"); > + } else if (ctlbits & IPIPE_PASS_MASK) > + p += sprintf(p, "passed"); > + else > + p += sprintf(p, "discarded"); > + > + if (ctlbits & IPIPE_STICKY_MASK) > + p += sprintf(p, ", sticky"); > + > + if (ipipe_virtual_irq_p(irq)) > + p += sprintf(p, ", virtual"); > + > + p += sprintf(p, "\n"); > + > + irq = _irq; > + } > + > + spin_unlock(&__ipipe_pipelock); > + > + len = p - page; > + > + if (len <= off + count) > + *eof = 1; > + > + *start = page + off; > + > + len -= off; > + > + if (len > count) > + len = count; > + > + if (len < 0) > + len = 0; > + > + return len; > +} > + > +void __ipipe_add_domain_proc(struct ipipe_domain *ipd) > +{ > + create_proc_read_entry(ipd->name,0444,ipipe_proc_root,&__ipipe_common_info_proc,ipd); > +} > + > +void __ipipe_remove_domain_proc(struct ipipe_domain *ipd) > +{ > + remove_proc_entry(ipd->name,ipipe_proc_root); > +} > + > +void ipipe_init_proc(void) > +{ > + ipipe_proc_root = create_proc_entry("ipipe",S_IFDIR, 0); > + create_proc_read_entry("version",0444,ipipe_proc_root,&__ipipe_version_info_proc,NULL); > + __ipipe_init_trace_proc(); > + __ipipe_add_domain_proc(ipipe_root_domain); > +} > + > +#endif /* CONFIG_PROC_FS */ > + > +EXPORT_SYMBOL(ipipe_virtualize_irq); > +EXPORT_SYMBOL(ipipe_control_irq); > +EXPORT_SYMBOL(ipipe_suspend_domain); > +EXPORT_SYMBOL(ipipe_alloc_virq); > +EXPORT_SYMBOL(ipipe_percpu_domain); > +EXPORT_SYMBOL(ipipe_root_domain); > +EXPORT_SYMBOL(ipipe_stall_pipeline_from); > +EXPORT_SYMBOL(ipipe_test_and_stall_pipeline_from); > +EXPORT_SYMBOL(ipipe_unstall_pipeline_from); > +EXPORT_SYMBOL(ipipe_restore_pipeline_from); > +EXPORT_SYMBOL(ipipe_test_and_unstall_pipeline_from); > +EXPORT_SYMBOL(ipipe_unstall_pipeline_head); > +EXPORT_SYMBOL(__ipipe_restore_pipeline_head); > +EXPORT_SYMBOL(__ipipe_unstall_root); > +EXPORT_SYMBOL(__ipipe_stall_root); > +EXPORT_SYMBOL(__ipipe_restore_root); > +EXPORT_SYMBOL(__ipipe_test_and_stall_root); > +EXPORT_SYMBOL(__ipipe_test_root); > +EXPORT_SYMBOL(__ipipe_dispatch_event); > +EXPORT_SYMBOL(__ipipe_dispatch_wired); > +EXPORT_SYMBOL(__ipipe_sync_stage); > +EXPORT_SYMBOL(__ipipe_pipeline); > +EXPORT_SYMBOL(__ipipe_pipelock); > +EXPORT_SYMBOL(__ipipe_virtual_irq_map); > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/ipipe/generic.c linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/generic.c > --- linux-2.6.16.5-tcl1/kernel/ipipe/generic.c 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/generic.c 2006-07-16 15:01:24.000000000 +0200 > @@ -0,0 +1,396 @@ > +/* -*- linux-c -*- > + * linux/kernel/ipipe/generic.c > + * > + * Copyright (C) 2002-2005 Philippe Gerum. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, > + * USA; either version 2 of the License, or (at your option) any later > + * version. > + * > + * 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. > + * > + * Architecture-independent I-PIPE services. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#ifdef CONFIG_PROC_FS > +#include > +#endif /* CONFIG_PROC_FS */ > + > +MODULE_DESCRIPTION("I-pipe"); > +MODULE_LICENSE("GPL"); > + > +static int __ipipe_ptd_key_count; > + > +static unsigned long __ipipe_ptd_key_map; > + > +/* ipipe_register_domain() -- Link a new domain to the pipeline. */ > + > +int ipipe_register_domain(struct ipipe_domain *ipd, > + struct ipipe_domain_attr *attr) > +{ > + struct list_head *pos; > + unsigned long flags; > + > + if (ipipe_current_domain != ipipe_root_domain) { > + printk(KERN_WARNING > + "I-pipe: Only the root domain may register a new domain.\n"); > + return -EPERM; > + } > + > + if (attr->priority == IPIPE_HEAD_PRIORITY && > + test_bit(IPIPE_AHEAD_FLAG,&__ipipe_pipeline_head()->flags)) > + return -EAGAIN; /* Cannot override current head. */ > + > + flags = ipipe_critical_enter(NULL); > + > + list_for_each(pos, &__ipipe_pipeline) { > + struct ipipe_domain *_ipd = > + list_entry(pos, struct ipipe_domain, p_link); > + if (_ipd->domid == attr->domid) > + break; > + } > + > + ipipe_critical_exit(flags); > + > + if (pos != &__ipipe_pipeline) > + /* A domain with the given id already exists -- fail. */ > + return -EBUSY; > + > + ipd->name = attr->name; > + ipd->domid = attr->domid; > + ipd->pdd = attr->pdd; > + ipd->flags = 0; > + > + if (attr->priority == IPIPE_HEAD_PRIORITY) { > + ipd->priority = INT_MAX; > + __set_bit(IPIPE_AHEAD_FLAG,&ipd->flags); > + } > + else > + ipd->priority = attr->priority; > + > + __ipipe_init_stage(ipd); > + > + INIT_LIST_HEAD(&ipd->p_link); > + > +#ifdef CONFIG_PROC_FS > + __ipipe_add_domain_proc(ipd); > +#endif /* CONFIG_PROC_FS */ > + > + flags = ipipe_critical_enter(NULL); > + > + list_for_each(pos, &__ipipe_pipeline) { > + struct ipipe_domain *_ipd = > + list_entry(pos, struct ipipe_domain, p_link); > + if (ipd->priority > _ipd->priority) > + break; > + } > + > + list_add_tail(&ipd->p_link, pos); > + > + ipipe_critical_exit(flags); > + > + printk(KERN_WARNING "I-pipe: Domain %s registered.\n", ipd->name); > + > + /* > + * Finally, allow the new domain to perform its initialization > + * chores. > + */ > + > + if (attr->entry != NULL) { > + ipipe_declare_cpuid; > + > + ipipe_lock_cpu(flags); > + > + ipipe_percpu_domain[cpuid] = ipd; > + attr->entry(); > + ipipe_percpu_domain[cpuid] = ipipe_root_domain; > + > + ipipe_load_cpuid(); /* Processor might have changed. */ > + > + if (ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0 && > + !test_bit(IPIPE_STALL_FLAG, > + &ipipe_root_domain->cpudata[cpuid].status)) > + __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); > + > + ipipe_unlock_cpu(flags); > + } > + > + return 0; > +} > + > +/* ipipe_unregister_domain() -- Remove a domain from the pipeline. */ > + > +int ipipe_unregister_domain(struct ipipe_domain *ipd) > +{ > + unsigned long flags; > + > + if (ipipe_current_domain != ipipe_root_domain) { > + printk(KERN_WARNING > + "I-pipe: Only the root domain may unregister a domain.\n"); > + return -EPERM; > + } > + > + if (ipd == ipipe_root_domain) { > + printk(KERN_WARNING > + "I-pipe: Cannot unregister the root domain.\n"); > + return -EPERM; > + } > +#ifdef CONFIG_SMP > + { > + int nr_cpus = num_online_cpus(), _cpuid; > + unsigned irq; > + > + /* > + * In the SMP case, wait for the logged events to drain on > + * other processors before eventually removing the domain > + * from the pipeline. > + */ > + > + ipipe_unstall_pipeline_from(ipd); > + > + flags = ipipe_critical_enter(NULL); > + > + for (irq = 0; irq < IPIPE_NR_IRQS; irq++) { > + clear_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control); > + clear_bit(IPIPE_STICKY_FLAG, &ipd->irqs[irq].control); > + set_bit(IPIPE_PASS_FLAG, &ipd->irqs[irq].control); > + } > + > + ipipe_critical_exit(flags); > + > + for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++) > + for (irq = 0; irq < IPIPE_NR_IRQS; irq++) > + while (ipd->cpudata[_cpuid].irq_counters[irq].pending_hits > 0) > + cpu_relax(); > + } > +#endif /* CONFIG_SMP */ > + > +#ifdef CONFIG_PROC_FS > + __ipipe_remove_domain_proc(ipd); > +#endif /* CONFIG_PROC_FS */ > + > + /* > + * Simply remove the domain from the pipeline and we are almost done. > + */ > + > + flags = ipipe_critical_enter(NULL); > + list_del_init(&ipd->p_link); > + ipipe_critical_exit(flags); > + > + __ipipe_cleanup_domain(ipd); > + > + printk(KERN_WARNING "I-pipe: Domain %s unregistered.\n", ipd->name); > + > + return 0; > +} > + > +/* > + * ipipe_propagate_irq() -- Force a given IRQ propagation on behalf of > + * a running interrupt handler to the next domain down the pipeline. > + * ipipe_schedule_irq() -- Does almost the same as above, but attempts > + * to pend the interrupt for the current domain first. > + */ > +int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head) > +{ > + struct list_head *ln; > + unsigned long flags; > + ipipe_declare_cpuid; > + > + if (irq >= IPIPE_NR_IRQS || > + (ipipe_virtual_irq_p(irq) > + && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map))) > + return -EINVAL; > + > + ipipe_lock_cpu(flags); > + > + ln = head; > + > + while (ln != &__ipipe_pipeline) { > + struct ipipe_domain *ipd = > + list_entry(ln, struct ipipe_domain, p_link); > + > + if (test_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control)) { > + ipd->cpudata[cpuid].irq_counters[irq].total_hits++; > + ipd->cpudata[cpuid].irq_counters[irq].pending_hits++; > + __ipipe_set_irq_bit(ipd, cpuid, irq); > + ipipe_unlock_cpu(flags); > + return 1; > + } > + > + ln = ipd->p_link.next; > + } > + > + ipipe_unlock_cpu(flags); > + > + return 0; > +} > + > +/* ipipe_free_virq() -- Release a virtual/soft interrupt. */ > + > +int ipipe_free_virq(unsigned virq) > +{ > + if (!ipipe_virtual_irq_p(virq)) > + return -EINVAL; > + > + clear_bit(virq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map); > + > + return 0; > +} > + > +void ipipe_init_attr(struct ipipe_domain_attr *attr) > +{ > + attr->name = "anon"; > + attr->domid = 1; > + attr->entry = NULL; > + attr->priority = IPIPE_ROOT_PRIO; > + attr->pdd = NULL; > +} > + > +/* > + * ipipe_catch_event() -- Interpose or remove an event handler for a > + * given domain. > + */ > +ipipe_event_handler_t ipipe_catch_event(struct ipipe_domain *ipd, > + unsigned event, > + ipipe_event_handler_t handler) > +{ > + ipipe_event_handler_t old_handler; > + int self = 0; > + > + if (event & IPIPE_EVENT_SELF) { > + event &= ~IPIPE_EVENT_SELF; > + self = 1; > + } > + > + if (event >= IPIPE_NR_EVENTS) > + return NULL; > + > + if (!(old_handler = xchg(&ipd->evhand[event],handler))) { > + if (handler) { > + if (self) > + ipd->evself |= (1LL << event); > + else > + __ipipe_event_monitors[event]++; > + } > + } > + else if (!handler) { > + if (ipd->evself & (1LL << event)) > + ipd->evself &= ~(1LL << event); > + else > + __ipipe_event_monitors[event]--; > + } else if ((ipd->evself & (1LL << event)) && !self) { > + __ipipe_event_monitors[event]++; > + ipd->evself &= ~(1LL << event); > + } else if (!(ipd->evself & (1LL << event)) && self) { > + __ipipe_event_monitors[event]--; > + ipd->evself |= (1LL << event); > + } > + > + return old_handler; > +} > + > +cpumask_t ipipe_set_irq_affinity (unsigned irq, cpumask_t cpumask) > +{ > +#ifdef CONFIG_SMP > + if (irq >= IPIPE_NR_XIRQS) > + /* Allow changing affinity of external IRQs only. */ > + return CPU_MASK_NONE; > + > + if (num_online_cpus() > 1) > + return __ipipe_set_irq_affinity(irq,cpumask); > +#endif /* CONFIG_SMP */ > + > + return CPU_MASK_NONE; > +} > + > +int fastcall ipipe_send_ipi (unsigned ipi, cpumask_t cpumask) > + > +{ > +#ifdef CONFIG_SMP > + return __ipipe_send_ipi(ipi,cpumask); > +#else /* !CONFIG_SMP */ > + return -EINVAL; > +#endif /* CONFIG_SMP */ > +} > + > +int ipipe_alloc_ptdkey (void) > +{ > + unsigned long flags; > + int key = -1; > + > + spin_lock_irqsave_hw(&__ipipe_pipelock,flags); > + > + if (__ipipe_ptd_key_count < IPIPE_ROOT_NPTDKEYS) { > + key = ffz(__ipipe_ptd_key_map); > + set_bit(key,&__ipipe_ptd_key_map); > + __ipipe_ptd_key_count++; > + } > + > + spin_unlock_irqrestore_hw(&__ipipe_pipelock,flags); > + > + return key; > +} > + > +int ipipe_free_ptdkey (int key) > +{ > + unsigned long flags; > + > + if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS) > + return -EINVAL; > + > + spin_lock_irqsave_hw(&__ipipe_pipelock,flags); > + > + if (test_and_clear_bit(key,&__ipipe_ptd_key_map)) > + __ipipe_ptd_key_count--; > + > + spin_unlock_irqrestore_hw(&__ipipe_pipelock,flags); > + > + return 0; > +} > + > +int fastcall ipipe_set_ptd (int key, void *value) > + > +{ > + if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS) > + return -EINVAL; > + > + current->ptd[key] = value; > + > + return 0; > +} > + > +void fastcall *ipipe_get_ptd (int key) > + > +{ > + if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS) > + return NULL; > + > + return current->ptd[key]; > +} > + > +EXPORT_SYMBOL(ipipe_register_domain); > +EXPORT_SYMBOL(ipipe_unregister_domain); > +EXPORT_SYMBOL(ipipe_free_virq); > +EXPORT_SYMBOL(ipipe_init_attr); > +EXPORT_SYMBOL(ipipe_catch_event); > +EXPORT_SYMBOL(ipipe_alloc_ptdkey); > +EXPORT_SYMBOL(ipipe_free_ptdkey); > +EXPORT_SYMBOL(ipipe_set_ptd); > +EXPORT_SYMBOL(ipipe_get_ptd); > +EXPORT_SYMBOL(ipipe_set_irq_affinity); > +EXPORT_SYMBOL(ipipe_send_ipi); > +EXPORT_SYMBOL(__ipipe_schedule_irq); > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/irq/handle.c linux-2.6.16.5-tcl1-ipipe/kernel/irq/handle.c > --- linux-2.6.16.5-tcl1/kernel/irq/handle.c 2006-05-07 15:37:02.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/irq/handle.c 2006-07-16 15:01:24.000000000 +0200 > @@ -81,6 +81,17 @@ fastcall int handle_IRQ_event(unsigned i > { > int ret, retval = 0, status = 0; > > +#ifdef CONFIG_IPIPE > + /* > + * If processing a timer tick, pass the original regs as > + * collected during preemption and not our phony - always > + * kernel-originated - frame, so that we don't wreck the > + * profiling code. > + */ > + if (__ipipe_tick_irq == irq) > + regs = __ipipe_tick_regs + smp_processor_id(); > +#endif /* CONFIG_IPIPE */ > + > if (!(action->flags & SA_INTERRUPT)) > local_irq_enable(); > > @@ -117,16 +128,20 @@ fastcall unsigned int __do_IRQ(unsigned > /* > * No locking required for CPU-local interrupts: > */ > +#ifndef CONFIG_IPIPE > if (desc->handler->ack) > desc->handler->ack(irq); > +#endif /* !CONFIG_IPIPE */ > action_ret = handle_IRQ_event(irq, regs, desc->action); > desc->handler->end(irq); > return 1; > } > > spin_lock(&desc->lock); > +#ifndef CONFIG_IPIPE > if (desc->handler->ack) > desc->handler->ack(irq); > +#endif /* !CONFIG_IPIPE */ > /* > * REPLAY is when Linux resends an IRQ that was dropped earlier > * WAITING is used by probe to mark irqs that are being tested > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/printk.c linux-2.6.16.5-tcl1-ipipe/kernel/printk.c > --- linux-2.6.16.5-tcl1/kernel/printk.c 2006-07-15 20:06:03.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/printk.c 2006-07-16 15:01:24.000000000 +0200 > @@ -520,6 +520,78 @@ __attribute__((weak)) unsigned long long > * printf(3) > */ > > +#ifdef CONFIG_IPIPE > + > +static ipipe_spinlock_t __ipipe_printk_lock = IPIPE_SPIN_LOCK_UNLOCKED; > + > +static int __ipipe_printk_fill; > + > +static char __ipipe_printk_buf[__LOG_BUF_LEN]; > + > +void __ipipe_flush_printk (unsigned virq, void *cookie) > +{ > + char *p = __ipipe_printk_buf; > + int len, lmax, out = 0; > + unsigned long flags; > + > + goto start; > + > + do { > + spin_unlock_irqrestore_hw(&__ipipe_printk_lock,flags); > + start: > + lmax = __ipipe_printk_fill; > + while (out < lmax) { > + len = strlen(p) + 1; > + printk("%s",p); > + p += len; > + out += len; > + } > + spin_lock_irqsave_hw(&__ipipe_printk_lock,flags); > + } > + while (__ipipe_printk_fill != lmax); > + > + __ipipe_printk_fill = 0; > + > + spin_unlock_irqrestore_hw(&__ipipe_printk_lock,flags); > +} > + > +asmlinkage int printk(const char *fmt, ...) > +{ > + int r, fbytes, oldcount; > + unsigned long flags; > + va_list args; > + > + va_start(args, fmt); > + > + if (ipipe_current_domain == ipipe_root_domain || > + test_bit(IPIPE_SPRINTK_FLAG,&ipipe_current_domain->flags) || > + oops_in_progress) { > + r = vprintk(fmt, args); > + goto out; > + } > + > + spin_lock_irqsave_hw(&__ipipe_printk_lock,flags); > + > + oldcount = __ipipe_printk_fill; > + fbytes = __LOG_BUF_LEN - oldcount; > + > + if (fbytes > 1) { > + r = vscnprintf(__ipipe_printk_buf + __ipipe_printk_fill, > + fbytes, fmt, args) + 1; /* account for the null byte */ > + __ipipe_printk_fill += r; > + } else > + r = 0; > + > + spin_unlock_irqrestore_hw(&__ipipe_printk_lock,flags); > + > + if (oldcount == 0) > + ipipe_trigger_irq(__ipipe_printk_virq); > +out: > + va_end(args); > + > + return r; > +} > +#else /* !CONFIG_IPIPE */ > asmlinkage int printk(const char *fmt, ...) > { > va_list args; > @@ -531,6 +603,7 @@ asmlinkage int printk(const char *fmt, . > > return r; > } > +#endif /* CONFIG_IPIPE */ > > /* cpu currently holding logbuf_lock */ > static volatile unsigned int printk_cpu = UINT_MAX; > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/sched.c linux-2.6.16.5-tcl1-ipipe/kernel/sched.c > --- linux-2.6.16.5-tcl1/kernel/sched.c 2006-07-13 15:49:59.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/sched.c 2006-07-16 15:01:24.000000000 +0200 > @@ -2872,13 +2872,18 @@ asmlinkage void __sched schedule(void) > unsigned long run_time; > int cpu, idx, new_prio; > > +#ifdef CONFIG_IPIPE > + if (unlikely(ipipe_current_domain != ipipe_root_domain)) { > + goto need_resched; > + } > +#endif /* CONFIG_IPIPE */ > /* > * Test if we are atomic. Since do_exit() needs to call into > * schedule() atomically, we ignore that path for now. > * Otherwise, whine if we are scheduling when we should not be. > */ > if (likely(!current->exit_state)) { > - if (unlikely(in_atomic())) { > + if (unlikely(!(current->state & TASK_ATOMICSWITCH) && in_atomic())) { > printk(KERN_ERR "scheduling while atomic: " > "%s/0x%08x/%d\n", > current->comm, preempt_count(), current->pid); > @@ -2887,8 +2892,19 @@ asmlinkage void __sched schedule(void) > } > profile_hit(SCHED_PROFILING, __builtin_return_address(0)); > > + if (unlikely(current->state & TASK_ATOMICSWITCH)) { > + current->state &= ~TASK_ATOMICSWITCH; > + goto preemption_off; > + } > need_resched: > preempt_disable(); > +preemption_off: > +#ifdef CONFIG_IPIPE > + if (unlikely(ipipe_current_domain != ipipe_root_domain)) { > + preempt_enable(); > + return; > + } > +#endif /* CONFIG_IPIPE */ > prev = current; > release_kernel_lock(prev); > need_resched_nonpreemptible: > @@ -3027,6 +3043,8 @@ switch_tasks: > prepare_task_switch(rq, next); > prev = context_switch(rq, prev, next); > barrier(); > + if (task_hijacked(prev)) > + return; > /* > * this_rq must be evaluated again because prev may have moved > * CPUs since it called schedule(), thus the 'rq' on its stack > @@ -3059,6 +3077,11 @@ asmlinkage void __sched preempt_schedule > struct task_struct *task = current; > int saved_lock_depth; > #endif > +#ifdef CONFIG_IPIPE > + /* Do not reschedule over non-Linux domains. */ > + if (ipipe_current_domain != ipipe_root_domain) > + return; > +#endif /* CONFIG_IPIPE */ > /* > * If there is a non-zero preempt_count or interrupts are disabled, > * we do not want to preempt the current task. Just return.. > @@ -3697,6 +3720,7 @@ recheck: > deactivate_task(p, rq); > oldprio = p->prio; > __setscheduler(p, policy, param->sched_priority); > + ipipe_setsched_notify(p); > if (array) { > __activate_task(p, rq); > /* > @@ -6165,3 +6189,50 @@ void set_curr_task(int cpu, task_t *p) > } > > #endif > + > +#ifdef CONFIG_IPIPE > + > +int ipipe_setscheduler_root (struct task_struct *p, int policy, int prio) > +{ > + prio_array_t *array; > + unsigned long flags; > + runqueue_t *rq; > + int oldprio; > + > + rq = task_rq_lock(p, &flags); > + array = p->array; > + if (array) > + deactivate_task(p, rq); > + oldprio = p->prio; > + __setscheduler(p, policy, prio); > + if (array) { > + __activate_task(p, rq); > + if (task_running(rq, p)) { > + if (p->prio > oldprio) > + resched_task(rq->curr); > + } else if (TASK_PREEMPTS_CURR(p, rq)) > + resched_task(rq->curr); > + } > + task_rq_unlock(rq, &flags); > + > + return 0; > +} > + > +EXPORT_SYMBOL(ipipe_setscheduler_root); > + > +int ipipe_reenter_root (struct task_struct *prev, int policy, int prio) > +{ > + finish_task_switch(this_rq(), prev); > + if (reacquire_kernel_lock(current) < 0) > + ; > + preempt_enable_no_resched(); > + > + if (current->policy != policy || current->rt_priority != prio) > + return ipipe_setscheduler_root(current,policy,prio); > + > + return 0; > +} > + > +EXPORT_SYMBOL(ipipe_reenter_root); > + > +#endif /* CONFIG_IPIPE */ > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/signal.c linux-2.6.16.5-tcl1-ipipe/kernel/signal.c > --- linux-2.6.16.5-tcl1/kernel/signal.c 2006-07-13 15:49:59.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/kernel/signal.c 2006-07-16 15:01:24.000000000 +0200 > @@ -604,6 +604,7 @@ void signal_wake_up(struct task_struct * > unsigned int mask; > > set_tsk_thread_flag(t, TIF_SIGPENDING); > + ipipe_sigwake_notify(t); /* TIF_SIGPENDING must be set first. */ > > /* > * For SIGKILL, we want to wake it up in the stopped/traced case. > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/lib/smp_processor_id.c linux-2.6.16.5-tcl1-ipipe/lib/smp_processor_id.c > --- linux-2.6.16.5-tcl1/lib/smp_processor_id.c 2006-05-07 15:37:02.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/lib/smp_processor_id.c 2006-07-16 15:01:24.000000000 +0200 > @@ -13,6 +13,11 @@ unsigned int debug_smp_processor_id(void > int this_cpu = raw_smp_processor_id(); > cpumask_t this_mask; > > +#ifdef CONFIG_IPIPE > + if (ipipe_current_domain != ipipe_root_domain) > + return this_cpu; > +#endif /* CONFIG_IPIPE */ > + > if (likely(preempt_count)) > goto out; > > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/lib/spinlock_debug.c linux-2.6.16.5-tcl1-ipipe/lib/spinlock_debug.c > --- linux-2.6.16.5-tcl1/lib/spinlock_debug.c 2006-05-07 16:42:15.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/lib/spinlock_debug.c 2006-07-16 15:01:24.000000000 +0200 > @@ -10,6 +10,7 @@ > #include > #include > #include > +#include > > static void spin_bug(spinlock_t *lock, const char *msg) > { > @@ -96,6 +97,8 @@ void _raw_spin_lock(spinlock_t *lock) > debug_spin_lock_after(lock); > } > > +EXPORT_SYMBOL(_raw_spin_lock); > + > int _raw_spin_trylock(spinlock_t *lock) > { > int ret = __raw_spin_trylock(&lock->raw_lock); > @@ -111,12 +114,16 @@ int _raw_spin_trylock(spinlock_t *lock) > return ret; > } > > +EXPORT_SYMBOL(_raw_spin_trylock); > + > void _raw_spin_unlock(spinlock_t *lock) > { > debug_spin_unlock(lock); > __raw_spin_unlock(&lock->raw_lock); > } > > +EXPORT_SYMBOL(_raw_spin_unlock); > + > static void rwlock_bug(rwlock_t *lock, const char *msg) > { > static long print_once = 1; > @@ -167,6 +174,8 @@ void _raw_read_lock(rwlock_t *lock) > __read_lock_debug(lock); > } > > +EXPORT_SYMBOL(_raw_read_lock); > + > int _raw_read_trylock(rwlock_t *lock) > { > int ret = __raw_read_trylock(&lock->raw_lock); > @@ -180,12 +189,16 @@ int _raw_read_trylock(rwlock_t *lock) > return ret; > } > > +EXPORT_SYMBOL(_raw_read_trylock); > + > void _raw_read_unlock(rwlock_t *lock) > { > RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); > __raw_read_unlock(&lock->raw_lock); > } > > +EXPORT_SYMBOL(_raw_read_unlock); > + > static inline void debug_write_lock_before(rwlock_t *lock) > { > RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); > @@ -241,6 +254,8 @@ void _raw_write_lock(rwlock_t *lock) > debug_write_lock_after(lock); > } > > +EXPORT_SYMBOL(_raw_write_lock); > + > int _raw_write_trylock(rwlock_t *lock) > { > int ret = __raw_write_trylock(&lock->raw_lock); > @@ -256,8 +271,12 @@ int _raw_write_trylock(rwlock_t *lock) > return ret; > } > > +EXPORT_SYMBOL(_raw_write_trylock); > + > void _raw_write_unlock(rwlock_t *lock) > { > debug_write_unlock(lock); > __raw_write_unlock(&lock->raw_lock); > } > + > +EXPORT_SYMBOL(_raw_write_unlock); > diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/mm/vmalloc.c linux-2.6.16.5-tcl1-ipipe/mm/vmalloc.c > --- linux-2.6.16.5-tcl1/mm/vmalloc.c 2006-05-07 15:37:03.000000000 +0200 > +++ linux-2.6.16.5-tcl1-ipipe/mm/vmalloc.c 2006-07-16 15:01:24.000000000 +0200 > @@ -19,6 +19,7 @@ > > #include > #include > +#include > > > DEFINE_RWLOCK(vmlist_lock); > @@ -148,10 +149,14 @@ int map_vm_area(struct vm_struct *area, > BUG_ON(addr >= end); > pgd = pgd_offset_k(addr); > do { > + pgd_t oldpgd; > + memcpy(&oldpgd,pgd,sizeof(pgd_t)); > next = pgd_addr_end(addr, end); > err = vmap_pud_range(pgd, addr, next, prot, pages); > if (err) > break; > + if (pgd_val(oldpgd) != pgd_val(*pgd)) > + set_pgdir(addr, *pgd); > } while (pgd++, addr = next, addr != end); > flush_cache_vmap((unsigned long) area->addr, end); > return err; > _______________________________________________ > Xenomai-core mailing list > Xenomai-core@domain.hid > https://mail.gna.org/listinfo/xenomai-core