diff options
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 81 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 5 | ||||
-rw-r--r-- | include/asm-powerpc/spu.h | 1 |
4 files changed, 64 insertions, 27 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 0d88a1c24f6..1758cec58bc 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 e2f10b5b8a6..fccc7709adb 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) |
49 | struct spu_prio_array { | 51 | struct 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 | ||
185 | static inline void unbind_context(struct spu *spu, struct spu_context *ctx) | 189 | static 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 | ||
203 | static struct spu *preempt_active(struct spu_runqueue *rq) | 210 | static 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; | 231 | static 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 | |||
245 | static 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 | ||
234 | static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags) | 263 | static 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 20f4e51d106..5bb75f22f72 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -37,6 +37,9 @@ enum { | |||
37 | 37 | ||
38 | struct spu_context_ops; | 38 | struct spu_context_ops; |
39 | 39 | ||
40 | #define SPU_CONTEXT_PREEMPT_nr 0UL | ||
41 | #define SPU_CONTEXT_PREEMPT (1UL << SPU_CONTEXT_PREEMPT_nr) | ||
42 | |||
40 | struct spu_context { | 43 | struct 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. */ |
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index dd91ed8563d..698c4cb08c6 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h | |||
@@ -129,6 +129,7 @@ struct spu { | |||
129 | struct mm_struct *mm; | 129 | struct mm_struct *mm; |
130 | struct spu_context *ctx; | 130 | struct spu_context *ctx; |
131 | struct spu_runqueue *rq; | 131 | struct spu_runqueue *rq; |
132 | unsigned long long timestamp; | ||
132 | pid_t pid; | 133 | pid_t pid; |
133 | int prio; | 134 | int prio; |
134 | int class_0_pending; | 135 | int class_0_pending; |