* [Xenomai-core] Re: Adeos (oldgen) 2.6.10 ppc64 r3
@ 2005-11-14 11:51 Heikki Lindholm
0 siblings, 0 replies; only message in thread
From: Heikki Lindholm @ 2005-11-14 11:51 UTC (permalink / raw)
To: adeos-main; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 162 bytes --]
A new Adeos patch for the 2.6.10 ppc64 (r3) with minor paranoia reduction.
Also from:
http://www.cs.helsinki.fi/group/nonsto/rtaippc64.html
-- Heikki Lindholm
[-- Attachment #2: adeos-linux-2.6.10-ppc64-r3.patch --]
[-- Type: text/plain, Size: 153845 bytes --]
diff -Nru linux-2.6.10/adeos/generic.c linux-2.6.10-adeos-ppc64-r3/adeos/generic.c
--- linux-2.6.10/adeos/generic.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/adeos/generic.c 2005-11-13 11:45:31.000000000 +0200
@@ -0,0 +1,640 @@
+/*
+ * linux/adeos/generic.c
+ *
+ * Copyright (C) 2002 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-independent ADEOS services.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+
+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] = 0;
+#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 (adp_root->cpudata[cpuid].irq_pending_hi != 0 &&
+ !test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status))
+ __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 nr_cpus = num_online_cpus(), _cpuid;
+ unsigned irq;
+
+ /* In the SMP case, wait for the logged events to drain on other
+ processors before eventually removing the domain from the
+ pipeline. */
+
+ 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 < nr_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 fastcall __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. */
+
+adevhand_t adeos_catch_event_from (adomain_t *adp, unsigned event, adevhand_t handler)
+
+{
+ adevhand_t oldhandler;
+
+ if (event >= ADEOS_NR_EVENTS)
+ return NULL;
+
+ if ((oldhandler = (adevhand_t)xchg(&adp->events[event].handler,handler)) == NULL)
+ {
+ if (handler)
+ __adeos_event_monitors[event]++;
+ }
+ else if (!handler)
+ __adeos_event_monitors[event]--;
+
+ return oldhandler;
+}
+
+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;
+
+ spin_lock_irqsave_hw(&__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++;
+ }
+
+ spin_unlock_irqrestore_hw(&__adeos_pipelock,flags);
+
+ return key;
+}
+
+int adeos_free_ptdkey (int key)
+
+{
+ unsigned long flags;
+
+ if (key < 0 || key >= adp_current->ptd_keymax)
+ return -EINVAL;
+
+ spin_lock_irqsave_hw(&__adeos_pipelock,flags);
+
+ if (test_and_clear_bit(key,&adp_current->ptd_keymap))
+ adp_current->ptd_keycount--;
+
+ spin_unlock_irqrestore_hw(&__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_ higher priority 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 fastcall 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 higher priority 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 fastcall 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 highest priority 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 fastcall adeos_lock_mutex (admutex_t *mutex)
+
+{
+ unsigned long flags; /* FIXME: won't work on SPARC */
+ spin_lock_irqsave_hw(&mutex->lock,flags);
+ return flags;
+}
+
+void fastcall adeos_unlock_mutex (admutex_t *mutex, unsigned long flags)
+
+{
+ spin_unlock_irqrestore_hw(&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 -Nru linux-2.6.10/adeos/Kconfig linux-2.6.10-adeos-ppc64-r3/adeos/Kconfig
--- linux-2.6.10/adeos/Kconfig 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/adeos/Kconfig 2005-11-13 11:45:31.000000000 +0200
@@ -0,0 +1,40 @@
+menu "Adeos support"
+
+config ADEOS
+ tristate "Adeos support"
+ default y
+ ---help---
+ Activate this option if you want the Adeos nanokernel to be
+ compiled in.
+
+config ADEOS_CORE
+ def_bool ADEOS
+
+config ADEOS_THREADS
+ bool "Threaded domains"
+ depends on ADEOS && !PPC64
+ default y
+ ---help---
+ This option causes the domains to run as lightweight
+ threads, which is useful for having seperate stacks
+ for domains. Enabling this option is the safest setting for
+ now; disabling it causes an experimental mode to be used
+ where interrupts/events are directly processed on behalf of
+ the preempted context. Say Y if unsure.
+
+config ADEOS_NOTHREADS
+ def_bool !ADEOS_THREADS
+
+config ADEOS_PROFILING
+ bool "Pipeline profiling"
+ depends on ADEOS
+ default n
+ ---help---
+ This option activates the profiling code which collects the
+ timestamps needed to measure the propagation time of
+ interrupts through the pipeline. Say N if unsure.
+
+config ADEOS_PREEMPT_RT
+ def_bool PREEMPT_NONE || PREEMPT_VOLUNTARY || PREEMPT_DESKTOP || PREEMPT_RT
+
+endmenu
diff -Nru linux-2.6.10/adeos/Makefile linux-2.6.10-adeos-ppc64-r3/adeos/Makefile
--- linux-2.6.10/adeos/Makefile 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/adeos/Makefile 2005-11-13 11:45:31.000000000 +0200
@@ -0,0 +1,15 @@
+#
+# Makefile for the Adeos layer.
+#
+
+obj-$(CONFIG_ADEOS) += adeos.o
+
+adeos-objs := generic.o
+
+adeos-$(CONFIG_X86) += x86.o
+
+adeos-$(CONFIG_IA64) += ia64.o
+
+adeos-$(CONFIG_PPC32) += ppc.o
+
+adeos-$(CONFIG_PPC64) += ppc64.o
diff -Nru linux-2.6.10/adeos/ppc64.c linux-2.6.10-adeos-ppc64-r3/adeos/ppc64.c
--- linux-2.6.10/adeos/ppc64.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/adeos/ppc64.c 2005-11-13 11:45:31.000000000 +0200
@@ -0,0 +1,527 @@
+/*
+ * linux/adeos/ppc64.c
+ *
+ * Adeos 64-bit PowerPC adoption
+ * Copyright (C) 2005 Taneli V������h������kangas and Heikki Lindholm
+ * based on previous work:
+ *
+ * Copyright (C) 2004 Philippe Gerum.
+ *
+ * Adeos/PPC port over 2.6 based on the previous 2.4 implementation by:
+ *
+ * Copyright (C) 2004 Wolfgang Grandegger.
+ *
+ * It follows closely the ARM and x86 ports of ADEOS.
+ *
+ * Copyright (C) 2003 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-dependent ADEOS support for PowerPC.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/cputable.h> /* cur_cpu_spec & CPU_FTR* */
+#include <asm/mmu_context.h> /* get_kernel_vsid */
+
+extern spinlock_t __adeos_pipelock;
+
+extern unsigned long __adeos_virtual_irq_map;
+
+extern struct list_head __adeos_pipeline;
+
+extern irq_desc_t irq_desc[];
+
+static struct hw_interrupt_type __adeos_std_irq_dtype[NR_IRQS];
+
+/*
+ * Check NULLs when calling dtype[].X ?
+ * (.end)
+ */
+
+static void __adeos_override_irq_enable (unsigned irq)
+
+{
+ unsigned long adflags, hwflags;
+ adeos_declare_cpuid;
+
+ adeos_hw_local_irq_save(hwflags);
+ adflags = adeos_test_and_stall_pipeline();
+ preempt_disable();
+ __adeos_unlock_irq(adp_cpu_current[cpuid],irq);
+ __adeos_std_irq_dtype[irq].enable(irq);
+ preempt_enable_no_resched();
+ adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+ adeos_hw_local_irq_restore(hwflags);
+}
+
+static void __adeos_override_irq_disable (unsigned irq)
+
+{
+ unsigned long adflags, hwflags;
+ adeos_declare_cpuid;
+
+ adeos_hw_local_irq_save(hwflags);
+ adflags = adeos_test_and_stall_pipeline();
+ preempt_disable();
+ __adeos_std_irq_dtype[irq].disable(irq);
+ __adeos_lock_irq(adp_cpu_current[cpuid],cpuid,irq);
+ preempt_enable_no_resched();
+ adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+ adeos_hw_local_irq_restore(hwflags);
+}
+
+static void __adeos_override_irq_end (unsigned irq)
+
+{
+ unsigned long adflags, hwflags;
+ adeos_declare_cpuid;
+
+ adeos_hw_local_irq_save(hwflags);
+ adflags = adeos_test_and_stall_pipeline();
+ preempt_disable();
+
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ __adeos_unlock_irq(adp_cpu_current[cpuid],irq);
+
+ __adeos_std_irq_dtype[irq].end(irq);
+
+ preempt_enable_no_resched();
+ adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+ adeos_hw_local_irq_restore(hwflags);
+}
+
+static void __adeos_override_irq_affinity (unsigned irq, cpumask_t mask)
+
+{
+ unsigned long adflags, hwflags;
+ adeos_declare_cpuid;
+
+ adeos_hw_local_irq_save(hwflags);
+ adflags = adeos_test_and_stall_pipeline();
+ preempt_disable();
+ __adeos_std_irq_dtype[irq].set_affinity(irq,mask);
+ preempt_enable_no_resched();
+ adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+ adeos_hw_local_irq_restore(hwflags);
+}
+
+static void __adeos_enable_sync (void)
+
+{
+ __adeos_decr_next[adeos_processor_id()] = __adeos_read_timebase() + get_dec();
+}
+
+/* __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(&__adeos_enable_sync);
+
+ /* First, virtualize all interrupts from the root domain. */
+
+ for (irq = 0; irq < NR_IRQS; irq++)
+ adeos_virtualize_irq(irq,
+ (void (*)(unsigned))&__adeos_do_IRQ,
+ &__adeos_ack_irq,
+ IPIPE_HANDLE_MASK|IPIPE_PASS_MASK);
+
+ /* We use a virtual IRQ to handle the timer irq (decrementer trap)
+ which has been allocated early in __adeos_init_platform(). */
+
+ adeos_virtualize_irq(ADEOS_TIMER_VIRQ,
+ (void (*)(unsigned))&__adeos_do_timer,
+ NULL,
+ 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++)
+ {
+ if (irq_desc[irq].handler != NULL)
+ __adeos_std_irq_dtype[irq] = *irq_desc[irq].handler;
+ }
+
+ /* The original controller structs are often shared, so we first
+ save them all before changing any of them. Notice that we don't
+ override the ack() handler since we will enforce the necessary
+ setup in __adeos_ack_irq(). */
+
+ for (irq = 0; irq < NR_IRQS; irq++)
+ {
+ struct hw_interrupt_type *handler = irq_desc[irq].handler;
+
+ if (handler == NULL)
+ continue;
+
+ if (handler->enable != NULL)
+ handler->enable = &__adeos_override_irq_enable;
+
+ if (handler->disable != NULL)
+ handler->disable = &__adeos_override_irq_disable;
+
+ if (handler->end != NULL)
+ handler->end = &__adeos_override_irq_end;
+
+ if (handler->set_affinity != NULL)
+ handler->set_affinity = &__adeos_override_irq_affinity;
+ }
+
+ __adeos_decr_next[adeos_processor_id()] = __adeos_read_timebase() + get_dec();
+
+ adp_pipelined = 1;
+
+ 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++)
+ {
+ if (irq_desc[irq].handler != NULL)
+ *irq_desc[irq].handler = __adeos_std_irq_dtype[irq];
+ }
+
+ adp_pipelined = 0;
+
+ 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)
+ - <none> => 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)
+{
+ irq_desc_t *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
+
+void __adeos_init_domain (adomain_t *adp, adattr_t *attr)
+
+{
+ int estacksz = attr->estacksz > 0 ? attr->estacksz : 16384, _cpuid;
+ unsigned long flags, *ksp;
+ adeos_declare_cpuid;
+
+ adeos_hw_local_irq_flags(flags);
+
+ for (_cpuid = 0; _cpuid < num_online_cpus(); _cpuid++)
+ {
+ adp->estackbase[_cpuid] = (unsigned long)kmalloc(estacksz,GFP_KERNEL);
+
+ if (adp->estackbase[_cpuid] == 0)
+ panic("Adeos: No memory for domain stack on CPU #%d",_cpuid);
+
+ adp->esp[_cpuid] = adp->estackbase[_cpuid];
+ ksp = (unsigned long *)((adp->esp[_cpuid] + estacksz - 16) & ~0xf);
+ *ksp = 0L; /* first stack frame back-chain */
+ ksp = ksp - STACK_FRAME_OVERHEAD; /* first stack frame (entry uses)
+ * (less would do) */
+ *ksp = (unsigned long)ksp+STACK_FRAME_OVERHEAD; /* second back-chain */
+ ksp = ksp - 224; /* domain context */
+ adp->esp[_cpuid] = (unsigned long)ksp - STACK_FRAME_OVERHEAD;
+ *((unsigned long *)adp->esp[_cpuid]) = (unsigned long)ksp + 224; /*back-chain*/
+ /* NOTE: these depend on _adeos_switch_domain ordering */
+ ksp[18] = (unsigned long)get_paca(); /* r13 needs to hold paca */
+ ksp[19] = (_cpuid == cpuid); /* r3 */
+ ksp[20] = ((unsigned long *)attr->entry)[1]; /* r2 = TOC base */
+ ksp[25] = ((unsigned long *)attr->entry)[0]; /* lr = entry addr. */
+ ksp[26] = flags & ~MSR_EE; /* msr */
+ }
+}
+
+#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)
+
+{
+ int nr_cpus = num_online_cpus();
+ int _cpuid;
+
+ adeos_unstall_pipeline_from(adp);
+
+ for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+ {
+#ifdef CONFIG_SMP
+ while (adp->cpudata[_cpuid].irq_pending_hi != 0)
+ cpu_relax();
+
+ while (test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[_cpuid].status))
+ cpu_relax();
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_ADEOS_THREADS
+ if (adp->estackbase[_cpuid] != 0)
+ kfree((void *)adp->estackbase[_cpuid]);
+#endif /* CONFIG_ADEOS_THREADS */
+ }
+}
+
+int adeos_get_sysinfo (adsysinfo_t *info)
+
+{
+ info->ncpus = num_online_cpus();
+ info->cpufreq = adeos_cpu_freq();
+ info->archdep.tmirq = ADEOS_TIMER_VIRQ;
+ info->archdep.tmfreq = info->cpufreq;
+
+ return 0;
+}
+
+static void __adeos_set_decr (void)
+
+{
+ adeos_declare_cpuid;
+
+ adeos_load_cpuid();
+
+ disarm_decr[cpuid] = (__adeos_decr_ticks != tb_ticks_per_jiffy);
+ __adeos_decr_next[cpuid] = __adeos_read_timebase() + __adeos_decr_ticks;
+ set_dec(__adeos_decr_ticks);
+}
+
+int adeos_tune_timer (unsigned long ns, int flags)
+
+{
+ unsigned long x, ticks;
+
+ if (flags & ADEOS_RESET_TIMER)
+ ticks = tb_ticks_per_jiffy;
+ else
+ {
+ ticks = ns * tb_ticks_per_jiffy / (1000000000 / HZ);
+
+ if (ticks > tb_ticks_per_jiffy)
+ return -EINVAL;
+ }
+
+ x = adeos_critical_enter(&__adeos_set_decr); /* Sync with all CPUs */
+ __adeos_decr_ticks = ticks;
+ __adeos_set_decr();
+ adeos_critical_exit(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;
+}
diff -Nru linux-2.6.10/arch/ppc64/Kconfig linux-2.6.10-adeos-ppc64-r3/arch/ppc64/Kconfig
--- linux-2.6.10/arch/ppc64/Kconfig 2004-12-24 23:34:58.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/Kconfig 2005-11-13 11:45:31.000000000 +0200
@@ -370,6 +370,8 @@
depends on VIOCONS || VIODASD || VIOCD || VIOTAPE || VETH
default y
+source "adeos/Kconfig"
+
source "arch/ppc64/oprofile/Kconfig"
source "arch/ppc64/Kconfig.debug"
diff -Nru linux-2.6.10/arch/ppc64/kernel/adeos.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/adeos.c
--- linux-2.6.10/arch/ppc64/kernel/adeos.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/adeos.c 2005-11-13 11:45:31.000000000 +0200
@@ -0,0 +1,700 @@
+/*
+ * linux/arch/ppc64/kernel/adeos.c
+ *
+ * Adeos 64-bit PowerPC adoption
+ * Copyright (C) 2005 Taneli V������h������kangas and Heikki Lindholm
+ * based on previous work:
+ *
+ * Copyright (C) 2004 Philippe Gerum.
+ *
+ * Adeos/PPC port over 2.6 based on the previous 2.4 implementation by:
+ *
+ * Copyright (C) 2004 Wolfgang Grandegger.
+ *
+ * It follows closely the ARM and x86 ports of ADEOS.
+ *
+ * Copyright (C) 2003 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-dependent ADEOS core support for PowerPC
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/machdep.h> /* ppc_md */
+
+#ifdef CONFIG_SMP
+
+static cpumask_t __adeos_cpu_sync_map;
+
+static cpumask_t __adeos_cpu_lock_map;
+
+static spinlock_t __adeos_cpu_barrier = SPIN_LOCK_UNLOCKED;
+
+static atomic_t __adeos_critical_count = ATOMIC_INIT(0);
+
+static void (*__adeos_cpu_sync)(void);
+
+#endif /* CONFIG_SMP */
+
+void do_IRQ(struct pt_regs *regs);
+
+extern struct list_head __adeos_pipeline;
+
+struct pt_regs __adeos_irq_regs;
+
+/* Current reload value for the decrementer. */
+unsigned long __adeos_decr_ticks;
+
+/* Next tick date (timebase value). */
+unsigned long __adeos_decr_next[ADEOS_NR_CPUS];
+
+static inline unsigned long ffnz (unsigned long ul) {
+
+ __asm__ __volatile__ ("cntlzd %0, %1" : "=r" (ul) : "r" (ul & (-ul)));
+ return 63 - ul;
+}
+
+#ifdef CONFIG_SMP
+
+/* Always called with hw interrupts off. */
+
+static void __adeos_do_critical_sync (unsigned irq)
+
+{
+ adeos_declare_cpuid;
+
+ adeos_load_cpuid();
+
+ cpu_set(cpuid,__adeos_cpu_sync_map);
+
+ /* Now we are in sync with the lock requestor running on another
+ CPU. Enter a spinning wait until he releases the global
+ lock. */
+ adeos_spin_lock(&__adeos_cpu_barrier);
+
+ /* Got it. Now get out. */
+
+ if (__adeos_cpu_sync)
+ /* Call the sync routine if any. */
+ __adeos_cpu_sync();
+
+ adeos_spin_unlock(&__adeos_cpu_barrier);
+
+ cpu_clear(cpuid,__adeos_cpu_sync_map);
+}
+
+#endif /* CONFIG_SMP */
+
+/* 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);
+
+#ifdef CONFIG_SMP
+ if (num_online_cpus() > 1) /* We might be running a SMP-kernel on a UP box... */
+ {
+ adeos_declare_cpuid;
+ cpumask_t lock_map;
+
+ adeos_load_cpuid();
+
+ if (!cpu_test_and_set(cpuid,__adeos_cpu_lock_map))
+ {
+ while (cpu_test_and_set(BITS_PER_LONG - 1,__adeos_cpu_lock_map))
+ {
+ /* Refer to the explanations found in
+ linux/arch/asm-i386/irq.c about
+ SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND for more about
+ this strange loop. */
+ int n = 0;
+ do { cpu_relax(); } while (++n < cpuid);
+ }
+
+ adeos_spin_lock(&__adeos_cpu_barrier);
+
+ __adeos_cpu_sync = syncfn;
+
+ /* Send the sync IPI to all processors but the current one. */
+ __adeos_send_IPI_allbutself(ADEOS_CRITICAL_VECTOR);
+
+ cpus_andnot(lock_map,cpu_online_map,__adeos_cpu_lock_map);
+
+ while (!cpus_equal(__adeos_cpu_sync_map,lock_map))
+ cpu_relax();
+ }
+
+ atomic_inc(&__adeos_critical_count);
+ }
+#endif /* CONFIG_SMP */
+
+ return flags;
+}
+
+/* adeos_critical_exit() -- Release the superlock. */
+
+void adeos_critical_exit (unsigned long flags)
+
+{
+#ifdef CONFIG_SMP
+ if (num_online_cpus() > 1) /* We might be running a SMP-kernel on a UP box... */
+ {
+ adeos_declare_cpuid;
+
+ adeos_load_cpuid();
+
+ if (atomic_dec_and_test(&__adeos_critical_count))
+ {
+ adeos_spin_unlock(&__adeos_cpu_barrier);
+
+ while (!cpus_empty(__adeos_cpu_sync_map))
+ cpu_relax();
+
+ cpu_clear(cpuid,__adeos_cpu_lock_map);
+ cpu_clear(BITS_PER_LONG - 1,__adeos_cpu_lock_map);
+ }
+ }
+#endif /* CONFIG_SMP */
+
+ adeos_hw_local_irq_restore(flags);
+}
+
+void __adeos_init_platform (void)
+
+{
+ unsigned timer_virq;
+
+ /* Allocate a virtual IRQ for the decrementer trap early to get it
+ mapped to IPIPE_VIRQ_BASE */
+
+ timer_virq = adeos_alloc_irq();
+
+ if (timer_virq != ADEOS_TIMER_VIRQ)
+ panic("Adeos: cannot reserve timer virq #%d (got #%d)",
+ ADEOS_TIMER_VIRQ,
+ timer_virq);
+
+ __adeos_decr_ticks = tb_ticks_per_jiffy;
+}
+
+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 */
+ }
+
+#ifdef CONFIG_SMP
+ adp->irqs[ADEOS_CRITICAL_IPI].acknowledge = &__adeos_ack_irq;
+ adp->irqs[ADEOS_CRITICAL_IPI].handler = &__adeos_do_critical_sync;
+ /* Immediately handle in the current domain but *never* pass */
+ adp->irqs[ADEOS_CRITICAL_IPI].control = IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SYSTEM_MASK;
+#endif /* CONFIG_SMP */
+}
+
+/* __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;
+ int level, rank;
+ adeos_declare_cpuid;
+ adomain_t *adp;
+ unsigned irq;
+
+ adeos_load_cpuid();
+ adp = adp_cpu_current[cpuid];
+ cpudata = &adp->cpudata[cpuid];
+
+ if (__test_and_set_bit(IPIPE_SYNC_FLAG,&cpudata->status))
+ return;
+
+ /* The policy here is to keep the dispatching code interrupt-free
+ by stalling the current stage. If the upper domain handler
+ (which we call) wants to re-enable interrupts while in a safe
+ portion of the code (e.g. SA_INTERRUPT flag unset for Linux's
+ sigaction()), it will have to unstall (then stall again before
+ returning to us!) the stage when it sees fit. */
+
+ while ((mask = (cpudata->irq_pending_hi & syncmask)) != 0)
+ {
+ /* Give a slight priority advantage to high-numbered IRQs
+ like the virtual ones. */
+ level = ffnz(mask);
+ __clear_bit(level,&cpudata->irq_pending_hi);
+
+ while ((submask = cpudata->irq_pending_lo[level]) != 0)
+ {
+ rank = ffnz(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]);
+
+ __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();
+ }
+ else
+ {
+ __clear_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+ adp->irqs[irq].handler(irq);
+ __set_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+ }
+
+#ifdef CONFIG_SMP
+ {
+ int _cpuid = adeos_processor_id();
+
+ if (_cpuid != cpuid) /* Handle CPU migration. */
+ {
+ /* We expect any domain to clear the SYNC bit each
+ time it switches in a new task, so that preemptions
+ and/or CPU migrations (in the SMP case) over the
+ ISR do not lock out the log syncer for some
+ indefinite amount of time. In the Linux case,
+ schedule() handles this (see kernel/sched.c). For
+ this reason, we don't bother clearing it here for
+ the source CPU in the migration handling case,
+ since it must have scheduled another task in by
+ now. */
+ cpuid = _cpuid;
+ cpudata = &adp->cpudata[cpuid];
+ __set_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+ }
+ }
+#endif /* CONFIG_SMP */
+
+ __clear_bit(IPIPE_STALL_FLAG,&cpudata->status);
+ }
+ }
+
+ __clear_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+}
+
+int __adeos_ack_irq (unsigned irq)
+
+{
+ irq_desc_t *desc = get_irq_desc(irq);
+
+ if (desc->handler->ack != NULL)
+ {
+ unsigned long adflags;
+ adeos_declare_cpuid;
+
+ /* No need to mask IRQs at hw level: we are always called from
+ __adeos_handle_irq(), so interrupts are already off. We
+ stall the pipeline so that spin_lock_irq*() ops won't
+ unintentionally flush it, since this could cause infinite
+ recursion. */
+
+ adeos_load_cpuid();
+ adflags = adeos_test_and_stall_pipeline();
+ preempt_disable();
+ spin_lock(&desc->lock);
+ desc->handler->ack(irq);
+ spin_unlock(&desc->lock);
+ preempt_enable_no_resched();
+ adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+ }
+
+ return 1;
+}
+
+static inline void __adeos_walk_pipeline (struct list_head *pos, int cpuid)
+
+{
+ adomain_t *this_domain = adp_cpu_current[cpuid];
+
+ 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)
+ {
+ /* Since the critical IPI might be dispatched by the
+ following actions, the current domain might not be
+ linked to the pipeline anymore after its handler
+ returns on SMP boxes, even if the domain remains valid
+ (see adeos_unregister_domain()), so don't make any
+ dangerous 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 (this_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+ !test_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status))
+ __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. */
+
+void __adeos_handle_irq (int irq, struct pt_regs *regs)
+
+{
+ struct list_head *head, *pos;
+ adeos_declare_cpuid;
+ int m_ack, s_ack;
+
+ m_ack = irq & ADEOS_IRQ_ACKED;
+ irq &= ADEOS_IRQ_ACKED_MASK;
+
+ if (irq >= IPIPE_NR_IRQS)
+ {
+ printk(KERN_ERR "Adeos: spurious interrupt %d\n",irq);
+ return;
+ }
+
+ 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 (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 *_adp = 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,&_adp->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. */
+
+ _adp->cpudata[cpuid].irq_hits[irq]++;
+ __adeos_set_irq_bit(_adp,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 (_adp->irqs[irq].acknowledge != NULL)
+ {
+ if (!m_ack)
+ m_ack = _adp->irqs[irq].acknowledge(irq);
+ else if (test_bit(IPIPE_SHARED_FLAG,&_adp->irqs[irq].control) && !s_ack)
+ s_ack = _adp->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,&_adp->irqs[irq].control))
+ break;
+
+ pos = _adp->p_link.next;
+ }
+
+ /* 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 higher priority domain. Once
+ the first and highest priority 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's version of the interrupt trap handler. */
+
+int __adeos_grab_irq (struct pt_regs *regs)
+
+{
+ extern int ppc_spurious_interrupts;
+ adeos_declare_cpuid;
+ int irq;
+
+ if (!adp_pipelined)
+ {
+ do_IRQ(regs);
+ return 1;
+ }
+
+ irq = ppc_md.get_irq(regs);
+ if (irq >= 0)
+ {
+ __adeos_handle_irq(irq,regs);
+ }
+ else
+ ppc_spurious_interrupts++;
+
+ adeos_load_cpuid();
+
+ return (adp_cpu_current[cpuid] == adp_root &&
+ !test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status));
+}
+
+/* ADEOS's version of irq.c:do_IRQ(). */
+
+void __adeos_do_IRQ (int irq, struct pt_regs *regs) {
+ irq_enter();
+ ppc_irq_dispatch_handler(regs, irq);
+ irq_exit();
+}
+
+/* ADEOS's version of the decrementer trap handler. */
+
+int __adeos_grab_timer (struct pt_regs *regs)
+
+{
+ adeos_declare_cpuid;
+
+ if (!adp_pipelined)
+ {
+ timer_interrupt(regs);
+ return 1;
+ }
+
+ /* On 970 CPUs DEC cannot be disabled and without setting DEC
+ * here, DEC interrupt would be triggered as soon as interrupts are
+ * enabled in __adeos_sync_stage
+ */
+ set_dec(0x7fffffff);
+
+ __adeos_irq_regs.msr = regs->msr; /* for do_timer() */
+
+ __adeos_handle_irq(ADEOS_TIMER_VIRQ,regs);
+
+ adeos_load_cpuid();
+
+ if (__adeos_decr_ticks != tb_ticks_per_jiffy)
+ {
+ unsigned long next_date, now;
+
+ next_date = __adeos_decr_next[cpuid];
+
+ while ((now = __adeos_read_timebase()) >= next_date)
+ next_date += __adeos_decr_ticks;
+
+ set_dec(next_date - now);
+
+ __adeos_decr_next[cpuid] = next_date;
+ }
+
+ return (adp_cpu_current[cpuid] == adp_root &&
+ !test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status));
+}
+
+void __adeos_do_timer (int irq, struct pt_regs *regs)
+
+{
+ timer_interrupt(regs);
+}
+
+asmlinkage int __adeos_check_root (struct pt_regs *regs)
+
+{
+ adeos_declare_cpuid;
+ /* This routine is called with hw interrupts off, so no migration
+ can occur while checking the identity of the current domain. */
+ adeos_load_cpuid();
+ 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 higher
+ priority 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.msr = flags;
+
+ __adeos_handle_irq(irq | ADEOS_IRQ_ACKED, ®s);
+
+ adeos_hw_local_irq_restore(flags);
+
+ return 1;
+}
+
+int __adeos_enter_syscall (struct pt_regs *regs)
+
+{
+ adeos_declare_cpuid;
+ unsigned long flags;
+
+ /* This routine either returns:
+ 0 -- if the syscall is to be passed to Linux;
+ 1 -- if the syscall should not be passed to Linux, and no
+ tail work should be performed;
+ -1 -- if the syscall should not be passed to Linux but the
+ tail work has to be performed. */
+
+ if (__adeos_event_monitors[ADEOS_SYSCALL_PROLOGUE] > 0 &&
+ __adeos_handle_event(ADEOS_SYSCALL_PROLOGUE,regs) > 0)
+ {
+ if (adp_current == adp_root && !in_atomic())
+ {
+ /* Sync pending VIRQs before _TIF_NEED_RESCHED is
+ * tested. */
+
+ adeos_lock_cpu(flags);
+
+ if ((adp_root->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+ __adeos_sync_stage(IPIPE_IRQMASK_VIRT);
+
+ adeos_unlock_cpu(flags);
+
+ return -1;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int __adeos_exit_syscall (void)
+
+{
+ if (__adeos_event_monitors[ADEOS_SYSCALL_EPILOGUE] > 0)
+ return __adeos_handle_event(ADEOS_SYSCALL_EPILOGUE,NULL);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(__adeos_init_stage);
+EXPORT_SYMBOL(__adeos_sync_stage);
+EXPORT_SYMBOL(__adeos_irq_regs);
+#ifdef CONFIG_ADEOS_THREADS
+EXPORT_SYMBOL(__adeos_switch_domain);
+#endif /* CONFIG_ADEOS_THREADS */
+EXPORT_SYMBOL(__adeos_do_IRQ);
+EXPORT_SYMBOL(__adeos_do_timer);
+EXPORT_SYMBOL(__adeos_decr_ticks);
+EXPORT_SYMBOL(__adeos_decr_next);
+EXPORT_SYMBOL(__adeos_current_threadinfo);
+EXPORT_SYMBOL(adeos_critical_enter);
+EXPORT_SYMBOL(adeos_critical_exit);
+EXPORT_SYMBOL(adeos_trigger_irq);
diff -Nru linux-2.6.10/arch/ppc64/kernel/entry.S linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/entry.S
--- linux-2.6.10/arch/ppc64/kernel/entry.S 2004-12-24 23:33:49.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/entry.S 2005-11-13 11:45:31.000000000 +0200
@@ -108,6 +108,23 @@
ori r11,r11,MSR_EE
mtmsrd r11,1
+#ifdef CONFIG_ADEOS_CORE
+ addi r3,r1,GPR0
+ bl .__adeos_enter_syscall
+ cmpdi r3,0
+ ld r0,GPR0(r1)
+ ld r3,GPR3(r1)
+ ld r4,GPR4(r1)
+ ld r5,GPR5(r1)
+ ld r6,GPR6(r1)
+ ld r7,GPR7(r1)
+ ld r8,GPR8(r1)
+ ld r9,GPR9(r1)
+ bgt adeos_end_syscall
+ blt syscall_exit
+ addi r9,r1,STACK_FRAME_OVERHEAD
+#endif /* CONFIG_ADEOS_CORE */
+
#ifdef SHOW_SYSCALLS
bl .do_show_syscall
REST_GPR(0,r1)
@@ -145,7 +162,13 @@
ldx r10,r11,r0 /* Fetch system call handler [ptr] */
mtctr r10
bctrl /* Call handler */
-
+#ifdef CONFIG_ADEOS_CORE
+ std r3,RESULT(r1)
+ bl .__adeos_exit_syscall
+ cmpdi r3,0
+ ld r3,RESULT(r1)
+ bne- syscall_exit_adeos
+#endif /* CONFIG_ADEOS_CORE */
syscall_exit:
#ifdef SHOW_SYSCALLS
std r3,GPR3(r1)
@@ -195,6 +218,39 @@
mtspr SRR1,r8
rfid
b . /* prevent speculative execution */
+#ifdef CONFIG_ADEOS_CORE
+syscall_exit_adeos:
+ ld r5,_CCR(r1)
+ ld r8,_MSR(r1)
+ ld r7,_NIP(r1)
+ stdcx. r0,0,r1 /* to clear pending reservations */
+ andi. r6,r8,MSR_PR
+ ld r4,_LINK(r1)
+ beq- 1f /* only restore r13 if */
+ ld r13,GPR13(r1) /* returning to usermode */
+1: ld r2,GPR2(r1)
+ ld r1,GPR1(r1)
+ li r12,MSR_RI
+ mfmsr r10 /* should this be done here? */
+ andc r10,r10,r12
+ mtmsrd r10,1 /* clear MSR.RI */
+ mtlr r4
+ mtcr r5
+ mtspr SRR0,r7
+ mtspr SRR1,r8
+ rfid
+ b . /* prevent speculative execution */
+#endif /* CONFIG_ADEOS_CORE */
+
+#ifdef CONFIG_ADEOS_CORE
+ .globl adeos_end_syscall
+adeos_end_syscall:
+ mfmsr r10
+ rldicl r10,r10,48,1
+ rotldi r10,r10,16
+ mtmsrd r10,1
+ b syscall_exit_adeos
+#endif /* CONFIG_ADEOS_CORE */
syscall_enosys:
li r3,-ENOSYS
@@ -400,6 +456,14 @@
beq 2f /* if yes, don't slbie it */
oris r0,r6,0x0800 /* set C (class) bit */
+#ifdef CONFIG_ADEOS_CORE
+ /* disable interrupts so that SLB and impl. specific
+ * address translation optimizations stay sane */
+ mfmsr r10
+ rldicl r9,r10,48,1 /* clear MSR_EE */
+ rotldi r9,r9,16
+ mtmsrd r9,1
+#endif /* CONFIG_ADEOS_CORE */
/* Bolt in the new stack SLB entry */
ld r7,KSP_VSID(r4) /* Get new stack's VSID */
oris r6,r6,(SLB_ESID_V)@h
@@ -408,7 +472,9 @@
slbie r0 /* Workaround POWER5 < DD2.1 issue */
slbmte r7,r6
isync
-
+#ifdef CONFIG_ADEOS_CORE
+ mtmsrd r10,1 /* remember old interrupt state */
+#endif /* CONFIG_ADEOS_CORE */
2:
END_FTR_SECTION_IFSET(CPU_FTR_SLB)
clrrdi r7,r8,THREAD_SHIFT /* base of new stack */
@@ -468,6 +534,13 @@
rotldi r9,r9,16
mtmsrd r9,1 /* Update machine state */
+#ifdef CONFIG_ADEOS_CORE
+ bl .__adeos_check_root
+ cmpdi r3,0
+ mfmsr r10 /* this is used later, might be messed */
+ beq- restore
+#endif /* CONFIG_ADEOS_CORE */
+
#ifdef CONFIG_PREEMPT
clrrdi r9,r1,THREAD_SHIFT /* current_thread_info() */
li r0,_TIF_NEED_RESCHED /* bits to check */
@@ -844,3 +917,124 @@
blr
#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+#ifdef CONFIG_ADEOS_CORE
+
+_GLOBAL(__adeos_ret_from_except_lite)
+ cmpdi r3,0
+ bne+ .ret_from_except_lite
+ b restore
+
+#ifdef CONFIG_ADEOS_THREADS
+
+/*
+ * r3 = adp_next, r4 = adp_cpu_current[adeos_processor_id()].
+ * NOTE: This code is _not_ SMP-compliant. Always called with hw
+ * interrupts off.
+ * TODO: implement (configure time) support for different ABIs?
+ */
+_GLOBAL(__adeos_switch_domain)
+
+ /* 27*8 = 216 for registers
+ * +8 padding for quad-word alignment as required by spec
+ * = 224 */
+ /* alloc stack frame (store and update r1) */
+ stdu r1,-224-STACK_FRAME_OVERHEAD(r1)
+
+ /* Save general purpose registers. (22) */
+ std r31,STACK_FRAME_OVERHEAD+0*8(r1)
+ std r30,STACK_FRAME_OVERHEAD+1*8(r1)
+ std r29,STACK_FRAME_OVERHEAD+2*8(r1)
+ std r28,STACK_FRAME_OVERHEAD+3*8(r1)
+ std r27,STACK_FRAME_OVERHEAD+4*8(r1)
+ std r26,STACK_FRAME_OVERHEAD+5*8(r1)
+ std r25,STACK_FRAME_OVERHEAD+6*8(r1)
+ std r24,STACK_FRAME_OVERHEAD+7*8(r1)
+ std r23,STACK_FRAME_OVERHEAD+8*8(r1)
+ std r22,STACK_FRAME_OVERHEAD+9*8(r1)
+ std r21,STACK_FRAME_OVERHEAD+10*8(r1)
+ std r20,STACK_FRAME_OVERHEAD+11*8(r1)
+ std r19,STACK_FRAME_OVERHEAD+12*8(r1)
+ std r18,STACK_FRAME_OVERHEAD+13*8(r1)
+ std r17,STACK_FRAME_OVERHEAD+14*8(r1)
+ std r16,STACK_FRAME_OVERHEAD+15*8(r1)
+ std r15,STACK_FRAME_OVERHEAD+16*8(r1)
+ std r14,STACK_FRAME_OVERHEAD+17*8(r1)
+ std r13,STACK_FRAME_OVERHEAD+18*8(r1)
+ std r3,STACK_FRAME_OVERHEAD+19*8(r1)
+ std r2,STACK_FRAME_OVERHEAD+20*8(r1)
+ std r0,STACK_FRAME_OVERHEAD+21*8(r1)
+
+ /* Save special registers. (5) */
+ mfctr r2
+ std r2,STACK_FRAME_OVERHEAD+22*8(r1)
+ mfcr r2
+ std r2,STACK_FRAME_OVERHEAD+23*8(r1)
+ mfxer r2
+ std r2,STACK_FRAME_OVERHEAD+24*8(r1)
+ mflr r2
+ std r2,STACK_FRAME_OVERHEAD+25*8(r1)
+ mfmsr r2
+ std r2,STACK_FRAME_OVERHEAD+26*8(r1)
+
+ /* Actual switch block. */
+ ld r2,0(r4) /* r2 = old_adp = adp_cpu_current[cpuid] */
+ std r1,0(r2) /* old_adp->esp[0] = sp */
+ std r3,0(r4) /* adp_cpu_current[cpuid] = new_adp */
+ /* CONFIG_SMP should sync here; but first, accesses to esp[]
+ would require cpuid-indexing. */
+ ld r1,0(r3) /* sp = new_adp->esp[0] */
+
+ /* Restore special registers. */
+ ld r2,STACK_FRAME_OVERHEAD+26*8(r1)
+ mtmsrd r2
+ ld r2,STACK_FRAME_OVERHEAD+25*8(r1)
+ mtlr r2
+ ld r2,STACK_FRAME_OVERHEAD+24*8(r1)
+ mtxer r2
+ ld r2,STACK_FRAME_OVERHEAD+23*8(r1)
+ mtcr r2
+ ld r2,STACK_FRAME_OVERHEAD+22*8(r1)
+ mtctr r2
+
+ /* Restore general purpose registers. */
+ ld r0,STACK_FRAME_OVERHEAD+21*8(r1)
+ ld r2,STACK_FRAME_OVERHEAD+20*8(r1)
+ ld r3,STACK_FRAME_OVERHEAD+19*8(r1)
+ ld r13,STACK_FRAME_OVERHEAD+18*8(r1)
+ ld r14,STACK_FRAME_OVERHEAD+17*8(r1)
+ ld r15,STACK_FRAME_OVERHEAD+16*8(r1)
+ ld r16,STACK_FRAME_OVERHEAD+15*8(r1)
+ ld r17,STACK_FRAME_OVERHEAD+14*8(r1)
+ ld r18,STACK_FRAME_OVERHEAD+13*8(r1)
+ ld r19,STACK_FRAME_OVERHEAD+12*8(r1)
+ ld r20,STACK_FRAME_OVERHEAD+11*8(r1)
+ ld r21,STACK_FRAME_OVERHEAD+10*8(r1)
+ ld r22,STACK_FRAME_OVERHEAD+9*8(r1)
+ ld r23,STACK_FRAME_OVERHEAD+8*8(r1)
+ ld r24,STACK_FRAME_OVERHEAD+7*8(r1)
+ ld r25,STACK_FRAME_OVERHEAD+6*8(r1)
+ ld r26,STACK_FRAME_OVERHEAD+5*8(r1)
+ ld r27,STACK_FRAME_OVERHEAD+4*8(r1)
+ ld r28,STACK_FRAME_OVERHEAD+3*8(r1)
+ ld r29,STACK_FRAME_OVERHEAD+2*8(r1)
+ ld r30,STACK_FRAME_OVERHEAD+1*8(r1)
+ ld r31,STACK_FRAME_OVERHEAD+0*8(r1)
+
+ addi r1,r1,224+STACK_FRAME_OVERHEAD
+
+ blr
+
+#endif /* CONFIG_ADEOS_THREADS */
+
+/* Returns the current threadinfo pointer in a way which is
+ insensitive to the underlying stack, by directly reading the
+ special purpose register #3. */
+/* could probably just use r13 and forget loading paca */
+_GLOBAL(__adeos_current_threadinfo)
+ mfspr r3,SPRG3 /* get PACA */
+ ld r3,PACACURRENT(r3)
+ blr
+
+#endif /* CONFIG_ADEOS_CORE */
+
diff -Nru linux-2.6.10/arch/ppc64/kernel/head.S linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/head.S
--- linux-2.6.10/arch/ppc64/kernel/head.S 2004-12-24 23:34:48.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/head.S 2005-11-13 11:45:31.000000000 +0200
@@ -381,6 +381,18 @@
bl hdlr; \
b .ret_from_except_lite
+#ifdef CONFIG_ADEOS_CORE
+#define ADEOS_EXCEPTION_COMMON_LITE(trap, label, hdlr) \
+ .align 7; \
+ .globl label##_common; \
+label##_common: \
+ EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \
+ DISABLE_INTS; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ bl hdlr; \
+ b .__adeos_ret_from_except_lite
+#endif /* CONFIG_ADEOS_CORE */
+
/*
* Start of pSeries system interrupt routines
*/
@@ -761,7 +773,12 @@
bl .MachineCheckException
b .ret_from_except
+
+#ifdef CONFIG_ADEOS_CORE
+ ADEOS_EXCEPTION_COMMON_LITE(0x900, Decrementer, .__adeos_grab_timer)
+#else /* !CONFIG_ADEOS_CORE */
STD_EXCEPTION_COMMON_LITE(0x900, Decrementer, .timer_interrupt)
+#endif /* CONFIG_ADEOS_CORE */
STD_EXCEPTION_COMMON(0xa00, Trap_0a, .UnknownException)
STD_EXCEPTION_COMMON(0xb00, Trap_0b, .UnknownException)
STD_EXCEPTION_COMMON(0xd00, SingleStep, .SingleStepException)
@@ -890,8 +907,13 @@
HardwareInterrupt_entry:
DISABLE_INTS
addi r3,r1,STACK_FRAME_OVERHEAD
+#ifdef CONFIG_ADEOS_CORE
+ bl .__adeos_grab_irq
+ b .__adeos_ret_from_except_lite
+#else /* !CONFIG_ADEOS_CORE */
bl .do_IRQ
b .ret_from_except_lite
+#endif /* CONFIG_ADEOS_CORE */
.align 7
.globl Alignment_common
diff -Nru linux-2.6.10/arch/ppc64/kernel/idle.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/idle.c
--- linux-2.6.10/arch/ppc64/kernel/idle.c 2004-12-24 23:35:24.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/idle.c 2005-11-13 11:45:31.000000000 +0200
@@ -131,6 +131,9 @@
while (!need_resched() && !cpu_is_offline(cpu)) {
barrier();
+#ifdef CONFIG_ADEOS_CORE
+ adeos_suspend_domain();
+#endif /* CONFIG_ADEOS_CORE */
/*
* Go into low thread priority and possibly
* low power mode.
@@ -288,8 +291,15 @@
{
while(1) {
/* check CPU type here */
- if (!need_resched())
+ if (!need_resched())
+#ifdef CONFIG_ADEOS_CORE
+ {
+ adeos_suspend_domain();
power4_idle();
+ }
+#else /* !CONFIG_ADEOS_CORE */
+ power4_idle();
+#endif /* CONFIG_ADEOS_CORE */
if (need_resched())
schedule();
}
diff -Nru linux-2.6.10/arch/ppc64/kernel/irq.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/irq.c
--- linux-2.6.10/arch/ppc64/kernel/irq.c 2004-12-24 23:34:32.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/irq.c 2005-11-13 11:45:31.000000000 +0200
@@ -134,14 +134,25 @@
if (desc->status & IRQ_PER_CPU) {
/* no locking required for CPU-local interrupts: */
+#ifdef CONFIG_ADEOS_CORE
+ if (!adp_pipelined)
+ ack_irq(irq);
+#else
ack_irq(irq);
+#endif /* CONFIG_ADEOS_CORE */
action_ret = handle_IRQ_event(irq, regs, desc->action);
desc->handler->end(irq);
return;
}
spin_lock(&desc->lock);
+#ifdef CONFIG_ADEOS_CORE
+ if (!adp_pipelined)
+ ack_irq(irq);
+#else
ack_irq(irq);
+#endif /* CONFIG_ADEOS_CORE */
+
/*
REPLAY is when Linux resends an IRQ that was dropped earlier
WAITING is used by probe to mark irqs that are being tested
diff -Nru linux-2.6.10/arch/ppc64/kernel/Makefile linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/Makefile
--- linux-2.6.10/arch/ppc64/kernel/Makefile 2004-12-24 23:35:39.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/Makefile 2005-11-13 11:45:31.000000000 +0200
@@ -62,4 +62,6 @@
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
+obj-$(CONFIG_ADEOS_CORE) += adeos.o
+
CFLAGS_ioctl32.o += -Ifs/
diff -Nru linux-2.6.10/arch/ppc64/kernel/ppc_ksyms.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.6.10/arch/ppc64/kernel/ppc_ksyms.c 2004-12-24 23:34:26.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/ppc_ksyms.c 2005-11-13 11:46:07.000000000 +0200
@@ -163,3 +163,30 @@
EXPORT_SYMBOL(paca);
EXPORT_SYMBOL(cur_cpu_spec);
EXPORT_SYMBOL(systemcfg);
+
+#ifdef CONFIG_ADEOS_CORE
+/* The following are per-platform convenience exports which are needed
+ by some Adeos domains loaded as kernel modules. */
+extern unsigned long disarm_decr[NR_CPUS];
+EXPORT_SYMBOL(disarm_decr);
+EXPORT_SYMBOL(tb_ticks_per_jiffy);
+EXPORT_SYMBOL(__switch_to);
+void show_stack(struct task_struct *task,
+ unsigned long *esp);
+EXPORT_SYMBOL(show_stack);
+EXPORT_SYMBOL(udbg_printf);
+
+/* these two are needed by the task switching code in fusion */
+extern void switch_stab(struct task_struct *tsk, struct mm_struct *mm);
+extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm);
+EXPORT_SYMBOL(switch_stab);
+EXPORT_SYMBOL(switch_slb);
+
+/* flush_tlb_pending() */
+EXPORT_PER_CPU_SYMBOL(ppc64_tlb_batch);
+EXPORT_SYMBOL(__flush_tlb_pending);
+
+EXPORT_SYMBOL(_switch);
+extern struct task_struct *last_task_used_math;
+EXPORT_SYMBOL(last_task_used_math);
+#endif /* CONFIG_ADEOS_CORE */
diff -Nru linux-2.6.10/arch/ppc64/kernel/time.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/time.c
--- linux-2.6.10/arch/ppc64/kernel/time.c 2004-12-24 23:35:28.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/time.c 2005-11-13 11:45:31.000000000 +0200
@@ -73,6 +73,9 @@
EXPORT_SYMBOL(jiffies_64);
+#ifdef CONFIG_ADEOS_CORE
+unsigned long disarm_decr[NR_CPUS];
+#endif /* CONFIG_ADEOS_CORE */
/* keep track of when we need to update the rtc */
time_t last_rtc_update;
extern int piranha_simulator;
@@ -293,6 +296,9 @@
next_dec = lpaca->next_jiffy_update_tb - cur_tb;
if (next_dec > lpaca->default_decr)
next_dec = lpaca->default_decr;
+#ifdef CONFIG_ADEOS_CORE
+ if (!disarm_decr[smp_processor_id()])
+#endif /* CONFIG_ADEOS_CORE */
set_dec(next_dec);
#ifdef CONFIG_PPC_ISERIES
diff -Nru linux-2.6.10/arch/ppc64/kernel/traps.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/traps.c
--- linux-2.6.10/arch/ppc64/kernel/traps.c 2004-12-24 23:34:47.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/kernel/traps.c 2005-11-13 11:45:31.000000000 +0200
@@ -75,6 +75,11 @@
if (debugger(regs))
return 1;
+#ifdef CONFIG_ADEOS_CORE
+ /* lets us see Oopses from other domains, too */
+ if (adp_current != adp_root)
+ adeos_set_printk_sync(adp_current);
+#endif /* CONFIG_ADEOS_CORE */
console_verbose();
spin_lock_irq(&die_lock);
bust_spinlocks(1);
@@ -185,9 +190,20 @@
}
#endif
+#ifdef CONFIG_ADEOS_CORE
+static inline int __adeos_pipeline_trap(int trap, struct pt_regs *regs)
+{
+ return __adeos_event_monitors[trap] > 0 ? __adeos_handle_event(trap,regs) : 0;
+}
+#endif /* CONFIG_ADEOS_CORE */
+
void
SystemResetException(struct pt_regs *regs)
{
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_SYSRESET_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
#ifdef CONFIG_PPC_PSERIES
if (fwnmi_active) {
struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
@@ -265,7 +281,11 @@
return;
}
#endif
-
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_MCE_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
+
if (debugger_fault_handler(regs))
return;
die("Machine check", regs, 0);
@@ -278,6 +298,11 @@
void
UnknownException(struct pt_regs *regs)
{
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_UNKNOWN_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
+
printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
regs->nip, regs->msr, regs->trap);
@@ -287,6 +312,10 @@
void
InstructionBreakpointException(struct pt_regs *regs)
{
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_IABR_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
if (debugger_iabr_match(regs))
return;
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
@@ -296,7 +325,10 @@
SingleStepException(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
-
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_SSTEP_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
if (debugger_sstep(regs))
return;
@@ -459,6 +491,11 @@
void
ProgramCheckException(struct pt_regs *regs)
{
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_PCE_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
+
if (regs->msr & 0x100000) {
/* IEEE FP exception */
parse_fpe(regs);
@@ -500,6 +537,10 @@
void KernelFPUnavailableException(struct pt_regs *regs)
{
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_KFPUNAVAIL_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
printk(KERN_EMERG "Unrecoverable FP Unavailable Exception "
"%lx at %lx\n", regs->trap, regs->nip);
die("Unrecoverable FP Unavailable Exception", regs, SIGABRT);
@@ -507,6 +548,11 @@
void AltivecUnavailableException(struct pt_regs *regs)
{
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_ALTUNAVAIL_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
+
#ifndef CONFIG_ALTIVEC
if (user_mode(regs)) {
/* A user program has executed an altivec instruction,
@@ -539,6 +585,10 @@
void
PerformanceMonitorException(struct pt_regs *regs)
{
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_PERFMON_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
perf_irq(regs);
}
@@ -554,7 +604,12 @@
emulate_single_step(regs);
return;
}
-
+#ifdef CONFIG_ADEOS_CORE
+ /* Assume that fixing alignment can always be done regardless
+ of the current domain. */
+ if (__adeos_pipeline_trap(ADEOS_ALIGNMENT_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
/* Operand address was bad */
if (fixed == -EFAULT) {
if (user_mode(regs)) {
@@ -577,6 +632,11 @@
int err;
siginfo_t info;
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_ALTASSIST_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
+
if (!user_mode(regs)) {
printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode"
" at %lx\n", regs->nip);
@@ -618,6 +678,10 @@
*/
void unrecoverable_exception(struct pt_regs *regs)
{
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_pipeline_trap(ADEOS_NREC_TRAP,regs))
+ return;
+#endif /* CONFIG_ADEOS_CORE */
printk(KERN_EMERG "Unrecoverable exception %lx at %lx\n",
regs->trap, regs->nip);
die("Unrecoverable exception", regs, SIGABRT);
diff -Nru linux-2.6.10/arch/ppc64/mm/fault.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/mm/fault.c
--- linux-2.6.10/arch/ppc64/mm/fault.c 2004-12-24 23:35:23.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/mm/fault.c 2005-11-13 11:45:31.000000000 +0200
@@ -95,6 +95,12 @@
BUG_ON((trap == 0x380) || (trap == 0x480));
+#ifdef CONFIG_ADEOS_CORE
+ if (__adeos_event_monitors[ADEOS_ACCESS_TRAP] > 0 &&
+ __adeos_handle_event(ADEOS_ACCESS_TRAP,regs) != 0)
+ return 0;
+#endif /* CONFIG_ADEOS_CORE */
+
if (trap == 0x300) {
if (debugger_fault_handler(regs))
return 0;
diff -Nru linux-2.6.10/arch/ppc64/mm/hash_native.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/mm/hash_native.c
--- linux-2.6.10/arch/ppc64/mm/hash_native.c 2004-12-24 23:34:30.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/mm/hash_native.c 2005-11-13 11:45:31.000000000 +0200
@@ -278,7 +278,7 @@
if (large)
avpn &= ~0x1UL;
- local_irq_save(flags);
+ adeos_hw_local_irq_save(flags);
native_lock_hpte(hptep);
dw0 = hptep->dw0.dw0;
@@ -301,7 +301,7 @@
if (lock_tlbie)
spin_unlock(&native_tlbie_lock);
}
- local_irq_restore(flags);
+ adeos_hw_local_irq_restore(flags);
}
static void native_flush_hash_range(unsigned long context,
@@ -316,7 +316,7 @@
/* XXX fix for large ptes */
unsigned long large = 0;
- local_irq_save(flags);
+ adeos_hw_local_irq_save(flags);
j = 0;
for (i = 0; i < number; i++) {
@@ -384,7 +384,7 @@
spin_unlock(&native_tlbie_lock);
}
- local_irq_restore(flags);
+ adeos_hw_local_irq_restore(flags);
}
#ifdef CONFIG_PPC_PSERIES
diff -Nru linux-2.6.10/arch/ppc64/mm/slb.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/mm/slb.c
--- linux-2.6.10/arch/ppc64/mm/slb.c 2004-12-24 23:34:57.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/mm/slb.c 2005-11-13 11:45:31.000000000 +0200
@@ -83,6 +83,9 @@
unsigned long pc = KSTK_EIP(tsk);
unsigned long stack = KSTK_ESP(tsk);
unsigned long unmapped_base;
+ unsigned long flags;
+
+ adeos_hw_local_irq_save(flags);
if (offset <= SLB_CACHE_ENTRIES) {
int i;
@@ -115,24 +118,35 @@
else
unmapped_base = TASK_UNMAPPED_BASE_USER64;
- if (pc >= KERNELBASE)
+ if (pc >= KERNELBASE) {
+ adeos_hw_local_irq_restore(flags);
return;
+ }
slb_allocate(pc);
- if (GET_ESID(pc) == GET_ESID(stack))
+ if (GET_ESID(pc) == GET_ESID(stack)) {
+ adeos_hw_local_irq_restore(flags);
return;
+ }
- if (stack >= KERNELBASE)
+ if (stack >= KERNELBASE) {
+ adeos_hw_local_irq_restore(flags);
return;
+ }
slb_allocate(stack);
if ((GET_ESID(pc) == GET_ESID(unmapped_base))
- || (GET_ESID(stack) == GET_ESID(unmapped_base)))
+ || (GET_ESID(stack) == GET_ESID(unmapped_base))) {
+ adeos_hw_local_irq_restore(flags);
return;
+ }
- if (unmapped_base >= KERNELBASE)
+ if (unmapped_base >= KERNELBASE) {
+ adeos_hw_local_irq_restore(flags);
return;
+ }
slb_allocate(unmapped_base);
+ adeos_hw_local_irq_restore(flags);
}
void slb_initialize(void)
diff -Nru linux-2.6.10/arch/ppc64/mm/tlb.c linux-2.6.10-adeos-ppc64-r3/arch/ppc64/mm/tlb.c
--- linux-2.6.10/arch/ppc64/mm/tlb.c 2004-12-24 23:34:45.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/arch/ppc64/mm/tlb.c 2005-11-13 11:45:31.000000000 +0200
@@ -122,7 +122,11 @@
cpumask_t tmp;
int local = 0;
+#ifdef CONFIG_ADEOS_CORE
+ BUG_ON(adp_current==adp_root && in_interrupt());
+#else /* !CONFIG_ADEOS_CORE */
BUG_ON(in_interrupt());
+#endif /* CONFIG_ADEOS_CORE */
cpu = get_cpu();
i = batch->index;
diff -Nru linux-2.6.10/Documentation/adeos.txt linux-2.6.10-adeos-ppc64-r3/Documentation/adeos.txt
--- linux-2.6.10/Documentation/adeos.txt 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/Documentation/adeos.txt 2005-11-13 11:45:31.000000000 +0200
@@ -0,0 +1,176 @@
+
+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.
+
+Regardless of the operations being done in the ipipe, the Adeos code
+does __not__ play with the interrupt masks. The only case where the
+hardware masks are altered is during the addition/removal of a domain
+from the ipipe. This also means that no OS 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://www.freesoftware.fsf.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.
+
+Adeos supports SMP, and APIC support 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 <rpm@xenomai.org>
+Karim Yaghmour <karim@domain.hid>
+
+----------------------------------------------------------------------
+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 -Nru linux-2.6.10/include/asm-ppc64/adeos.h linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/adeos.h
--- linux-2.6.10/include/asm-ppc64/adeos.h 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/adeos.h 2005-11-13 11:58:38.000000000 +0200
@@ -0,0 +1,444 @@
+/*
+ * include/asm-ppc64/adeos.h
+ *
+ * Adeos 64-bit PowerPC adoption
+ * Copyright (C) 2005 Taneli V������h������kangas and Heikki Lindholm
+ * based on previous work:
+ *
+ * Copyright (C) 2004 Philippe Gerum.
+ *
+ * Adeos/PPC port over 2.6 based on the previous 2.4 implementation by:
+ *
+ * Copyright (C) 2004 Wolfgang Grandegger.
+ *
+ * It follows closely the ARM and x86 ports of ADEOS.
+ *
+ * Copyright (C) 2002 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PPC64_ADEOS_H
+#define __PPC64_ADEOS_H
+
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <linux/list.h>
+#include <linux/cpumask.h>
+#include <linux/threads.h>
+
+#define ADEOS_ARCH_STRING "r3/ppc64"
+#define ADEOS_MAJOR_NUMBER 3
+#define ADEOS_MINOR_NUMBER 255
+
+#define ADEOS_IRQ_ACKED 0x1000
+#define ADEOS_IRQ_ACKED_MASK (ADEOS_IRQ_ACKED - 1)
+
+#ifdef CONFIG_SMP
+
+#error "Adeos/ppc64: SMP not yet implemented"
+
+#define ADEOS_NR_CPUS NR_CPUS
+#define ADEOS_CRITICAL_IPI 0
+
+#define adeos_processor_id() (__adeos_current_threadinfo()->cpu)
+
+#define adeos_declare_cpuid int cpuid
+#define adeos_load_cpuid() do { \
+ (cpuid) = adeos_processor_id(); \
+ } while(0)
+#define adeos_lock_cpu(flags) do { \
+ adeos_hw_local_irq_save(flags); \
+ (cpuid) = adeos_processor_id(); \
+ } while(0)
+#define adeos_unlock_cpu(flags) adeos_hw_local_irq_restore(flags)
+#define adeos_get_cpu(flags) adeos_lock_cpu(flags)
+#define adeos_put_cpu(flags) adeos_unlock_cpu(flags)
+#define adp_current (adp_cpu_current[adeos_processor_id()])
+
+#else /* !CONFIG_SMP */
+
+#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() /* nop */
+#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) /* nop */
+#define adp_current (adp_cpu_current[0])
+
+#endif /* CONFIG_SMP */
+
+ /* PPC traps */
+#define ADEOS_ACCESS_TRAP 0 /* Data or instruction access exception */
+#define ADEOS_ALIGNMENT_TRAP 1 /* Alignment exception */
+#define ADEOS_ALTUNAVAIL_TRAP 2 /* Altivec unavailable */
+#define ADEOS_PCE_TRAP 3 /* Program check exception */
+#define ADEOS_MCE_TRAP 4 /* Machine check exception */
+#define ADEOS_UNKNOWN_TRAP 5 /* Unknown exception */
+#define ADEOS_IABR_TRAP 6 /* Instruction breakpoint */
+#define ADEOS_SSTEP_TRAP 7 /* Single-step exception */
+#define ADEOS_NREC_TRAP 8 /* Non-recoverable exception */
+#define ADEOS_ALTASSIST_TRAP 9 /* Altivec assist exception */
+#define ADEOS_SYSRESET_TRAP 10 /* System reset exception */
+#define ADEOS_KFPUNAVAIL_TRAP 11 /* Kernel FP Unavailable exception */
+#define ADEOS_PERFMON_TRAP 12 /* Performance Monitor exception */
+#define ADEOS_NR_FAULTS 13
+/* 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)
+#define ADEOS_ENTER_PROCESS (ADEOS_FIRST_KEVENT + 4)
+#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_RENICE_PROCESS (ADEOS_FIRST_KEVENT + 8)
+#define ADEOS_USER_EVENT (ADEOS_FIRST_KEVENT + 9)
+#define ADEOS_LAST_KEVENT (ADEOS_USER_EVENT)
+
+#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 */
+
+ u64 cpufreq; /* CPU frequency (in Hz) */
+
+ /* Arch-dependent block */
+
+ struct {
+ unsigned tmirq; /* Decrementer virtual IRQ */
+ u64 tmfreq; /* Timebase frequency */
+ } 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 6 /* 2^6 for 64bits arch. */
+
+#define IPIPE_IRQMASK_ANY (~0L)
+#define IPIPE_IRQMASK_VIRT (IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG))
+
+/* The first virtual interrupt is reserved for the timer (see
+ __adeos_init_platform). */
+#define ADEOS_TIMER_VIRQ IPIPE_VIRQ_BASE
+
+typedef struct adomain {
+
+ /* -- Section: offset-based references are made on these fields
+ from inline assembly code. Please don't move or reorder. */
+#ifdef CONFIG_ADEOS_THREADS
+ unsigned long esp[ADEOS_NR_CPUS]; /* Domain stack pointers */
+#endif /* CONFIG_ADEOS_THREADS */
+ void (*dswitch)(void); /* Domain switch hook */
+ /* -- End of section. */
+
+ struct list_head p_link; /* Link in pipeline */
+
+ struct adcpudata {
+ unsigned long status;
+ unsigned long irq_pending_hi;
+ unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
+ 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];
+
+ struct adomain *m_link; /* Link in mutex sleep queue */
+
+ unsigned long flags;
+
+ 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
+ unsigned long estackbase[ADEOS_NR_CPUS];
+#endif /* CONFIG_ADEOS_THREADS */
+
+} adomain_t;
+
+/* The following macros must be used hw interrupts off. */
+
+#define __adeos_set_irq_bit(adp,cpuid,irq) \
+do { \
+ 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 { \
+ __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 { \
+ 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 { \
+ if (test_and_clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) { \
+ int __cpuid, __nr_cpus = num_online_cpus(); \
+ for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) \
+ if ((adp)->cpudata[__cpuid].irq_hits[irq] > 0) { /* We need atomic ops next. */ \
+ 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 { \
+ int __cpuid, __nr_cpus = num_online_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)
+
+static inline void adeos_hw_local_irq_save_ptr(unsigned long *flags)
+{
+ unsigned long msr;
+ msr = mfmsr();
+ *flags = msr;
+ __mtmsrd(msr & ~MSR_EE, 1);
+ __asm__ __volatile__("": : :"memory");
+}
+
+#define adeos_hw_local_irq_save_flags(flags) adeos_hw_local_irq_save_ptr(&(flags))
+#define adeos_hw_local_irq_restore(flags) do { \
+ __asm__ __volatile__("": : :"memory"); \
+ __mtmsrd((flags), 1); \
+} while(0)
+
+static inline void adeos_hw_local_irq_disable(void)
+{
+ unsigned long msr;
+ msr = mfmsr();
+ __mtmsrd(msr & ~MSR_EE, 1);
+ __asm__ __volatile__("": : :"memory");
+}
+
+static inline void adeos_hw_local_irq_enable(void)
+{
+ unsigned long msr;
+ __asm__ __volatile__("": : :"memory");
+ msr = mfmsr();
+ __mtmsrd(msr | MSR_EE, 1);
+}
+
+#define adeos_hw_local_irq_save(flags) ({adeos_hw_local_irq_save_flags(flags);adeos_hw_local_irq_disable();})
+#define adeos_hw_save_flags_and_sti(flags) ({adeos_hw_local_irq_save_flags(flags);adeos_hw_local_irq_enable();})
+
+#define adeos_hw_cli() adeos_hw_local_irq_disable()
+#define adeos_hw_sti() adeos_hw_local_irq_enable()
+
+#define adeos_hw_local_irq_flags(flags) ((flags) = mfmsr())
+#define adeos_hw_test_iflag(x) ((x) & MSR_EE)
+#define adeos_hw_irqs_disabled() \
+({ \
+ unsigned long flags; \
+ adeos_hw_local_irq_flags(flags);\
+ !adeos_hw_test_iflag(flags); \
+})
+
+#define adeos_hw_tsc(t) (t = mftb())
+
+extern unsigned long tb_ticks_per_jiffy;
+
+#define adeos_cpu_freq() (HZ * tb_ticks_per_jiffy)
+
+#define adeos_spin_lock(x) _spin_lock(x)
+#define adeos_spin_unlock(x) _spin_unlock(x)
+#define adeos_spin_trylock(x) _spin_trylock(x)
+#define adeos_write_lock(x) _write_lock(x)
+#define adeos_write_unlock(x) _write_unlock(x)
+#define adeos_write_trylock(x) _write_trylock(x)
+#define adeos_read_lock(x) _read_lock(x)
+#define adeos_read_unlock(x) _read_unlock(x)
+#define raw_spinlock_t spinlock_t
+#define RAW_SPIN_LOCK_UNLOCKED SPIN_LOCK_UNLOCKED
+#define raw_rwlock_t rwlock_t
+#define RAW_RW_LOCK_UNLOCKED RW_LOCK_UNLOCKED
+
+#define spin_lock_irqsave_hw(lock,flags) adeos_spin_lock_irqsave(lock, flags)
+#define spin_unlock_irqrestore_hw(lock,flags) adeos_spin_unlock_irqrestore(lock, flags)
+
+#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)
+
+#define adeos_read_lock_irqsave(lock, flags) \
+do { \
+ adeos_hw_local_irq_save(flags); \
+ adeos_read_lock(lock); \
+} while (0)
+
+#define adeos_read_unlock_irqrestore(lock, flags) \
+do { \
+ adeos_read_unlock(lock); \
+ adeos_hw_local_irq_restore(flags); \
+} while (0)
+
+#define adeos_write_lock_irqsave(lock, flags) \
+do { \
+ adeos_hw_local_irq_save(flags); \
+ adeos_write_lock(lock); \
+} while (0)
+
+#define adeos_write_unlock_irqrestore(lock, flags) \
+do { \
+ adeos_write_unlock(lock); \
+ adeos_hw_local_irq_restore(flags); \
+} 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_platform() do { } while(0)
+
+#define __adeos_read_timebase() ({ unsigned long t; adeos_hw_tsc(t); t; })
+
+void __adeos_init_platform(void);
+
+void __adeos_enable_pipeline(void);
+
+void __adeos_disable_pipeline(void);
+
+void __adeos_init_stage(adomain_t *adp);
+
+void __adeos_sync_stage(unsigned long syncmask);
+
+int __adeos_ack_irq(unsigned irq);
+
+void __adeos_do_IRQ(int irq,
+ struct pt_regs *regs);
+
+void __adeos_do_timer(int irq,
+ struct pt_regs *regs);
+
+struct thread_info *__adeos_current_threadinfo(void);
+
+#ifdef CONFIG_ADEOS_THREADS
+
+int __adeos_switch_domain(adomain_t *adp,
+ adomain_t **currentp);
+
+/* Called with hw interrupts off. */
+static inline void __adeos_switch_to (adomain_t *out,
+ adomain_t *in,
+ int cpuid)
+{
+ extern adomain_t *adp_cpu_current[];
+
+ __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;
+
+extern unsigned long __adeos_virtual_irq_map;
+
+extern unsigned long __adeos_decr_ticks;
+
+extern unsigned long __adeos_decr_next[];
+
+#endif /* !__PPC64_ADEOS_H */
diff -Nru linux-2.6.10/include/asm-ppc64/hw_irq.h linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/hw_irq.h
--- linux-2.6.10/include/asm-ppc64/hw_irq.h 2004-12-24 23:35:40.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/hw_irq.h 2005-11-13 11:45:31.000000000 +0200
@@ -19,6 +19,37 @@
int timer_interrupt(struct pt_regs *);
extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
+#ifdef CONFIG_ADEOS_CORE
+
+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 __adeos_restore_root(unsigned long flags);
+
+#define irqs_disabled() __adeos_test_root()
+
+static inline void local_irq_disable(void) {
+ __adeos_stall_root();
+}
+
+static inline void local_irq_enable(void) {
+ __adeos_unstall_root();
+}
+
+static inline void local_irq_save_ptr(unsigned long *flags) {
+ *flags = __adeos_test_and_stall_root();
+}
+
+static inline void local_irq_restore(unsigned long flags) {
+ __adeos_restore_root(flags);
+}
+
+#define local_save_flags(flags) ((flags) = __adeos_test_root())
+#define local_irq_save(flags) local_irq_save_ptr(&flags)
+
+#else /* !CONFIG_ADEOS_CORE */
+
#ifdef CONFIG_PPC_ISERIES
extern unsigned long local_get_flags(void);
@@ -75,6 +106,8 @@
#endif /* CONFIG_PPC_ISERIES */
+#endif /* CONFIG_ADEOS_CORE */
+
#define mask_irq(irq) \
({ \
irq_desc_t *desc = get_irq_desc(irq); \
diff -Nru linux-2.6.10/include/asm-ppc64/mmu_context.h linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/mmu_context.h
--- linux-2.6.10/include/asm-ppc64/mmu_context.h 2004-12-24 23:34:31.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/mmu_context.h 2005-11-13 11:45:31.000000000 +0200
@@ -82,9 +82,17 @@
{
unsigned long flags;
+#ifdef CONFIG_ADEOS_CORE
+ adeos_hw_local_irq_save(flags);
+#else /* !CONFIG_ADEOS_CORE */
local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
switch_mm(prev, next, current);
+#ifdef CONFIG_ADEOS_CORE
+ adeos_hw_local_irq_restore(flags);
+#else /* !CONFIG_ADEOS_CORE */
local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
}
/* VSID allocation
diff -Nru linux-2.6.10/include/asm-ppc64/smp.h linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/smp.h
--- linux-2.6.10/include/asm-ppc64/smp.h 2004-12-24 23:33:47.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/smp.h 2005-11-13 11:45:31.000000000 +0200
@@ -37,8 +37,12 @@
struct pt_regs;
extern void smp_message_recv(int, struct pt_regs *);
-
+#ifdef CONFIG_ADEOS_CORE
+#include <asm/adeos.h>
+#define smp_processor_id() adeos_processor_id()
+#else /* !CONFIG_ADEOS_CORE */
#define smp_processor_id() (get_paca()->paca_index)
+#endif /* CONFIG_ADEOS_CORE */
#define hard_smp_processor_id() (get_paca()->hw_cpu_id)
extern cpumask_t cpu_sibling_map[NR_CPUS];
diff -Nru linux-2.6.10/include/asm-ppc64/time.h linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/time.h
--- linux-2.6.10/include/asm-ppc64/time.h 2004-12-24 23:34:44.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/include/asm-ppc64/time.h 2005-11-13 11:45:31.000000000 +0200
@@ -23,6 +23,9 @@
#include <asm/iSeries/HvCall.h>
/* time.c */
+#ifdef CONFIG_ADEOS_CORE
+extern unsigned long disarm_decr[NR_CPUS];
+#endif /* CONFIG_ADEOS_CORE */
extern unsigned long tb_ticks_per_jiffy;
extern unsigned long tb_ticks_per_usec;
extern unsigned long tb_ticks_per_sec;
diff -Nru linux-2.6.10/include/linux/adeos.h linux-2.6.10-adeos-ppc64-r3/include/linux/adeos.h
--- linux-2.6.10/include/linux/adeos.h 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/include/linux/adeos.h 2005-11-13 11:45:31.000000000 +0200
@@ -0,0 +1,553 @@
+/*
+ * include/linux/adeos.h
+ *
+ * Copyright (C) 2002,2003,2004 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_ADEOS_H
+#define __LINUX_ADEOS_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_ADEOS_CORE
+
+#include <linux/spinlock.h>
+#include <asm/adeos.h>
+
+#define ADEOS_VERSION_PREFIX "2.6"
+#define ADEOS_VERSION_STRING (ADEOS_VERSION_PREFIX ADEOS_ARCH_STRING)
+#define ADEOS_RELEASE_NUMBER (0x02060000|((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_SYNC_FLAG 3 /* The interrupt syncer is running for the domain */
+
+#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_SYNC_MASK (1 << IPIPE_SYNC_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 {
+
+ raw_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 { RAW_SPIN_LOCK_UNLOCKED, NULL, NULL, -1 }
+#else /* !CONFIG_SMP */
+#define ADEOS_MUTEX_UNLOCKED { RAW_SPIN_LOCK_UNLOCKED, NULL, NULL }
+#endif /* CONFIG_SMP */
+#else /* !CONFIG_ADEOS_THREADS */
+#define ADEOS_MUTEX_UNLOCKED { RAW_SPIN_LOCK_UNLOCKED }
+#endif /* CONFIG_ADEOS_THREADS */
+
+} admutex_t;
+
+typedef void (*adevhand_t)(adevinfo_t *);
+
+extern int adp_pipelined;
+
+extern adomain_t *adp_cpu_current[],
+ *adp_root;
+
+extern int __adeos_event_monitors[];
+
+extern unsigned __adeos_printk_virq;
+
+extern unsigned long __adeos_virtual_irq_map;
+
+extern struct list_head __adeos_pipeline;
+
+extern raw_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_flush_printk(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;
+}
+
+static inline void __adeos_enter_process(void) {
+
+ if (__adeos_event_monitors[ADEOS_ENTER_PROCESS] > 0)
+ __adeos_handle_event(ADEOS_ENTER_PROCESS,NULL);
+}
+
+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);
+}
+
+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;
+}
+
+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 __adeos_setscheduler_root(struct task_struct *p,
+ int policy,
+ int prio);
+
+void __adeos_reenter_root(struct task_struct *prev,
+ int policy,
+ int prio);
+
+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 */
+
+static inline int __adeos_domain_work_p (adomain_t *adp, int cpuid)
+
+{
+ return (!test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status) &&
+ adp->cpudata[cpuid].irq_pending_hi != 0);
+}
+
+static inline void __adeos_switch_to (adomain_t *out, adomain_t *in, int cpuid)
+
+{
+ void adeos_suspend_domain(void);
+
+ /* "in" is guaranteed to be closer than "out" from the head of the
+ pipeline (and obviously different). */
+
+ adp_cpu_current[cpuid] = in;
+
+ if (in->dswitch)
+ in->dswitch();
+
+ adeos_suspend_domain(); /* Sync stage and propagate interrupts. */
+ 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);
+}
+
+adevhand_t adeos_catch_event_from(adomain_t *adp,
+ unsigned event,
+ adevhand_t handler);
+
+static inline adevhand_t adeos_catch_event (unsigned event, adevhand_t handler)
+
+{
+ 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);
+}
+
+#define spin_lock_irqsave_hw_cond(lock,flags) spin_lock_irqsave_hw(lock,flags)
+#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock_irqrestore_hw(lock,flags)
+
+#define pic_irq_lock(irq) \
+ do { \
+ adeos_declare_cpuid; \
+ adeos_load_cpuid(); \
+ __adeos_lock_irq(adp_cpu_current[cpuid], cpuid, irq); \
+ } while(0)
+
+#define pic_irq_unlock(irq) \
+ do { \
+ adeos_declare_cpuid; \
+ adeos_load_cpuid(); \
+ __adeos_unlock_irq(adp_cpu_current[cpuid], irq); \
+ } while(0)
+
+#else /* !CONFIG_ADEOS_CORE */
+
+#define spin_lock_irqsave_hw(lock,flags) spin_lock_irqsave(lock, flags)
+#define spin_unlock_irqrestore_hw(lock,flags) spin_unlock_irqrestore(lock, flags)
+#define spin_lock_irqsave_hw_cond(lock,flags) do { flags = 0; spin_lock(lock); } while(0)
+#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock(lock)
+
+#define pic_irq_lock(irq) do { } while(0)
+#define pic_irq_unlock(irq) do { } while(0)
+
+#endif /* CONFIG_ADEOS_CORE */
+
+#endif /* !__LINUX_ADEOS_H */
diff -Nru linux-2.6.10/include/linux/preempt.h linux-2.6.10-adeos-ppc64-r3/include/linux/preempt.h
--- linux-2.6.10/include/linux/preempt.h 2004-12-24 23:34:26.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/include/linux/preempt.h 2005-11-13 11:45:31.000000000 +0200
@@ -25,6 +25,47 @@
asmlinkage void preempt_schedule(void);
+#ifdef CONFIG_ADEOS_CORE
+
+#include <asm/adeos.h>
+
+extern adomain_t *adp_cpu_current[],
+ *adp_root;
+
+#define preempt_disable() \
+do { \
+ if (adp_current == adp_root) { \
+ inc_preempt_count(); \
+ barrier(); \
+ } \
+} while (0)
+
+#define preempt_enable_no_resched() \
+do { \
+ if (adp_current == adp_root) { \
+ barrier(); \
+ dec_preempt_count(); \
+ } \
+} while (0)
+
+#define preempt_check_resched() \
+do { \
+ if (adp_current == adp_root) { \
+ if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
+ preempt_schedule(); \
+ } \
+} while (0)
+
+#define preempt_enable() \
+do { \
+ if (adp_current == adp_root) { \
+ preempt_enable_no_resched(); \
+ preempt_check_resched(); \
+ } \
+} while (0)
+
+#else /* !CONFIG_ADEOS_CORE */
+
#define preempt_disable() \
do { \
inc_preempt_count(); \
@@ -49,6 +90,8 @@
preempt_check_resched(); \
} while (0)
+#endif /* CONFIG_ADEOS_CORE */
+
#else
#define preempt_disable() do { } while (0)
diff -Nru linux-2.6.10/include/linux/sched.h linux-2.6.10-adeos-ppc64-r3/include/linux/sched.h
--- linux-2.6.10/include/linux/sched.h 2004-12-24 23:33:59.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/include/linux/sched.h 2005-11-13 11:45:31.000000000 +0200
@@ -4,6 +4,9 @@
#include <asm/param.h> /* for HZ */
#include <linux/config.h>
+#ifdef CONFIG_ADEOS_CORE
+#include <linux/adeos.h>
+#endif /* CONFIG_ADEOS_CORE */
#include <linux/capability.h>
#include <linux/threads.h>
#include <linux/kernel.h>
@@ -664,6 +667,10 @@
struct mempolicy *mempolicy;
short il_next; /* could be shared with used_math */
#endif
+
+#ifdef CONFIG_ADEOS_CORE
+ void *ptd[ADEOS_ROOT_NPTDKEYS];
+#endif /* CONFIG_ADEOS_CORE */
};
static inline pid_t process_group(struct task_struct *tsk)
diff -Nru linux-2.6.10/init/main.c linux-2.6.10-adeos-ppc64-r3/init/main.c
--- linux-2.6.10/init/main.c 2004-12-24 23:34:01.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/init/main.c 2005-11-13 11:45:31.000000000 +0200
@@ -526,6 +526,11 @@
init_timers();
softirq_init();
time_init();
+#ifdef CONFIG_ADEOS_CORE
+ /* On PPC, we need calibrated values for the decrementer to
+ initialize, so run time_init() first. */
+ __adeos_init();
+#endif /* CONFIG_ADEOS_CORE */
/*
* HACK ALERT! This is early. We're enabling the console before
@@ -652,6 +657,11 @@
sock_init();
do_initcalls();
+
+#ifdef CONFIG_ADEOS
+ /* i.e. Permanent pipelining from boot onwards. */
+ __adeos_takeover();
+#endif /* CONFIG_ADEOS */
}
static void do_pre_smp_initcalls(void)
diff -Nru linux-2.6.10/kernel/adeos.c linux-2.6.10-adeos-ppc64-r3/kernel/adeos.c
--- linux-2.6.10/kernel/adeos.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/adeos.c 2005-11-13 11:45:31.000000000 +0200
@@ -0,0 +1,826 @@
+/*
+ * linux/kernel/adeos.c
+ *
+ * Copyright (C) 2002,2003,2004 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-independent ADEOS core support.
+ */
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+/* The pre-defined domain slot for the root domain. */
+static adomain_t adeos_root_domain;
+
+/* A constant pointer to the root domain. */
+adomain_t *adp_root = &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. */
+raw_spinlock_t __adeos_pipelock = RAW_SPIN_LOCK_UNLOCKED;
+
+/* The pipeline data structure. Enqueues adomain_t objects by priority. */
+struct list_head __adeos_pipeline;
+
+/* A global flag telling whether Adeos pipelining is engaged. */
+int adp_pipelined;
+
+/* 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_platform(); /* 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_init_platform();
+
+ __adeos_printk_virq = adeos_alloc_irq(); /* Cannot fail here. */
+ adp->irqs[__adeos_printk_virq].handler = &__adeos_flush_printk;
+ 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);
+}
+
+/* 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 higher priority 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 CONFIG_REGPARM is enabled... */
+{
+ 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 higher priority 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->cpudata[cpuid].irq_pending_hi != 0 &&
+ !test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status))
+ {
+ if (next_domain != this_domain)
+ __adeos_switch_to(this_domain,next_domain,cpuid);
+ else
+ __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+ adeos_load_cpuid(); /* Processor might have changed. */
+ }
+
+ 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);
+
+ /* Note: Domain migration may occur while running event or
+ interrupt handlers, in which case the current register set
+ is going to be recycled for a different domain than the
+ initiating one. We do care for that, always tracking the
+ current domain descriptor upon return from those
+ handlers. */
+
+ if (next_domain->events[event].handler != NULL)
+ {
+ adp_cpu_current[cpuid] = next_domain;
+ evinfo.domid = start_domain->domid;
+ adeos_unlock_cpu(flags);
+ 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)
+ this_domain = adp_cpu_current[cpuid];
+
+ propagate = evinfo.propagate;
+ }
+
+ if (next_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+ !test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status))
+ {
+ adp_cpu_current[cpuid] = next_domain;
+ __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+ adeos_load_cpuid();
+
+ if (adp_cpu_current[cpuid] != next_domain)
+ this_domain = adp_cpu_current[cpuid];
+ }
+
+ adp_cpu_current[cpuid] = this_domain;
+
+ if (next_domain == this_domain || !propagate)
+ break;
+ }
+
+ adeos_unlock_cpu(flags);
+
+ return !propagate;
+}
+
+#endif /* CONFIG_ADEOS_THREADS */
+
+void __adeos_stall_root (void)
+
+{
+ if (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 (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 (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 (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 fastcall __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 fastcall 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
+ __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 (this_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+ !test_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status))
+ __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);
+
+#ifdef CONFIG_SMP
+ adeos_load_cpuid(); /* Processor might have changed. */
+ cpudata = &this_domain->cpudata[cpuid];
+#endif /* CONFIG_SMP */
+
+ /* Clear the sleep bit for the incoming domain. */
+ __clear_bit(IPIPE_SLEEP_FLAG,&cpudata->status);
+
+ /* 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_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;
+
+ spin_lock_irqsave_hw(&__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;
+ }
+
+ spin_unlock_irqrestore_hw(&__adeos_pipelock,flags);
+
+ return irq;
+}
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/proc_fs.h>
+
+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, "\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 (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 = num_online_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);
+}
+
+EXPORT_SYMBOL(adeos_suspend_domain);
+EXPORT_SYMBOL(adeos_alloc_irq);
+EXPORT_SYMBOL(adp_cpu_current);
+EXPORT_SYMBOL(adp_root);
+EXPORT_SYMBOL(adp_pipelined);
+EXPORT_SYMBOL(__adeos_handle_event);
+EXPORT_SYMBOL(__adeos_unstall_root);
+EXPORT_SYMBOL(__adeos_stall_root);
+EXPORT_SYMBOL(__adeos_restore_root);
+EXPORT_SYMBOL(__adeos_test_and_stall_root);
+EXPORT_SYMBOL(__adeos_test_root);
+EXPORT_SYMBOL(__adeos_dump_state);
+EXPORT_SYMBOL(__adeos_pipeline);
+EXPORT_SYMBOL(__adeos_pipelock);
+EXPORT_SYMBOL(__adeos_virtual_irq_map);
+EXPORT_SYMBOL(__adeos_event_monitors);
+EXPORT_SYMBOL(adeos_unstall_pipeline_from);
+#ifdef CONFIG_ADEOS_PROFILING
+EXPORT_SYMBOL(__adeos_profile_data);
+#endif /* CONFIG_ADEOS_PROFILING */
+/* The following are convenience exports which are needed by some
+ Adeos domains loaded as kernel modules. */
+EXPORT_SYMBOL(do_exit);
diff -Nru linux-2.6.10/kernel/exit.c linux-2.6.10-adeos-ppc64-r3/kernel/exit.c
--- linux-2.6.10/kernel/exit.c 2004-12-24 23:35:27.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/exit.c 2005-11-13 11:45:31.000000000 +0200
@@ -809,6 +809,9 @@
group_dead = atomic_dec_and_test(&tsk->signal->live);
if (group_dead)
acct_process(code);
+#ifdef CONFIG_ADEOS_CORE
+ __adeos_exit_process(tsk);
+#endif /* CONFIG_ADEOS_CORE */
__exit_mm(tsk);
exit_sem(tsk);
diff -Nru linux-2.6.10/kernel/fork.c linux-2.6.10-adeos-ppc64-r3/kernel/fork.c
--- linux-2.6.10/kernel/fork.c 2004-12-24 23:33:59.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/fork.c 2005-11-13 11:45:31.000000000 +0200
@@ -1021,6 +1021,14 @@
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 */
retval = 0;
fork_out:
diff -Nru linux-2.6.10/kernel/Makefile linux-2.6.10-adeos-ppc64-r3/kernel/Makefile
--- linux-2.6.10/kernel/Makefile 2004-12-24 23:34:26.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/Makefile 2005-11-13 11:45:31.000000000 +0200
@@ -9,6 +9,7 @@
rcupdate.o intermodule.o extable.o params.o posix-timers.o \
kthread.o wait.o kfifo.o sys_ni.o
+obj-$(CONFIG_ADEOS_CORE) += adeos.o
obj-$(CONFIG_FUTEX) += futex.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
obj-$(CONFIG_SMP) += cpu.o spinlock.o
diff -Nru linux-2.6.10/kernel/panic.c linux-2.6.10-adeos-ppc64-r3/kernel/panic.c
--- linux-2.6.10/kernel/panic.c 2004-12-24 23:35:29.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/panic.c 2005-11-13 11:45:31.000000000 +0200
@@ -70,6 +70,9 @@
va_end(args);
printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
bust_spinlocks(0);
+#ifdef CONFIG_ADEOS_CORE
+ __adeos_dump_state();
+#endif /* CONFIG_ADEOS_CORE */
#ifdef CONFIG_SMP
smp_send_stop();
diff -Nru linux-2.6.10/kernel/printk.c linux-2.6.10-adeos-ppc64-r3/kernel/printk.c
--- linux-2.6.10/kernel/printk.c 2004-12-24 23:35:40.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/printk.c 2005-11-13 11:45:31.000000000 +0200
@@ -509,6 +509,66 @@
* then changes console_loglevel may break. This is because console_loglevel
* is inspected when the actual printing occurs.
*/
+#ifdef CONFIG_ADEOS_CORE
+
+static raw_spinlock_t __adeos_printk_lock = RAW_SPIN_LOCK_UNLOCKED;
+
+static int __adeos_printk_fill;
+
+static char __adeos_printk_buf[__LOG_BUF_LEN];
+
+void __adeos_flush_printk (unsigned virq)
+{
+ char *p = __adeos_printk_buf;
+ int out = 0, len;
+
+ clear_bit(ADEOS_PPRINTK_FLAG,&adp_root->flags);
+
+ while (out < __adeos_printk_fill) {
+ len = strlen(p) + 1;
+ printk("%s",p);
+ p += len;
+ out += len;
+ }
+ __adeos_printk_fill = 0;
+}
+
+asmlinkage int printk(const char *fmt, ...)
+{
+ unsigned long flags;
+ int r, fbytes;
+ va_list args;
+
+ va_start(args, fmt);
+
+ if (adp_current == adp_root ||
+ test_bit(ADEOS_SPRINTK_FLAG,&adp_current->flags) ||
+ oops_in_progress) {
+ r = vprintk(fmt, args);
+ goto out;
+ }
+
+ adeos_spin_lock_irqsave(&__adeos_printk_lock,flags);
+
+ fbytes = __LOG_BUF_LEN - __adeos_printk_fill;
+
+ if (fbytes > 1) {
+ r = vscnprintf(__adeos_printk_buf + __adeos_printk_fill,
+ fbytes, fmt, args) + 1; /* account for the null byte */
+ __adeos_printk_fill += r;
+ } else
+ r = 0;
+
+ adeos_spin_unlock_irqrestore(&__adeos_printk_lock,flags);
+
+ if (!test_and_set_bit(ADEOS_PPRINTK_FLAG,&adp_root->flags))
+ adeos_trigger_irq(__adeos_printk_virq);
+out:
+ va_end(args);
+
+ return r;
+}
+#else /* !CONFIG_ADEOS_CORE */
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
@@ -520,6 +580,7 @@
return r;
}
+#endif /* CONFIG_ADEOS_CORE */
asmlinkage int vprintk(const char *fmt, va_list args)
{
diff -Nru linux-2.6.10/kernel/sched.c linux-2.6.10-adeos-ppc64-r3/kernel/sched.c
--- linux-2.6.10/kernel/sched.c 2004-12-24 23:35:24.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/sched.c 2005-11-13 11:45:32.000000000 +0200
@@ -302,7 +302,16 @@
* Default context-switch locking:
*/
#ifndef prepare_arch_switch
+#ifdef CONFIG_ADEOS_CORE
+#define prepare_arch_switch(rq,prev,next) \
+do { \
+ struct { struct task_struct *prev, *next; } arg = { (prev), (next) }; \
+ __adeos_schedule_head(&arg); \
+ adeos_hw_cli(); \
+} while(0)
+#else /* !CONFIG_ADEOS_CORE */
# define prepare_arch_switch(rq, next) do { } while (0)
+#endif /* CONFIG_ADEOS_CORE */
# define finish_arch_switch(rq, next) spin_unlock_irq(&(rq)->lock)
# define task_running(rq, p) ((rq)->curr == (p))
#endif
@@ -1367,6 +1376,9 @@
if (current->set_child_tid)
put_user(current->pid, current->set_child_tid);
+#ifdef CONFIG_ADEOS_CORE
+ __adeos_enter_process();
+#endif /* CONFIG_ADEOS_CORE */
}
/*
@@ -2535,6 +2547,11 @@
unsigned long run_time;
int cpu, idx;
+#ifdef CONFIG_ADEOS_CORE
+ if (adp_current != adp_root) /* Let's be helpful and conservative. */
+ return;
+#endif /* CONFIG_ADEOS_CORE */
+
/*
* Test if we are atomic. Since do_exit() needs to call into
* schedule() atomically, we ignore that path for now.
@@ -2684,9 +2701,28 @@
rq->curr = next;
++*switch_count;
- prepare_arch_switch(rq, next);
+#ifdef CONFIG_ADEOS_CORE
+ prepare_arch_switch(rq, prev, next);
+#else /* !CONFIG_ADEOS_CORE */
+ prepare_arch_switch(rq, next);
+#endif /* CONFIG_ADEOS_CORE */
prev = context_switch(rq, prev, next);
barrier();
+#ifdef CONFIG_ADEOS_CORE
+ if (adp_pipelined)
+ {
+ __clear_bit(IPIPE_SYNC_FLAG,&adp_root->cpudata[task_cpu(current)].status);
+ adeos_hw_sti();
+ }
+
+ if (__adeos_schedule_tail(prev) > 0 || adp_current != adp_root)
+ /* Someone has just recycled the register set of
+ prev for running over a non-root domain, or
+ some event handler in the pipeline asked for a
+ truncated scheduling tail. Don't perform the
+ Linux housekeeping chores, at least not now. */
+ return;
+#endif /* CONFIG_ADEOS_CORE */
finish_task_switch(prev);
} else
@@ -3148,6 +3184,16 @@
retval = security_task_setscheduler(p, policy, &lp);
if (retval)
goto out_unlock;
+#ifdef CONFIG_ADEOS_CORE
+ {
+ struct { struct task_struct *task; int policy; struct sched_param *param; } evdata = { p, policy, &lp };
+ if (__adeos_renice_process(&evdata))
+ {
+ retval = 0;
+ goto out_unlock;
+ }
+ }
+#endif /* CONFIG_ADEOS_CORE */
/*
* To be able to change p->policy safely, the apropriate
* runqueue lock must be held.
@@ -4676,3 +4722,62 @@
}
#endif /* CONFIG_MAGIC_SYSRQ */
+
+#ifdef CONFIG_ADEOS_CORE
+
+int __adeos_setscheduler_root (struct task_struct *p, int policy, int prio)
+{
+ prio_array_t *array;
+ unsigned long flags;
+ runqueue_t *rq;
+ int oldprio;
+
+ if (prio < 1 || prio > MAX_RT_PRIO-1)
+ return -EINVAL;
+
+ read_lock_irq(&tasklist_lock);
+ rq = task_rq_lock(p, &flags);
+ array = p->array;
+ if (array)
+ deactivate_task(p, rq);
+ oldprio = p->prio;
+ __setscheduler(p, policy, prio);
+ if (array) {
+ __activate_task(p, rq);
+ if (task_running(rq, p)) {
+ if (p->prio > oldprio)
+ resched_task(rq->curr);
+ } else if (TASK_PREEMPTS_CURR(p, rq))
+ resched_task(rq->curr);
+ }
+ task_rq_unlock(rq, &flags);
+ read_unlock_irq(&tasklist_lock);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(__adeos_setscheduler_root);
+
+void __adeos_reenter_root (struct task_struct *prev,
+ int policy,
+ int prio)
+{
+ finish_task_switch(prev);
+ if (reacquire_kernel_lock(current) < 0)
+ ;
+ preempt_enable_no_resched();
+
+ if (current->policy != policy || current->rt_priority != prio)
+ __adeos_setscheduler_root(current,policy,prio);
+}
+
+EXPORT_SYMBOL(__adeos_reenter_root);
+
+void __adeos_schedule_back_root (struct task_struct *prev)
+{
+ __adeos_reenter_root(prev,current->policy,current->rt_priority);
+}
+
+EXPORT_SYMBOL(__adeos_schedule_back_root);
+
+#endif /* CONFIG_ADEOS_CORE */
diff -Nru linux-2.6.10/kernel/signal.c linux-2.6.10-adeos-ppc64-r3/kernel/signal.c
--- linux-2.6.10/kernel/signal.c 2004-12-24 23:34:32.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/signal.c 2005-11-13 11:45:32.000000000 +0200
@@ -576,6 +576,13 @@
set_tsk_thread_flag(t, TIF_SIGPENDING);
+#ifdef CONFIG_ADEOS_CORE
+ {
+ struct { struct task_struct *t; } evdata = { t };
+ __adeos_kick_process(&evdata);
+ }
+#endif /* CONFIG_ADEOS_CORE */
+
/*
* If resume is set, we want to wake it up in the TASK_STOPPED case.
* We don't check for TASK_STOPPED because there is a race with it
@@ -823,6 +830,17 @@
BUG();
#endif
+#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;
+ }
+#endif /* CONFIG_ADEOS_CORE */
+
if (((unsigned long)info > 2) && (info->si_code == SI_TIMER))
/*
* Set up a return to indicate that we dropped the signal.
diff -Nru linux-2.6.10/kernel/sysctl.c linux-2.6.10-adeos-ppc64-r3/kernel/sysctl.c
--- linux-2.6.10/kernel/sysctl.c 2004-12-24 23:33:59.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/kernel/sysctl.c 2005-11-13 11:45:32.000000000 +0200
@@ -946,6 +946,9 @@
#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 -Nru linux-2.6.10/Makefile linux-2.6.10-adeos-ppc64-r3/Makefile
--- linux-2.6.10/Makefile 2004-12-24 23:35:01.000000000 +0200
+++ linux-2.6.10-adeos-ppc64-r3/Makefile 2005-11-13 11:45:32.000000000 +0200
@@ -558,6 +558,8 @@
ifeq ($(KBUILD_EXTMOD),)
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/
+core-$(CONFIG_ADEOS) += adeos/
+
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m)))
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2005-11-14 11:51 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-11-14 11:51 [Xenomai-core] Re: Adeos (oldgen) 2.6.10 ppc64 r3 Heikki Lindholm
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.