summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c9
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c43
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h5
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 d581f4e..04ad2e3 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 a973e79..353a8fa 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 ba4b01e..2f25e68 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 85b182d..0c43789 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);