diff options
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/run.c | 9 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 43 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 5 |
4 files changed, 56 insertions, 3 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index d581f4ec99b..04ad2e364e9 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -54,7 +54,9 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) if (gang) spu_gang_add_ctx(gang, ctx); ctx->rt_priority = current->rt_priority; + ctx->policy = current->policy; ctx->prio = current->prio; + INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick); goto out; out_free: kfree(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index a973e79e9fd..353a8fa07ab 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -164,8 +164,10 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc) (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; @@ -176,6 +178,7 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, { int ret = 0; + spu_stop_tick(ctx); *status = ctx->ops->status_read(ctx); *npc = ctx->ops->npc_read(ctx); spu_release(ctx); @@ -329,8 +332,10 @@ long spufs_run_spu(struct file *file, struct spu_context *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); diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index ba4b01e01ac..2f25e68b4ba 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -44,7 +44,7 @@ #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); @@ -55,6 +55,7 @@ struct spu_prio_array { }; static struct spu_prio_array *spu_prio; +static struct workqueue_struct *spu_sched_wq; static inline int node_allowed(int node) { @@ -68,6 +69,40 @@ 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 @@ -437,10 +472,15 @@ int __init spu_sched_init(void) { 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++) { @@ -471,4 +511,5 @@ void __exit spu_sched_exit(void) mutex_unlock(&spu_prio->active_mutex[node]); } kfree(spu_prio); + destroy_workqueue(spu_sched_wq); } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 85b182d1646..0c437891dfd 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -82,8 +82,10 @@ struct spu_context { /* scheduler fields */ struct list_head rq; + struct delayed_work sched_work; unsigned long sched_flags; unsigned long rt_priority; + int policy; int prio; }; @@ -195,6 +197,9 @@ enum { 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); |