[Cbe-oss-dev] PATCH [3/7] reorganize spu_run_init
Luke Browning
lukebr at linux.vnet.ibm.com
Thu Nov 1 11:07:16 EST 2007
This patch cleans up spu_run_init so that it does all of the spu initialization
for spufs_run_spu. It initializes the spu context as much as possible before
it activates the spu and writes the runcntl register.
Signed-off-by: Luke Browning <lukebr at linux.vnet.ibm.com>
---
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/run.c
@@ -148,23 +148,41 @@ out:
static int spu_run_init(struct spu_context *ctx, u32 * npc)
{
unsigned long runcntl;
+ int ret;
spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
if (ctx->flags & SPU_CREATE_ISOLATE) {
+ /*
+ * Force activation of spu. Isolated state assumes that
+ * special loader context is loaded and running on spu.
+ */
+ if (ctx->state == SPU_STATE_SAVED) {
+ spu_set_timeslice(ctx);
+
+ ret = spu_activate(ctx, 0);
+ if (ret)
+ return ret;
+ }
if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) {
- int ret = spu_setup_isolated(ctx);
+ ret = spu_setup_isolated(ctx);
if (ret)
return ret;
}
- /* if userspace has set the runcntrl register (eg, to issue an
- * isolated exit), we need to re-set it here */
+ /*
+ * If userspace has set the runcntrl register (eg, to
+ * issue an isolated exit), we need to re-set it here
+ */
runcntl = ctx->ops->runcntl_read(ctx) &
(SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
if (runcntl == 0)
runcntl = SPU_RUNCNTL_RUNNABLE;
+
+ spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
+ ctx->ops->runcntl_write(ctx, runcntl);
+
} else {
unsigned long privcntl;
@@ -176,11 +194,17 @@ static int spu_run_init(struct spu_conte
ctx->ops->npc_write(ctx, *npc);
ctx->ops->privcntl_write(ctx, privcntl);
- }
- ctx->ops->runcntl_write(ctx, runcntl);
+ if (ctx->state == SPU_STATE_SAVED) {
+ spu_set_timeslice(ctx);
+ ret = spu_activate(ctx, 0);
+ if (ret)
+ return ret;
+ }
- spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
+ spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
+ ctx->ops->runcntl_write(ctx, runcntl);
+ }
return 0;
}
@@ -349,25 +373,8 @@ long spufs_run_spu(struct file *file, st
ctx->event_return = 0;
spu_acquire(ctx);
- if (ctx->state == SPU_STATE_SAVED) {
- __spu_update_sched_info(ctx);
- spu_set_timeslice(ctx);
-
- ret = spu_activate(ctx, 0);
- if (ret) {
- spu_release(ctx);
- goto out;
- }
- } else {
- /*
- * We have to update the scheduling priority under active_mutex
- * to protect against find_victim().
- *
- * No need to update the timeslice ASAP, it will get updated once
- * the current one has expired.
- */
- spu_update_sched_info(ctx);
- }
+
+ spu_update_sched_info(ctx);
ret = spu_run_init(ctx, npc);
if (ret) {
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/sched.c
@@ -105,6 +105,12 @@ void spu_set_timeslice(struct spu_contex
void __spu_update_sched_info(struct spu_context *ctx)
{
/*
+ * assert that the context is not on the runqueue, so it is safe
+ * to change its scheduling parameters.
+ */
+ BUG_ON(!list_empty(&ctx->rq));
+
+ /*
* 32-Bit assignment are atomic on powerpc, and we don't care about
* memory ordering here because retriving the controlling thread is
* per defintion racy.
@@ -113,7 +119,7 @@ void __spu_update_sched_info(struct spu_
/*
* We do our own priority calculations, so we normally want
- * ->static_prio to start with. Unfortunately thies field
+ * ->static_prio to start with. Unfortunately this field
* contains junk for threads with a realtime scheduling
* policy so we have to look at ->prio in this case.
*/
@@ -124,23 +130,28 @@ void __spu_update_sched_info(struct spu_
ctx->policy = current->policy;
/*
- * A lot of places that don't hold list_mutex poke into
- * cpus_allowed, including grab_runnable_context which
- * already holds the runq_lock. So abuse runq_lock
- * to protect this field aswell.
+ * TO DO: the context may be loaded, so we may need to activate
+ * it again on a different node. But it shouldn't hurt anything
+ * to update its parameters, because we know that the scheduler
+ * is not actively looking at this field, since it is not on the
+ * runqueue. The context will be rescheduled on the proper node
+ * if it is timesliced or preempted.
*/
- spin_lock(&spu_prio->runq_lock);
ctx->cpus_allowed = current->cpus_allowed;
- spin_unlock(&spu_prio->runq_lock);
}
void spu_update_sched_info(struct spu_context *ctx)
{
- int node = ctx->spu->node;
+ int node;
- mutex_lock(&cbe_spu_info[node].list_mutex);
- __spu_update_sched_info(ctx);
- mutex_unlock(&cbe_spu_info[node].list_mutex);
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ node = ctx->spu->node;
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ __spu_update_sched_info(ctx);
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+ } else {
+ __spu_update_sched_info(ctx);
+ }
}
static int __node_allowed(struct spu_context *ctx, int node)
@@ -604,6 +615,10 @@ static struct spu *find_victim(struct sp
* higher priority contexts before lower priority
* ones, so this is safe until we introduce
* priority inheritance schemes.
+ *
+ * XXX if the highest priority context is locked,
+ * this can loop a long time. Might be better to
+ * look at another context or give up after X retries.
*/
if (!mutex_trylock(&victim->state_mutex)) {
victim = NULL;
@@ -611,10 +626,10 @@ static struct spu *find_victim(struct sp
}
spu = victim->spu;
- if (!spu) {
+ if (!spu || victim->prio <= ctx->prio) {
/*
* This race can happen because we've dropped
- * the active list mutex. No a problem, just
+ * the active list mutex. Not a problem, just
* restart the search.
*/
mutex_unlock(&victim->state_mutex);
@@ -873,7 +888,7 @@ static void spusched_wake(unsigned long
static int spusched_thread(void *unused)
{
- struct spu *spu, *next;
+ struct spu *spu;
int node;
while (!kthread_should_stop()) {
@@ -973,7 +988,7 @@ int __init spu_sched_init(void)
void __exit spu_sched_exit(void)
{
- struct spu *spu, *tmp;
+ struct spu *spu;
int node;
remove_proc_entry("spu_loadavg", NULL);
More information about the cbe-oss-dev
mailing list