diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/adeos/armv.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/adeos/armv.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/adeos/armv.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/adeos/armv.c 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,491 @@ +/* + * linux/adeos/armv.c + * + * Copyright (C) 2002-2005 Philippe Gerum. + * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * various tweaks, fixes (e.g. call asm_do_IRQ() instead of do_IRQ() and + * optimizations (e.g. backport of unthreaded support from Adeos/x86 for 2.6) + * + * 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 ADEOS support for ARM. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ARCH_EP93XX +#include +#endif + +extern spinlock_t __adeos_pipelock; + +extern struct irqdesc irq_desc[]; + +extern struct pt_regs __adeos_irq_regs; + +asmlinkage void asm_do_IRQ(int irq, + struct pt_regs *regs); + +struct irqdesc __adeos_std_irq_desc[NR_IRQS]; + +static void __adeos_override_irq_mask (unsigned irq) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + + adeos_hw_local_irq_save(hwflags); + adflags = adeos_test_and_stall_pipeline(); +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + __adeos_std_irq_desc[irq].mask(irq); + __adeos_lock_irq(adp_cpu_current[cpuid],cpuid,irq); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_hw_local_irq_restore(hwflags); +} + +static void __adeos_override_irq_unmask (unsigned irq) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + + adeos_hw_local_irq_save(hwflags); + adflags = adeos_test_and_stall_pipeline(); +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + __adeos_unlock_irq(adp_cpu_current[cpuid],irq); + __adeos_std_irq_desc[irq].unmask(irq); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_hw_local_irq_restore(hwflags); +} + +static void __adeos_override_irq_mask_ack (unsigned irq) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + + adeos_hw_local_irq_save(hwflags); + adflags = adeos_test_and_stall_pipeline(); +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + __adeos_std_irq_desc[irq].mask_ack(irq); + /* No locking here, since this would prevent to sync the stage. */ +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_hw_local_irq_restore(hwflags); +} + +static int __adeos_ack_irq (unsigned irq) + +{ + struct irqdesc *desc = irq_desc + irq; + desc->mask_ack(irq); + return 1; +} + +/* __adeos_enable_pipeline() -- Take over the interrupt control from + the root domain (i.e. Linux). After this routine has returned, all + interrupts go through the pipeline. */ + +void __adeos_enable_pipeline (void) + +{ + unsigned long flags; + unsigned irq; + + flags = adeos_critical_enter(NULL); + + /* First, virtualize all interrupts from the root domain. */ + + for (irq = 0; irq < NR_IRQS; irq++) + /* Note that according to Russel King asm_do_IRQ() has to be used as the + * handler, not do_IRQ() (at least for 2.4.21-rmk7) as the original + * ADEOS code had here. */ + adeos_virtualize_irq(irq, + (void (*)(unsigned))&asm_do_IRQ, + &__adeos_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++) + __adeos_std_irq_desc[irq] = irq_desc[irq]; + + /* The original controller structs are often shared, so we first + save them all before changing any of them. Notice that we don't + redirect the ack handler since the relevant IC management code + is already Adeos-aware. */ + + for (irq = 0; irq < NR_IRQS; irq++) + { + if (irq_desc[irq].mask != NULL) + irq_desc[irq].mask = &__adeos_override_irq_mask; + + if (irq_desc[irq].unmask != NULL) + irq_desc[irq].unmask = &__adeos_override_irq_unmask; + + if (irq_desc[irq].mask_ack != NULL) + irq_desc[irq].mask_ack = &__adeos_override_irq_mask_ack; + } + +#ifdef CONFIG_ADEOS_MODULE + adp_pipelined = 1; +#endif /* CONFIG_ADEOS_MODULE */ + + adeos_critical_exit(flags); +} + +/* __adeos_disable_pipeline() -- Disengage the pipeline. */ + +void __adeos_disable_pipeline (void) + +{ + unsigned long flags; + unsigned irq; + + flags = adeos_critical_enter(NULL); + + /* Restore interrupt controllers. */ + + for (irq = 0; irq < NR_IRQS; irq++) + irq_desc[irq] = __adeos_std_irq_desc[irq]; + +#ifdef CONFIG_ADEOS_MODULE + adp_pipelined = 0; +#endif /* CONFIG_ADEOS_MODULE */ + + adeos_critical_exit(flags); +} + +/* adeos_virtualize_irq_from() -- Attach a handler (and optionally a + hw acknowledge routine) to an interrupt for the given domain. */ + +int adeos_virtualize_irq_from (adomain_t *adp, + unsigned irq, + void (*handler)(unsigned irq), + int (*acknowledge)(unsigned irq), + unsigned modemask) +{ + unsigned long flags; + int err; + + if (irq >= IPIPE_NR_IRQS) + return -EINVAL; + + if (adp->irqs[irq].control & IPIPE_SYSTEM_MASK) + return -EPERM; + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + if (handler != NULL) + { + /* A bit of hack here: if we are re-virtualizing an IRQ just + to change the acknowledge routine by passing the special + ADEOS_SAME_HANDLER value, then allow to recycle the current + handler for the IRQ. This allows Linux device drivers + managing shared IRQ lines to call adeos_virtualize_irq() in + addition to request_irq() just for the purpose of + interposing their own shared acknowledge routine. */ + + if (handler == ADEOS_SAME_HANDLER) + { + handler = adp->irqs[irq].handler; + + if (handler == NULL) + { + err = -EINVAL; + goto unlock_and_exit; + } + } + else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 && + adp->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; + } + + if ((modemask & IPIPE_STICKY_MASK) != 0) + modemask |= IPIPE_HANDLE_MASK; + } + else + modemask &= ~(IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SHARED_MASK); + + if (acknowledge == NULL) + { + if ((modemask & IPIPE_SHARED_MASK) == 0) + /* Acknowledge handler unspecified -- this is ok in + non-shared management mode, but we will force the use + of the Linux-defined handler instead. */ + acknowledge = adp_root->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; + } + } + + adp->irqs[irq].handler = handler; + adp->irqs[irq].acknowledge = acknowledge; + adp->irqs[irq].control = modemask; + + if (irq < NR_IRQS && + handler != NULL && + !adeos_virtual_irq_p(irq) && + (modemask & IPIPE_ENABLE_MASK) != 0) + { + if (adp != adp_current) + { + /* 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 'adp' descriptor which + thus may be different from adp_current. */ + err = -EPERM; + goto unlock_and_exit; + } + + enable_irq(irq); + } + + err = 0; + +unlock_and_exit: + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return err; +} + +/* adeos_control_irq() -- Change an interrupt mode. This affects the + way a given interrupt is handled by ADEOS for the current + domain. setmask is a bitmask telling whether: + - the interrupt should be passed to the domain (IPIPE_HANDLE_MASK), + and/or + - the interrupt should be passed down to the lower priority domain(s) + in the pipeline (IPIPE_PASS_MASK). + This leads to four possibilities: + - PASS only => Ignore the interrupt + - HANDLE only => Terminate the interrupt (process but don't pass down) + - PASS + HANDLE => Accept the interrupt (process and pass down) + - => Discard the interrupt + - DYNAMIC is currently an alias of HANDLE since it marks an interrupt + which is processed by the current domain but not implicitely passed + down to the pipeline, letting the domain's handler choose on a case- + by-case basis whether the interrupt propagation should be forced + using adeos_propagate_irq(). + clrmask clears the corresponding bits from the control field before + setmask is applied. +*/ + +int adeos_control_irq (unsigned irq, + unsigned clrmask, + unsigned setmask) +{ + struct irqdesc *desc; + unsigned long flags; + + if (irq >= IPIPE_NR_IRQS) + return -EINVAL; + + if (adp_current->irqs[irq].control & IPIPE_SYSTEM_MASK) + return -EPERM; + + if (((setmask|clrmask) & IPIPE_SHARED_MASK) != 0) + return -EINVAL; + + desc = irq_desc + irq; + + if (adp_current->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); + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + adp_current->irqs[irq].control &= ~clrmask; + adp_current->irqs[irq].control |= setmask; + + if ((setmask & IPIPE_ENABLE_MASK) != 0) + enable_irq(irq); + else if ((clrmask & IPIPE_ENABLE_MASK) != 0) + disable_irq(irq); + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return 0; +} + +#ifdef CONFIG_ADEOS_THREADS + +static inline unsigned long __current_domain_access_control (void) + +{ + unsigned long domain_access_control; + __asm__ __volatile__ ("mrc p15, 0, %0, c3, c0" : "=r" (domain_access_control)); + return domain_access_control; +} + +void __adeos_init_domain (adomain_t *adp, adattr_t *attr) + +{ + int estacksz = attr->estacksz > 0 ? attr->estacksz : 8192, _cpuid; + unsigned long init_arch_flags, init_domain_access_control; + adeos_declare_cpuid; + + adeos_load_cpuid(); + adeos_hw_local_irq_flags(init_arch_flags); + init_domain_access_control = __current_domain_access_control(); + + for (_cpuid = 0; _cpuid < smp_num_cpus; _cpuid++) + { + int **psp = &adp->esp[_cpuid]; + + adp->estackbase[_cpuid] = (int *)kmalloc(estacksz,GFP_KERNEL); + + if (adp->estackbase[_cpuid] == NULL) + panic("Adeos: No memory for domain stack on CPU #%d",_cpuid); + + adp->esp[_cpuid] = adp->estackbase[_cpuid]; + **psp = 0; + *psp = (int *)(((unsigned long)*psp + estacksz - 60) & ~0x3); + *--(*psp) = (int)attr->entry; /* r14=lr */ + *--(*psp) = 0; /* r11=fp */ + *--(*psp) = 0; /* r10=sl */ + *--(*psp) = 0; /* r9 */ + *--(*psp) = 0; /* r8 */ + *--(*psp) = 0; /* r7 */ + *--(*psp) = 0; /* r6 */ + *--(*psp) = 0; /* r5 */ + *--(*psp) = 0; /* r4 */ + *--(*psp) = 0; /* r3 */ + *--(*psp) = 0; /* r2 */ + *--(*psp) = 0; /* r1 */ + *--(*psp) = (_cpuid == cpuid); /* r0=iflag */ + *--(*psp) = init_arch_flags; /* cpsr_SVC */ + *--(*psp) = init_domain_access_control; + } +} + +#else /* !CONFIG_ADEOS_THREADS */ + +void __adeos_init_domain (adomain_t *adp, adattr_t *attr) + +{} + +#endif /* CONFIG_ADEOS_THREADS */ + +void __adeos_cleanup_domain (adomain_t *adp) + +{ + adeos_unstall_pipeline_from(adp); + +#ifdef CONFIG_ADEOS_THREADS + if (adp->estackbase[0] != NULL) + kfree(adp->estackbase[0]); +#endif /* CONFIG_ADEOS_THREADS */ +} + +int adeos_get_sysinfo (adsysinfo_t *info) + +{ + info->ncpus = 1; +#ifndef CONFIG_ARCH_EP93XX + info->cpufreq = CLOCK_TICK_RATE; +#else + /* use TSC frequency, because that's what cpufreq is used for, + * although it has nothing to do with CPU-frequency on EP-93XX + * it's just timer4's frequency */ + info->cpufreq = FREQ_EP93XX_TSC; +#endif + info->archdep.tmirq = ADEOS_TIMER_IRQ; + + return 0; +} + +int adeos_tune_timer (unsigned long ns, int flags) + +{ + unsigned long x, hz; + + if (flags & ADEOS_RESET_TIMER) + hz = HZ; + else + { + hz = 1000000000 / ns; + + if (hz < HZ) + return -EINVAL; + } + + adeos_hw_local_irq_save(x); + + __adeos_tune_timer(hz); + + adeos_hw_local_irq_restore(x); + + return 0; +} + +/* adeos_send_ipi() -- Send a specified service IPI to a set of + processors. */ + +int adeos_send_ipi (unsigned ipi, cpumask_t cpumask) + +{ + printk(KERN_WARNING "Adeos: Call to unimplemented adeos_send_ipi() from %s\n",adp_current->name); + return 0; +} + +EXPORT_SYMBOL(__adeos_std_irq_desc); + diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/adeos/generic.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/adeos/generic.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/adeos/generic.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/adeos/generic.c 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,641 @@ +/* + * linux/adeos/generic.c + * + * Copyright (C) 2002 Philippe Gerum. + * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * backport from Adeos for 2.6 to 2.4 + * + * 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 ADEOS services. + */ + +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Adeos nanokernel"); +MODULE_AUTHOR("Philippe Gerum"); +MODULE_LICENSE("GPL"); + +/* adeos_register_domain() -- Add a new domain to the system. All + client domains must call this routine to register themselves to + ADEOS before using its services. */ + +int adeos_register_domain (adomain_t *adp, adattr_t *attr) + +{ + struct list_head *pos; + unsigned long flags; + int n; + + if (adp_current != adp_root) + { + printk(KERN_WARNING "Adeos: Only the root domain may register a new domain.\n"); + return -EPERM; + } + + flags = adeos_critical_enter(NULL); + + list_for_each(pos,&__adeos_pipeline) { + adomain_t *_adp = list_entry(pos,adomain_t,p_link); + if (_adp->domid == attr->domid) + break; + } + + adeos_critical_exit(flags); + + if (pos != &__adeos_pipeline) + /* A domain with the given id already exists -- fail. */ + return -EBUSY; + + for (n = 0; n < ADEOS_NR_CPUS; n++) + { + /* Each domain starts in sleeping state on every CPU. */ + adp->cpudata[n].status = (1 << IPIPE_SLEEP_FLAG); +#ifdef CONFIG_ADEOS_THREADS + adp->estackbase[n] = NULL; +#endif /* CONFIG_ADEOS_THREADS */ + } + + adp->name = attr->name; + adp->priority = attr->priority; + adp->domid = attr->domid; + adp->dswitch = attr->dswitch; + adp->flags = 0; + adp->ptd_setfun = attr->ptdset; + adp->ptd_getfun = attr->ptdget; + adp->ptd_keymap = 0; + adp->ptd_keycount = 0; + adp->ptd_keymax = attr->nptdkeys; + + for (n = 0; n < ADEOS_NR_EVENTS; n++) + /* Event handlers must be cleared before the i-pipe stage is + inserted since an exception may occur on behalf of the new + emerging domain. */ + adp->events[n].handler = NULL; + + if (attr->entry != NULL) + __adeos_init_domain(adp,attr); + + /* Insert the domain in the interrupt pipeline last, so it won't + be resumed for processing interrupts until it has a valid stack + context. */ + + __adeos_init_stage(adp); + + INIT_LIST_HEAD(&adp->p_link); + + flags = adeos_critical_enter(NULL); + + list_for_each(pos,&__adeos_pipeline) { + adomain_t *_adp = list_entry(pos,adomain_t,p_link); + if (adp->priority > _adp->priority) + break; + } + + list_add_tail(&adp->p_link,pos); + + adeos_critical_exit(flags); + + printk(KERN_WARNING "Adeos: Domain %s registered.\n",adp->name); + + /* Finally, allow the new domain to perform its initialization + chores. */ + + if (attr->entry != NULL) + { + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + +#ifdef CONFIG_ADEOS_THREADS + __adeos_switch_to(adp_root,adp,cpuid); +#else /* !CONFIG_ADEOS_THREADS */ + adp_cpu_current[cpuid] = adp; + attr->entry(1); + adp_cpu_current[cpuid] = adp_root; +#endif /* CONFIG_ADEOS_THREADS */ + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (!test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status) && + adp_root->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + + adeos_unlock_cpu(flags); + } + + return 0; +} + +/* adeos_unregister_domain() -- Remove a domain from the system. All + client domains must call this routine to unregister themselves from + the ADEOS layer. */ + +int adeos_unregister_domain (adomain_t *adp) + +{ + unsigned long flags; + unsigned event; + + if (adp_current != adp_root) + { + printk(KERN_WARNING "Adeos: Only the root domain may unregister a domain.\n"); + return -EPERM; + } + + if (adp == adp_root) + { + printk(KERN_WARNING "Adeos: Cannot unregister the root domain.\n"); + return -EPERM; + } + + for (event = 0; event < ADEOS_NR_EVENTS; event++) + /* Need this to update the monitor count. */ + adeos_catch_event_from(adp,event,NULL); + +#ifdef CONFIG_SMP + { + int _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. */ + + adeos_unstall_pipeline_from(adp); + + flags = adeos_critical_enter(NULL); + + for (irq = 0; irq < IPIPE_NR_IRQS; irq++) + { + clear_bit(IPIPE_HANDLE_FLAG,&adp->irqs[irq].control); + clear_bit(IPIPE_STICKY_FLAG,&adp->irqs[irq].control); + set_bit(IPIPE_PASS_FLAG,&adp->irqs[irq].control); + } + + adeos_critical_exit(flags); + + for (_cpuid = 0; _cpuid < smp_num_cpus; _cpuid++) + { + for (irq = 0; irq < IPIPE_NR_IRQS; irq++) + while (adp->cpudata[_cpuid].irq_hits[irq] > 0) + cpu_relax(); + + while (test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[_cpuid].status)) + cpu_relax(); + + while (!test_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[_cpuid].status)) + cpu_relax(); + } + } +#endif /* CONFIG_SMP */ + + /* Simply remove the domain from the pipeline and we are almost + done. */ + + flags = adeos_critical_enter(NULL); + list_del_init(&adp->p_link); + adeos_critical_exit(flags); + + __adeos_cleanup_domain(adp); + + printk(KERN_WARNING "Adeos: Domain %s unregistered.\n",adp->name); + + return 0; +} + +/* adeos_propagate_irq() -- Force a given IRQ propagation on behalf of + a running interrupt handler to the next domain down the pipeline. + Returns non-zero if a domain has received the interrupt + notification, zero otherwise. + This call is useful for handling shared interrupts among domains. + e.g. pipeline = [domain-A]---[domain-B]... + Both domains share IRQ #X. + - domain-A handles IRQ #X but does not pass it down (i.e. Terminate + or Dynamic interrupt control mode) + - domain-B handles IRQ #X (i.e. Terminate or Accept interrupt + control modes). + When IRQ #X is raised, domain-A's handler determines whether it + should process the interrupt by identifying its source. If not, + adeos_propagate_irq() is called so that the next domain down the + pipeline which handles IRQ #X is given a chance to process it. This + process can be repeated until the end of the pipeline is + reached. */ + +/* adeos_schedule_irq() -- Almost the same as adeos_propagate_irq(), + but attempts to pend the interrupt for the current domain first. */ + +int __adeos_schedule_irq (unsigned irq, struct list_head *head) + +{ + struct list_head *ln; + unsigned long flags; + adeos_declare_cpuid; + + if (irq >= IPIPE_NR_IRQS || + (adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map))) + return -EINVAL; + + adeos_lock_cpu(flags); + + ln = head; + + while (ln != &__adeos_pipeline) + { + adomain_t *adp = list_entry(ln,adomain_t,p_link); + + if (test_bit(IPIPE_HANDLE_FLAG,&adp->irqs[irq].control)) + { + adp->cpudata[cpuid].irq_hits[irq]++; + __adeos_set_irq_bit(adp,cpuid,irq); + adeos_unlock_cpu(flags); + return 1; + } + + ln = adp->p_link.next; + } + + adeos_unlock_cpu(flags); + + return 0; +} + +/* adeos_free_irq() -- Return a previously allocated virtual/soft + pipelined interrupt to the pool of allocatable interrupts. */ + +int adeos_free_irq (unsigned irq) + +{ + if (irq >= IPIPE_NR_IRQS) + return -EINVAL; + + clear_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map); + + return 0; +} + +cpumask_t adeos_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) + /* Allow changing affinity of external IRQs only. */ + return __adeos_set_irq_affinity(irq,cpumask); +#endif /* CONFIG_SMP */ + + return CPU_MASK_NONE; +} + +/* adeos_catch_event_from() -- Interpose an event handler starting + from a given domain. */ + +int adeos_catch_event_from (adomain_t *adp, unsigned event, void (*handler)(adevinfo_t *)) + +{ + if (event >= ADEOS_NR_EVENTS) + return -EINVAL; + + if (!xchg(&adp->events[event].handler,handler)) + { + if (handler) + __adeos_event_monitors[event]++; + } + else if (!handler) + __adeos_event_monitors[event]--; + + return 0; +} + +void adeos_init_attr (adattr_t *attr) + +{ + attr->name = "Anonymous"; + attr->domid = 1; + attr->entry = NULL; + attr->estacksz = 0; /* Let ADEOS choose a reasonable stack size */ + attr->priority = ADEOS_ROOT_PRI; + attr->dswitch = NULL; + attr->nptdkeys = 0; + attr->ptdset = NULL; + attr->ptdget = NULL; +} + +int adeos_alloc_ptdkey (void) + +{ + unsigned long flags; + int key = -1; + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + if (adp_current->ptd_keycount < adp_current->ptd_keymax) + { + key = ffz(adp_current->ptd_keymap); + set_bit(key,&adp_current->ptd_keymap); + adp_current->ptd_keycount++; + } + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return key; +} + +int adeos_free_ptdkey (int key) + +{ + unsigned long flags; + + if (key < 0 || key >= adp_current->ptd_keymax) + return -EINVAL; + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + if (test_and_clear_bit(key,&adp_current->ptd_keymap)) + adp_current->ptd_keycount--; + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return 0; +} + +int adeos_set_ptd (int key, void *value) + +{ + if (key < 0 || key >= adp_current->ptd_keymax) + return -EINVAL; + + if (!adp_current->ptd_setfun) + { + printk(KERN_WARNING "Adeos: No ptdset hook for %s\n",adp_current->name); + return -EINVAL; + } + + adp_current->ptd_setfun(key,value); + + return 0; +} + +void *adeos_get_ptd (int key) + +{ + if (key < 0 || key >= adp_current->ptd_keymax) + return NULL; + + if (!adp_current->ptd_getfun) + { + printk(KERN_WARNING "Adeos: No ptdget hook for %s\n",adp_current->name); + return NULL; + } + + return adp_current->ptd_getfun(key); +} + +int adeos_init_mutex (admutex_t *mutex) + +{ + admutex_t initm = ADEOS_MUTEX_UNLOCKED; + *mutex = initm; + return 0; +} + +#ifdef CONFIG_ADEOS_THREADS + +int adeos_destroy_mutex (admutex_t *mutex) + +{ + if (!adeos_spin_trylock(&mutex->lock) && + adp_current != adp_root && + mutex->owner != adp_current) + return -EBUSY; + + return 0; +} + +static inline void __adeos_sleepon_mutex (admutex_t *mutex, adomain_t *sleeper, int cpuid) + +{ + adomain_t *owner = mutex->owner; + + /* Make the current domain (== sleeper) wait for the mutex to be + released. Adeos' pipelined scheme guarantees that the new + sleeper _is_ more prioritary than any aslept domain since we + have stalled each sleeper's stage. Must be called with local hw + interrupts off. */ + + sleeper->m_link = mutex->sleepq; + mutex->sleepq = sleeper; + __adeos_switch_to(adp_cpu_current[cpuid],owner,cpuid); + mutex->owner = sleeper; + adeos_spin_unlock(&mutex->lock); +} + +unsigned long adeos_lock_mutex (admutex_t *mutex) + +{ + unsigned long flags, hwflags; + adeos_declare_cpuid; + adomain_t *adp; + + if (!adp_pipelined) + { + adeos_hw_local_irq_save(hwflags); + flags = !adeos_hw_test_iflag(hwflags); + adeos_spin_lock(&mutex->lock); + return flags; + } + + adeos_lock_cpu(hwflags); + + adp = adp_cpu_current[cpuid]; + + flags = __test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + /* Two cases to handle here on SMP systems, only one for UP: + 1) in case of a conflicting access from a prioritary domain + running on the same cpu, make this domain sleep on the mutex, + and resume the current owner so it can release the lock asap. + 2) in case of a conflicting access from any domain on a + different cpu than the current owner's, simply enter a spinning + loop. Note that testing mutex->owncpu is safe since it is only + changed by the current owner, and set to -1 when the mutex is + unlocked. */ + +#ifdef CONFIG_SMP + while (!adeos_spin_trylock(&mutex->lock)) + { + if (mutex->owncpu == cpuid) + { + __adeos_sleepon_mutex(mutex,adp,cpuid); + adeos_load_cpuid(); + } + } + + mutex->owncpu = cpuid; +#else /* !CONFIG_SMP */ + while (mutex->owner != NULL && mutex->owner != adp) + __adeos_sleepon_mutex(mutex,adp,cpuid); +#endif /* CONFIG_SMP */ + + mutex->owner = adp; + + adeos_unlock_cpu(hwflags); + + return flags; +} + +void adeos_unlock_mutex (admutex_t *mutex, unsigned long flags) + +{ + unsigned long hwflags; + adeos_declare_cpuid; + adomain_t *adp; + + if (!adp_pipelined) + { + adeos_spin_unlock(&mutex->lock); + + if (flags) + adeos_hw_cli(); + else + adeos_hw_sti(); + + return; + } + +#ifdef CONFIG_SMP + mutex->owncpu = -1; +#endif /* CONFIG_SMP */ + + if (!flags) + adeos_hw_sti(); /* Absolutely needed. */ + + adeos_lock_cpu(hwflags); + + if (mutex->sleepq != NULL) + { + adomain_t *sleeper = mutex->sleepq; + /* Wake up the first most prioritary sleeper. */ + mutex->sleepq = sleeper->m_link; + __adeos_switch_to(adp_cpu_current[cpuid],sleeper,cpuid); + adeos_load_cpuid(); + } + else + { + mutex->owner = NULL; + adeos_spin_unlock(&mutex->lock); + } + + adp = adp_cpu_current[cpuid]; + + if (flags) + __set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + else + { + __clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (adp->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + + adeos_unlock_cpu(hwflags); +} + +#else /* !CONFIG_ADEOS_THREADS */ + +int adeos_destroy_mutex (admutex_t *mutex) + +{ + if (!adeos_spin_trylock(&mutex->lock) && + adp_current != adp_root) + return -EBUSY; + + return 0; +} + +unsigned long adeos_lock_mutex (admutex_t *mutex) + +{ + unsigned long flags; /* FIXME: won't work on SPARC */ + adeos_spin_lock_irqsave(&mutex->lock,flags); + return flags; +} + +void adeos_unlock_mutex (admutex_t *mutex, unsigned long flags) + +{ + adeos_spin_unlock_irqrestore(&mutex->lock,flags); +} + +#endif /* CONFIG_ADEOS_THREADS */ + +void __adeos_takeover (void) + +{ + __adeos_enable_pipeline(); + printk(KERN_WARNING "Adeos: Pipelining started.\n"); +} + +#ifdef MODULE + +static int __init adeos_init_module (void) + +{ + __adeos_takeover(); + return 0; +} + +static void __exit adeos_exit_module (void) + +{ + __adeos_disable_pipeline(); + printk(KERN_WARNING "Adeos: Pipelining stopped.\n"); +} + +module_init(adeos_init_module); +module_exit(adeos_exit_module); + +#endif /* MODULE */ + +EXPORT_SYMBOL(adeos_register_domain); +EXPORT_SYMBOL(adeos_unregister_domain); +EXPORT_SYMBOL(adeos_virtualize_irq_from); +EXPORT_SYMBOL(adeos_control_irq); +EXPORT_SYMBOL(__adeos_schedule_irq); +EXPORT_SYMBOL(adeos_free_irq); +EXPORT_SYMBOL(adeos_send_ipi); +EXPORT_SYMBOL(adeos_catch_event_from); +EXPORT_SYMBOL(adeos_init_attr); +EXPORT_SYMBOL(adeos_get_sysinfo); +EXPORT_SYMBOL(adeos_tune_timer); +EXPORT_SYMBOL(adeos_alloc_ptdkey); +EXPORT_SYMBOL(adeos_free_ptdkey); +EXPORT_SYMBOL(adeos_set_ptd); +EXPORT_SYMBOL(adeos_get_ptd); +EXPORT_SYMBOL(adeos_set_irq_affinity); +EXPORT_SYMBOL(adeos_init_mutex); +EXPORT_SYMBOL(adeos_destroy_mutex); +EXPORT_SYMBOL(adeos_lock_mutex); +EXPORT_SYMBOL(adeos_unlock_mutex); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/adeos/Makefile linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/adeos/Makefile --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/adeos/Makefile 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/adeos/Makefile 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,33 @@ +# +# Makefile for the Adeos layer. +# + +O_TARGET := built-in.o + +list-multi := adeos.o +export-objs := generic.o +adeos-objs := generic.o + +ifdef CONFIG_X86 +adeos-objs += x86.o +endif + +ifdef CONFIG_ARM +ifdef CONFIG_UCLINUX +adeos-objs += armnommu.o +else +adeos-objs += armv.o +export-objs += armv.o +endif +endif + +ifdef CONFIG_PPC +adeos-objs += ppc.o +endif + +obj-$(CONFIG_ADEOS) += adeos.o + +include $(TOPDIR)/Rules.make + +adeos.o: $(adeos-objs) + $(LD) -r -o $@ $(adeos-objs) diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/config.in linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/config.in --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/config.in 2004-08-03 19:25:37.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/config.in 2005-08-12 15:41:58.000000000 -0600 @@ -556,6 +556,13 @@ if [ "$CONFIG_SA1100_ACCELENT" = "y" ]; fi fi bool 'Networking support' CONFIG_NET + +tristate 'Adeos support' CONFIG_ADEOS +if [ "$CONFIG_ADEOS" != "n" ]; then + define_bool CONFIG_ADEOS_CORE y + bool 'Adeos domains are threads' CONFIG_ADEOS_THREADS +fi + bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL @@ -789,7 +796,9 @@ if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then # -- ahaigh@arm.com (23 August 2002) define_bool CONFIG_FRAME_POINTER n else + if [ "$CONFIG_ARCH_EP9301" != "y" ]; then define_bool CONFIG_FRAME_POINTER y + fi fi bool 'Verbose user fault messages' CONFIG_DEBUG_USER @@ -797,6 +806,9 @@ bool 'Include debugging information in k dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +if [ "$CONFIG_ARCH_EP9301" = "y" ]; then + dep_bool ' Compile Kernel with frame pointers' CONFIG_FRAME_POINTER $CONFIG_DEBUG_KERNEL +fi dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL dep_bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL dep_bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/adeos.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/adeos.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/adeos.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/adeos.c 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,527 @@ +/* + * linux/arch/arm/kernel/adeos.c + * + * Copyright (C) 2002-2005 Philippe Gerum. + * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * various tweaks, fixes (e.g. call asm_do_IRQ() instead of do_IRQ() and + * optimizations, backport of unthreaded support from Adeos/x86 for 2.6 + * + * 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 ADEOS core support for ARM. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +asmlinkage void asm_do_IRQ(int irq, + struct pt_regs *regs); + +struct pt_regs __adeos_irq_regs; + +/* adeos_critical_enter() -- Grab the superlock for entering a global + critical section. On this uniprocessor-only arch, this is identical + to hw cli(). */ + +unsigned long adeos_critical_enter (void (*syncfn)(void)) + +{ + unsigned long flags; + adeos_hw_local_irq_save(flags); + return flags; +} + +/* adeos_critical_exit() -- Release the superlock. */ + +void adeos_critical_exit (unsigned long flags) { + + adeos_hw_local_irq_restore(flags); +} + +void __adeos_init_stage (adomain_t *adp) + +{ + int cpuid, n; + + for (cpuid = 0; cpuid < ADEOS_NR_CPUS; cpuid++) + { + adp->cpudata[cpuid].irq_pending_hi = 0; + + for (n = 0; n < IPIPE_IRQ_IWORDS; n++) + adp->cpudata[cpuid].irq_pending_lo[n] = 0; + + for (n = 0; n < IPIPE_NR_IRQS; n++) + adp->cpudata[cpuid].irq_hits[n] = 0; + } + + for (n = 0; n < IPIPE_NR_IRQS; n++) + { + adp->irqs[n].acknowledge = NULL; + adp->irqs[n].handler = NULL; + adp->irqs[n].control = IPIPE_PASS_MASK; /* Pass but don't handle */ + } +} + +/* compute number of most-significant 1-bit (100...0 -> 31, 00...01 -> 0), input + * must not be 0 */ + +#if __LINUX_ARM_ARCH__ >= 5 + +extern inline int flnz (unsigned long word) + +{ + /* clz is only supported >= ARMv5 */ + int i; + /* effect of "clz i, word": + * if (word == 0) i = 32; else i = 31 - (bit position of most significant '1' in word) */ + __asm__( + "clz %0, %1" + : /* output */ "=r" (i) + : /* input */ "r" (word) + ); + /* word != 0 => i = 31 - (bit position of most significant '1' in word) */ + return 31 - i; +} + +#else /* __LINUX_ARM_ARCH__ < 5 */ + +static int flnz (unsigned long word) + +{ + int i = 0; + + if ((word & 0xFFFF0000UL) != 0) { + word >>= 16; + i += 16; + } + if ((word & 0xFF00UL) != 0) { + word >>= 8; + i += 8; + } + if ((word & 0xF0UL) != 0) { + word >>= 4; + i += 4; + } + if ((word & 0xCUL) != 0) { + word >>= 2; + i += 2; + } + if ((word & 0x2UL) != 0) + i += 1; + return i; +} + +#endif /* __LINUX_ARM_ARCH__ >= 5 */ + +/* __adeos_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 __adeos_sync_stage (unsigned long syncmask) + +{ + unsigned long mask, submask; + struct adcpudata *cpudata; + adeos_declare_cpuid; + int level, rank; + adomain_t *adp; + unsigned irq; + + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); + + adeos_load_cpuid(); + adp = adp_cpu_current[cpuid]; + cpudata = &adp->cpudata[cpuid]; + + do + { + /* 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) + { + /* Give a slight priority advantage to high-numbered IRQs + like the virtual ones. */ + level = flnz(mask); + __clear_bit(level,&cpudata->irq_pending_hi); + + while ((submask = cpudata->irq_pending_lo[level]) != 0) + { + rank = flnz(submask); + irq = (level << IPIPE_IRQ_ISHIFT) + rank; + + if (test_bit(IPIPE_LOCK_FLAG,&adp->irqs[irq].control)) + { + __clear_bit(rank,&cpudata->irq_pending_lo[level]); + continue; + } + + if (--cpudata->irq_hits[irq] == 0) + __clear_bit(rank,&cpudata->irq_pending_lo[level]); + + /* Allow the sync routine to be reentered on behalf of + the IRQ handler and any execution context switched + in by the IRQ handler. The latter also means that + returning from the switched out context is always + safe even if the sync routine has been reentered in + the meantime. */ + + __set_bit(IPIPE_STALL_FLAG,&cpudata->status); + +#ifdef CONFIG_ADEOS_PROFILING + __adeos_profile_data[cpuid].irqs[irq].n_synced++; + adeos_hw_tsc(__adeos_profile_data[cpuid].irqs[irq].t_synced); +#endif /* CONFIG_ADEOS_PROFILING */ + + if (adp == adp_root) + adeos_hw_sti(); + + ((void (*)(unsigned, struct pt_regs *))adp->irqs[irq].handler)(irq,&__adeos_irq_regs); + + adeos_hw_cli(); + + __clear_bit(IPIPE_STALL_FLAG,&cpudata->status); + } + } + } + while ((cpudata->irq_pending_hi & syncmask) != 0); +} + +/* __adeos_walk_pipeline(): Must be called with local interrupts + disabled. */ + +static inline void __adeos_walk_pipeline (struct list_head *pos, int cpuid) + +{ + adomain_t *this_domain = adp_cpu_current[cpuid]; + + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); + + while (pos != &__adeos_pipeline) + { + adomain_t *next_domain = list_entry(pos,adomain_t,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) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + else + { + __adeos_switch_to(this_domain,next_domain,cpuid); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (!test_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status) && + this_domain->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + + break; + } + else if (next_domain == this_domain) + break; + + pos = next_domain->p_link.next; + } +} + +/* __adeos_handle_irq() -- ADEOS's generic IRQ handler. An optimistic + interrupt protection log is maintained here for each domain. + Interrupts are off on entry. + Please note that this function is never called if RTAI immediate interrupt + dispatching is active (see entry-armv.S and arm/hal.c) */ + +asmlinkage int __adeos_handle_irq (int irq, struct pt_regs *regs) + +{ + struct list_head *head, *pos; + adeos_declare_cpuid; + int m_ack, s_ack; + + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); + + m_ack = irq & 0x100; + irq &= 0xff; + + if (unlikely(!adp_pipelined)) + { + /* Note that according to Russel King asm_do_IRQ() has to be called (at + * least for 2.4.21-rmk7), not do_IRQ() as the original ADEOS code had + * here. */ + asm_do_IRQ(irq,regs); + return 1; /* do Linux return-to-user stuff */ + } + + if (!adeos_virtual_irq_p(irq)) + irq = fixup_irq(irq); + + if (irq >= IPIPE_NR_IRQS) + { + printk(KERN_ERR "ADEOS: spurious interrupt %d\n",irq); + goto out; + } + + adeos_load_cpuid(); + +#ifdef CONFIG_ADEOS_PROFILING + __adeos_profile_data[cpuid].irqs[irq].n_handled++; + adeos_hw_tsc(__adeos_profile_data[cpuid].irqs[irq].t_handled); +#endif /* CONFIG_ADEOS_PROFILING */ + + s_ack = m_ack; + + if (unlikely(test_bit(IPIPE_STICKY_FLAG,&adp_cpu_current[cpuid]->irqs[irq].control))) + head = &adp_cpu_current[cpuid]->p_link; + else + head = __adeos_pipeline.next; + + /* Ack the interrupt. */ + + pos = head; + + while (pos != &__adeos_pipeline) + { + adomain_t *next_domain = list_entry(pos,adomain_t,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_hits[irq]++; + __adeos_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 (!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; + } + + if (likely(irq == ADEOS_TIMER_IRQ)) + { + __adeos_irq_regs.ARM_cpsr = regs->ARM_cpsr; + __adeos_irq_regs.ARM_pc = regs->ARM_pc; + } + + /* 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. To understand this code properly, one must keep + in mind that domains having a higher priority than the current + one are sleeping on the adeos_suspend_domain() service. In + addition, domains having a lower priority have been preempted + by an interrupt dispatched to a more prioritary domain. Once + the first and most prioritary stage has been selected here, the + subsequent stages will be activated in turn when each visited + domain calls adeos_suspend_domain() to wake up its neighbour + down the pipeline. */ + + __adeos_walk_pipeline(head,cpuid); + + adeos_load_cpuid(); + +out: + /* Tell entry-code if it should perform Linux stuff when returning to user + * space (return != 0) or not (return == 0). (Linux doesn't expect + * schedule() etc. to be called when interrupts are disabled from its + * perspective (i.e. root-ipipe is stalled) or current domain is not Linux.) */ + return (adp_cpu_current[cpuid] == adp_root && + !test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status)); +} + +/* adeos_trigger_irq() -- Push the interrupt to the pipeline entry + just like if it has been actually received from a hw source. This + both works for real and virtual interrupts. This also means that + the current domain might be immediately preempted by a more + prioritary domain who happens to handle this interrupt. */ + +int adeos_trigger_irq (unsigned irq) + +{ + struct pt_regs regs; + unsigned long flags; + + if (irq >= IPIPE_NR_IRQS || + (adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map))) + return -EINVAL; + + adeos_hw_local_irq_save(flags); + + regs.ARM_cpsr = flags; + + __adeos_handle_irq(irq | 0x100,®s); + + adeos_hw_local_irq_restore(flags); + + return 1; +} + +extern inline void __save_root_stall_flag_to_ibit (struct pt_regs *regs) + +{ + adeos_declare_cpuid; + if (test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status)) + regs->ARM_cpsr |= I_BIT; + else + regs->ARM_cpsr &= ~I_BIT; +} + +/* Save the root's domain stall bit in the user's CPSR I-bit (assumption: + * hw-interrupt are always enabled in user-space) so that the proper pipeline + * state for the root stage can be restored when returning from one of the + * following exception: + * swi (swi should (can?) only be used in user mode!) + * irq in user mode + * undefined instruction in user mode + * data abort in user mode + * prefetch abort in user mode + * return from fork (returns to user mode) + * i.e. all those that go through ret_fast_syscall, ret_disable_irq or + * ret_to_user, see entry-common.S and entry-armv.S */ +asmlinkage void __adeos_user_exception_save_root (struct pt_regs *regs) + +{ + if (likely(adp_pipelined)) + __save_root_stall_flag_to_ibit(regs); +} + +asmlinkage int __adeos_enter_syscall (struct pt_regs *regs, int scno) + +{ + /* hw-irqs are enabled when this function is entered */ + if (unlikely(__adeos_event_monitors[ADEOS_SYSCALL_PROLOGUE] > 0)) + { + long oldip = regs->ARM_ip; + int stop_event; + + ADEOS_PARANOIA_ASSERT(!adeos_hw_irqs_disabled()); + + regs->ARM_ip = scno; + stop_event = __adeos_handle_event(ADEOS_SYSCALL_PROLOGUE,regs); + regs->ARM_ip = oldip; + + /* We might enter here over a non-root domain and exit over + * the root one as a result of the issued syscall, so the interrupt + * flag might not have been fixed-up during entering the kernel. + * If the event is propageted (i.e. linux handles the syscall) we + * need to fix up the interrupt flag as + * __adeos_user_exception_save_root() is called upon returning to user + * space. */ + if (!stop_event) + __save_root_stall_flag_to_ibit(regs); + + return stop_event; + } + + return 0; +} + +asmlinkage int __adeos_exit_syscall (void) + +{ + /* hw-irqs are enabled when this function is entered */ + if (unlikely(__adeos_event_monitors[ADEOS_SYSCALL_EPILOGUE] > 0)) + return __adeos_handle_event(ADEOS_SYSCALL_EPILOGUE,NULL); + + return 0; +} + +asmlinkage void __adeos_ret_to_user_restore_root (struct pt_regs *regs) + +{ + adeos_declare_cpuid; + + if (unlikely(!adp_pipelined)) + return; + + ADEOS_PARANOIA_ASSERT(!adeos_hw_irqs_disabled()); + + /* Restore root's ipipe stall state as it used to be on kernel entry. + * Side-effect: hw-irqs are forced to be enabled in user-mode. */ + + if (regs->ARM_cpsr & I_BIT) + { + regs->ARM_cpsr &= ~I_BIT; + adeos_hw_cli(); + __set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + } + else + { + adeos_hw_cli(); + __clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + + /* Sync all IRQs here, who knows when the next interrupt will happen + * (only then will the stage be synced!). */ + if (adp_root->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + /* We return with hw-irqs disabled, ready for restoring registers. */ +} + +/* default handler for Adeos syscall (will be replaced by non-root domain, e.g. + * RTAI for LXRT calls and SRQs */ +asmlinkage int __adeos_handle_syscall(struct pt_regs *regs) + +{ + /* just return error code and do fast return from syscall */ + *(long long*)®s->ARM_r0 = -ENODEV; + return 1; +} diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/armksyms.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/armksyms.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/armksyms.c 2004-07-22 13:48:58.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/armksyms.c 2005-08-12 15:41:58.000000000 -0600 @@ -56,6 +56,7 @@ extern int sys_exit(int); */ extern void __ashldi3(void); extern void __ashrdi3(void); +extern void __divdi3(void); extern void __divsi3(void); extern void __lshrdi3(void); extern void __modsi3(void); @@ -86,6 +87,36 @@ extern void __do_softirq(void); __attribute__((section("__ksymtab"))) = \ { (unsigned long)&orig, __kstrtab_##sym }; +#ifdef CONFIG_ADEOS_CORE +#ifdef CONFIG_ADEOS_MODULE +EXPORT_SYMBOL(adp_pipelined); +#include +EXPORT_SYMBOL(asm_do_IRQ); +#endif /* CONFIG_ADEOS_MODULE */ +EXPORT_SYMBOL(adeos_critical_enter); +EXPORT_SYMBOL(adeos_critical_exit); +EXPORT_SYMBOL(adeos_trigger_irq); +EXPORT_SYMBOL(__adeos_sync_stage); +EXPORT_SYMBOL(__adeos_irq_regs); +EXPORT_SYMBOL(__adeos_tune_timer); +#ifdef CONFIG_ADEOS_THREADS +EXPORT_SYMBOL(__adeos_switch_domain); +#endif /* CONFIG_ADEOS_THREADS */ +EXPORT_SYMBOL(__adeos_handle_irq); +/* The following are per-platform convenience exports which are needed + by some Adeos domains loaded as kernel modules. */ +extern struct irqdesc irq_desc[]; +EXPORT_SYMBOL_NOVERS(irq_desc); +EXPORT_SYMBOL_NOVERS(__switch_to); +extern void show_regs(struct pt_regs * regs); +EXPORT_SYMBOL_NOVERS(show_regs); +EXPORT_SYMBOL(adeos_syscall_entry); +EXPORT_SYMBOL(adeos_irq_entry); +EXPORT_SYMBOL(adeos_root_domain); +/* for debugging */ +EXPORT_SYMBOL(__backtrace); +#endif /* CONFIG_ADEOS_CORE */ + /* * floating point math emulator support. * These symbols will never change their calling convention... @@ -227,6 +258,7 @@ EXPORT_SYMBOL_NOVERS(__put_user_8); /* gcc lib functions */ EXPORT_SYMBOL_NOVERS(__ashldi3); EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__divdi3); EXPORT_SYMBOL_NOVERS(__divsi3); EXPORT_SYMBOL_NOVERS(__lshrdi3); EXPORT_SYMBOL_NOVERS(__modsi3); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/entry-armv.S linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/entry-armv.S --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/entry-armv.S 2004-08-03 19:25:38.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/entry-armv.S 2005-08-12 15:41:58.000000000 -0600 @@ -4,6 +4,13 @@ * Copyright (C) 1996,1997,1998 Russell King. * ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk) * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * Adeos support for EP93xx + * + * Copyright (C) 2005 Adriano Bess (awbess@gmail.com) + * Ronald Gomes (ronaldfloripa@ig.com.br), + * Automatisa Sistemas + * Small fixes on Adeos for TS7200 board * 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 * published by the Free Software Foundation. @@ -16,7 +23,6 @@ #include #include "entry-header.S" - #ifdef IOC_BASE /* IOC / IOMD based hardware */ #include @@ -459,6 +465,9 @@ ENTRY(soft_irq_mask) .macro disable_fiq .endm + @ get number of irq from PIC + @ is irq <=> Z flag is 0 (ne), number of interrupt to be + @ handled is in \irqnr // Exit: irqnr Highest priority IRQ currently active // flags NE irqnr valid // EQ irqnr not valid (spurious IRQ) @@ -662,6 +671,9 @@ ENTRY(anakin_active_irqs) /* * Invalid mode handlers */ +#ifdef CONFIG_ADEOS_CORE +/* No need to change anything here, kernel will panic anyhow. */ +#endif __pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go stmia sp, {r0 - lr} @ Save XXX r0 - lr ldr r4, .LCabt @@ -711,12 +723,27 @@ __dabt_svc: sub sp, sp, #S_FRAME_SIZE ldr r2, .LCabt add r0, sp, #S_FRAME_SIZE ldmia r2, {r2 - r4} @ get pc, cpsr +#ifdef CONFIG_ADEOS_CORE + @ Earliest point we can enable hw-interrupts because of values + @ saved in __temp_abt (i.e. disabled irqs guards against values + @ being changed). + @ No other domain than root should generate this + @ exception => it is OK to enable irqs. +@ *TODO* check if root domain? (call __adeos_handle_event(SIGxxx)?) + @ There is no need to restore root's stall state (as it is not + @ changed by the exception). + enable_irq ip +#endif /* CONFIG_ADEOS_CORE */ add r5, sp, #S_SP mov r1, lr stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro +#ifdef CONFIG_ADEOS_CORE + @ Interrupts are alredy enabled. +#else /* !CONFIG_ADEOS_CORE */ mrs r9, cpsr @ Enable interrupts if they were tst r3, #I_BIT biceq r9, r9, #I_BIT @ previously +#endif /* CONFIG_ADEOS_CORE */ /* * This routine must not corrupt r9 */ @@ -727,11 +754,14 @@ __dabt_svc: sub sp, sp, #S_FRAME_SIZE #else bl cpu_data_abort #endif +#ifdef CONFIG_ADEOS_CORE + @ cpu_data_abort does not change hw-irqs, no need to reenable them. +#else /* !CONFIG_ADEOS_CORE */ msr cpsr_c, r9 +#endif /* !CONFIG_ADEOS_CORE */ mov r2, sp bl SYMBOL_NAME(do_DataAbort) - mov r0, #I_BIT | MODE_SVC - msr cpsr_c, r0 + disable_irq r0 @ disable interrupt hard ldr r0, [sp, #S_PSR] msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -751,7 +781,11 @@ __irq_svc: sub sp, sp, #S_FRAME_SIZE @ routine called with r0 = irq number, r1 = struct pt_regs * @ adrsvc ne, lr, 1b +#ifdef CONFIG_ADEOS_CORE + ldrne pc, adeos_irq_entry @ ...(r0 = irq number, r1 = struct pt_regs *) +#else /* !CONFIG_ADEOS_CORE */ bne asm_do_IRQ +#endif /*CONFIG_ADEOS_CORE */ ldr r0, [sp, #S_PSR] @ irqs are already disabled msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -764,6 +798,17 @@ __und_svc: sub sp, sp, #S_FRAME_SIZE ldr r7, .LCund mov r6, lr ldmia r7, {r7 - r9} +#ifdef CONFIG_ADEOS_CORE + @ Earliest point we can enable hw-interrupts because of values + @ saved in __temp_und (i.e. disabled irqs guards against values + @ being changed). + @ No other domain than root should generate this + @ exception => it is OK to enable irqs. +@ *TODO* check if root domain? (call __adeos_handle_event(SIGxxx)?) + @ There is no need to restore root's stall state (as it is not + @ changed by the exception). + enable_irq ip +#endif /* CONFIG_ADEOS_CORE */ add r5, sp, #S_FRAME_SIZE add r4, sp, #S_SP stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro @@ -771,12 +816,21 @@ __und_svc: sub sp, sp, #S_FRAME_SIZE adrsvc al, r9, 1f @ r9 = normal FP return bl call_fpe @ lr = undefined instr return +#ifdef CONFIG_ADEOS_CORE + @ undefined instruction -> inform Adeos about it (this is *not* the + @ "FPU usage" event because there is no FPU support in Adeos for ARM) + mov r0, #4 @ SIGILL + mov r1, sp @ struct pt_regs *regs + bl __adeos_handle_event + cmp r0, #0 + bne 1f @ !propagate -> return +#endif /* CONFIG_ADEOS_CORE */ + mov r0, r5 @ unsigned long pc mov r1, sp @ struct pt_regs *regs bl SYMBOL_NAME(do_undefinstr) -1: mov r0, #I_BIT | MODE_SVC - msr cpsr_c, r0 +1: disable_irq r0 ldr lr, [sp, #S_PSR] @ Get SVC cpsr msr spsr, lr ldmia sp, {r0 - pc}^ @ Restore SVC registers @@ -787,18 +841,32 @@ __pabt_svc: sub sp, sp, #S_FRAME_SIZE ldr r2, .LCabt add r0, sp, #S_FRAME_SIZE ldmia r2, {r2 - r4} @ get pc, cpsr +#ifdef CONFIG_ADEOS_CORE + @ Earliest point we can enable hw-interrupts because of values + @ saved in __temp_abt (i.e. disabled irqs guards against values + @ being changed). + @ No other domain than root should generate this + @ exception => it is OK to enable irqs. +@ *TODO* check if root domain? (call __adeos_handle_event(SIGxxx)?) + @ There is no need to restore root's stall state (as it is not + @ changed by the exception). + enable_irq ip +#endif /* CONFIG_ADEOS_CORE */ add r5, sp, #S_SP mov r1, lr stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro +#ifdef CONFIG_ADEOS_CORE + @ Interrupts are already enabled. +#else /* !CONFIG_ADEOS_CORE */ mrs r9, cpsr @ Enable interrupts if they were tst r3, #I_BIT biceq r9, r9, #I_BIT @ previously msr cpsr_c, r9 +#endif /* CONFIG_ADEOS_CORE */ mov r0, r2 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler - mov r0, #I_BIT | MODE_SVC - msr cpsr_c, r0 + disable_irq r0 ldr r0, [sp, #S_PSR] msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -811,7 +879,12 @@ __pabt_svc: sub sp, sp, #S_FRAME_SIZE .LCprocfns: .word SYMBOL_NAME(processor) #endif .LCfp: .word SYMBOL_NAME(fp_enter) - +#ifdef CONFIG_ADEOS_CORE + @ Hook for RTAI immediate irq dispatching. + .globl SYMBOL_NAME(adeos_irq_entry) +SYMBOL_NAME(adeos_irq_entry): + .word SYMBOL_NAME(__adeos_handle_irq) @ Adeos default irq handler +#endif /* CONFIG_ADEOS_CORE */ irq_prio_table /* @@ -825,6 +898,20 @@ __dabt_usr: sub sp, sp, #S_FRAME_SIZE @ ldmia r7, {r2 - r4} @ Get USR pc, cpsr stmia r5, {r2 - r4} @ Save USR pc, cpsr, old_r0 stmdb r5, {sp, lr}^ +#ifdef CONFIG_ADEOS_CORE + @ Earliest point we can enable hw-interrupts because of + @ "stmdb ...,{ }^" (it stores the user registers which are + @ protected by the disabled irqs). + enable_irq ip + mov r5, r1 @ save registers + mov r6, r2 + mov r4, r3 + mov r0, sp @ regs (arg for func.) + bl SYMBOL_NAME(__adeos_user_exception_save_root) + mov r3, r4 @ restore registers + mov r2, r6 + mov r1, r5 +#endif alignment_trap r7, r7, __temp_abt zero_fp #ifdef MULTI_CPU @@ -834,8 +921,11 @@ __dabt_usr: sub sp, sp, #S_FRAME_SIZE @ #else bl cpu_data_abort #endif - mov r2, #MODE_SVC - msr cpsr_c, r2 @ Enable interrupts +#ifdef CONFIG_ADEOS_CORE + @ Interrupts are already enabled. +#else /* !CONFIG_ADEOS_CORE */ + enable_irq r2 @ Enable interrupts +#endif /* CONFIG_ADEOS_CORE */ mov r2, sp adrsvc al, lr, ret_from_exception b SYMBOL_NAME(do_DataAbort) @@ -851,15 +941,46 @@ __irq_usr: sub sp, sp, #S_FRAME_SIZE alignment_trap r4, r7, __temp_irq zero_fp 1: get_irqnr_and_base r0, r6, r5, lr +#ifdef CONFIG_ADEOS_CORE + beq 2f @ no irq -> fast return + /* assert(was-irq) */ + mov r1, sp + mov lr, pc + ldr pc, adeos_irq_entry @ ...(r0 = irq number, r1 = struct pt_regs *) + @ Adeos irq handler returns with hw-irqs disabled. + teq r0, #0 @ r0 = return code of adeos_irq_entry() + /* r0 == 0 <=> irq did not happen in Linux context OR root-ipipe is stalled + * do a fast return to user-mode to avoid schedule etc. + * (either context is not right or interrupt would never + * have happened without Adeos (so Linux doesn't expect + * schedule etc.)) + * r0 != 0 <=> irq did happen in Linux context and root-ipipe is not stalled + * "normal" interrupt in Linux context, do like original + * code and return to user-mode via ret_to_user + */ + bne 3f +2: /* assert(!was-irq || !in-linux-context || root-ipipe-is-stalled) */ + restore_user_regs +3: /* assert(was-irq && in-linux-context && !root-ipipe-is-stalled) */ + @ We have to fix-up the interrupt flag in the saved CPSR + @ so that ret_to_user restores the stall state correctly. + enable_irq ip @ do it with hw-irqs enabled + mov r0, sp + bl SYMBOL_NAME(__adeos_user_exception_save_root) + mov why, #0 @ hw-irqs are still enabled + get_current_task tsk + b ret_to_user +#else /* !CONFIG_ADEOS_CORE */ movne r1, sp adrsvc ne, lr, 1b @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ bne asm_do_IRQ - mov why, #0 + mov why, #0 @ we come here with interrupts already disabled get_current_task tsk b ret_to_user +#endif /* CONFIG_ADEOS_CORE */ .ltorg @@ -871,6 +992,14 @@ __und_usr: sub sp, sp, #S_FRAME_SIZE @ ldmia r4, {r5 - r7} stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 stmdb r8, {sp, lr}^ @ Save user sp, lr +#ifdef CONFIG_ADEOS_CORE + @ Earliest point we can enable hw-interrupts because of + @ "stmdb ...,{ }^" (it stores the user registers which are + @ protected by the disabled irqs). + enable_irq ip + mov r0, sp @ regs (arg for func.) + bl SYMBOL_NAME(__adeos_user_exception_save_root) +#endif /* CONFIG_ADEOS_CORE */ alignment_trap r4, r7, __temp_und zero_fp tst r6, #T_BIT @ Thumb mode @@ -878,17 +1007,27 @@ __und_usr: sub sp, sp, #S_FRAME_SIZE @ adrsvc al, r9, ret_from_exception @ r9 = normal FP return adrsvc al, lr, fpundefinstr @ lr = undefined instr return -call_fpe: enable_irq r10 - get_current_task r10 +call_fpe: get_current_task r10 mov r8, #1 strb r8, [r10, #TSK_USED_MATH] @ set current->used_math ldr r4, .LCfp add r10, r10, #TSS_FPESAVE @ r10 = workspace ldr pc, [r4] @ Call FP module USR entry point -fpundefinstr: mov r0, #MODE_SVC - msr cpsr_c, r0 @ Enable interrupts +fpundefinstr: enable_irq r0 @ Enable interrupts +#ifdef CONFIG_ADEOS_CORE + @ undefined instruction -> inform Adeos about it (this is *not* the + @ "FPU usage" event because there is no FPU support in Adeos for ARM) + mov r5, lr @ save lr + mov r0, #4 @ SIGILL + mov r1, sp @ struct pt_regs *regs + bl __adeos_handle_event + cmp r0, #0 + bne ret_from_exception @ !propagate -> return + mov r0, r5 @ r0 = old lr +#else /* !CONFIG_ADEOS_CORE */ mov r0, lr +#endif /* CONFIG_ADEOS_CORE */ mov r1, sp adrsvc al, lr, ret_from_exception b SYMBOL_NAME(do_undefinstr) @@ -901,10 +1040,21 @@ __pabt_usr: sub sp, sp, #S_FRAME_SIZE @ ldmia r4, {r5 - r7} @ Get USR pc, cpsr stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr +#ifdef CONFIG_ADEOS_CORE + @ Earliest point we can enable hw-interrupts because of + @ "stmdb ...,{ }^" (it stores the user registers which are + @ protected by the disabled irqs). + enable_irq ip + mov r0, sp @ regs + bl SYMBOL_NAME(__adeos_user_exception_save_root) +#endif /* CONFIG_ADEOS_CORE */ alignment_trap r4, r7, __temp_abt zero_fp - mov r0, #MODE_SVC - msr cpsr_c, r0 @ Enable interrupts +#ifdef CONFIG_ADEOS_CORE + @ Interrupts are already enabled. +#else /* !CONFIG_ADEOS_CORE */ + enable_irq r0 @ Enable interrupts +#endif /* CONFIG_ADEOS_CORE */ mov r0, r5 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler @@ -913,7 +1063,12 @@ __pabt_usr: sub sp, sp, #S_FRAME_SIZE @ * This is the return code to user mode for abort handlers */ ENTRY(ret_from_exception) +#ifdef CONFIG_ADEOS_CORE + @ hw-irqs should already be enabled, but be paranoid + enable_irq r1 +#else /* !CONFIG_ADEOS_CORE */ disable_irq r1 +#endif /* CONFIG_ADEOS_CORE */ mov why, #0 get_current_task tsk b ret_to_user @@ -927,6 +1082,11 @@ ENTRY(fp_enter) * r0 = previous, r1 = next, return previous. * previous and next are guaranteed not to be the same. */ +#ifdef CONFIG_ADEOS_CORE +/* I think hw-irqs must be disabled on entry to protect spsr_svc from being + * modified by an interrupt. (Although I haven't found anything in plain + * Linux that guarantees irqs to be disabled ...) */ +#endif ENTRY(__switch_to) stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack mrs ip, cpsr @@ -939,6 +1099,34 @@ ENTRY(__switch_to) msr spsr, ip @ Save tasks CPSR into SPSR for this return ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously +#ifdef CONFIG_ADEOS_CORE +#ifdef CONFIG_ADEOS_THREADS +/* + * Domain switch code. Interrupts must be off on entry. + * r0 = incoming domain, r1 = &adp_cpu_current[cpuid] + * Contributed by Jerome Poichet + */ + +ENTRY(__adeos_switch_domain) + stmfd sp!, {r0 - sl, fp, lr} @ push most registers onto stack (scratch ip never) + mrs ip, cpsr @ get current cpsr_SVC and + str ip, [sp, #-4]! @ push it onto stack + mrc p15, 0, r2, c3, c0 @ get current domain_access_control and + str r2, [sp, #-4]! @ push it onto stack + + ldr r2, [r1] @ r2 = adp_cpu_current[cpuid] (outgoing domain) + str sp, [r2, #4] @ save outgoing sp_SVC + str r0, [r1] @ adp_cpu_current[cpuid] = incoming_domain + ldr sp, [r0, #4] @ load incoming sp_SVC + + ldr r2, [sp], #4 @ pop previous domain_access_control from stack + ldr ip, [sp], #4 @ pop previous cpsr_SVC from stack + mcr p15, 0, r2, c3, c0 @ restore previous domain_access_control + msr spsr, ip @ replace current spsr_SVC with previous cpsr_SVC + ldmfd sp!, {r0 - sl, fp, pc}^ @ pop previous registers, pc = previous lr +#endif /* CONFIG_ADEOS_THREADS */ +#endif /* CONFIG_ADEOS_CORE */ + .section ".text.init",#alloc,#execinstr /* * Vector stubs. NOTE that we only align 'vector_IRQ' to a cache line boundary, @@ -1161,6 +1349,19 @@ __stubs_end: .equ __real_stubs_start, .LCvectors + 0x200 +/* + * Exception vectors (see ARM Architecture Reference Manual, 2.6 Exceptions) + * Vector base is either 0x00000000 or 0xffff0000. + * offset execption type + * 00 reset + * 04 undefined instruction + * 08 software interrupt + * 0C prefetch abort (instruction fetch memory abort) + * 10 data abort (data access memory abort) + * 14 address ecxeption (no longer used) + * 18 interrupt + * 1C fast interrupt + */ .LCvectors: swi SYS_ERROR0 b __real_stubs_start + (vector_undefinstr - __stubs_start) ldr pc, __real_stubs_start + (.LCvswi - __stubs_start) diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/entry-common.S linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/entry-common.S --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/entry-common.S 2004-07-22 13:48:58.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/entry-common.S 2005-08-12 15:41:58.000000000 -0600 @@ -3,6 +3,9 @@ * * Copyright (C) 2000 Russell King * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * Adeos support for EP93xx + * * 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 * published by the Free Software Foundation. @@ -27,6 +30,57 @@ ENTRY(__do_softirq) bl do_softirq ldmfd sp!, {r0 - r3, ip, pc} +#ifdef CONFIG_ADEOS_CORE +/* + * This is how user mode exceptions are handled under Adeos (i.e. when + * hw-irqs are enabled, how to return to user mode, etc.): + * + ret_from_fork + * enable-irq + * ... + * goto ret_disable_irq + * + __sys_trace_return + * enable-irq + * ... + * goto ret_disable_irq + * + vector_swi: + * enable-irq + * if (is-adeos-syscall) { + * r = adeos_syscall_entry(pt_regs) + * if (r != 0) { disable_irq; goto adeos_fast_ret } + * enable-irq + * goto ret_to_user + * } + * if (__adeos_enter_syscall() != 0) { disable-irq; goto adeos_fast_ret } + * __adeos_user_exception_save_root() + * syscall() + * goto ret_fast_syscall + * + __irq_usr (if (was-irq && in-linux-context && !root-ipipe-is-stalled)): + * if (adeos_irq_entry(irq, regs) == 0) restore_user_regs + * enable-irq + * __adeos_user_exception_save_root() + * goto ret_to_user + * + __und_usr: + * enable-irq + * __adeos_user_exception_save_root() + * fp-emu() + * if (!fp-was-ok) { enable-irq; if (__adeos_handle_event()) do_undefinstr() } + * goto ret_from_exception + * + __dabt_usr: + * enable-irq + * __adeos_user_exception_save_root() + * cpu_data_abort() + * do_DataAbort() + * goto ret_from_exception + * + __pabt_usr: + * enable-irq + * __adeos_user_exception_save_root() + * do_PrefetchAbort() + * goto ret_from_exception + * + ret_from_exception: + * enable-irq + * goto ret_to_user + */ +#endif /* CONFIG_ADEOS_CORE */ .align 5 /* * This is the fast syscall return path. We do as little as @@ -34,12 +88,32 @@ ENTRY(__do_softirq) * stack. */ ret_fast_syscall: +#ifdef CONFIG_ADEOS_CORE + mov r7, r0 @ save return code + bl __adeos_exit_syscall + cmp r0, #0 + mov r0, r7 @ restore return code + bne 1f @ don't propagate (but restore root's ipipe stall flag) +#else /* !CONFIG_ADEOS_CORE */ disable_irq r1 @ ensure IRQs are disabled +#endif /* CONFIG_ADEOS_CORE */ ldr r1, [tsk, #TSK_NEED_RESCHED] ldr r2, [tsk, #TSK_SIGPENDING] teq r1, #0 @ need_resched || sigpending teqeq r2, #0 bne slow +#ifdef CONFIG_ADEOS_CORE +1: @ Entered from ret_fast_syscall if (!need_resched && !sigpending) + @ || __adeos_exit_syscall() says do not propagate. + @ Restore root's ipipe stall flag. + mov r7, r0 @ save r0 + add r0, sp, #S_OFF @ let r0 point to user regs + bl SYMBOL_NAME(__adeos_ret_to_user_restore_root) + @ comes back with hw-irqs disabled + mov r0, r7 @ restore r0 +adeos_fast_ret: + @ hw-irqs must be disabled here! +#endif /* CONFIG_ADEOS_CORE */ fast_restore_user_regs /* @@ -55,9 +129,11 @@ slow: str r0, [sp, #S_R0+S_OFF]! @ retur reschedule: bl SYMBOL_NAME(schedule) ret_disable_irq: +#ifndef CONFIG_ADEOS_CORE + @ We disable irqs just before restoring the registers, not now. disable_irq r1 @ ensure IRQs are disabled -ENTRY(ret_to_user) -ret_slow_syscall: +#endif /* !CONFIG_ADEOS_CORE */ +ENTRY(ret_to_user) @ return from exception to user-mode ldr r1, [tsk, #TSK_NEED_RESCHED] ldr r2, [tsk, #TSK_SIGPENDING] teq r1, #0 @ need_resched => schedule() @@ -65,6 +141,12 @@ ret_slow_syscall: 1: teq r2, #0 @ sigpending => do_signal() bne __do_signal restore: +#ifdef CONFIG_ADEOS_CORE + @ Restore root's ipipe stall flag. + mov r0, sp @ let r0 point to user regs + bl SYMBOL_NAME(__adeos_ret_to_user_restore_root) + @ comes back with hw-irqs disabled +#endif /* CONFIG_ADEOS_CORE */ restore_user_regs __do_signal: @@ -73,7 +155,9 @@ __do_signal: mov r1, sp @ 'regs' mov r2, why @ 'syscall' bl SYMBOL_NAME(do_signal) @ note the bl above sets lr +#ifndef CONFIG_ADEOS_CORE disable_irq r1 @ ensure IRQs are disabled +#endif /* !CONFIG_ADEOS_CORE */ b restore /* @@ -82,6 +166,11 @@ __do_signal: * calling schedule_tail). */ ENTRY(ret_from_fork) +#ifdef CONFIG_ADEOS_CORE + enable_irq ip @ should already be enabled, be paranoid + @ Note, that the i_bit in the saved cpsr is 0 and the new process + @ will be started with an unstalled stage. +#endif /* CONFIG_ADEOS_CORE */ bl SYMBOL_NAME(schedule_tail) get_current_task tsk ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing @@ -143,9 +232,27 @@ ENTRY(vector_swi) str r4, [sp, #-S_OFF]! @ push fifth arg get_current_task tsk - ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing bic scno, scno, #0xff000000 @ mask off SWI op-code +#ifdef CONFIG_ADEOS_CORE + ldr tbl, .adeos_syscall_magic @ check if it is the Adeos syscall + cmp scno, tbl + beq handle_adeos_syscall +#endif /* CONFIG_ADEOS_CORE */ eor scno, scno, #OS_NUMBER << 20 @ check OS number +#ifdef CONFIG_ADEOS_CORE + add r0, sp, #S_OFF @ let r0 point to user regs + mov r1, scno + bl __adeos_enter_syscall @ event "enter Linux syscall" + cmp r0, #0 @ r0 == 0 <=> propagate + movne r0, #-EINVAL @ !propagate -> return EINVAL + disable_irq_cond ne @ !propagate -> disable hw-irqs + addeq tbl, sp, #S_OFF @ propagate -> tbl = saved user regs + bne adeos_fast_ret @ !propagate -> fast-return + mov r0, tbl @ saved regs + bl SYMBOL_NAME(__adeos_user_exception_save_root) + ldmia tbl, {r0-r3} @ restore syscall args from saved regs +#endif /* CONFIG_ADEOS_CORE */ + ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing adr tbl, sys_call_table @ load syscall table pointer tst ip, #PT_TRACESYS @ are we tracing syscalls? bne __sys_trace @@ -161,6 +268,27 @@ ENTRY(vector_swi) bcs SYMBOL_NAME(arm_syscall) b SYMBOL_NAME(sys_ni_syscall) @ not private func +#ifdef CONFIG_ADEOS_CORE +handle_adeos_syscall: + @ handle Adeos syscall (used by RTAI for LXRT calls and SRQs) + ldr ip, adeos_syscall_entry + add r0, sp, #S_OFF @ r0 <- ptr to saved regs + mov lr, pc + mov pc, ip @ adeos_syscall_entry(pt_regs*) + cmp r0 , #0 @ slow or fast return? + @ long long return value is in saved r0/r1, r0 is not loaded from stack + @ by fast_restore_user_regs => load it here. + ldrne r0, [sp, #S_R0 + S_OFF] + @ r0 != 0 -> fast + disable_irq_cond ne + bne adeos_fast_ret + @ r0 == 0 -> slow return + enable_irq ip + add sp, sp, #S_OFF @ fix stack-pointer for restore_user_regs + mov why, #0 @ no longer a real syscall + b ret_to_user +#endif /* CONFIG_ADEOS_CORE */ + /* * This is the really slow path. We're going to be doing * context switches, and waiting for our parent to respond. @@ -178,6 +306,9 @@ __sys_trace: b 2b __sys_trace_return: +#ifdef CONFIG_ADEOS_CORE + enable_irq ip @ should already be enabled, be paranoid +#endif /* CONFIG_ADEOS_CORE */ str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 mov r1, sp mov r0, #1 @ trace exit [IP = 1] @@ -190,6 +321,15 @@ __sys_trace_return: __cr_alignment: .word SYMBOL_NAME(cr_alignment) #endif +#ifdef CONFIG_ADEOS_CORE + @ special syscall to make transition from user-space to kernel-space + @ (used by RTAI to implement LXRT calls and SRQs) +.adeos_syscall_magic: + .word 0x9ffff0 @ see asm-arm/rtai_vectors.h + .globl SYMBOL_NAME(adeos_syscall_entry) +SYMBOL_NAME(adeos_syscall_entry): + .word SYMBOL_NAME(__adeos_handle_syscall) @ Adeos default syscall handler +#endif /* CONFIG_ADEOS_CORE */ .type sys_call_table, #object ENTRY(sys_call_table) diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/entry-header.S linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/entry-header.S --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/entry-header.S 2004-07-22 13:48:58.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/entry-header.S 2005-08-12 15:41:58.000000000 -0600 @@ -71,11 +71,12 @@ #ifdef CONFIG_CPU_32 .macro set_cpsr_c, reg, mode -#if 1 +#if 0 /* broken binutils */ mov \reg, \mode msr cpsr_c, \reg #else + /* binutils 2.14.90 are OK -- mike@firmix.at */ msr cpsr_c, \mode #endif .endm @@ -88,6 +89,16 @@ set_cpsr_c \temp, #MODE_SVC .endm +#ifdef CONFIG_ADEOS_CORE + .macro set_cpsr_c_cond, cond, mode + msr\cond cpsr_c, \mode + .endm + + .macro disable_irq_cond, cond + set_cpsr_c_cond \cond, #I_BIT | MODE_SVC + .endm +#endif + .macro save_user_regs sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ Calling r0 - r12 diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/irq.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/irq.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/irq.c 2004-08-03 19:25:38.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/irq.c 2005-08-12 15:41:58.000000000 -0600 @@ -152,6 +152,10 @@ int get_irq_list(char *buf) return p - buf; } +#ifdef CONFIG_ADEOS_CORE +/* increase performance by disabling IRQ lock detection */ +#define check_irq_lock(desc, irq, regs) (0) +#else /* !CONFIG_ADEOS_CORE */ /* * IRQ lock detection. * @@ -183,6 +187,7 @@ static int check_irq_lock(struct irqdesc } return 0; } +#endif /* CONFIG_ADEOS_CORE */ static void __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) @@ -220,6 +225,9 @@ void do_IRQ(int irq, struct pt_regs * re * Acknowledge and clear the IRQ, but (if its * a level-based IRQ, don't mask it) */ +#ifdef CONFIG_ADEOS_CORE + if (!adp_pipelined) +#endif /* CONFIG_ADEOS_CORE */ desc->mask_ack(irq); /* @@ -310,6 +318,11 @@ static void do_pending_irqs(struct pt_re */ asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs) { +#ifdef CONFIG_ADEOS_CORE + /* Only fix-up irq if pipline is not active (then it was already done + * in __adeos_handle_irq(). */ + if (!adp_pipelined) +#endif /* CONFIG_ADEOS_CORE */ irq = fixup_irq(irq); /* @@ -346,6 +359,7 @@ asmlinkage void asm_do_IRQ(int irq, stru return; } +#ifndef CONFIG_ADEOS_CORE /* increase performance by disabling IRQ lock detection */ static void irqlck_timeout(unsigned long _data) { struct irqdesc *desc = (struct irqdesc *)_data; @@ -364,6 +378,7 @@ static void irqlck_timeout(unsigned long spin_unlock(&irq_controller_lock); } +#endif /* !CONFIG_ADEOS_CORE */ #ifdef CONFIG_ARCH_ACORN void do_ecard_IRQ(int irq, struct pt_regs *regs) @@ -678,9 +693,11 @@ void __init init_IRQ(void) irq_desc[irq].mask = dummy_mask_unmask_irq; irq_desc[irq].unmask = dummy_mask_unmask_irq; INIT_LIST_HEAD(&irq_desc[irq].pend); +#ifndef CONFIG_ADEOS_CORE /* increase performance by disabling IRQ lock detection */ init_timer(&irq_desc[irq].lck_timer); irq_desc[irq].lck_timer.data = (unsigned long)&irq_desc[irq]; irq_desc[irq].lck_timer.function = irqlck_timeout; +#endif /* !CONFIG_ADEOS_CORE */ } init_arch_irq(); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/Makefile linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/Makefile --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/Makefile 2004-07-22 13:48:58.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/Makefile 2005-08-12 15:41:58.000000000 -0600 @@ -39,7 +39,7 @@ obj-m := obj-n := obj- := -export-objs := armksyms.o dma.o ecard.o fiq.o io.o oldlatches.o time.o +export-objs := adeos.o armksyms.o dma.o ecard.o fiq.o io.o oldlatches.o time.o no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \ $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \ @@ -52,6 +52,7 @@ ifneq ($(findstring y,$(no-irq-arch)),y) obj-y += irq-arch.o endif +obj-$(CONFIG_ADEOS_CORE) += adeos.o obj-$(CONFIG_ARCH_ACORN) += ecard.o fiq.o time-acorn.o obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o obj-$(CONFIG_ARCH_RISCSTATION) += time-acorn.o diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/process.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/process.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/process.c 2004-07-22 13:48:58.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/process.c 2005-08-12 15:41:58.000000000 -0600 @@ -72,10 +72,22 @@ void (*pm_power_off)(void); */ void default_idle(void) { +#ifdef CONFIG_ADEOS_CORE + /* if we don't do a hard cli, we might miss an interrupt and + * sleep for an indefinite time (system lock-up or increased + * interrupt latency) -- */ + adeos_hw_cli(); +#else local_irq_disable(); +#endif if (!current->need_resched && !hlt_counter) arch_idle(); +#ifdef CONFIG_ADEOS_CORE + adeos_hw_sti(); + ADEOS_PARANOIA_ASSERT(test_bit(IPIPE_STALL_FLAG, &adp_root->cpudata[adeos_processor_id()].status) == 0); +#else local_irq_enable(); +#endif } /* @@ -91,12 +103,19 @@ void cpu_idle(void) current->counter = -100; while (1) { +#ifdef CONFIG_ADEOS_CORE + adeos_suspend_domain(); + leds_event(led_idle_start); + while (!current->need_resched) + default_idle(); +#else /* !CONFIG_ADEOS_CORE */ void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; leds_event(led_idle_start); while (!current->need_resched) idle(); +#endif /* CONFIG_ADEOS_CORE */ leds_event(led_idle_end); schedule(); #ifndef CONFIG_NO_PGT_CACHE diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/setup.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/setup.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/setup.c 2004-07-22 13:48:58.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/setup.c 2005-08-12 15:41:58.000000000 -0600 @@ -554,6 +554,20 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con; #endif #endif + +#if 0 + /* *DEBUG* initialise ports for debbuging with oscillioscope */ + /* EGPIO0/A0 */ + outl(inl(GPIO_AINTEN) & ~1UL, GPIO_AINTEN); /* no interrupt on A0 */ + outl(inl(GPIO_AEOI) | 1UL, GPIO_AEOI); /* clear interrupt */ + outl(inl(GPIO_PADDR) | 1UL, GPIO_PADDR); /* set to output */ + outl(inl(GPIO_PADR) & ~1UL, GPIO_PADR); /* set value to 0 */ + /* EGPIO9/B1 */ + outl(inl(GPIO_BINTEN) & ~2UL, GPIO_BINTEN); /* disable interrupt */ + outl(inl(GPIO_BEOI) | 2UL, GPIO_BEOI); /* clear interrupt */ + outl(inl(GPIO_PBDDR) | 2UL, GPIO_PBDDR); /* set to output */ + outl(inl(GPIO_PBDR) & ~2UL, GPIO_PBDR); /* set value to 0 */ +#endif } static const char *hwcap_str[] = { @@ -593,6 +607,23 @@ static int c_show(struct seq_file *m, vo seq_printf(m, "Serial\t\t: %08x%08x\n", system_serial_high, system_serial_low); +#if 0 + /* *DEBUG* */ + static struct { char *n; unsigned long o; } x[] = { + { "IRQSTATUS", VIC0IRQSTATUS}, + { "RAWINTR", VIC0RAWINTR}, + { "INTENABLE", VIC0INTENABLE}, + { "SOFTINT", VIC0SOFTINT}, + }; + unsigned long base[2] = {VIC0_BASE, VIC1_BASE}; + int i, j; + for (i = 0; i < 2; ++i) { + for (j = 0; j < 4; ++j) { + seq_printf(m, "VIC%d%s\t: %08x\n", i, x[j].n, inl(base[i] + (x[j].o - VIC0_BASE))); + + } + } +#endif return 0; } diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/time.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/time.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/time.c 2004-07-22 13:48:58.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/time.c 2005-08-12 15:41:58.000000000 -0600 @@ -224,3 +224,15 @@ void __init time_init(void) setup_timer(); } + +#ifdef CONFIG_ADEOS_CORE + +/* Simply inline the arch-specific code to set the frequency of the + timer. Interrrupts must be masked on entry. */ + +void __adeos_tune_timer (unsigned long hz) { + + __adeos_set_timer(hz); +} + +#endif /* CONFIG_ADEOS_CORE */ diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/traps.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/traps.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/kernel/traps.c 2004-07-22 13:48:58.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/kernel/traps.c 2005-08-12 15:41:58.000000000 -0600 @@ -44,6 +44,7 @@ const char *processor_modes[]= static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; +#ifdef CONFIG_FRAME_POINTER /* * Stack pointers should always be within the kernels view of * physical memory. If it is not there, then we can't dump @@ -56,6 +57,7 @@ static int verify_stack(unsigned long sp return 0; } +#endif /* * Dump out the contents of some memory nicely... @@ -184,12 +186,21 @@ NORET_TYPE void die(const char *str, str { struct task_struct *tsk = current; +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root) + adeos_set_printk_sync(adp_current); +#endif /* CONFIG_ADEOS_CORE */ console_verbose(); spin_lock_irq(&die_lock); printk("Internal error: %s: %x\n", str, err); printk("CPU: %d\n", smp_processor_id()); show_regs(regs); +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root) + printk("Adeos domain %s", adp_current->name); + else +#endif /* CONFIG_ADEOS_CORE */ printk("Process %s (pid: %d, stack limit = 0x%p)\n", current->comm, current->pid, tsk + 1); @@ -285,6 +296,10 @@ asmlinkage void bad_mode(struct pt_regs { unsigned int vectors = vectors_base(); +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root) + adeos_set_printk_sync(adp_current); +#endif /* CONFIG_ADEOS_CORE */ console_verbose(); printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n", diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/lib/udivdi3.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/lib/udivdi3.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/lib/udivdi3.c 2004-07-22 13:48:57.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/lib/udivdi3.c 2005-08-12 15:41:58.000000000 -0600 @@ -240,3 +240,42 @@ __umoddi3 (UDItype u, UDItype v) return w; } +/* added signed variant for RTAI */ + +static inline DItype +__negdi2 (DItype u) +{ + DIunion w; + DIunion uu; + + uu.ll = u; + + w.s.low = -uu.s.low; + w.s.high = -uu.s.high - ((USItype) w.s.low > 0); + + return w.ll; +} + +DItype +__divdi3 (DItype u, DItype v) +{ + word_type c = 0; + DIunion uu, vv; + DItype w; + + uu.ll = u; + vv.ll = v; + + if (uu.s.high < 0) + c = ~c, + uu.ll = __negdi2 (uu.ll); + if (vv.s.high < 0) + c = ~c, + vv.ll = __negdi2 (vv.ll); + + w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0); + if (c) + w = __negdi2 (w); + + return w; +} diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mach-ep93xx/irq.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mach-ep93xx/irq.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mach-ep93xx/irq.c 2004-07-22 13:48:59.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mach-ep93xx/irq.c 2005-08-12 15:41:58.000000000 -0600 @@ -50,6 +50,24 @@ * ************************************************************************/ +static void ep93xx_mask_ack_irq_timer1(unsigned int irq) +{ + outl((1 << IRQ_TIMER1), VIC0INTENCLEAR); + outl(1, TIMER1CLEAR); +} + +static void ep93xx_mask_ack_irq_timer2(unsigned int irq) +{ + outl((1 << IRQ_TIMER2), VIC0INTENCLEAR); + outl(1, TIMER2CLEAR); +} + +static void ep93xx_mask_ack_irq_timer3(unsigned int irq) +{ + outl((1 << (IRQ_TIMER3 - 32)), VIC1INTENCLEAR ); + outl(1, TIMER3CLEAR); +} + static void ep93xx_mask_irq(unsigned int irq) { if (irq < 32) @@ -89,5 +107,10 @@ void __init ep93xx_init_irq(void) irq_desc[i].mask = ep93xx_mask_irq; irq_desc[i].unmask = ep93xx_unmask_irq; } + /* let mask_ack of selected irqs really ack on hardware level + * (makes live a lot easier with Adeos) */ + irq_desc[IRQ_TIMER1].mask_ack = ep93xx_mask_ack_irq_timer1; + irq_desc[IRQ_TIMER2].mask_ack = ep93xx_mask_ack_irq_timer2; + irq_desc[IRQ_TIMER3].mask_ack = ep93xx_mask_ack_irq_timer3; + /* TODO: add ack functions for other interrupts? */ } - diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mach-ep93xx/Makefile linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mach-ep93xx/Makefile --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mach-ep93xx/Makefile 2004-07-22 13:48:59.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mach-ep93xx/Makefile 2005-08-12 15:41:58.000000000 -0600 @@ -16,7 +16,7 @@ obj-m := obj-n := obj- := -export-objs := pcipool.o +export-objs := time.o ssp.o obj-$(CONFIG_EP93XX_DMA)+= dma_ep93xx.o diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mach-ep93xx/ssp.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mach-ep93xx/ssp.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mach-ep93xx/ssp.c 2004-07-22 13:48:59.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mach-ep93xx/ssp.c 2005-08-12 15:41:58.000000000 -0600 @@ -28,6 +28,7 @@ * I2S Codec CS4228 = EGPIO7 == 1 * Serial Flash AT25F1024 = EGPIO7 == 0 */ +#include #include #include @@ -692,3 +693,5 @@ static int SSP_Write_I2SCodec */ return 0; } + +EXPORT_SYMBOL(SSPDriver); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mach-ep93xx/time.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mach-ep93xx/time.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mach-ep93xx/time.c 2004-07-22 13:48:59.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mach-ep93xx/time.c 2005-08-12 15:41:58.000000000 -0600 @@ -6,19 +6,33 @@ * (c) Copyright 2001 LynuxWorks, Inc., San Jose, CA. All rights reserved. * Copyright (C) 2002-2003 Cirrus Logic, Inc. * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * tie wall-clock to TSC (i.e. timer4) + * * 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 * published by the Free Software Foundation. */ +#include #include #include #include +#include #include #include +#include extern int (*set_rtc)(void); +/* EP93XX-based 64 bit TSC (overflow time: ~600000 years) */ +volatile ep93xx_tsc_t ep93xx_tsc; + +/* jiffies counter without overflow problems (overflow time: ~6 billion years + * @ HZ=100) to keep jiffies in sync with TSC) */ +volatile unsigned long long ep93xx_jiffies_done; + + static int ep93xx_set_rtc(void) { outl( xtime.tv_sec, RTCLR ); @@ -37,7 +51,58 @@ static int ep93xx_rtc_init(void) return 0; } -__initcall(ep93xx_rtc_init); +//__initcall(ep93xx_rtc_init); + + +/* return time since last jiffy tick, in usecs */ +static unsigned long +ep93xx_gettimeoffset(void) +{ + /* Reading 64-bit value ep93xx_jiffies_done is safe although it is modified + * in timer interrupt handler (because this function is called with irqs disabled). + * This is even true for RTAI (value is only modified in Linux context). */ + unsigned long long tsc_offset = ep93xx_rdtsc() - (ep93xx_jiffies_done * FREQ_EP93XX_TSC) / HZ; + return (tsc_offset * 1000000LLU) / (unsigned long long)FREQ_EP93XX_TSC; +} + +/* set up EP93xx timers */ +void __init +ep93xx_setup_timer(void) +{ + extern unsigned long (*gettimeoffset)(void); + gettimeoffset = ep93xx_gettimeoffset; + /* + * Timer 1 is used to generate the periodic jiffies timer interrupt. + * It has a clock frequency of ca. 508.47 kHz. + * + * Timer 4 is the upwards counting time-stamp counter (TSC). It has a exact + * clock frequency of 983.04 kHz and is used as an absolute reference + * clock, i.e. jiffies are synced to it (makes life a lot easier with + * RTAI) and the wall-clock time-offset is also calculated from it (so RTAI + * can change timer 1's load-value without effecting the wall-clock). + */ + + /* set up 64 bit tsc and jiffies handling */ + ep93xx_tsc.ll = 0; + ep93xx_jiffies_done = 0; + + /* disable timers */ + outl(0, TIMER1CONTROL); + outl(0, TIMER4VALUEHIGH); + + /* set timer 1 reload value for periodic mode (defined by value of + * include/asm-arm/arch-ep93xx/timex.h:CLOCK_TICK_RATE) */ + outl(LATCH - 1, TIMER1LOAD); + + /* start timers */ + outl(0x100, TIMER4VALUEHIGH); /* 983.04 kHz clock */ + outl(0xc8, TIMER1CONTROL); /* periodic mode, 508 kHz clock */ + xtime.tv_sec = inl(RTCDR); +} +#ifdef CONFIG_ADEOS_CORE +EXPORT_SYMBOL(ep93xx_tsc); +EXPORT_SYMBOL(ep93xx_jiffies_done); +#endif /* CONFIG_ADEOS_CORE */ diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/Makefile linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/Makefile --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/Makefile 2004-08-23 09:50:06.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/Makefile 2005-08-12 15:41:58.000000000 -0600 @@ -13,7 +13,7 @@ GZFLAGS :=-9 CFLAGS +=-Uarm -fno-common -pipe ifeq ($(CONFIG_FRAME_POINTER),y) -CFLAGS :=$(CFLAGS:-fomit-frame-pointer=-mapcs -mno-sched-prolog) +CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog endif CFLAGS :=$(CFLAGS:-O2=-Os) diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mm/ioremap.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mm/ioremap.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mm/ioremap.c 2004-08-03 19:25:39.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mm/ioremap.c 2005-08-12 15:41:58.000000000 -0600 @@ -107,6 +107,9 @@ remap_area_pages(unsigned long address, if (remap_area_pmd(pmd, address, end - address, pfn + (address >> PAGE_SHIFT), flags)) break; +#ifdef CONFIG_ADEOS_CORE + set_pgdir(address, *dir); +#endif error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mm/proc-arm920.S linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mm/proc-arm920.S --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/arch/arm/mm/proc-arm920.S 2004-08-03 19:25:39.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/arch/arm/mm/proc-arm920.S 2005-08-12 15:41:58.000000000 -0600 @@ -465,8 +465,8 @@ ENTRY(cpu_arm920_set_pgd) bcs 2b @ entries 63 to 0 subs r1, r1, #1 << 5 bcs 1b @ segments 7 to 0 -#endif mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache +#endif mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs @@ -576,6 +576,13 @@ __arm920_setup: #ifndef CONFIG_CPU_ICACHE_DISABLE orr r0, r0, #0x1000 @ ...1 .... .... .... #endif +#if 0 /* don't use it, no improvment in avg/worst case latency */ +#ifdef CONFIG_ADEOS_CORE + @ enable round-robin cache replacement + @ (because worst case it is more predictable) + orr r0, r0, #0x4000 @ .1.. .... .... .... +#endif /* CONFIG_ADEOS_CORE */ +#endif mov pc, lr .text diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/Documentation/adeos.txt linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/Documentation/adeos.txt --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/Documentation/adeos.txt 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/Documentation/adeos.txt 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,172 @@ + +The Adeos nanokernel is based on research and publications made in the +early '90s on the subject of nanokernels. Our basic method was to +reverse the approach described in most of the papers on the subject. +Instead of first building the nanokernel and then building the client +OSes, we started from a live and known-to-be-functional OS, Linux, and +inserted a nanokernel beneath it. Starting from Adeos, other client +OSes can now be put side-by-side with the Linux kernel. + +To this end, Adeos enables multiple domains to exist simultaneously on +the same hardware. None of these domains see each other, but all of +them see Adeos. A domain is most probably a complete OS, but there is +no assumption being made regarding the sophistication of what's in +a domain. + +To share the hardware among the different OSes, Adeos implements an +interrupt pipeline (ipipe). Every OS domain has an entry in the ipipe. +Each interrupt that comes in the ipipe is passed on to every domain +in the ipipe. Instead of disabling/enabling interrupts, each domain +in the pipeline only needs to stall/unstall his pipeline stage. If +an ipipe stage is stalled, then the interrupts do not progress in the +ipipe until that stage has been unstalled. Each stage of the ipipe +can, of course, decide to do a number of things with an interrupt. +Among other things, it can decide that it's the last recipient of the +interrupt. In that case, the ipipe does not propagate the interrupt +to the rest of the domains in the ipipe. + +No hosted domain is allowed to use the real hardware cli/sti. But this +is OK, since the stall/unstall calls achieve the same functionality. + +Our approach is based on the following papers (links to these +papers are provided at the bottom of this message): +[1] D. Probert, J. Bruno, and M. Karzaorman. "Space: a new approach to +operating system abstraction." In: International Workshop on Object +Orientation in Operating Systems, pages 133-137, October 1991. +[2] D. Probert, J. Bruno. "Building fundamentally extensible application- +specific operating systems in Space", March 1995. +[3] D. Cheriton, K. Duda. "A caching model of operating system kernel +functionality". In: Proc. Symp. on Operating Systems Design and +Implementation, pages 179-194, Monterey CA (USA), 1994. +[4] D. Engler, M. Kaashoek, and J. O'Toole Jr. "Exokernel: an operating +system architecture for application-specific resource management", +December 1995. + +If you don't want to go fetch the complete papers, here's a summary. +The first 2 discuss the Space nanokernel, the 3rd discussed the cache +nanokernel, and the last discusses exokernel. + +The complete Adeos approach has been thoroughly documented in a whitepaper +published more than a year ago entitled "Adaptive Domain Environment +for Operating Systems" and available here: http://www.opersys.com/adeos +The current implementation is slightly different. Mainly, we do not +implement the functionality to move Linux out of ring 0. Although of +interest, this approach is not very portable. + +Instead, our patch taps right into Linux's main source of control +over the hardware, the interrupt dispatching code, and inserts an +interrupt pipeline which can then serve all the nanokernel's clients, +including Linux. + +This is not a novelty in itself. Other OSes have been modified in such +a way for a wide range of purposes. One of the most interesting +examples is described by Stodolsky, Chen, and Bershad in a paper +entitled "Fast Interrupt Priority Management in Operating System +Kernels" published in 1993 as part of the Usenix Microkernels and +Other Kernel Architectures Symposium. In that case, cli/sti were +replaced by virtual cli/sti which did not modify the real interrupt +mask in any way. Instead, interrupts were defered and delivered to +the OS upon a call to the virtualized sti. + +Mainly, this resulted in increased performance for the OS. Although +we haven't done any measurements on Linux's interrupt handling +performance with Adeos, our nanokernel includes by definition the +code implementing the technique described in the abovementioned +Stodolsky paper, which we use to redirect the hardware interrupt flow +to the pipeline. + +i386 and armnommu are currently supported. Most of the +architecture-dependent code is easily portable to other architectures. + +Aside of adding the Adeos module (driver/adeos), we also modified some +files to tap into Linux interrupt and system event dispatching (all +the modifications are encapsulated in #ifdef CONFIG_ADEOS_*/#endif). + +We modified the idle task so it gives control back to Adeos in order for +the ipipe to continue propagation. + +We modified init/main.c to initialize Adeos very early in the startup. + +Of course, we also added the appropriate makefile modifications and +config options so that you can choose to enable/disable Adeos as +part of the kernel build configuration. + +Adeos' public API is fully documented here: +http://home.gna.org/adeos/doc/api/index.html. + +In Linux's case, adeos_register_domain() is called very early during +system startup. + +To add your domain to the ipipe, you need to: +1) Register your domain with Adeos using adeos_register_domain() +2) Call adeos_virtualize_irq() for all the IRQs you wish to be +notified about in the ipipe. + +That's it. Provided you gave Adeos appropriate handlers in step +#2, your interrupts will be delivered via the ipipe. + +During runtime, you may change your position in the ipipe using +adeos_renice_domain(). You may also stall/unstall the pipeline +and change the ipipe's handling of the interrupts according to your +needs. + +Over x86, Adeos supports SMP, and local/IO-APIC on UP. + +Here are some of the possible uses for Adeos (this list is far +from complete): +1) Much like User-Mode Linux, it should now be possible to have 2 +Linux kernels living side-by-side on the same hardware. In contrast +to UML, this would not be 2 kernels one ontop of the other, but +really side-by-side. Since Linux can be told at boot time to use +only one portion of the available RAM, on a 128MB machine this +would mean that the first could be made to use the 0-64MB space and +the second would use the 64-128MB space. We realize that many +modifications are required. Among other things, one of the 2 kernels +will not need to conduct hardware initialization. Nevertheless, this +possibility should be studied closer. + +2) It follows from #1 that adding other kernels beside Linux should +be feasible. BSD is a prime candidate, but it would also be nice to +see what virtualizers such as VMWare and Plex86 could do with Adeos. +Proprietary operating systems could potentially also be accomodated. + +3) All the previous work that has been done on nanokernels should now +be easily ported to Linux. Mainly, we would be very interested to +hear about extensions to Adeos. Primarily, we have no mechanisms +currently enabling multiple domains to share information. The papers +mentioned earlier provide such mechanisms, but we'd like to see +actual practical examples. + +4) Kernel debuggers' main problem (tapping into the kernel's +interrupts) is solved and it should then be possible to provide +patchless kernel debuggers. They would then become loadable kernel +modules. + +5) Drivers who require absolute priority and dislike other kernel +portions who use cli/sti can now create a domain of their own +and place themselves before Linux in the ipipe. This provides a +mechanism for the implementation of systems that can provide guaranteed +realtime response. + +Philippe Gerum +Karim Yaghmour + +---------------------------------------------------------------------- +Links to papers: +1- +http://citeseer.nj.nec.com/probert91space.html +ftp://ftp.cs.ucsb.edu/pub/papers/space/iwooos91.ps.gz (not working) +http://www4.informatik.uni-erlangen.de/~tsthiel/Papers/Space-iwooos91.ps.gz + +2- +http://www.cs.ucsb.edu/research/trcs/abstracts/1995-06.shtml +http://www4.informatik.uni-erlangen.de/~tsthiel/Papers/Space-trcs95-06.ps.gz + +3- +http://citeseer.nj.nec.com/kenneth94caching.html +http://guir.cs.berkeley.edu/projects/osprelims/papers/cachmodel-OSkernel.ps.gz + +4- +http://citeseer.nj.nec.com/engler95exokernel.html +ftp://ftp.cag.lcs.mit.edu/multiscale/exokernel.ps.Z +---------------------------------------------------------------------- diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/drivers/char/tty_io.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/drivers/char/tty_io.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/drivers/char/tty_io.c 2004-08-03 19:28:46.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/drivers/char/tty_io.c 2005-08-12 15:41:58.000000000 -0600 @@ -1948,12 +1948,12 @@ static void flush_to_ldisc(void *private queue_task(&tty->flip.tqueue, &tq_timer); return; } + save_flags(flags); cli(); if (tty->flip.buf_num) { cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; tty->flip.buf_num = 0; - save_flags(flags); cli(); tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; } else { @@ -1961,7 +1961,6 @@ static void flush_to_ldisc(void *private fp = tty->flip.flag_buf; tty->flip.buf_num = 1; - save_flags(flags); cli(); tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; } diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/drivers/serial/ep93xx_amba.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/drivers/serial/ep93xx_amba.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/drivers/serial/ep93xx_amba.c 2004-08-24 13:26:50.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/drivers/serial/ep93xx_amba.c 2005-08-12 15:41:58.000000000 -0600 @@ -348,11 +348,30 @@ csambauart_rx_chars(struct uart_port *po status = UART_GET_FR(port); while (UART_RX_DATA(status) && max_count--) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { +#if 1 + /* no room in flip buffer (TTY_DONT_FLIP is set), + * discard rx FIFO contents to clear IRQ *FIXME* + * Hardware with auto flow control would benefit from + * leaving the data in the FIFO and disabling the rx IRQ + * until space becomes available. */ + do { + UART_GET_CHAR(port); + port->icount.overrun++; + status = UART_GET_FR(port); + } while (UART_RX_DATA(status) && (max_count-- > 0)); + return; +#else + /* calling this from irq is not allowed (although a lot + * of drivers do it, but with Adeos it really shows!) + * - */ tty->flip.tqueue.routine((void *)tty); if (tty->flip.count >= TTY_FLIPBUF_SIZE) { - printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + /* having this here is dangerous (system-lock up + * due to message flood) - */ + /* printk(KERN_WARNING "TTY_DONT_FLIP set\n"); */ return; } +#endif } ch = UART_GET_CHAR(port); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/adeos.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/adeos.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/adeos.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/adeos.h 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,321 @@ +/* + * include/asm-arm/adeos.h + * + * Copyright (C) 2002,2003,2004 Philippe Gerum. + * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * support for EP9301, backport of unthreaded support from Adeos/x86 for 2.6 + * + * 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_ADEOS_H +#define __ARM_ADEOS_H + +struct task_struct; + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARCH_EP9301 +#define ADEOS_ARCH_STRING "r17c3/arm-ep9301" +#define ADEOS_MAJOR_NUMBER 17 +#define ADEOS_MINOR_NUMBER 3 +#define ADEOS_TIMER_IRQ IRQ_TIMER1 +#else +#error "Adeos: unsupported ARM architecture, sorry..." +#endif /* CONFIG_ARCH_EP9301 */ + +typedef unsigned long cpumask_t; +#define CPU_MASK_NONE ((cpumask_t)0) + +#define ADEOS_NR_CPUS 1 +#define adeos_processor_id() 0 +/* Array references using this index should be optimized out. */ +#define adeos_declare_cpuid const int cpuid = 0 +#define adeos_load_cpuid() do { /* nop */ } while(0) +#define adeos_lock_cpu(flags) adeos_hw_local_irq_save(flags) +#define adeos_unlock_cpu(flags) adeos_hw_local_irq_restore(flags) +#define adeos_get_cpu(flags) do { flags = flags; } while(0) +#define adeos_put_cpu(flags) do { /* nop */ } while(0) +#define adp_current (adp_cpu_current[0]) + +/* ARM fault traps */ +#define ADEOS_NR_FAULTS 32 +/* Pseudo-vectors used for kernel events */ +#define ADEOS_FIRST_KEVENT ADEOS_NR_FAULTS +#define ADEOS_SYSCALL_PROLOGUE (ADEOS_FIRST_KEVENT) +#define ADEOS_SYSCALL_EPILOGUE (ADEOS_FIRST_KEVENT + 1) +#define ADEOS_SCHEDULE_HEAD (ADEOS_FIRST_KEVENT + 2) +#define ADEOS_SCHEDULE_TAIL (ADEOS_FIRST_KEVENT + 3) +#ifdef CONFIG_ADEOS_EVENT_ENTER_PROCESS +#define ADEOS_ENTER_PROCESS (ADEOS_FIRST_KEVENT + 4) +#endif /* CONFIG_ADEOS_EVENT_ENTER_PROCESS */ +#define ADEOS_EXIT_PROCESS (ADEOS_FIRST_KEVENT + 5) +#define ADEOS_SIGNAL_PROCESS (ADEOS_FIRST_KEVENT + 6) +#define ADEOS_KICK_PROCESS (ADEOS_FIRST_KEVENT + 7) +#define ADEOS_LAST_KEVENT (ADEOS_KICK_PROCESS) +#ifdef CONFIG_ADEOS_EVENT_RENICE_PROCESS +#define ADEOS_RENICE_PROCESS (ADEOS_FIRST_KEVENT + 8) +#undef ADEOS_LAST_KEVENT +#define ADEOS_LAST_KEVENT (ADEOS_RENICE_PROCESS) +#endif /* CONFIG_ADEOS_EVENT_RENICE_PROCESS */ +#ifdef CONFIG_ADEOS_EVENT_USER_PROCESS +#define ADEOS_USER_EVENT (ADEOS_FIRST_KEVENT + 9) +#undef ADEOS_LAST_KEVENT +#define ADEOS_LAST_KEVENT (ADEOS_USER_EVENT) +#endif /* !CONFIG_ADEOS_EVENT_USER_PROCESS */ + +#define ADEOS_NR_EVENTS (ADEOS_LAST_KEVENT + 1) + +typedef struct adevinfo { + + unsigned domid; + unsigned event; + void *evdata; + + volatile int propagate; /* Private */ + +} adevinfo_t; + +typedef struct adsysinfo { + + int ncpus; /* Number of CPUs on board */ + + unsigned long long cpufreq; /* CPU frequency (in Hz) */ + + /* Arch-dependent block */ + + struct { + unsigned tmirq; /* Timer tick IRQ */ + } archdep; + +} adsysinfo_t; + +#define IPIPE_NR_XIRQS NR_IRQS +/* 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_IRQ_ISHIFT 5 /* 2^5 for 32bits arch. */ + +#define IPIPE_IRQMASK_ANY (~0UL) +#define IPIPE_IRQMASK_VIRT (IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG)) + +typedef struct adomain { + + /* -- Section: offset-based references may be made on these fields + from inline assembly code. Please don't move or reorder. */ + void (*dswitch)(void) /* Domain switch hook */ + __attribute__ ((__aligned__ (32))); /* align every element of array (gcc bug workaround) */ +#ifdef CONFIG_ADEOS_THREADS + int *esp[ADEOS_NR_CPUS]; /* Domain stack pointers */ +#endif /* CONFIG_ADEOS_THREADS */ + /* -- End of section. */ + + struct list_head p_link; /* Link in pipeline */ + + struct adcpudata { + volatile unsigned long status; + volatile unsigned long irq_pending_hi; + volatile unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS]; + volatile unsigned irq_hits[IPIPE_NR_IRQS]; +#ifdef CONFIG_ADEOS_THREADS + adevinfo_t event_info; +#endif /* CONFIG_ADEOS_THREADS */ + } cpudata[ADEOS_NR_CPUS]; + + struct { + int (*acknowledge)(unsigned irq); + void (*handler)(unsigned irq); + unsigned long control; + } irqs[IPIPE_NR_IRQS]; + + struct { + void (*handler)(adevinfo_t *evinfo); + } events[ADEOS_NR_EVENTS]; + + unsigned long flags; + + struct adomain *m_link; /* Link in mutex sleep queue */ + + unsigned domid; + + const char *name; + + int priority; + + int ptd_keymax; + int ptd_keycount; + unsigned long ptd_keymap; + void (*ptd_setfun)(int, void *); + void *(*ptd_getfun)(int); + +#ifdef CONFIG_ADEOS_THREADS + int *estackbase[ADEOS_NR_CPUS]; +#endif /* CONFIG_ADEOS_THREADS */ + +} adomain_t __attribute__ ((__aligned__ (32))); + +#define adeos_hw_test_iflag(x) (!((x) & I_BIT)) /* We don't use the FIRQs */ + +#define adeos_hw_irqs_disabled() \ +({ \ + unsigned long flags; \ + adeos_hw_local_irq_flags(flags); \ + !adeos_hw_test_iflag(flags); \ +}) + +/* The following macros must be used hw interrupts off. */ + +#define __adeos_set_irq_bit(adp,cpuid,irq) \ +do { \ + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); \ + if (!test_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) { \ + __set_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ + __set_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[cpuid].irq_pending_hi); \ + } \ +} while(0) + +#define __adeos_clear_pend(adp,cpuid,irq) \ +do { \ + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); \ + __clear_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ + if ((adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT] == 0) \ + __clear_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[cpuid].irq_pending_hi); \ +} while(0) + +#define __adeos_lock_irq(adp,cpuid,irq) \ +do { \ + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); \ + if (!__test_and_set_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) \ + __adeos_clear_pend(adp,cpuid,irq); \ +} while(0) + +#define __adeos_unlock_irq(adp,irq) \ +do { \ + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); \ + int __cpuid, __nr_cpus = smp_num_cpus; \ + if (__test_and_clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) \ + for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) \ + if ((adp)->cpudata[__cpuid].irq_hits[irq] > 0) { \ + __set_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[__cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ + __set_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[__cpuid].irq_pending_hi); \ + } \ +} while(0) + +#define __adeos_clear_irq(adp,irq) \ +do { \ + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); \ + int __cpuid, __nr_cpus = smp_num_cpus; \ + __clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control); \ + for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) { \ + (adp)->cpudata[__cpuid].irq_hits[irq] = 0; \ + __adeos_clear_pend(adp,__cpuid,irq); \ + } \ +} while(0) + +#define adeos_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && (irq) < IPIPE_NR_IRQS) + +#define adeos_hw_save_flags_and_sti(x) do { adeos_hw_local_irq_flags(x); adeos_hw_sti(); } while(0) + +#define adeos_hw_tsc(t) 0 +#define adeos_cpu_freq() CLOCK_TICK_RATE + +#ifdef CONFIG_PREEMPT +#define adeos_spin_lock(x) _raw_spin_lock(x) +#define adeos_spin_unlock(x) _raw_spin_unlock(x) +#define adeos_spin_trylock(x) _raw_spin_trylock(x) +#else /* !CONFIG_PREEMPT */ +#define adeos_spin_lock(x) spin_lock(x) +#define adeos_spin_unlock(x) spin_unlock(x) +#define adeos_spin_trylock(x) spin_trylock(x) +#endif /* CONFIG_PREEMPT */ + +#define adeos_spin_lock_irqsave(x,flags) do { adeos_hw_local_irq_save(flags); adeos_spin_lock(x); } while (0) +#define adeos_spin_unlock_irqrestore(x,flags) do { adeos_spin_unlock(x); adeos_hw_local_irq_restore(flags); } while (0) +#define adeos_spin_lock_disable(x) do { adeos_hw_cli(); adeos_spin_lock(x); } while (0) +#define adeos_spin_unlock_enable(x) do { adeos_spin_unlock(x); adeos_hw_sti(); } while (0) + +/* Private interface -- Internal use only */ + +struct adattr; + +void __adeos_init(void); + +void __adeos_init_domain(adomain_t *adp, + struct adattr *attr); + +void __adeos_cleanup_domain(adomain_t *adp); + +#define __adeos_check_machine() do { } while(0) + +void __adeos_enable_pipeline(void); + +void __adeos_disable_pipeline(void); + +void __adeos_init_stage(adomain_t *adp); + +void FASTCALL(__adeos_sync_stage(unsigned long syncmask)); + +void __adeos_tune_timer(unsigned long hz); + +asmlinkage int __adeos_handle_irq(int irq, + struct pt_regs *regs); + +#ifdef CONFIG_ADEOS_THREADS + +asmlinkage int __adeos_switch_domain(adomain_t *adp, + adomain_t **currentp); + +/* Called with hw interrupts off. */ +extern inline void __adeos_switch_to(adomain_t *out, + adomain_t *in, + int cpuid) +{ + extern adomain_t *adp_cpu_current[]; + + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); + + __adeos_switch_domain(in,&adp_cpu_current[cpuid]); + + if (out->dswitch != NULL) + out->dswitch(); +} + +#endif /* CONFIG_ADEOS_THREADS */ + +extern struct pt_regs __adeos_irq_regs; + +/* hook for non-Linux syscalls (i.e. RTAI syscall) (see linux/arch/arm/kernel/entry-common.S) */ +extern int (*adeos_syscall_entry)(struct pt_regs *regs); + +/* hook for interrupt handling (default value: __adeos_handle_irq, see + * linux/arch/arm/kernel/entry-armv.S) */ +extern int (*adeos_irq_entry)(int irq, struct pt_regs *regs); + +#endif /* !__ARM_ADEOS_H */ diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/ep93xx_tsc.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/ep93xx_tsc.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/ep93xx_tsc.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/ep93xx_tsc.h 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,122 @@ +/* + * linux/include/asm-arm/arch-ep93xx/ep93xx_rdtsc.h + * + * 64 bit time-stamp counter (TSC) for absolute real-time clock without + * overflow-problems (>1/2 million years). + * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH + * + * 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; 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 __ASM_ARM_ARCH_EP93XX_H_ +#define __ASM_ARM_ARCH_EP93XX_H_ + +/* tsc's clock frequency (EP93XX's timer 4) */ +#define FREQ_EP93XX_TSC (983040) + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +/* jiffies counter without overflow problems (overflow time: ~6 billion years + * @ HZ=100) to keep Linux-jiffies in sync with 64 bit TSC */ +extern volatile unsigned long long ep93xx_jiffies_done; + +/* + * 64 bit tsc from hardware's 32 bit tsc, hardware has actually 40 bits, but + * even this is not enough to avoid an overflow during a reboot-less time (for + * a TSC clock frequency of 983040 Hz): + * bits overflow + * 32 1.2 hours + * 40 13 days + * 64 595034 years + */ +typedef union _ep93xx_tsc_t { + unsigned long long ll; + struct { + unsigned long low; + unsigned long high; + } u; +} ep93xx_tsc_t; +extern volatile ep93xx_tsc_t ep93xx_tsc; + +/* read EP93XX-based 64 bit TSC irq-safe (overflow time: ~600000 years) */ +extern inline unsigned long long +ep93xx_rdtsc(void) +{ + register ep93xx_tsc_t tsc; + register unsigned long low_now; + + /* get snapshot of global tsc (ldm is irq-safe!) */ + __asm__( + "ldmia %[glbl_tsc], %M[tsc]\n" + : /* output */ [tsc] "=r" (tsc.ll) + : /* input */ [glbl_tsc] "r" (&ep93xx_tsc.ll), + "m" (ep93xx_tsc) + ); + /* read current low tsc (i.e. low 32 bits of hardware timer) */ + low_now = inl(TIMER4VALUELOW); + /* check for overflow in relation to global ep93xx_tsc and correct high 32 + * bits if necessary */ + if (low_now < tsc.u.low) + ++tsc.u.high; + tsc.u.low = low_now; + return tsc.ll; +} + +/* irq-safe read & update in-memory tsc (good place to call this is the 100 HZ + * interrupt) */ +extern inline unsigned long long +ep93xx_read_and_update_tsc(void) +{ + register ep93xx_tsc_t tsc; + register unsigned long low_now; + int do_update; + + /* get snapshot of global tsc (ldm is irq safe!) */ + __asm__( + "ldmia %[glbl_tsc], %M[tsc]\n" + : /* output */ [tsc] "=r" (tsc.ll) + : /* input */ [glbl_tsc] "r" (&ep93xx_tsc.ll), + "m" (ep93xx_tsc) + ); + /* read current low tsc (i.e. low 32 bits of hardware timer) */ + low_now = inl(TIMER4VALUELOW); + /* check for overflow in relation to global ep93xx_tsc and correct high 32 + * bits if necessary */ + if (low_now < tsc.u.low) + ++tsc.u.high; + /* update at least 4 times per period (i.e. each 18 minutes) */ + do_update = (low_now - tsc.u.low >= 0x40000000); + tsc.u.low = low_now; + if (do_update) { + /* update global tsc (stm is irq-safe!) */ + __asm__( + "stmia %[glbl_tsc], %M[tsc]\n" + : /* output */ "=m" (ep93xx_tsc) + : /* input */ [tsc] "r" (tsc.ll), + [glbl_tsc] "r" (&ep93xx_tsc.ll) + ); + } + + return tsc.ll; +} + +#endif /* __KERNEL */ + +#endif /* __ASM_ARM_ARCH_EP93XX_H_ */ diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/irq.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/irq.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/irq.h 2004-07-22 13:50:54.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/irq.h 2005-08-12 15:41:58.000000000 -0600 @@ -17,4 +17,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef _ASM_ARCH_EP93XX_IRQ_H +#define _ASM_ARCH_EP93XX_IRQ_H + #define fixup_irq(i) (i) + +#endif /* _ASM_ARCH_EP93XX_IRQ_H */ diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/system.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/system.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/system.h 2004-09-10 12:47:33.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/system.h 2005-08-12 15:41:58.000000000 -0600 @@ -21,16 +21,17 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H +#include #include #include #include -static void arch_idle(void) +static inline void arch_idle(void) { cpu_do_idle(); } -extern __inline__ void arch_reset(char mode) +extern inline void arch_reset(char mode) { // // Enable the watchdog timer so that it will reset the part. diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/time.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/time.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/time.h 2005-01-18 15:35:57.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/time.h 2005-08-12 15:41:58.000000000 -0600 @@ -5,6 +5,9 @@ * * Copyright (C) 2002-2003 Cirrus Logic, Inc. * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * more Adeos/RTAI friendly + * * 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; either version 2 of the License, or @@ -22,32 +25,48 @@ #include #include #include +#include /* First timer channel used for timer interrupt */ /* * IRQ handler for the timer + * + * interrupts are disabled because timer_irq has SA_INTERRUPT set (see + * arch/arm/time.c) (of course not if Adeos is active) */ -static void ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void +ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - - // ...clear the interrupt - outl( 1, TIMER1CLEAR ); - + /* Note, that the irq needs to be acked on a timer-hardware specific + * level (i.e. write 1 to TIMER1CLEAR). But because + * irq_desc[IRQ_TIMER1].mask_ack does that (non-standard modification), it + * does not have to be done here. This makes this function safe to use when + * RTAI/Adeos is active and handles the interrupts */ + do_leds(); + { + /* full jiffies according to TSC (i.e. absolute clock) */ + unsigned long long realtime_jiffies = + (ep93xx_read_and_update_tsc() * HZ) / FREQ_EP93XX_TSC; + /* call do_timer() as often as it is necessary to keep jiffies in sync + * with TSC, take care that jiffies are never ahead the TSC + * (gettimeoffset is unsigned) */ + while (ep93xx_jiffies_done < realtime_jiffies) { do_timer(regs); + ++ep93xx_jiffies_done; + } + } do_profile(regs); } /* - * Set up timer interrupt, and return the current time in seconds. + * Set up timer interrupt */ -extern __inline__ void setup_timer(void) +extern inline void +setup_timer(void) { + ep93xx_setup_timer(); timer_irq.handler = ep93xx_timer_interrupt; - - /* - * Make irqs happen for the system timer - */ setup_arm_irq(IRQ_TIMER1, &timer_irq); /* @@ -69,3 +88,14 @@ extern __inline__ void setup_timer(void) outl( 0xC8, TIMER1CONTROL ); } + +#ifdef CONFIG_ADEOS_CORE +static inline void +__adeos_set_timer(unsigned long hz) +{ + unsigned long delay = (CLOCK_TICK_RATE + hz/2) / hz - 1; + outl(0, TIMER1CONTROL); /* stop timer */ + outl(delay, TIMER1LOAD); /* set load value */ + outl(0xc8, TIMER1CONTROL); /* set 508 kHz clock, periodic mode & enable timer */ +} +#endif /* CONFIG_ADEOS_CORE */ diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/timex.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/timex.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/arch-ep93xx/timex.h 2004-07-22 13:50:54.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/arch-ep93xx/timex.h 2005-08-12 15:41:58.000000000 -0600 @@ -5,6 +5,9 @@ * * Copyright (C) 1999 ARM Limited * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * corrected CLOCK_TICK_RATE, added defines for exact frequency + * * 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; either version 2 of the License, or @@ -23,4 +26,21 @@ /* * ?? */ -#define CLOCK_TICK_RATE (50000000 / 16) +#ifndef _ASM_ARM_ARCH_EP93XX_H +#define _ASM_ARM_ARCH_EP93XX_H + +/* + * The original value of 508000 is completly wrong. Table 4-2 on page 74 of the + * EP9301 User's Manual gives the frequency as 508.4689 kHz and specifies that + * all timer clocks are derived from the external 14.7456 MHz oscillator by + * division. Hence, the correct frequency is most likely + * 14745.6 / 29 = 508.468965... kHz (rounded integer: 508469 Hz). + * -- Michael Neuhauser + */ +#define CLOCK_TICK_RATE (508469) + +/* exact value (non-standard macros) */ +#define CLOCK_TICK_RATE_NUM (14745600) +#define CLOCK_TICK_RATE_DEN (29) + +#endif /* _ASM_ARM_ARCH_EP93XX_H */ diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/atomic.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/atomic.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/atomic.h 2004-07-22 13:50:53.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/atomic.h 2005-08-12 15:41:58.000000000 -0600 @@ -26,9 +26,19 @@ typedef struct { volatile int counter; } #define ATOMIC_INIT(i) { (i) } -#ifdef __KERNEL__ +/* RTAI needs some atomic functions in user-space (for liblxrt) */ +#if defined(__KERNEL__) || defined(CONFIG_ADEOS_CORE) + #include +#ifdef CONFIG_ADEOS_CORE +#define _atomic_save_flags_cli(x) adeos_hw_local_irq_save(flags) +#define _atomic_restore_flags(x) adeos_hw_local_irq_restore(flags) +#else +#define _atomic_save_flags_cli(x) local_irq_save(x) +#define _atomic_restore_flags(x) local_irq_restore(x) +#endif + #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) @@ -36,36 +46,36 @@ static inline void atomic_add(int i, vol { unsigned long flags; - local_irq_save(flags); + _atomic_save_flags_cli(flags); v->counter += i; - local_irq_restore(flags); + _atomic_restore_flags(flags); } static inline void atomic_sub(int i, volatile atomic_t *v) { unsigned long flags; - local_irq_save(flags); + _atomic_save_flags_cli(flags); v->counter -= i; - local_irq_restore(flags); + _atomic_restore_flags(flags); } static inline void atomic_inc(volatile atomic_t *v) { unsigned long flags; - local_irq_save(flags); + _atomic_save_flags_cli(flags); v->counter += 1; - local_irq_restore(flags); + _atomic_restore_flags(flags); } static inline void atomic_dec(volatile atomic_t *v) { unsigned long flags; - local_irq_save(flags); + _atomic_save_flags_cli(flags); v->counter -= 1; - local_irq_restore(flags); + _atomic_restore_flags(flags); } static inline int atomic_dec_and_test(volatile atomic_t *v) @@ -73,10 +83,10 @@ static inline int atomic_dec_and_test(vo unsigned long flags; int val; - local_irq_save(flags); + _atomic_save_flags_cli(flags); val = v->counter; v->counter = val -= 1; - local_irq_restore(flags); + _atomic_restore_flags(flags); return val == 0; } @@ -86,10 +96,10 @@ static inline int atomic_add_negative(in unsigned long flags; int val; - local_irq_save(flags); + _atomic_save_flags_cli(flags); val = v->counter; v->counter = val += i; - local_irq_restore(flags); + _atomic_restore_flags(flags); return val < 0; } @@ -98,9 +108,9 @@ static inline void atomic_clear_mask(uns { unsigned long flags; - local_irq_save(flags); + _atomic_save_flags_cli(flags); *addr &= ~mask; - local_irq_restore(flags); + _atomic_restore_flags(flags); } /* Atomic operations are already serializing on ARM */ @@ -109,5 +119,5 @@ static inline void atomic_clear_mask(uns #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() -#endif +#endif /* defined(__KERNEL__) || defined(CONFIG_ADEOS_CORE) */ #endif diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/bitops.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/bitops.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/bitops.h 2004-07-22 13:50:53.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/bitops.h 2005-08-12 15:41:58.000000000 -0600 @@ -86,7 +86,7 @@ extern int find_next_zero_bit(void * add /* * This routine doesn't need to be atomic. */ -static inline int test_bit(int nr, const void * addr) +static inline int test_bit(int nr, const volatile void * addr) { return (((unsigned char *) addr)[nr >> 3] >> (nr & 7)) & 1; } diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/hw_irq.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/hw_irq.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/hw_irq.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/hw_irq.h 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,7 @@ +/* + * hw_irq.h + * + * just a dummy for include/linux/irq.c + */ + +#include diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/irq.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/irq.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/irq.h 2004-07-22 13:50:53.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/irq.h 2005-08-12 15:41:58.000000000 -0600 @@ -1,6 +1,7 @@ #ifndef __ASM_ARM_IRQ_H #define __ASM_ARM_IRQ_H +#include #include #ifndef irq_cannonicalize @@ -23,6 +24,8 @@ extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); +extern asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs); + #endif diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/mach/irq.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/mach/irq.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/mach/irq.h 2004-07-22 13:50:53.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/mach/irq.h 2005-08-12 15:41:58.000000000 -0600 @@ -10,6 +10,8 @@ #ifndef __ASM_ARM_MACH_IRQ_H #define __ASM_ARM_MACH_IRQ_H +#include + struct irqdesc { unsigned int triggered: 1; /* IRQ has occurred */ unsigned int running : 1; /* IRQ is running */ @@ -28,6 +30,7 @@ struct irqdesc { void (*unmask)(unsigned int irq); /* Unmask IRQ */ struct irqaction *action; +#ifndef CONFIG_ADEOS_CORE /* no IRQ lock detection to increase performance */ /* * IRQ lock detection */ @@ -36,6 +39,7 @@ struct irqdesc { unsigned int lck_jif; int lck_warned; struct timer_list lck_timer; +#endif /* !CONFIG_ADEOS_CORE */ }; extern struct irqdesc irq_desc[]; diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/pgalloc.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/pgalloc.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/pgalloc.h 2004-07-22 13:50:53.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/pgalloc.h 2005-08-12 15:41:58.000000000 -0600 @@ -138,4 +138,33 @@ static inline pgd_t *pgd_alloc(struct mm extern int do_check_pgt_cache(int, int); +#ifdef CONFIG_ADEOS_CORE +extern inline void set_pgdir(unsigned long address, pgd_t entry) +{ + struct task_struct * p; + pgd_t *pgd; +#ifdef CONFIG_SMP + int i; +#endif + + read_lock(&tasklist_lock); + for_each_task(p) { + if (!p->mm) + continue; + *pgd_offset(p->mm,address) = entry; + } + read_unlock(&tasklist_lock); +#ifndef CONFIG_SMP + for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)__pgd_next(pgd)) + pgd[pgd_index(address)] = entry; +#else + /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can + modify pgd caches of other CPUs as well. -jj */ + for (i = 0; i < NR_CPUS; i++) + for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)__pgd_next(pgd)) + pgd[pgd_index(address)] = entry; +#endif +} +#endif /* CONFIG_ADEOS_CORE */ + #endif diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/proc-armv/processor.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/proc-armv/processor.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/proc-armv/processor.h 2004-08-03 19:17:09.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/proc-armv/processor.h 2005-08-12 15:41:58.000000000 -0600 @@ -18,6 +18,7 @@ #ifndef __ASM_PROC_PROCESSOR_H #define __ASM_PROC_PROCESSOR_H +#include #include #define KERNEL_STACK_SIZE PAGE_SIZE diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/proc-armv/system.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/proc-armv/system.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/proc-armv/system.h 2004-07-22 13:50:54.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/proc-armv/system.h 2005-08-12 15:41:58.000000000 -0600 @@ -42,6 +42,114 @@ extern unsigned long cr_alignment; /* de #define vectors_base() (0) #endif +/* ========================================================================= */ +#if defined(CONFIG_ADEOS_CORE) + +/* --------------------------------- Adeos --------------------------------- */ + +extern inline void __adeos_stall_root(void); + +extern inline void __adeos_unstall_root(void); + +extern inline unsigned long __adeos_test_root(void); + +extern inline unsigned long __adeos_test_and_stall_root(void); + +void __adeos_restore_root(unsigned long flags); + +#define __stf() __adeos_unstall_root() +#define __clf() __adeos_stall_root() + +#define local_save_flags(x) ((x) = __adeos_test_root()) +#define local_irq_save(x) ((x) = __adeos_test_and_stall_root()) +#define local_irq_restore(x) __adeos_restore_root(x) +#define local_irq_set(x) do { ((x) = __adeos_test_root()); __adeos_unstall_root(); } while (0) +#define local_irq_disable() __adeos_stall_root() +#define local_irq_enable() __adeos_unstall_root() + +#define irqs_disabled() __adeos_test_root() + +#define adeos_hw_cli() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ cli\n" \ +" orr %0, %0, #128\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory"); \ + }) + +#define adeos_hw_sti() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ sti\n" \ +" bic %0, %0, #128\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory"); \ + }) + + +#define adeos_hw_stf() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ stf\n" \ +" bic %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory"); \ + }) + +#define adeos_hw_clf() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ clf\n" \ +" orr %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory"); \ + }) + + +#define adeos_hw_local_irq_save(x) \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ save_flags_cli\n" \ +" orr %1, %0, #128\n" \ +" msr cpsr_c, %1" \ + : "=r" (x), "=r" (temp) \ + : \ + : "memory"); \ + }) + +#define adeos_hw_local_irq_restore(x) \ + __asm__ __volatile__( \ + "msr cpsr_c, %0 @ restore_flags\n" \ + : \ + : "r" (x) \ + : "memory") + +#define adeos_hw_local_irq_flags(x) \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ save_flags\n" \ + : "=r" (x) \ + : \ + : "memory") + +#else /* !CONFIG_ADEOS_CORE */ + +/* ------------------------------- Linux ------------------------------ */ + + /* * Save the current interrupt enable state & disable IRQs */ @@ -151,6 +259,9 @@ extern unsigned long cr_alignment; /* de : "r" (x) \ : "memory") +#endif /* CONFIG_ADEOS_CORE */ +/* ========================================================================= */ + #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110) /* * On the StrongARM, "swp" is terminally broken since it bypasses the @@ -165,8 +276,22 @@ extern unsigned long cr_alignment; /* de * dependent on the processor type. */ #define swp_is_buggy +#else +#undef swp_is_buggy #endif +#ifdef CONFIG_ADEOS_CORE + +#define _xchg_save_flags_cli(flags) adeos_hw_local_irq_save(flags) +#define _xchg_restore_flags(flags) adeos_hw_local_irq_restore(flags) + +#else /* !CONFIG_ADEOS_CORE */ + +#define _xchg_save_flags_cli(flags) local_irq_save(flags) +#define _xchg_restore_flags(flags) local_irq_restore(flags) + +#endif /* CONFIG_ADEOS_CORE */ + static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { extern void __bad_xchg(volatile void *, int); @@ -178,17 +303,17 @@ static inline unsigned long __xchg(unsig switch (size) { #ifdef swp_is_buggy case 1: - local_irq_save(flags); + _xchg_save_flags_cli(flags); ret = *(volatile unsigned char *)ptr; *(volatile unsigned char *)ptr = x; - local_irq_restore(flags); + _xchg_restore_flags(flags); break; case 4: - local_irq_save(flags); + _xchg_save_flags_cli(flags); ret = *(volatile unsigned long *)ptr; *(volatile unsigned long *)ptr = x; - local_irq_restore(flags); + _xchg_restore_flags(flags); break; #else case 1: __asm__ __volatile__ ("swpb %0, %1, [%2]" diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/system.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/system.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/asm-arm/system.h 2004-07-22 13:50:53.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/asm-arm/system.h 2005-08-12 15:41:58.000000000 -0600 @@ -54,8 +54,36 @@ extern asmlinkage void __backtrace(void) #define set_wmb(var, value) do { var = value; wmb(); } while (0) #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); +#ifdef CONFIG_ADEOS_CORE + +/* the cli is needed to because of the mm-switch (cache, TLB) and __switch_to() */ +#define prepare_to_switch(prev, next) \ + do { \ + struct { struct task_struct *prev, *next; } arg = { (prev), (next) }; \ + __adeos_schedule_head(&arg); \ + } while(0) + +#else /* !CONFIG_ADEOS_CORE */ + #define prepare_to_switch() do { } while(0) +#endif /* CONFIG_ADEOS_CORE */ + +#ifdef CONFIG_EP93XX_CRUNCH +#include +#define crunch_switch(prev, next) \ + do { \ + if (prev->flags & PF_USEDFPU) { \ + save_crunch(prev); \ + crunch_disable(); \ + } \ + prev->flags &= ~PF_USEDFPU; \ + mb(); \ + } while (0) +#else +#define crunch_switch(prev, next) do { } while (0); +#endif + /* * switch_to(prev, next) should switch from task `prev' to `next' * `prev' will never be the same as `next'. @@ -63,12 +91,32 @@ extern asmlinkage void __backtrace(void) */ extern struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next); +#ifdef CONFIG_ADEOS_CORE + +/* make a copy of the original definition */ +#define switch_to_orig(prev, next, last) \ + do { \ + crunch_switch(prev, next); \ + last = __switch_to(prev, next); \ + mb(); \ + } while (0) + +/* add sti to original code to revert cli from from prepare_to_switch() */ +#define switch_to(prev, next, last) \ + do { \ + switch_to_orig(prev, next, last); \ + } while (0) + +#else /* !CONFIG_ADEOS_CORE */ + #define switch_to(prev,next,last) \ do { \ last = __switch_to(prev,next); \ mb(); \ } while (0) +#endif /* CONFIG_ADEOS_CORE */ + /* For spinlocks etc */ #define __save_flags_cli(x) local_irq_save(x) #define __save_flags(x) local_save_flags(x) @@ -94,12 +142,14 @@ extern struct task_struct *__switch_to(s #define clf() __clf() #define stf() __stf() +#ifndef CONFIG_ADEOS_CORE #define irqs_disabled() \ ({ \ unsigned long flags; \ local_save_flags(flags); \ flags & PSR_I_BIT; \ }) +#endif /* !CONFIG_ADEOS_CORE */ #define save_flags(x) local_save_flags(x) #define restore_flags(x) local_irq_restore(x) @@ -111,4 +161,8 @@ extern struct task_struct *__switch_to(s #endif /* __KERNEL__ */ +#define HAVE_DISABLE_HLT +void disable_hlt(void); +void enable_hlt(void); + #endif diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/linux/adeos.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/linux/adeos.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/linux/adeos.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/linux/adeos.h 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,543 @@ +/* + * include/linux/adeos.h + * + * Copyright (C) 2002,2003,2004 Philippe Gerum. + * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * various tweaks, fixes and optimizations, backport of unthreaded + * support from Adeos/x86 for 2.6 + * + * 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_ADEOS_H +#define __LINUX_ADEOS_H + +#include + +/* be paranoid and check assumptions (mostly if hw-irqs are off)? */ +#undef ADEOS_PARANOIA +//#define ADEOS_PARANOIA 1 +#ifdef ADEOS_PARANOIA +#define ADEOS_PARANOIA_ASSERT(cond) BUG_ON(!(cond)) +#else +#define ADEOS_PARANOIA_ASSERT(cond) do { /* nop */ } while (0) +#endif + +#include + +#define ADEOS_VERSION_PREFIX "2.4" +#define ADEOS_VERSION_STRING (ADEOS_VERSION_PREFIX ADEOS_ARCH_STRING) +#define ADEOS_RELEASE_NUMBER (0x02040000|((ADEOS_MAJOR_NUMBER&0xff)<<8)|(ADEOS_MINOR_NUMBER&0xff)) + +#define ADEOS_ROOT_PRI 100 +#define ADEOS_ROOT_ID 0 +#define ADEOS_ROOT_NPTDKEYS 4 /* Must be <= 32 */ + +#define ADEOS_RESET_TIMER 0x1 +#define ADEOS_SAME_HANDLER ((void (*)(unsigned))(-1)) + +/* Global domain flags */ +#define ADEOS_SPRINTK_FLAG 0 /* Synchronous printk() allowed */ +#define ADEOS_PPRINTK_FLAG 1 /* Asynchronous printk() request pending */ + +/* Per-cpu pipeline flags. + WARNING: some implementation might refer to those flags + non-symbolically in assembly portions (e.g. x86). */ +#define IPIPE_STALL_FLAG 0 /* Stalls a pipeline stage */ +#define IPIPE_XPEND_FLAG 1 /* Exception notification is pending */ +#define IPIPE_SLEEP_FLAG 2 /* Domain has self-suspended */ + +#define IPIPE_HANDLE_FLAG 0 +#define IPIPE_PASS_FLAG 1 +#define IPIPE_ENABLE_FLAG 2 +#define IPIPE_DYNAMIC_FLAG IPIPE_HANDLE_FLAG +#define IPIPE_EXCLUSIVE_FLAG 3 +#define IPIPE_STICKY_FLAG 4 +#define IPIPE_SYSTEM_FLAG 5 +#define IPIPE_LOCK_FLAG 6 +#define IPIPE_SHARED_FLAG 7 +#define IPIPE_CALLASM_FLAG 8 /* Arch-dependent -- might be unused. */ + +#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_EXCLUSIVE_MASK (1 << IPIPE_EXCLUSIVE_FLAG) +#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_CALLASM_MASK (1 << IPIPE_CALLASM_FLAG) + +#define IPIPE_DEFAULT_MASK (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK) + +typedef struct adattr { + + 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)(int); /* Domain entry point */ + int estacksz; /* Stack size for entry context -- 0 means unspec */ + void (*dswitch)(void); /* Handler called each time the domain is switched in */ + int nptdkeys; /* Max. number of per-thread data keys */ + void (*ptdset)(int,void *); /* Routine to set pt values */ + void *(*ptdget)(int); /* Routine to get pt values */ + +} adattr_t; + +typedef struct admutex { + + spinlock_t lock; + +#ifdef CONFIG_ADEOS_THREADS + adomain_t *sleepq, /* Pending domain queue */ + *owner; /* Domain owning the mutex */ +#ifdef CONFIG_SMP + volatile int owncpu; +#define ADEOS_MUTEX_UNLOCKED { SPIN_LOCK_UNLOCKED, NULL, NULL, -1 } +#else /* !CONFIG_SMP */ +#define ADEOS_MUTEX_UNLOCKED { SPIN_LOCK_UNLOCKED, NULL, NULL } +#endif /* CONFIG_SMP */ +#else /* !CONFIG_ADEOS_THREADS */ +#define ADEOS_MUTEX_UNLOCKED { SPIN_LOCK_UNLOCKED } +#endif /* CONFIG_ADEOS_THREADS */ + +} admutex_t; + +#ifdef CONFIG_ADEOS_MODULE +extern int adp_pipelined; +#else /* !CONFIG_ADEOS_MODULE */ +#define adp_pipelined (1) /* optimize away flag tests if not compiled as module */ +#endif /* CONFIG_ADEOS_MODULE */ + +#ifdef SMP + +extern adomain_t *adp_cpu_current[], + *adp_root; + +#else + +extern adomain_t adeos_root_domain; +extern adomain_t *adp_cpu_current[]; +#define adp_root (&adeos_root_domain) + +#endif + +extern int __adeos_event_monitors[]; + +extern unsigned __adeos_printk_virq; + +extern unsigned long __adeos_virtual_irq_map; + +extern struct list_head __adeos_pipeline; + +extern spinlock_t __adeos_pipelock; + +#ifdef CONFIG_ADEOS_PROFILING + +typedef struct adprofdata { + + struct { + unsigned long long t_handled; + unsigned long long t_synced; + unsigned long n_handled; + unsigned long n_synced; + } irqs[IPIPE_NR_IRQS]; + +} adprofdata_t; + +extern adprofdata_t __adeos_profile_data[ADEOS_NR_CPUS]; + +#endif /* CONFIG_ADEOS_PROFILING */ + +/* Private interface */ + +#ifdef CONFIG_PROC_FS +void __adeos_init_proc(void); +#endif /* CONFIG_PROC_FS */ + +void __adeos_takeover(void); + +asmlinkage int __adeos_handle_event(unsigned event, + void *evdata); + +void __adeos_sync_console(unsigned irq); + +void __adeos_dump_state(void); + +static inline void __adeos_schedule_head(void *evdata) { + + if (__adeos_event_monitors[ADEOS_SCHEDULE_HEAD] > 0) + __adeos_handle_event(ADEOS_SCHEDULE_HEAD,evdata); +} + +static inline int __adeos_schedule_tail(void *evdata) { + + if (__adeos_event_monitors[ADEOS_SCHEDULE_TAIL] > 0) + return __adeos_handle_event(ADEOS_SCHEDULE_TAIL,evdata); + + return 0; +} + +#ifdef CONFIG_ADEOS_EVENT_ENTER_PROCESS +static inline void __adeos_enter_process(void) { + + if (__adeos_event_monitors[ADEOS_ENTER_PROCESS] > 0) + __adeos_handle_event(ADEOS_ENTER_PROCESS,NULL); +} +#endif /* CONFIG_ADEOS_EVENT_ENTER_PROCESS */ + +static inline void __adeos_exit_process(void *evdata) { + + if (__adeos_event_monitors[ADEOS_EXIT_PROCESS] > 0) + __adeos_handle_event(ADEOS_EXIT_PROCESS,evdata); +} + +static inline int __adeos_signal_process(void *evdata) { + + if (__adeos_event_monitors[ADEOS_SIGNAL_PROCESS] > 0) + return __adeos_handle_event(ADEOS_SIGNAL_PROCESS,evdata); + + return 0; +} + +static inline void __adeos_kick_process(void *evdata) { + + if (__adeos_event_monitors[ADEOS_KICK_PROCESS] > 0) + __adeos_handle_event(ADEOS_KICK_PROCESS,evdata); +} + +#ifdef CONFIG_ADEOS_EVENT_RENICE_PROCESS +static inline int __adeos_renice_process(void *evdata) { + + if (__adeos_event_monitors[ADEOS_RENICE_PROCESS] > 0) + return __adeos_handle_event(ADEOS_RENICE_PROCESS,evdata); + + return 0; +} +#endif /* CONFIG_ADEOS_EVENT_RENICE_PROCESS */ + +void __adeos_stall_root(void); + +void __adeos_unstall_root(void); + +unsigned long __adeos_test_root(void); + +unsigned long __adeos_test_and_stall_root(void); + +void FASTCALL(__adeos_restore_root(unsigned long flags)); + +void __adeos_schedule_back_root(struct task_struct *prev); + +int FASTCALL(__adeos_schedule_irq(unsigned irq, + struct list_head *head)); + +#define __adeos_pipeline_head_p(adp) (&(adp)->p_link == __adeos_pipeline.next) + +#ifdef CONFIG_ADEOS_THREADS + +static inline int __adeos_domain_work_p (adomain_t *adp, int cpuid) + +{ + return (!test_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[cpuid].status) || + (!test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status) && + adp->cpudata[cpuid].irq_pending_hi != 0) || + test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[cpuid].status)); +} + +#else /* !CONFIG_ADEOS_THREADS */ + +/* Called with hw interrupts off. */ +static inline void __adeos_switch_to (adomain_t *out, adomain_t *in, int cpuid) + +{ + void adeos_suspend_domain(void); + int s; + + ADEOS_PARANOIA_ASSERT(adeos_hw_irqs_disabled()); + + adp_cpu_current[cpuid] = in; + + if (in->dswitch) + in->dswitch(); + + /* Make sure adeos_suspend_domain() will not sync beyond the + current domain. "in" is guaranteed to be closer than "out" from + the head of the pipeline (and obviously different). */ + s = __test_and_clear_bit(IPIPE_SLEEP_FLAG,&out->cpudata[cpuid].status); + + adeos_suspend_domain(); /* Sync stage and propagate interrupts. */ + + if (s) + __set_bit(IPIPE_SLEEP_FLAG,&out->cpudata[cpuid].status); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (adp_cpu_current[cpuid] == in) + /* Otherwise, something has changed the current domain under + our feet recycling the register set; do not override. */ + adp_cpu_current[cpuid] = out; +} + +#endif /* CONFIG_ADEOS_THREADS */ + +/* Public interface */ + +int adeos_register_domain(adomain_t *adp, + adattr_t *attr); + +int adeos_unregister_domain(adomain_t *adp); + +void adeos_suspend_domain(void); + +int adeos_virtualize_irq_from(adomain_t *adp, + unsigned irq, + void (*handler)(unsigned irq), + int (*acknowledge)(unsigned irq), + unsigned modemask); + +static inline int adeos_virtualize_irq(unsigned irq, + void (*handler)(unsigned irq), + int (*acknowledge)(unsigned irq), + unsigned modemask) { + + return adeos_virtualize_irq_from(adp_current, + irq, + handler, + acknowledge, + modemask); +} + +int adeos_control_irq(unsigned irq, + unsigned clrmask, + unsigned setmask); + +cpumask_t adeos_set_irq_affinity(unsigned irq, + cpumask_t cpumask); + +static inline int adeos_share_irq (unsigned irq, int (*acknowledge)(unsigned irq)) { + + return adeos_virtualize_irq(irq, + ADEOS_SAME_HANDLER, + acknowledge, + IPIPE_SHARED_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK); +} + +unsigned adeos_alloc_irq(void); + +int adeos_free_irq(unsigned irq); + +int FASTCALL(adeos_trigger_irq(unsigned irq)); + +static inline int adeos_propagate_irq(unsigned irq) { + + return __adeos_schedule_irq(irq,adp_current->p_link.next); +} + +static inline int adeos_schedule_irq(unsigned irq) { + + return __adeos_schedule_irq(irq,&adp_current->p_link); +} + +int FASTCALL(adeos_send_ipi(unsigned ipi, + cpumask_t cpumask)); + +static inline void adeos_stall_pipeline_from (adomain_t *adp) + +{ + adeos_declare_cpuid; +#ifdef CONFIG_SMP + unsigned long flags; + + adeos_lock_cpu(flags); + + __set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (!__adeos_pipeline_head_p(adp)) + adeos_unlock_cpu(flags); +#else /* CONFIG_SMP */ + set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (__adeos_pipeline_head_p(adp)) + adeos_hw_cli(); +#endif /* CONFIG_SMP */ +} + +static inline unsigned long adeos_test_pipeline_from (adomain_t *adp) + +{ + unsigned long flags, s; + adeos_declare_cpuid; + + adeos_get_cpu(flags); + s = test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + adeos_put_cpu(flags); + + return s; +} + +static inline unsigned long adeos_test_and_stall_pipeline_from (adomain_t *adp) + +{ + adeos_declare_cpuid; + unsigned long s; +#ifdef CONFIG_SMP + unsigned long flags; + + adeos_lock_cpu(flags); + + s = __test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (!__adeos_pipeline_head_p(adp)) + adeos_unlock_cpu(flags); +#else /* CONFIG_SMP */ + s = test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (__adeos_pipeline_head_p(adp)) + adeos_hw_cli(); +#endif /* CONFIG_SMP */ + + return s; +} + +void FASTCALL(adeos_unstall_pipeline_from(adomain_t *adp)); + +static inline unsigned long adeos_test_and_unstall_pipeline_from(adomain_t *adp) + +{ + unsigned long flags, s; + adeos_declare_cpuid; + + adeos_get_cpu(flags); + s = test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + adeos_unstall_pipeline_from(adp); + adeos_put_cpu(flags); + + return s; +} + +static inline void adeos_unstall_pipeline(void) + +{ + adeos_unstall_pipeline_from(adp_current); +} + +static inline unsigned long adeos_test_and_unstall_pipeline(void) + +{ + return adeos_test_and_unstall_pipeline_from(adp_current); +} + +static inline unsigned long adeos_test_pipeline (void) + +{ + return adeos_test_pipeline_from(adp_current); +} + +static inline unsigned long adeos_test_and_stall_pipeline (void) + +{ + return adeos_test_and_stall_pipeline_from(adp_current); +} + +static inline void adeos_restore_pipeline_from (adomain_t *adp, unsigned long flags) + +{ + if (flags) + adeos_stall_pipeline_from(adp); + else + adeos_unstall_pipeline_from(adp); +} + +static inline void adeos_stall_pipeline (void) + +{ + adeos_stall_pipeline_from(adp_current); +} + +static inline void adeos_restore_pipeline (unsigned long flags) + +{ + adeos_restore_pipeline_from(adp_current,flags); +} + +static inline void adeos_restore_pipeline_nosync (adomain_t *adp, unsigned long flags, int cpuid) + +{ + /* If cpuid is current, then it must be held on entry + (adeos_get_cpu/adeos_hw_local_irq_save/adeos_hw_cli). */ + + if (flags) + set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + else + clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); +} + +int adeos_catch_event_from(adomain_t *adp, + unsigned event, + void (*handler)(adevinfo_t *)); + +static inline int adeos_catch_event (unsigned event, void (*handler)(adevinfo_t *)) + +{ + return adeos_catch_event_from(adp_current,event,handler); +} + +static inline void adeos_propagate_event(adevinfo_t *evinfo) + +{ + evinfo->propagate = 1; +} + +void adeos_init_attr(adattr_t *attr); + +int adeos_get_sysinfo(adsysinfo_t *sysinfo); + +int adeos_tune_timer(unsigned long ns, + int flags); + +int adeos_alloc_ptdkey(void); + +int adeos_free_ptdkey(int key); + +int adeos_set_ptd(int key, + void *value); + +void *adeos_get_ptd(int key); + +unsigned long adeos_critical_enter(void (*syncfn)(void)); + +void adeos_critical_exit(unsigned long flags); + +int adeos_init_mutex(admutex_t *mutex); + +int adeos_destroy_mutex(admutex_t *mutex); + +unsigned long FASTCALL(adeos_lock_mutex(admutex_t *mutex)); + +void FASTCALL(adeos_unlock_mutex(admutex_t *mutex, + unsigned long flags)); + +static inline void adeos_set_printk_sync (adomain_t *adp) { + set_bit(ADEOS_SPRINTK_FLAG,&adp->flags); +} + +static inline void adeos_set_printk_async (adomain_t *adp) { + clear_bit(ADEOS_SPRINTK_FLAG,&adp->flags); +} + +#endif /* !__LINUX_ADEOS_H */ diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/linux/sched.h linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/linux/sched.h --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/include/linux/sched.h 2004-08-03 19:17:32.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/include/linux/sched.h 2005-08-12 15:41:58.000000000 -0600 @@ -125,6 +125,10 @@ struct completion; #include +#ifdef CONFIG_ADEOS_CORE +#include +#endif /* CONFIG_ADEOS_CORE */ + /* * This serializes "schedule()" and also protects * the run-queue from deletions/modifications (but @@ -415,6 +419,10 @@ struct task_struct { /* journalling filesystem info */ void *journal_info; + +#ifdef CONFIG_ADEOS_CORE + void *ptd[ADEOS_ROOT_NPTDKEYS]; +#endif /* CONFIG_ADEOS_CORE */ }; /* @@ -465,6 +473,12 @@ extern void yield(void); */ extern struct exec_domain default_exec_domain; +#ifdef CONFIG_ADEOS_CORE +#define INIT_TASK_ADEOS ptd: { [0 ... ADEOS_ROOT_NPTDKEYS - 1] = 0 }, +#else +#define INIT_TASK_ADEOS /* nothing */ +#endif + /* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) @@ -510,6 +524,7 @@ extern struct exec_domain default_exec_d blocked: {{0}}, \ alloc_lock: SPIN_LOCK_UNLOCKED, \ journal_info: NULL, \ + INIT_TASK_ADEOS \ } diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/init/main.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/init/main.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/init/main.c 2004-08-03 19:33:51.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/init/main.c 2005-08-12 15:41:58.000000000 -0600 @@ -370,6 +370,9 @@ asmlinkage void __init start_kernel(void parse_options(command_line); trap_init(); init_IRQ(); +#ifdef CONFIG_ADEOS_CORE + __adeos_init(); +#endif /* CONFIG_ADEOS_CORE */ sched_init(); softirq_init(); time_init(); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/adeos.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/adeos.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/adeos.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/adeos.c 2005-08-12 15:41:58.000000000 -0600 @@ -0,0 +1,783 @@ +/* + * linux/kernel/adeos.c + * + * Copyright (C) 2002,2003,2004 Philippe Gerum. + * + * Copyright (C) 2004-2005 Michael Neuhauser, Firmix Software GmbH (mike@firmix.at) + * various tweaks, fixes and optimizations (e.g. no adp_root variable, no + * adp_pipelined unless module) backport of unthreaded support from + * Adeos/x86 for 2.6, general sync Adeos/x86 for 2.6 + * + * 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 ADEOS core support. + */ + +#include +#ifdef CONFIG_PROC_FS +#include +#endif /* CONFIG_PROC_FS */ + +/* The pre-defined domain slot for the root domain. */ +adomain_t adeos_root_domain; + +/* A pointer to the current domain. */ +adomain_t *adp_cpu_current[ADEOS_NR_CPUS] = { [ 0 ... ADEOS_NR_CPUS - 1] = &adeos_root_domain }; + +/* The spinlock protecting from races while modifying the pipeline. */ +spinlock_t __adeos_pipelock = SPIN_LOCK_UNLOCKED; + +/* The pipeline data structure. Enqueues adomain_t objects by priority. */ +struct list_head __adeos_pipeline; + +#ifdef CONFIG_ADEOS_MODULE +/* A global flag telling whether Adeos pipelining is engaged. */ +int adp_pipelined; +#endif /* CONFIG_ADEOS_MODULE */ + +/* An array of global counters tracking domains monitoring events. */ +int __adeos_event_monitors[ADEOS_NR_EVENTS] = { [ 0 ... ADEOS_NR_EVENTS - 1] = 0 }; + +/* The allocated VIRQ map. */ +unsigned long __adeos_virtual_irq_map = 0; + +/* A VIRQ to kick printk() output out when the root domain is in control. */ +unsigned __adeos_printk_virq; + +#ifdef CONFIG_ADEOS_PROFILING +adprofdata_t __adeos_profile_data[ADEOS_NR_CPUS]; +#endif /* CONFIG_ADEOS_PROFILING */ + +static void __adeos_set_root_ptd (int key, void *value) { + + current->ptd[key] = value; +} + +static void *__adeos_get_root_ptd (int key) { + + return current->ptd[key]; +} + +/* adeos_init() -- Initialization routine of the ADEOS layer. Called + by the host kernel early during the boot procedure. */ + +void __adeos_init (void) + +{ + adomain_t *adp = &adeos_root_domain; + + __adeos_check_machine(); /* Do platform dependent checks first. */ + + /* + A lightweight registration code for the root domain. Current + assumptions are: + - We are running on the boot CPU, and secondary CPUs are still + lost in space. + - adeos_root_domain has been zero'ed. + */ + + INIT_LIST_HEAD(&__adeos_pipeline); + + adp->name = "Linux"; + adp->domid = ADEOS_ROOT_ID; + adp->priority = ADEOS_ROOT_PRI; + adp->ptd_setfun = &__adeos_set_root_ptd; + adp->ptd_getfun = &__adeos_get_root_ptd; + adp->ptd_keymax = ADEOS_ROOT_NPTDKEYS; + + __adeos_init_stage(adp); + + INIT_LIST_HEAD(&adp->p_link); + list_add_tail(&adp->p_link,&__adeos_pipeline); + + __adeos_printk_virq = adeos_alloc_irq(); /* Cannot fail here. */ + adp->irqs[__adeos_printk_virq].handler = &__adeos_sync_console; + adp->irqs[__adeos_printk_virq].acknowledge = NULL; + adp->irqs[__adeos_printk_virq].control = IPIPE_HANDLE_MASK; + + printk(KERN_INFO "Adeos %s: Root domain %s registered.\n", + ADEOS_VERSION_STRING, + adp->name); + +#ifdef CONFIG_ADEOS + __adeos_takeover(); +#endif /* CONFIG_ADEOS */ +} + +/* adeos_handle_event() -- Adeos' generic event handler. This routine + calls the per-domain handlers registered for a given + exception/event. Each domain before the one which raised the event + in the pipeline will get a chance to process the event. The latter + will eventually be allowed to process its own event too if a valid + handler exists for it. Handler executions are always scheduled by + the domain which raised the event for the prioritary domains + wanting to be notified of such event. Note: evdata might be + NULL. */ + +#ifdef CONFIG_ADEOS_THREADS + +asmlinkage int __adeos_handle_event (unsigned event, void *evdata) +/* asmlinkage is there just in case -mregparm is used... */ +{ + struct list_head *pos, *npos; + adomain_t *this_domain; + unsigned long flags; + adeos_declare_cpuid; + adevinfo_t evinfo; + int propagate = 1; + + adeos_lock_cpu(flags); + + this_domain = adp_cpu_current[cpuid]; + + list_for_each_safe(pos,npos,&__adeos_pipeline) { + + adomain_t *next_domain = list_entry(pos,adomain_t,p_link); + + if (next_domain->events[event].handler != NULL) + { + if (next_domain == this_domain) + { + adeos_unlock_cpu(flags); + evinfo.domid = this_domain->domid; + evinfo.event = event; + evinfo.evdata = evdata; + evinfo.propagate = 0; + this_domain->events[event].handler(&evinfo); + propagate = evinfo.propagate; + goto done; + } + + next_domain->cpudata[cpuid].event_info.domid = this_domain->domid; + next_domain->cpudata[cpuid].event_info.event = event; + next_domain->cpudata[cpuid].event_info.evdata = evdata; + next_domain->cpudata[cpuid].event_info.propagate = 0; + __set_bit(IPIPE_XPEND_FLAG,&next_domain->cpudata[cpuid].status); + + /* Let the prioritary domain process the event. */ + __adeos_switch_to(this_domain,next_domain,cpuid); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (!next_domain->cpudata[cpuid].event_info.propagate) + { + propagate = 0; + break; + } + } + + if (next_domain == this_domain) + break; + } + + adeos_unlock_cpu(flags); + +done: + return !propagate; +} + +#else /* !CONFIG_ADEOS_THREADS */ + +asmlinkage int __adeos_handle_event (unsigned event, void *evdata) +/* asmlinkage is there just in case CONFIG_REGPARM is enabled... */ +{ + adomain_t *start_domain, *this_domain, *next_domain; + struct list_head *pos, *npos; + unsigned long flags; + adeos_declare_cpuid; + adevinfo_t evinfo; + int propagate = 1; + + adeos_lock_cpu(flags); + + start_domain = this_domain = adp_cpu_current[cpuid]; + + list_for_each_safe(pos,npos,&__adeos_pipeline) { + + next_domain = list_entry(pos,adomain_t,p_link); + + if (next_domain->events[event].handler != NULL) + { + adp_cpu_current[cpuid] = next_domain; + adeos_unlock_cpu(flags); + evinfo.domid = start_domain->domid; + evinfo.event = event; + evinfo.evdata = evdata; + evinfo.propagate = 0; + next_domain->events[event].handler(&evinfo); + adeos_lock_cpu(flags); + + if (adp_cpu_current[cpuid] != next_domain) + /* Something has changed the current domain under our + feet recycling the register set; take note. */ + this_domain = adp_cpu_current[cpuid]; + + propagate = evinfo.propagate; + } + + if (next_domain == this_domain || !propagate) + break; + } + + adp_cpu_current[cpuid] = this_domain; + + adeos_unlock_cpu(flags); + + return !propagate; +} + +#endif /* CONFIG_ADEOS_THREADS */ + +void __adeos_stall_root (void) + +{ + if (likely(adp_pipelined)) + { + adeos_declare_cpuid; + +#ifdef CONFIG_SMP + unsigned long flags; + adeos_lock_cpu(flags); + __set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + adeos_unlock_cpu(flags); +#else /* !CONFIG_SMP */ + set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); +#endif /* CONFIG_SMP */ + } + else + adeos_hw_cli(); +} + +void __adeos_unstall_root (void) + +{ + if (likely(adp_pipelined)) + { + adeos_declare_cpuid; + + adeos_hw_cli(); + + adeos_load_cpuid(); + + __clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + + if (adp_root->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + + adeos_hw_sti(); /* Needed in both cases. */ +} + +unsigned long __adeos_test_root (void) + +{ + if (likely(adp_pipelined)) + { + adeos_declare_cpuid; + unsigned long s; + +#ifdef CONFIG_SMP + unsigned long flags; + adeos_lock_cpu(flags); + s = test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + adeos_unlock_cpu(flags); +#else /* !CONFIG_SMP */ + s = test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); +#endif /* CONFIG_SMP */ + + return s; + } + + return adeos_hw_irqs_disabled(); +} + +unsigned long __adeos_test_and_stall_root (void) + +{ + unsigned long flags; + + if (likely(adp_pipelined)) + { + adeos_declare_cpuid; + unsigned long s; + +#ifdef CONFIG_SMP + adeos_lock_cpu(flags); + s = __test_and_set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + adeos_unlock_cpu(flags); +#else /* !CONFIG_SMP */ + s = test_and_set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); +#endif /* CONFIG_SMP */ + + return s; + } + + adeos_hw_local_irq_save(flags); + + return !adeos_hw_test_iflag(flags); +} + +void __adeos_restore_root (unsigned long flags) + +{ + if (flags) + __adeos_stall_root(); + else + __adeos_unstall_root(); +} + +/* adeos_unstall_pipeline_from() -- Unstall the interrupt pipeline and + synchronize pending events from a given domain. */ + +void adeos_unstall_pipeline_from (adomain_t *adp) + +{ + adomain_t *this_domain; + struct list_head *pos; + unsigned long flags; + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + + __clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + this_domain = adp_cpu_current[cpuid]; + + if (adp == this_domain) + { + if (adp->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + + goto release_cpu_and_exit; + } + + /* Attempt to flush all events that might be pending at the + unstalled domain level. This code is roughly lifted from + arch/i386/kernel/adeos.c:__adeos_walk_pipeline(). */ + + list_for_each(pos,&__adeos_pipeline) { + + adomain_t *next_domain = list_entry(pos,adomain_t,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) + { + /* Since the critical IPI might be triggered by the + following actions, the current domain might not be + linked to the pipeline anymore after its handler + returns on SMP boxen, even if the domain remains valid + (see adeos_unregister_domain()), so don't make any + hazardous assumptions here. */ + + if (next_domain == this_domain) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + else + { + __adeos_switch_to(this_domain,next_domain,cpuid); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (!test_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status) && + this_domain->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + + break; + } + else if (next_domain == this_domain) + break; + } + +release_cpu_and_exit: + + if (__adeos_pipeline_head_p(adp)) + adeos_hw_sti(); + else + adeos_unlock_cpu(flags); +} + +/* adeos_suspend_domain() -- tell the ADEOS layer that the current + domain is now dormant. The calling domain is switched out, while + the next domain with work in progress or pending in the pipeline is + switched in. */ + +#ifdef CONFIG_ADEOS_THREADS + +#define __flush_pipeline_stage() \ +do { \ + if (!test_bit(IPIPE_STALL_FLAG,&cpudata->status) && \ + cpudata->irq_pending_hi != 0) \ + { \ + __adeos_sync_stage(IPIPE_IRQMASK_ANY); \ + adeos_load_cpuid(); \ + cpudata = &this_domain->cpudata[cpuid]; \ + } \ +} while(0) + +void adeos_suspend_domain (void) + +{ + adomain_t *this_domain, *next_domain; + struct adcpudata *cpudata; + struct list_head *ln; + unsigned long flags; + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + + this_domain = next_domain = adp_cpu_current[cpuid]; + cpudata = &this_domain->cpudata[cpuid]; + + /* A suspending domain implicitely unstalls the pipeline. */ + __clear_bit(IPIPE_STALL_FLAG,&cpudata->status); + + /* Make sure that no event remains stuck in the pipeline. This + could happen with emerging SMP instances, or domains which + forget to unstall their stage before calling us. */ + __flush_pipeline_stage(); + + for (;;) + { + ln = next_domain->p_link.next; + + if (ln == &__adeos_pipeline) /* End of pipeline reached? */ + /* Caller should loop on its idle task on return. */ + goto release_cpu_and_exit; + + next_domain = list_entry(ln,adomain_t,p_link); + + /* Make sure the domain was preempted (i.e. not sleeping) or + has some event to process before switching to it. */ + + if (__adeos_domain_work_p(next_domain,cpuid)) + break; + } + + /* Mark the outgoing domain as aslept (i.e. not preempted). */ + __set_bit(IPIPE_SLEEP_FLAG,&cpudata->status); + + /* Suspend the calling domain, switching to the next one. */ + __adeos_switch_to(this_domain,next_domain,cpuid); + + /* Clear the sleep bit for the incoming domain. */ + __clear_bit(IPIPE_SLEEP_FLAG,&cpudata->status); + +#ifdef CONFIG_SMP + adeos_load_cpuid(); /* Processor might have changed. */ + cpudata = &this_domain->cpudata[cpuid]; +#endif /* CONFIG_SMP */ + + /* Now, we are back into the calling domain. Flush the interrupt + log and fire the event interposition handler if needed. CPU + migration is allowed in SMP-mode on behalf of an event handler + provided that the current domain raised it. Otherwise, it's + not. */ + + __flush_pipeline_stage(); + + if (__test_and_clear_bit(IPIPE_XPEND_FLAG,&cpudata->status)) + { + adeos_unlock_cpu(flags); + this_domain->events[cpudata->event_info.event].handler(&cpudata->event_info); + return; + } + +release_cpu_and_exit: + + adeos_unlock_cpu(flags); + + /* Return to the point of suspension in the calling domain. */ +} + +#else /* !CONFIG_ADEOS_THREADS */ + +void adeos_suspend_domain (void) + +{ + adomain_t *this_domain, *next_domain; + struct list_head *ln; + unsigned long flags; + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + + this_domain = next_domain = adp_cpu_current[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 == &__adeos_pipeline) + break; + + next_domain = list_entry(ln,adomain_t,p_link); + + if (!test_bit(IPIPE_SLEEP_FLAG,&next_domain->cpudata[cpuid].status) || + test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status)) + break; + + if (next_domain->cpudata[cpuid].irq_pending_hi == 0) + continue; + + adp_cpu_current[cpuid] = next_domain; + + if (next_domain->dswitch) + next_domain->dswitch(); + + sync_stage: + + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (adp_cpu_current[cpuid] != next_domain) + /* Something has changed the current domain under our feet + recycling the register set; take note. */ + this_domain = adp_cpu_current[cpuid]; + } + + adp_cpu_current[cpuid] = this_domain; + + adeos_unlock_cpu(flags); +} + +#endif /* CONFIG_ADEOS_THREADS */ + +/* adeos_alloc_irq() -- Allocate a virtual/soft pipelined interrupt. + Virtual interrupts are handled in exactly the same way than their + hw-generated counterparts. This is a very basic, one-way only, + inter-domain communication system (see adeos_trigger_irq()). Note: + it is not necessary for a domain to allocate a virtual interrupt to + trap it using adeos_virtualize_irq(). The newly allocated VIRQ + number which can be passed to other IRQ-related services is + returned on success, zero otherwise (i.e. no more virtual interrupt + channel is available). We need this service as part of the Adeos + bootstrap code, hence it must reside in a built-in area. */ + +unsigned adeos_alloc_irq (void) + +{ + unsigned long flags, irq = 0; + int ipos; + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + if (__adeos_virtual_irq_map != ~0) + { + ipos = ffz(__adeos_virtual_irq_map); + set_bit(ipos,&__adeos_virtual_irq_map); + irq = ipos + IPIPE_VIRQ_BASE; + } + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return irq; +} + +#ifdef CONFIG_PROC_FS + +#include + +static struct proc_dir_entry *adeos_proc_entry; + +static int __adeos_read_proc (char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + unsigned long ctlbits; + struct list_head *pos; + unsigned irq, _irq; + char *p = page; + int len; + +#ifdef CONFIG_ADEOS_MODULE + p += sprintf(p,"Adeos %s -- Pipelining: %s",ADEOS_VERSION_STRING,adp_pipelined ? "active" : "stopped"); +#else /* !CONFIG_ADEOS_MODULE */ + p += sprintf(p,"Adeos %s -- Pipelining: permanent",ADEOS_VERSION_STRING); +#endif /* CONFIG_ADEOS_MODULE */ +#ifdef CONFIG_ADEOS_THREADS + p += sprintf(p, " (threaded)\n\n"); +#else /* CONFIG_ADEOS_THREADS */ + p += sprintf(p, " (unthreaded)\n\n"); +#endif /* CONFIG_ADEOS_THREADS */ + + spin_lock(&__adeos_pipelock); + + list_for_each(pos,&__adeos_pipeline) { + + adomain_t *adp = list_entry(pos,adomain_t,p_link); + + p += sprintf(p,"%8s: priority=%d, id=0x%.8x, ptdkeys=%d/%d\n", + adp->name, + adp->priority, + adp->domid, + adp->ptd_keycount, + adp->ptd_keymax); + irq = 0; + + while (irq < IPIPE_NR_IRQS) + { + ctlbits = (adp->irqs[irq].control & (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_STICKY_MASK)); + + if (irq >= IPIPE_NR_XIRQS && !adeos_virtual_irq_p(irq)) + { + /* There might be a hole between the last external IRQ + and the first virtual one; skip it. */ + irq++; + continue; + } + + if (adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_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 (adeos_virtual_irq_p(_irq) != adeos_virtual_irq_p(irq) || + (adeos_virtual_irq_p(_irq) && + !test_bit(_irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)) || + ctlbits != (adp->irqs[_irq].control & (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_STICKY_MASK))) + break; + } + + if (_irq == irq + 1) + p += sprintf(p,"\tirq%u: ",irq); + else + p += sprintf(p,"\tirq%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 Adeos. + 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 + 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 (ctlbits & IPIPE_SHARED_MASK) + p += sprintf(p,", shared"); + + if (adeos_virtual_irq_p(irq)) + p += sprintf(p,", virtual"); + + p += sprintf(p,"\n"); + + irq = _irq; + } + } + + spin_unlock(&__adeos_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 __adeos_init_proc (void) { + + adeos_proc_entry = create_proc_read_entry("adeos", + 0444, + NULL, + &__adeos_read_proc, + NULL); +} + +#endif /* CONFIG_PROC_FS */ + +void __adeos_dump_state (void) + +{ + int _cpuid, nr_cpus = smp_num_cpus; + struct list_head *pos; + unsigned long flags; + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + + printk(KERN_WARNING "Adeos: Current domain=%s on CPU #%d [stackbase=%p]\n", + adp_current->name, + cpuid, +#ifdef CONFIG_ADEOS_THREADS + (void *)adp_current->estackbase[cpuid] +#else /* !CONFIG_ADEOS_THREADS */ + current +#endif /* CONFIG_ADEOS_THREADS */ + ); + + list_for_each(pos,&__adeos_pipeline) { + + adomain_t *adp = list_entry(pos,adomain_t,p_link); + + for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++) + printk(KERN_WARNING "%8s[cpuid=%d]: priority=%d, status=0x%lx, pending_hi=0x%lx\n", + adp->name, + _cpuid, + adp->priority, + adp->cpudata[_cpuid].status, + adp->cpudata[_cpuid].irq_pending_hi); + } + + adeos_unlock_cpu(flags); +} diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/exit.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/exit.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/exit.c 2004-07-22 13:50:27.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/exit.c 2005-08-12 15:41:58.000000000 -0600 @@ -439,6 +439,9 @@ fake_volatile: #ifdef CONFIG_BSD_PROCESS_ACCT acct_process(code); #endif +#ifdef CONFIG_ADEOS_CORE + __adeos_exit_process(tsk); +#endif /* CONFIG_ADEOS_CORE */ __exit_mm(tsk); lock_kernel(); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/fork.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/fork.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/fork.c 2004-08-03 19:33:52.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/fork.c 2005-08-12 15:41:58.000000000 -0600 @@ -240,7 +240,13 @@ static struct mm_struct * mm_init(struct atomic_set(&mm->mm_count, 1); init_rwsem(&mm->mmap_sem); mm->page_table_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_ADEOS_CORE + adeos_spin_lock(&init_mm.page_table_lock); +#endif /* CONFIG_ADEOS_CORE */ mm->pgd = pgd_alloc(mm); +#ifdef CONFIG_ADEOS_CORE + adeos_spin_unlock(&init_mm.page_table_lock); +#endif /* CONFIG_ADEOS_CORE */ mm->def_flags = 0; if (mm->pgd) return mm; @@ -272,7 +278,14 @@ struct mm_struct * mm_alloc(void) inline void __mmdrop(struct mm_struct *mm) { BUG_ON(mm == &init_mm); +#ifdef CONFIG_ADEOS_CORE + adeos_hw_sti(); + adeos_spin_lock(&init_mm.page_table_lock); +#endif /* CONFIG_ADEOS_CORE */ pgd_free(mm->pgd); +#ifdef CONFIG_ADEOS_CORE + adeos_spin_unlock(&init_mm.page_table_lock); +#endif /* CONFIG_ADEOS_CORE */ check_pgt_cache(); destroy_context(mm); free_mm(mm); @@ -816,6 +829,15 @@ int do_fork(unsigned long clone_flags, u nr_threads++; write_unlock_irq(&tasklist_lock); +#ifdef CONFIG_ADEOS_CORE + { + int k; + + for (k = 0; k < ADEOS_ROOT_NPTDKEYS; k++) + p->ptd[k] = NULL; + } +#endif /* CONFIG_ADEOS_CORE */ + if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/ksyms.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/ksyms.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/ksyms.c 2004-08-03 19:33:52.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/ksyms.c 2005-08-12 15:41:58.000000000 -0600 @@ -59,6 +59,34 @@ #include #endif +#ifdef CONFIG_ADEOS_CORE +EXPORT_SYMBOL(adeos_suspend_domain); +EXPORT_SYMBOL(adp_cpu_current); +EXPORT_SYMBOL(adeos_alloc_irq); +EXPORT_SYMBOL(__adeos_init_stage); +EXPORT_SYMBOL(__adeos_handle_event); +EXPORT_SYMBOL(__adeos_stall_root); +EXPORT_SYMBOL(__adeos_unstall_root); +EXPORT_SYMBOL(__adeos_test_root); +EXPORT_SYMBOL(__adeos_test_and_stall_root); +EXPORT_SYMBOL(__adeos_restore_root); +EXPORT_SYMBOL(__adeos_schedule_back_root); +EXPORT_SYMBOL(__adeos_dump_state); +EXPORT_SYMBOL(adeos_unstall_pipeline_from); +extern struct list_head __adeos_pipeline; +EXPORT_SYMBOL(__adeos_pipeline); +extern spinlock_t __adeos_pipelock; +EXPORT_SYMBOL(__adeos_pipelock); +extern unsigned long __adeos_virtual_irq_map; +EXPORT_SYMBOL(__adeos_virtual_irq_map); +EXPORT_SYMBOL(__adeos_event_monitors); +/* The following are convenience exports which are needed by some + Adeos domains loaded as kernel modules. */ +EXPORT_SYMBOL_NOVERS(__mmdrop); +EXPORT_SYMBOL_NOVERS(do_fork); +EXPORT_SYMBOL_NOVERS(do_exit); +#endif /* CONFIG_ADEOS_CORE */ + extern void set_device_ro(kdev_t dev,int flag); extern void *sys_call_table; diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/Makefile linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/Makefile --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/Makefile 2004-07-22 13:50:27.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/Makefile 2005-08-12 15:41:58.000000000 -0600 @@ -9,7 +9,7 @@ O_TARGET := kernel.o -export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \ +export-objs = adeos.o signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \ printk.o fork.o cpufreq.o obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ @@ -22,6 +22,7 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_ADEOS_CORE) += adeos.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/panic.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/panic.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/panic.c 2004-08-03 19:33:52.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/panic.c 2005-08-12 15:41:58.000000000 -0600 @@ -68,6 +68,9 @@ NORET_TYPE void panic(const char * fmt, printk(KERN_EMERG "In idle task - not syncing\n"); else sys_sync(); +#ifdef CONFIG_ADEOS_CORE + __adeos_dump_state(); +#endif /* CONFIG_ADEOS_CORE */ bust_spinlocks(0); #ifdef CONFIG_SMP diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/printk.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/printk.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/printk.c 2004-08-03 19:33:52.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/printk.c 2005-08-12 15:41:58.000000000 -0600 @@ -29,6 +29,17 @@ #include +#ifdef CONFIG_ADEOS_CORE +#undef spin_lock_irq +#define spin_lock_irq(lock) adeos_spin_lock_disable(lock) +#undef spin_unlock_irq +#define spin_unlock_irq(lock) adeos_spin_unlock_enable(lock) +#undef spin_lock_irqsave +#define spin_lock_irqsave(lock, flags) adeos_spin_lock_irqsave(lock,flags) +#undef spin_unlock_irqrestore +#define spin_unlock_irqrestore(lock, flags) adeos_spin_unlock_irqrestore(lock,flags) +#endif /* CONFIG_ADEOS_CORE */ + #if !defined(CONFIG_LOG_BUF_SHIFT) || (CONFIG_LOG_BUF_SHIFT == 0) #if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) #define LOG_BUF_LEN (65536) @@ -450,6 +461,21 @@ asmlinkage int printk(const char *fmt, . log_level_unknown = 1; } +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root && !test_bit(ADEOS_SPRINTK_FLAG,&adp_current->flags)) { + /* When operating in asynchronous printk() mode, ensure + the console drivers and klogd wakeup are only run by + Linux, delegating the actual output to the root domain + by mean of a virtual IRQ kicking our sync handler. If + the current domain has a lower priority than Linux, + then we'll get immediately preempted by it. In + synchronous printk() mode, immediately call the console + drivers. */ + spin_unlock_irqrestore(&logbuf_lock, flags); + adeos_trigger_irq(__adeos_printk_virq); + goto out; + } +#endif /* CONFIG_ADEOS_CORE */ if (!arch_consoles_callable()) { /* * On some architectures, the consoles are not usable @@ -458,7 +484,11 @@ asmlinkage int printk(const char *fmt, . spin_unlock_irqrestore(&logbuf_lock, flags); goto out; } +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root || !down_trylock(&console_sem)) { +#else /* !CONFIG_ADEOS_CORE */ if (!down_trylock(&console_sem)) { +#endif /* CONFIG_ADEOS_CORE */ /* * We own the drivers. We can drop the spinlock and let * release_console_sem() print the text @@ -528,12 +558,38 @@ void release_console_sem(void) call_console_drivers(_con_start, _log_end); } console_may_schedule = 0; +#ifdef CONFIG_ADEOS_CORE + if (adp_root != adp_current) { + spin_unlock_irqrestore(&logbuf_lock, flags); + return; + } + spin_unlock_irqrestore(&logbuf_lock, flags); + up(&console_sem); +#else /* !CONFIG_ADEOS_CORE */ up(&console_sem); spin_unlock_irqrestore(&logbuf_lock, flags); +#endif /* CONFIG_ADEOS_CORE */ if (must_wake_klogd && !oops_in_progress) wake_up_interruptible(&log_wait); } +#ifdef CONFIG_ADEOS_CORE +void __adeos_sync_console (unsigned virq) { + + /* This handler always runs on behalf of the root (Linux) domain. */ + unsigned long flags; + + spin_lock_irqsave(&logbuf_lock, flags); + + if (arch_consoles_callable() && !down_trylock(&console_sem)) { + spin_unlock_irqrestore(&logbuf_lock, flags); + console_may_schedule = 0; + release_console_sem(); + } else + spin_unlock_irqrestore(&logbuf_lock, flags); +} +#endif /* CONFIG_ADEOS_CORE */ + /** console_conditional_schedule - yield the CPU if required * * If the console code is currently allowed to sleep, and diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/sched.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/sched.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/sched.c 2004-08-03 19:33:52.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/sched.c 2005-08-12 15:41:58.000000000 -0600 @@ -532,6 +532,9 @@ needs_resched: asmlinkage void schedule_tail(struct task_struct *prev) { __schedule_tail(prev); +#ifdef CONFIG_ADEOS_EVENT_ENTER_PROCESS + __adeos_enter_process(); +#endif /* CONFIG_ADEOS_EVENT_ENTER_PROCESS */ } /* @@ -551,6 +554,10 @@ asmlinkage void schedule(void) struct list_head *tmp; int this_cpu, c; +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root) /* Let's be helpful and conservative. */ + return; +#endif /* CONFIG_ADEOS_CORE */ spin_lock_prefetch(&runqueue_lock); @@ -668,7 +675,13 @@ repeat_schedule: * but prev is set to (the just run) 'last' process by switch_to(). * This might sound slightly confusing but makes tons of sense. */ +#ifdef CONFIG_ADEOS_CORE + prepare_to_switch(prev, next); + /* disable hw-irqs (for sake of LXRT scheduler), are re-enabled after switch */ + adeos_hw_cli(); +#else /* !CONFIG_ADEOS_CORE */ prepare_to_switch(); +#endif /* CONFIG_ADEOS_CORE */ { struct mm_struct *mm = next->mm; struct mm_struct *oldmm = prev->active_mm; @@ -693,6 +706,13 @@ repeat_schedule: * stack. */ switch_to(prev, next, prev); +#ifdef CONFIG_ADEOS_CORE + adeos_hw_sti(); + if (__adeos_schedule_tail(prev) > 0) + /* Some event handler asked for a truncated + scheduling tail. Just obey. */ + return; +#endif /* CONFIG_ADEOS_CORE */ __schedule_tail(prev); same_process: @@ -702,6 +722,20 @@ same_process: return; } +#ifdef CONFIG_ADEOS_CORE + +void __adeos_schedule_back_root (struct task_struct *prev) + +{ + __schedule_tail(prev); + reacquire_kernel_lock(current); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ +} + +#endif /* CONFIG_ADEOS_CORE */ + /* * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just wake everything * up. If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the @@ -989,6 +1023,13 @@ static int setscheduler(pid_t pid, int p goto out_unlock; retval = 0; +#ifdef CONFIG_ADEOS_EVENT_RENICE_PROCESS + { + struct { struct task_struct *task; int policy; struct sched_param *param; } evdata = { p, policy, &lp }; + if (__adeos_renice_process(&evdata)) + goto out_unlock; + } +#endif /* CONFIG_ADEOS_EVENT_RENICE_PROCESS */ p->policy = policy; p->rt_priority = lp.sched_priority; diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/signal.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/signal.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/signal.c 2004-08-03 19:33:52.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/signal.c 2005-08-12 15:41:58.000000000 -0600 @@ -496,6 +496,13 @@ static inline void signal_wake_up(struct { t->sigpending = 1; +#ifdef CONFIG_ADEOS_CORE + { + struct { struct task_struct *t; } evdata = { t }; + __adeos_kick_process(&evdata); + } +#endif /* CONFIG_ADEOS_CORE */ + #ifdef CONFIG_SMP /* * If the task is running on a different CPU @@ -554,6 +561,17 @@ printk("SIG queue (%s:%d): %d ", t->comm if (!sig || !t->sig) goto out_nolock; +#ifdef CONFIG_ADEOS_CORE + /* If some domain handler in the pipeline doesn't ask for + propagation, return success pretending that 'sig' was + delivered. */ + { + struct { struct task_struct *task; int sig; } evdata = { t, sig }; + if (__adeos_signal_process(&evdata)) + goto out_nolock; + } +#endif /* CONFIG_ADEOS_CORE */ + spin_lock_irqsave(&t->sigmask_lock, flags); handle_stop_signal(sig, t); diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/sysctl.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/sysctl.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/kernel/sysctl.c 2004-08-03 19:33:52.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/kernel/sysctl.c 2005-08-12 15:41:58.000000000 -0600 @@ -360,6 +360,9 @@ void __init sysctl_init(void) #ifdef CONFIG_PROC_FS register_proc_table(root_table, proc_sys_root); init_irq_proc(); +#ifdef CONFIG_ADEOS_CORE + __adeos_init_proc(); +#endif /* CONFIG_ADEOS_CORE */ #endif } diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/Makefile linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/Makefile --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/Makefile 2005-03-11 09:02:10.000000000 -0700 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/Makefile 2005-08-12 15:42:54.000000000 -0600 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 26 -EXTRAVERSION =-vrs1-cirrus-1-2-1-ts8 +EXTRAVERSION =-vrs1-cirrus-1-2-1-ts8-rt KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -18,7 +18,7 @@ FINDHPATH = $(HPATH)/asm $(HPATH)/linux HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -Os -fomit-frame-pointer -CROSS_COMPILE = $(shell cd $(TOPDIR)/../../tools/crosstool/arm-9tdmi-linux-gnu/gcc-3.3.4-glibc-2.3.2/bin/ && pwd)/arm-9tdmi-linux-gnu- +CROSS_COMPILE = /usr/local/opt/crosstool/arm-linux/gcc-3.3.4-glibc-2.3.2/bin/arm-linux- # # Include the make variables (CC, etc...) # @@ -34,7 +34,7 @@ OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump MAKEFILES = $(TOPDIR)/.config GENKSYMS = /sbin/genksyms -DEPMOD = /sbin/depmod +DEPMOD = /usr/local/opt/crosstool/arm-linux/gcc-3.3.4-glibc-2.3.2/sbin/depmod MODFLAGS = -DMODULE CFLAGS_KERNEL = PERL = perl @@ -126,13 +126,14 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/f NETWORKS =net/network.o LIBS =$(TOPDIR)/lib/lib.a -SUBDIRS =kernel drivers mm fs net ipc lib crypto +SUBDIRS =kernel adeos drivers mm fs net ipc lib crypto DRIVERS-n := DRIVERS-y := DRIVERS-m := DRIVERS- := +DRIVERS-$(CONFIG_ADEOS) += adeos/built-in.o DRIVERS-$(CONFIG_ACPI_BOOT) += drivers/acpi/acpi.o DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o diff -urNpb linux-2.4.26-vrs1-cirrus-1-2-1-ts8/mm/memory.c linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/mm/memory.c --- linux-2.4.26-vrs1-cirrus-1-2-1-ts8/mm/memory.c 2004-08-03 19:33:53.000000000 -0600 +++ linux-2.4.26-vrs1-cirrus-1-2-1-ts8-rt/mm/memory.c 2005-08-12 15:41:58.000000000 -0600 @@ -492,13 +492,32 @@ int get_user_pages(struct task_struct *t vma = find_extend_vma(mm, start); +#if 0 if ( !vma || (pages && vma->vm_flags & VM_IO) || !(flags & vma->vm_flags) ) +#else + /* fix for lock-up upon mlockall() & mmap(/dev/mem) (i.e. to access + * hardware in real-time process) */ + int vm_io = vma ? vma->vm_flags & VM_IO : 0; + if (!vma || (pages && vm_io) || !(flags & vma->vm_flags)) +#endif return i ? : -EFAULT; spin_lock(&mm->page_table_lock); do { +#if 0 struct page *map; while (!(map = follow_page(mm, start, write))) { +#else + /* fix for lock-up upon mlockall() & mmap(/dev/mem) (i.e. to access + * hardware in real-time process) */ + struct page *map = NULL; + /* + * We don't follow pagetables for VM_IO regions - they + * have no pageframes. And the caller passed NULL + * for `pages' anyway. + */ + while (!vm_io && !(map = follow_page(mm,start,write))) { +#endif spin_unlock(&mm->page_table_lock); switch (handle_mm_fault(mm, vma, start, write)) { case 1: