Index: mutek/include/mutek/scheduler.h
===================================================================
--- mutek/include/mutek/scheduler.h	(revision 1388)
+++ mutek/include/mutek/scheduler.h	(working copy)
@@ -50,13 +50,9 @@
 CONTAINER_TYPE	     (sched_queue, DLIST, struct sched_context_s
 {
   CONTAINER_ENTRY_TYPE(DLIST) list_entry;
-  sched_queue_root_t    *root;		//< keep track of associated scheduler queue
+  struct scheduler_s *scheduler;		//< keep track of associated scheduler queue
   struct context_s	context;	//< execution context
 
-#if defined (CONFIG_MUTEK_SCHEDULER_STATIC) && defined(CONFIG_HEXO_IPI)
-  void			*cpu_cls;	//< used as cpu identifier for IPIs
-#endif
-
   void			*private;
 
 #ifdef CONFIG_MUTEK_SCHEDULER_MIGRATION_AFFINITY
Index: mutek/scheduler.c
===================================================================
--- mutek/scheduler.c	(revision 1388)
+++ mutek/scheduler.c	(working copy)
@@ -66,86 +66,79 @@
   return next;
 }
 
+#if defined(CONFIG_HEXO_IPI)
+#define CONTAINER_LOCK_idle_cpu_queue HEXO_SPIN
+CONTAINER_TYPE(idle_cpu_queue, CLIST, struct ipi_endpoint_s, idle_cpu_queue_list_entry);
+CONTAINER_FUNC(idle_cpu_queue, CLIST, static inline, idle_cpu_queue, list_entry);
+#endif
+
+struct scheduler_s
+{
+    sched_queue_root_t root;
+#if defined(CONFIG_HEXO_IPI)
+# if defined (CONFIG_MUTEK_SCHEDULER_MIGRATION)
+    idle_cpu_queue_root_t idle_cpu;
+# elif defined (CONFIG_MUTEK_SCHEDULER_STATIC)
+    struct ipi_endpoint_s *ipi_endpoint;
+# endif
+#endif
+};
+
 /************************************************************************/
 
 #if defined (CONFIG_MUTEK_SCHEDULER_MIGRATION)
 
 /* scheduler root */
-static sched_queue_root_t	CPU_NAME_DECL(sched_root);
+static struct scheduler_s CPU_NAME_DECL(scheduler);
 
-# if defined(CONFIG_HEXO_IPI)
-/* sleeping cpu list */
-
-CONTAINER_TYPE(sched_cls_queue, CLIST, struct sched_cls_item_s
-{
-  CONTAINER_ENTRY_TYPE(CLIST)	list_entry;
-}, list_entry);
-
-CONTAINER_FUNC(sched_cls_queue, CLIST, static inline, sched_cls_queue, list_entry);
-
-static sched_cls_queue_root_t cls_queue;
-
-static CPU_LOCAL struct sched_cls_item_s sched_cls_item;
-
-#  define GET_CLS_FROM_ITEM(item) ((void*)((uintptr_t)(item) - (uintptr_t)&sched_cls_item))
-# endif /* IPI */
-
 /* return scheduler root */
-static inline sched_queue_root_t *
-__sched_root(void)
+static inline struct scheduler_s *
+__scheduler_get(void)
 {
-  return & CPU_NAME_DECL(sched_root);
+  return & CPU_NAME_DECL(scheduler);
 }
 
-static inline
-void __sched_context_push(struct sched_context_s *sched_ctx)
-{
-	sched_queue_pushback(sched_ctx->root, sched_ctx);
-#if defined(CONFIG_HEXO_IPI)
-	struct sched_cls_item_s *idle = sched_cls_queue_pop(&cls_queue);
-	if ( idle ) {
-		ipi_post(GET_CLS_FROM_ITEM(idle));
-		sched_cls_queue_pushback(&cls_queue, idle);
-	}
-#endif /* IPI */
-}
-
 /************************************************************************/
 
 #elif defined (CONFIG_MUTEK_SCHEDULER_STATIC)
 
 /* scheduler root */
-static CPU_LOCAL sched_queue_root_t	sched_root;
+static CPU_LOCAL struct scheduler_s	scheduler;
 
 /* return scheduler root */
-static inline sched_queue_root_t *
-__sched_root(void)
+static inline struct scheduler_s *
+__scheduler_get(void)
 {
-  return CPU_LOCAL_ADDR(sched_root);
+  return CPU_LOCAL_ADDR(scheduler);
 }
 
+#endif
+
 static inline
 void __sched_context_push(struct sched_context_s *sched_ctx)
 {
-	sched_queue_pushback(sched_ctx->root, sched_ctx);
+    struct scheduler_s *sched = sched_ctx->scheduler;
+	sched_queue_pushback(&sched->root, sched_ctx);
 #if defined(CONFIG_HEXO_IPI)
-	ipi_post(sched_ctx->cpu_cls);
+# if defined (CONFIG_MUTEK_SCHEDULER_MIGRATION)
+	struct ipi_endpoint_s *idle = idle_cpu_queue_pop(&sched->idle_cpu);
+	if ( idle )
+		ipi_post(idle);
+    /* Push it back, we may have a race otherwise */
+    idle_cpu_queue_pushback(&sched->idle_cpu, idle);
+# elif defined (CONFIG_MUTEK_SCHEDULER_STATIC)
+    ipi_post(sched->ipi_endpoint);
+# endif
 #endif /* IPI */
 }
 
-#endif
-
 /************************************************************************/
 
 /* idle context runtime */
 static CONTEXT_ENTRY(sched_context_idle)
 {
-  sched_queue_root_t *root = __sched_root();
+  struct scheduler_s *sched = __scheduler_get();
 
-#if defined(CONFIG_MUTEK_SCHEDULER_MIGRATION) && defined(CONFIG_HEXO_IPI)
-  sched_cls_queue_push(&cls_queue, CPU_LOCAL_ADDR(sched_cls_item));
-#endif
-
   /* release lock acquired in previous sched_context_switch() call */
   sched_unlock();
   cpu_interrupt_disable();
@@ -160,8 +153,13 @@
       /* CPU sleep waiting for interrupts */
       cpu_interrupt_wait();
 #elif defined(CONFIG_HEXO_IPI)
-      if (CPU_LOCAL_GET(ipi_icu_dev))
+      if (ipi_endpoint_isvalid(CPU_LOCAL_ADDR(ipi_endpoint))) {
+# if defined(CONFIG_MUTEK_SCHEDULER_MIGRATION)
+          idle_cpu_queue_push(&sched->idle_cpu, CPU_LOCAL_ADDR(ipi_endpoint));
 		  cpu_interrupt_wait();
+          idle_cpu_queue_remove(&sched->idle_cpu, CPU_LOCAL_ADDR(ipi_endpoint));
+# endif
+      }
 #endif
 
       /* Let enough time for pending interrupts to execute and assume
@@ -169,21 +167,15 @@
 	 reloading after interrupts execution. */
       cpu_interrupt_process();
 
-      sched_queue_wrlock(root);
+      sched_queue_wrlock(&sched->root);
 
-      if ((next = __sched_candidate_noidle(root)) != NULL)
+      if ((next = __sched_candidate_noidle(&sched->root)) != NULL)
 	{
-#if defined(CONFIG_MUTEK_SCHEDULER_MIGRATION) && defined(CONFIG_HEXO_IPI)
-	  sched_cls_queue_remove(&cls_queue, CPU_LOCAL_ADDR(sched_cls_item));
-#endif
 	  context_switch_to(&next->context);
-#if defined(CONFIG_MUTEK_SCHEDULER_MIGRATION) && defined(CONFIG_HEXO_IPI)
-	  sched_cls_queue_push(&cls_queue, CPU_LOCAL_ADDR(sched_cls_item));
-#endif
 	  //	  printk("(c%i idle)", cpu_id());
 	}
 
-      sched_queue_unlock(root);
+      sched_queue_unlock(&sched->root);
     }
 }
 
@@ -195,21 +187,21 @@
    with interrupts disabled */
 void sched_context_switch(void)
 {
-  sched_queue_root_t *root = __sched_root();
+  struct scheduler_s *sched = __scheduler_get();
   struct sched_context_s *next;
 
   assert(!cpu_is_interruptible());
 
-  sched_queue_wrlock(root);
+  sched_queue_wrlock(&sched->root);
 
-  if ((next = __sched_candidate_noidle(root)))
+  if ((next = __sched_candidate_noidle(&sched->root)))
     {
       /* push context back in running queue */
-      sched_queue_nolock_pushback(root, CONTEXT_LOCAL_GET(sched_cur));
+      sched_queue_nolock_pushback(&sched->root, CONTEXT_LOCAL_GET(sched_cur));
       context_switch_to(&next->context);
     }
 
-  sched_queue_unlock(root);
+  sched_queue_unlock(&sched->root);
 }
 
 /* Must be called with interrupts disabled and sched locked */
@@ -220,7 +212,7 @@
   struct sched_context_s	*next;
 
   /* get next running context */
-  next = __sched_candidate(__sched_root());
+  next = __sched_candidate(&__scheduler_get()->root);
   context_jump_to(&next->context);
 }
 
@@ -228,14 +220,14 @@
 {
   assert(!cpu_is_interruptible());
 
-  sched_queue_wrlock(__sched_root());
+  sched_queue_wrlock(&__scheduler_get()->root);
 }
 
 void sched_unlock(void)
 {
   assert(!cpu_is_interruptible());
 
-  sched_queue_unlock(__sched_root());
+  sched_queue_unlock(&__scheduler_get()->root);
 }
 
 void sched_context_init(struct sched_context_s *sched_ctx)
@@ -245,12 +237,8 @@
 			sched_cur, sched_ctx);
 
   sched_ctx->private = NULL;
-  sched_ctx->root = __sched_root();
+  sched_ctx->scheduler = __scheduler_get();
 
-#if defined (CONFIG_MUTEK_SCHEDULER_STATIC) && defined(CONFIG_HEXO_IPI)
-  sched_ctx->cpu_cls = (void*)CPU_GET_CLS();
-#endif
-
 #ifdef CONFIG_MUTEK_SCHEDULER_CANDIDATE_FCN
   sched_ctx->is_candidate = NULL;
 #endif
@@ -268,7 +256,7 @@
 void sched_wait_callback(sched_queue_root_t *queue,
 		         void (*callback)(void *ctx), void *ctx)
 {
-  sched_queue_root_t *root = __sched_root();
+  struct scheduler_s *sched = __scheduler_get();
   struct sched_context_s *next;
 
   assert(!cpu_is_interruptible());
@@ -278,10 +266,10 @@
   callback(ctx);
 
   /* get next running context */
-  sched_queue_wrlock(root);
-  next = __sched_candidate(root);
+  sched_queue_wrlock(&sched->root);
+  next = __sched_candidate(&sched->root);
   context_switch_to(&next->context);
-  sched_queue_unlock(root);
+  sched_queue_unlock(&sched->root);
 }
 
 /* push current context in the 'queue', unlock it and switch to next
@@ -289,7 +277,7 @@
    interrupts disabled */
 void sched_wait_unlock(sched_queue_root_t *queue)
 {
-  sched_queue_root_t *root = __sched_root();
+  struct scheduler_s *sched = __scheduler_get();
   struct sched_context_s *next;
 
   assert(!cpu_is_interruptible());
@@ -299,10 +287,10 @@
   sched_queue_unlock(queue);
 
   /* get next running context */
-  sched_queue_wrlock(root);
-  next = __sched_candidate(root);
+  sched_queue_wrlock(&sched->root);
+  next = __sched_candidate(&sched->root);
   context_switch_to(&next->context);
-  sched_queue_unlock(root);
+  sched_queue_unlock(&sched->root);
 }
 
 /* Switch to next context available in the 'root' queue, do not put
@@ -311,32 +299,32 @@
    disabled */
 void sched_context_stop(void)
 {
-  sched_queue_root_t *root = __sched_root();
+  struct scheduler_s *sched = __scheduler_get();
   struct sched_context_s *next;
 
   assert(!cpu_is_interruptible());
 
   /* get next running context */
-  sched_queue_wrlock(root);
-  next = __sched_candidate(root);
+  sched_queue_wrlock(&sched->root);
+  next = __sched_candidate(&sched->root);
   context_switch_to(&next->context);
-  sched_queue_unlock(root);
+  sched_queue_unlock(&sched->root);
 }
 
 /* Same as sched_context_stop but unlock given spinlock before switching */
 void sched_context_stop_unlock(lock_t *lock)
 {
-  sched_queue_root_t *root = __sched_root();
+  struct scheduler_s *sched = __scheduler_get();
   struct sched_context_s *next;
 
   assert(!cpu_is_interruptible());
 
   /* get next running context */
-  sched_queue_wrlock(root);
+  sched_queue_wrlock(&sched->root);
   lock_release(lock);
-  next = __sched_candidate(root);
+  next = __sched_candidate(&sched->root);
   context_switch_to(&next->context);
-  sched_queue_unlock(root);
+  sched_queue_unlock(&sched->root);
 }
 
 /* Must be called with interrupts disabled and queue locked */
@@ -352,13 +340,22 @@
   return sched_ctx;
 }
 
+static void __sched_init(struct scheduler_s *sched)
+{
+  sched_queue_init(&sched->root);
+#if defined(CONFIG_HEXO_IPI)
+# if defined(CONFIG_MUTEK_SCHEDULER_MIGRATION)
+    idle_cpu_queue_init(&sched->idle_cpu);
+# elif defined(CONFIG_MUTEK_SCHEDULER_STATIC)
+    sched->ipi_endpoint = NULL;
+# endif
+#endif
+}
+
 void sched_global_init(void)
 {
 #if defined (CONFIG_MUTEK_SCHEDULER_MIGRATION)
-# if defined(CONFIG_HEXO_IPI)
-  sched_cls_queue_init(&cls_queue);
-# endif
-  sched_queue_init(__sched_root());
+    __sched_init(__scheduler_get());
 #endif
 }
 
@@ -379,7 +376,7 @@
   assert(err == 0);
 
 #if defined (CONFIG_MUTEK_SCHEDULER_STATIC)
-  sched_queue_init(__sched_root());
+  __sched_init(__scheduler_get());
 #endif
 }
 
@@ -422,10 +419,7 @@
 void sched_affinity_add(struct sched_context_s *sched_ctx, cpu_id_t cpu)
 {
   void *cls = CPU_GET_CLS_ID(cpu);
-#if defined(CONFIG_HEXO_IPI)
-  sched_ctx->cpu_cls = cls;
-#endif
-  sched_ctx->root = CPU_LOCAL_CLS_ADDR(cls, sched_root);
+  sched_ctx->scheduler = CPU_LOCAL_CLS_ADDR(cls, scheduler);
 }
 
 void sched_affinity_remove(struct sched_context_s *sched_ctx, cpu_id_t cpu)
Index: mutek/fdt_consumer.c
===================================================================
--- mutek/fdt_consumer.c	(revision 1388)
+++ mutek/fdt_consumer.c	(working copy)
@@ -119,12 +119,10 @@
 		priv->state = IN_CPUS;
 #if defined(CONFIG_HEXO_IPI)
 		if ( priv->ipi_dev && priv->ipi_dev->drv ) {
-			dprintk("Preparing ipi dev\n");
-			void *foo = dev_icu_setupipi(priv->ipi_dev, priv->ipi_no);
-			dprintk("  CPU %d using %p:%d as ipi device, cls=%p, priv=%p\n",
-				   priv->cpuid, priv->ipi_dev, priv->ipi_no,
-				   cpu_local_storage[priv->cpuid], foo);
-			ipi_hook_cpu(cpu_local_storage[priv->cpuid], priv->ipi_dev, foo);
+            ipi_hook_endpoint(
+                CPU_LOCAL_CLS_ADDR(cpu_local_storage[priv->cpuid], ipi_endpoint),
+                priv->ipi_dev,
+                priv->ipi_no);
 		} else {
 			dprintk("  No IPI dev for CPU %d\n", priv->cpuid);
 		}
Index: hexo/ipi.c
===================================================================
--- hexo/ipi.c	(revision 1388)
+++ hexo/ipi.c	(working copy)
@@ -25,43 +25,44 @@
 #include <device/device.h>
 #include <hexo/ipi.h>
 
-static CPU_LOCAL ipi_queue_root_t ipi_fifo = CONTAINER_ROOT_INITIALIZER(ipi_queue, DLIST);
-CPU_LOCAL struct device_s *ipi_icu_dev = 0;
-CPU_LOCAL void *ipi_cpu_id;
+CONTAINER_FUNC(ipi_queue, DLIST, static inline, ipi_queue);
 
-error_t ipi_post(void *cpu_cls)
+CPU_LOCAL struct ipi_endpoint_s ipi_endpoint = {};
+
+error_t ipi_post(struct ipi_endpoint_s *endpoint)
 {
-  struct device_s *icu = *CPU_LOCAL_CLS_ADDR(cpu_cls, ipi_icu_dev);
+    struct device_s *icu = endpoint->icu_dev;
 
-  if (!icu)
-    return -EOPNOTSUPP;
+    if (!icu)
+        return -EOPNOTSUPP;
 
-  return dev_icu_sendipi(icu, *CPU_LOCAL_CLS_ADDR(cpu_cls, ipi_cpu_id));
+    return dev_icu_sendipi(icu, endpoint->priv);
 }
 
-error_t ipi_post_rq(void *cpu_cls, struct ipi_request_s *rq)
+error_t ipi_post_rq(struct ipi_endpoint_s *endpoint, struct ipi_request_s *rq)
 {
-  if (ipi_queue_pushback(CPU_LOCAL_CLS_ADDR(cpu_cls, ipi_fifo), rq))
-    return ipi_post(cpu_cls);
+    if (ipi_queue_pushback(&endpoint->ipi_fifo, rq))
+        return ipi_post(endpoint);
 
-  return -ENOMEM;
+    return -ENOMEM;
 }
 
 void ipi_process_rq()
 {
-  struct ipi_request_s *rq;
+    struct ipi_request_s *rq;
+    ipi_queue_root_t *fifo = &(CPU_LOCAL_ADDR(ipi_endpoint)->ipi_fifo);
 
-  while ((rq = ipi_queue_pop(CPU_LOCAL_ADDR(ipi_fifo))))
-    rq->func(rq->private);
+    while ((rq = ipi_queue_pop(fifo)))
+        rq->func(rq->private);
 }
 
-void ipi_hook_cpu(void *cpu_cls,
-				  struct device_s *ipi_icudev,
-				  void *privdata)
+error_t ipi_hook_endpoint(struct ipi_endpoint_s *endpoint,
+                          struct device_s *ipi_dev,
+                          uint_fast8_t ipi_no)
 {
-	struct device_s **icu = CPU_LOCAL_CLS_ADDR(cpu_cls, ipi_icu_dev);
-	void ** priv = CPU_LOCAL_CLS_ADDR(cpu_cls, ipi_cpu_id);
+    void *foo = dev_icu_setupipi(ipi_dev, ipi_no);
+    endpoint->icu_dev = ipi_dev;
+    endpoint->priv = foo;
 
-	*icu = ipi_icudev;
-	*priv = privdata;
+    return 0;
 }
Index: hexo/include/hexo/ipi.h
===================================================================
--- hexo/include/hexo/ipi.h	(revision 1388)
+++ hexo/include/hexo/ipi.h	(working copy)
@@ -40,9 +40,6 @@
 
 typedef IPI_MSG_FUNC(ipi_msg_func_t);
 
-extern CPU_LOCAL struct device_s *ipi_icu_dev;
-extern CPU_LOCAL void *ipi_cpu_id;
-
 #define CONTAINER_LOCK_ipi_queue HEXO_SPIN
 
 CONTAINER_TYPE(ipi_queue, DLIST,
@@ -53,41 +50,65 @@
   ipi_queue_entry_t queue_entry;
 }, queue_entry);
 
-CONTAINER_FUNC(ipi_queue, DLIST, static inline, ipi_queue);
+struct ipi_endpoint_s
+{
+    struct device_s *icu_dev;
+    void *priv;
+    ipi_queue_root_t ipi_fifo;
+#if defined (CONFIG_MUTEK_SCHEDULER_MIGRATION)
+    CONTAINER_ENTRY_TYPE(CLIST) idle_cpu_queue_list_entry;
+#endif
+};
 
+extern CPU_LOCAL struct ipi_endpoint_s ipi_endpoint;
+
+
 /**
-   Send an ipi to given processor. Processor is identified using its
-   cpu local storage pointer.
+   Send an ipi to given endpoint.
+
+   @param endpoint Pointer to ipi endpoint
    @return zero if ipi was sent
-   @see #CPU_LOCAL_ID_ADDR
  */
-error_t ipi_post(void *cpu_cls);
+error_t ipi_post(struct ipi_endpoint_s *endpoint);
 
 /**
    Attach the given callback for execution on target processor and
-   send an ipi to given processor on success  Processor is identified using its
-   cpu local storage pointer.
+   send an ipi to given endpoint.
 
+   @param endpoint Pointer to ipi endpoint
+   @param rq Request buffer
    @return zero if message was attached and ipi sent
    @see #CPU_LOCAL_ID_ADDR
  */
-error_t ipi_post_rq(void *cpu_cls, struct ipi_request_s *rq);
+error_t ipi_post_rq(struct ipi_endpoint_s *endpoint, struct ipi_request_s *rq);
 
 /**
-   Request processing of pending messages on current processor. Called from icu driver
+   Request processing of pending messages on current processor. Must
+   be called from icu driver
  */
 void ipi_process_rq();
 
 /**
-   Setup a IPI device for a given CPU.
+   Setup a IPI device for a given endpoint.
 
-   @param cpu_cls CPU's cls to hook up in
-   @param ipi_icudev Icudev handling the IPIs
-   @param privdata Icudev private data returned by @ref dev_icu_setupipi
+   @param endpoint IPI endpoint to set up
+   @param ipi_dev ICU device handling the IPI
+   @param ipi_no IPI number in ICU device @tt ipi_dev
  */
-void ipi_hook_cpu(void *cpu_cls,
-				  struct device_s *ipi_icudev,
-				  void *privdata);
+error_t ipi_hook_endpoint(struct ipi_endpoint_s *endpoint,
+                          struct device_s *ipi_dev,
+                          uint_fast8_t ipi_no);
 
+/**
+   Checks whether a given endpoint may receive IPIs.
+
+   @param endpoint IPI endpoint to check
+   @return whether endpoint may receive IPIs
+*/
+static inline
+bool_t ipi_endpoint_isvalid(struct ipi_endpoint_s *endpoint)
+{
+    return endpoint->icu_dev != NULL;
+}
+
 #endif
-
Index: examples/common/build_options.conf
===================================================================
--- examples/common/build_options.conf	(revision 1399)
+++ examples/common/build_options.conf	(working copy)
@@ -27,3 +27,6 @@
 
 %section thumb
   CONFIG_CPU_ARM_THUMB
+
+%section ipi
+  CONFIG_HEXO_IPI 
Index: examples/hello/hello.c
===================================================================
--- examples/hello/hello.c	(revision 1388)
+++ examples/hello/hello.c	(working copy)
@@ -2,8 +2,10 @@
 #include <pthread.h>
 #include <mutek/printk.h>
 
+#define THREADS 4
+
 pthread_mutex_t m;
-pthread_t a, b;
+pthread_t thread[THREADS];
 
 void *f(void *param)
 {
@@ -19,7 +21,9 @@
 void app_start()
 {
   pthread_mutex_init(&m, NULL);
-  pthread_create(&a, NULL, f, "Hello world\n");
-  pthread_create(&b, NULL, f, "Hello world\n");
+  size_t i;
+  for (i = 0; i < THREADS; ++i) {
+      pthread_create(&thread[i], NULL, f, "Hello world\n");
+  }
 }
 
Index: examples/hello/config
===================================================================
--- examples/hello/config	(revision 1388)
+++ examples/hello/config	(working copy)
@@ -7,9 +7,6 @@
   # Application license
   CONFIG_LICENSE_APP_LGPL
 
-  # Mutek features
-  CONFIG_HEXO_IPI undefined
-
   # Libs
   CONFIG_PTHREAD
 
