(SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
                if (runcntl == 0)
                        runcntl = SPU_RUNCNTL_RUNNABLE;
-       } else
+       } else {
+               spu_start_tick(ctx);
                ctx->ops->npc_write(ctx, *npc);
+       }
 
        ctx->ops->runcntl_write(ctx, runcntl);
        return ret;
 {
        int ret = 0;
 
+       spu_stop_tick(ctx);
        *status = ctx->ops->status_read(ctx);
        *npc = ctx->ops->npc_read(ctx);
        spu_release(ctx);
                }
                if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
                        ret = spu_reacquire_runnable(ctx, npc, &status);
-                       if (ret)
+                       if (ret) {
+                               spu_stop_tick(ctx);
                                goto out2;
+                       }
                        continue;
                }
                ret = spu_process_events(ctx);
 
 #include <asm/spu_priv1.h>
 #include "spufs.h"
 
-#define SPU_MIN_TIMESLICE      (100 * HZ / 1000)
+#define SPU_TIMESLICE  (HZ)
 
 struct spu_prio_array {
        DECLARE_BITMAP(bitmap, MAX_PRIO);
 };
 
 static struct spu_prio_array *spu_prio;
+static struct workqueue_struct *spu_sched_wq;
 
 static inline int node_allowed(int node)
 {
        return 1;
 }
 
+void spu_start_tick(struct spu_context *ctx)
+{
+       if (ctx->policy == SCHED_RR)
+               queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE);
+}
+
+void spu_stop_tick(struct spu_context *ctx)
+{
+       if (ctx->policy == SCHED_RR)
+               cancel_delayed_work(&ctx->sched_work);
+}
+
+void spu_sched_tick(struct work_struct *work)
+{
+       struct spu_context *ctx =
+               container_of(work, struct spu_context, sched_work.work);
+       struct spu *spu;
+       int rearm = 1;
+
+       mutex_lock(&ctx->state_mutex);
+       spu = ctx->spu;
+       if (spu) {
+               int best = sched_find_first_bit(spu_prio->bitmap);
+               if (best <= ctx->prio) {
+                       spu_deactivate(ctx);
+                       rearm = 0;
+               }
+       }
+       mutex_unlock(&ctx->state_mutex);
+
+       if (rearm)
+               spu_start_tick(ctx);
+}
+
 /**
  * spu_add_to_active_list - add spu to active list
  * @spu:       spu to add to the active list
 {
        int i;
 
+       spu_sched_wq = create_singlethread_workqueue("spusched");
+       if (!spu_sched_wq)
+               return 1;
+
        spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL);
        if (!spu_prio) {
                printk(KERN_WARNING "%s: Unable to allocate priority queue.\n",
                       __FUNCTION__);
+                      destroy_workqueue(spu_sched_wq);
                return 1;
        }
        for (i = 0; i < MAX_PRIO; i++) {
                mutex_unlock(&spu_prio->active_mutex[node]);
        }
        kfree(spu_prio);
+       destroy_workqueue(spu_sched_wq);
 }
 
 
        /* scheduler fields */
        struct list_head rq;
+       struct delayed_work sched_work;
        unsigned long sched_flags;
        unsigned long rt_priority;
+       int policy;
        int prio;
 };
 
 int spu_activate(struct spu_context *ctx, unsigned long flags);
 void spu_deactivate(struct spu_context *ctx);
 void spu_yield(struct spu_context *ctx);
+void spu_start_tick(struct spu_context *ctx);
+void spu_stop_tick(struct spu_context *ctx);
+void spu_sched_tick(struct work_struct *work);
 int __init spu_sched_init(void);
 void __exit spu_sched_exit(void);