aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/cell/spufs
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/cell/spufs')
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c81
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h5
3 files changed, 63 insertions, 27 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 0d88a1c24f67..1758cec58bc7 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -116,8 +116,10 @@ int spu_acquire_runnable(struct spu_context *ctx)
116 int ret = 0; 116 int ret = 0;
117 117
118 down_read(&ctx->state_sema); 118 down_read(&ctx->state_sema);
119 if (ctx->state == SPU_STATE_RUNNABLE) 119 if (ctx->state == SPU_STATE_RUNNABLE) {
120 ctx->spu->prio = current->prio;
120 return 0; 121 return 0;
122 }
121 /* ctx is about to be freed, can't acquire any more */ 123 /* ctx is about to be freed, can't acquire any more */
122 if (!ctx->owner) { 124 if (!ctx->owner) {
123 ret = -EINVAL; 125 ret = -EINVAL;
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index e2f10b5b8a6a..fccc7709adbe 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -45,6 +45,8 @@
45#include <asm/spu_csa.h> 45#include <asm/spu_csa.h>
46#include "spufs.h" 46#include "spufs.h"
47 47
48#define SPU_MIN_TIMESLICE (100 * HZ / 1000))
49
48#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1) 50#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
49struct spu_prio_array { 51struct spu_prio_array {
50 atomic_t nr_blocked; 52 atomic_t nr_blocked;
@@ -168,6 +170,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
168 spu->number); 170 spu->number);
169 spu->ctx = ctx; 171 spu->ctx = ctx;
170 spu->flags = 0; 172 spu->flags = 0;
173 ctx->flags = 0;
171 ctx->spu = spu; 174 ctx->spu = spu;
172 ctx->ops = &spu_hw_ops; 175 ctx->ops = &spu_hw_ops;
173 spu->pid = current->pid; 176 spu->pid = current->pid;
@@ -180,6 +183,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
180 mb(); 183 mb();
181 spu_unmap_mappings(ctx); 184 spu_unmap_mappings(ctx);
182 spu_restore(&ctx->csa, spu); 185 spu_restore(&ctx->csa, spu);
186 spu->timestamp = jiffies;
183} 187}
184 188
185static inline void unbind_context(struct spu *spu, struct spu_context *ctx) 189static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
@@ -188,6 +192,7 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
188 spu->pid, spu->number); 192 spu->pid, spu->number);
189 spu_unmap_mappings(ctx); 193 spu_unmap_mappings(ctx);
190 spu_save(&ctx->csa, spu); 194 spu_save(&ctx->csa, spu);
195 spu->timestamp = jiffies;
191 ctx->state = SPU_STATE_SAVED; 196 ctx->state = SPU_STATE_SAVED;
192 spu->ibox_callback = NULL; 197 spu->ibox_callback = NULL;
193 spu->wbox_callback = NULL; 198 spu->wbox_callback = NULL;
@@ -197,38 +202,62 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
197 spu->prio = MAX_PRIO; 202 spu->prio = MAX_PRIO;
198 ctx->ops = &spu_backing_ops; 203 ctx->ops = &spu_backing_ops;
199 ctx->spu = NULL; 204 ctx->spu = NULL;
205 ctx->flags = 0;
206 spu->flags = 0;
200 spu->ctx = NULL; 207 spu->ctx = NULL;
201} 208}
202 209
203static struct spu *preempt_active(struct spu_runqueue *rq) 210static void spu_reaper(void *data)
204{ 211{
205 struct list_head *p; 212 struct spu_context *ctx = data;
206 struct spu *worst, *spu; 213 struct spu *spu;
207 214
208 worst = list_entry(rq->active_list.next, struct spu, sched_list); 215 down_write(&ctx->state_sema);
209 list_for_each(p, &rq->active_list) { 216 spu = ctx->spu;
210 spu = list_entry(p, struct spu, sched_list); 217 if (spu && (ctx->flags & SPU_CONTEXT_PREEMPT)) {
211 if (spu->prio > worst->prio) { 218 if (atomic_read(&spu->rq->prio.nr_blocked)) {
212 worst = spu; 219 pr_debug("%s: spu=%d\n", __func__, spu->number);
220 ctx->ops->runcntl_stop(ctx);
221 spu_deactivate(ctx);
222 wake_up_all(&ctx->stop_wq);
223 } else {
224 clear_bit(SPU_CONTEXT_PREEMPT_nr, &ctx->flags);
213 } 225 }
214 } 226 }
215 if (current->prio < worst->prio) { 227 up_write(&ctx->state_sema);
216 struct spu_context *ctx = worst->ctx; 228 put_spu_context(ctx);
229}
217 230
218 spu = worst; 231static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu)
219 if (down_write_trylock(&ctx->state_sema)) { 232{
220 pr_debug("%s: booting pid=%d from SPU %d\n", 233 struct spu_context *ctx = get_spu_context(spu->ctx);
221 __FUNCTION__, spu->pid, spu->number); 234 unsigned long now = jiffies;
222 del_active(rq, spu); 235 unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE;
223 up(&rq->sem); 236
224 wake_up_all(&ctx->stop_wq); 237 set_bit(SPU_CONTEXT_PREEMPT_nr, &ctx->flags);
225 ctx->ops->runcntl_stop(ctx); 238 INIT_WORK(&ctx->reap_work, spu_reaper, ctx);
226 unbind_context(spu, ctx); 239 if (time_after(now, expire))
227 up_write(&ctx->state_sema); 240 schedule_work(&ctx->reap_work);
228 return spu; 241 else
242 schedule_delayed_work(&ctx->reap_work, expire - now);
243}
244
245static void check_preempt_active(struct spu_runqueue *rq)
246{
247 struct list_head *p;
248 struct spu *worst = NULL;
249
250 list_for_each(p, &rq->active_list) {
251 struct spu *spu = list_entry(p, struct spu, sched_list);
252 struct spu_context *ctx = spu->ctx;
253 if (!(ctx->flags & SPU_CONTEXT_PREEMPT)) {
254 if (!worst || (spu->prio > worst->prio)) {
255 worst = spu;
256 }
229 } 257 }
230 } 258 }
231 return NULL; 259 if (worst && (current->prio < worst->prio))
260 schedule_spu_reaper(rq, worst);
232} 261}
233 262
234static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags) 263static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags)
@@ -256,10 +285,7 @@ static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags)
256 continue; 285 continue;
257 } 286 }
258 } else { 287 } else {
259 if (is_best_prio(rq)) { 288 check_preempt_active(rq);
260 if ((spu = preempt_active(rq)) != NULL)
261 return spu;
262 }
263 prio_wait(rq, ctx, flags); 289 prio_wait(rq, ctx, flags);
264 if (signal_pending(current)) { 290 if (signal_pending(current)) {
265 prio_wakeup(rq); 291 prio_wakeup(rq);
@@ -361,6 +387,8 @@ void spu_yield(struct spu_context *ctx)
361 spu_deactivate(ctx); 387 spu_deactivate(ctx);
362 ctx->state = SPU_STATE_SAVED; 388 ctx->state = SPU_STATE_SAVED;
363 need_yield = 1; 389 need_yield = 1;
390 } else if (spu) {
391 spu->prio = MAX_PRIO;
364 } 392 }
365 up_write(&ctx->state_sema); 393 up_write(&ctx->state_sema);
366 if (unlikely(need_yield)) 394 if (unlikely(need_yield))
@@ -399,6 +427,7 @@ int __init spu_sched_init(void)
399 pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number); 427 pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number);
400 add_idle(rq, spu); 428 add_idle(rq, spu);
401 spu->rq = rq; 429 spu->rq = rq;
430 spu->timestamp = jiffies;
402 } 431 }
403 if (!rq->nr_idle) { 432 if (!rq->nr_idle) {
404 printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__); 433 printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__);
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 20f4e51d1069..5bb75f22f722 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -37,6 +37,9 @@ enum {
37 37
38struct spu_context_ops; 38struct spu_context_ops;
39 39
40#define SPU_CONTEXT_PREEMPT_nr 0UL
41#define SPU_CONTEXT_PREEMPT (1UL << SPU_CONTEXT_PREEMPT_nr)
42
40struct spu_context { 43struct spu_context {
41 struct spu *spu; /* pointer to a physical SPU */ 44 struct spu *spu; /* pointer to a physical SPU */
42 struct spu_state csa; /* SPU context save area. */ 45 struct spu_state csa; /* SPU context save area. */
@@ -55,6 +58,8 @@ struct spu_context {
55 struct fasync_struct *ibox_fasync; 58 struct fasync_struct *ibox_fasync;
56 struct fasync_struct *wbox_fasync; 59 struct fasync_struct *wbox_fasync;
57 struct spu_context_ops *ops; 60 struct spu_context_ops *ops;
61 struct work_struct reap_work;
62 u64 flags;
58}; 63};
59 64
60/* SPU context query/set operations. */ 65/* SPU context query/set operations. */