aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2007-02-13 15:54:23 -0500
committerArnd Bergmann <arnd@klappe.arndb.de>2007-02-13 15:55:41 -0500
commit079cdb61614c466c939ebf74c7ef6745667bc61e (patch)
tree0ba9ef0d3f8e04b31483e7dce2231f1f5f38d74b /arch
parent8389998ae9ea2888c86c446f7911ddced50052a1 (diff)
[POWERPC] spufs: runqueue simplification
This is the biggest patch in this series, and it reworks the guts of the spu scheduler runqueue mechanism: - instead of embedding a waitqueue in the runqueue there is now a simple doubly-linked list, the actual wakeups happen by reusing the stop_wq in the spu context (maybe we should rename it one day) - spu_free and spu_prio_wakeup are merged into a single spu_reschedule function - various functionality is split out into small helpers, and kerneldoc comments are added in various places to document what's going on. - spu_activate is rewritten into a tight loop by removing test for various impossible conditions and using the infrastructure in this patch. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c159
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h1
2 files changed, 93 insertions, 67 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 03b357ce3987..6f8e2257c5a6 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -49,7 +49,8 @@
49#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1) 49#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
50struct spu_prio_array { 50struct spu_prio_array {
51 unsigned long bitmap[SPU_BITMAP_SIZE]; 51 unsigned long bitmap[SPU_BITMAP_SIZE];
52 wait_queue_head_t waitq[MAX_PRIO]; 52 struct list_head runq[MAX_PRIO];
53 spinlock_t runq_lock;
53 struct list_head active_list[MAX_NUMNODES]; 54 struct list_head active_list[MAX_NUMNODES];
54 struct mutex active_mutex[MAX_NUMNODES]; 55 struct mutex active_mutex[MAX_NUMNODES];
55}; 56};
@@ -196,61 +197,91 @@ static int spu_unbind_context(struct spu *spu, struct spu_context *ctx)
196 return was_active; 197 return was_active;
197} 198}
198 199
199static inline void spu_add_wq(wait_queue_head_t * wq, wait_queue_t * wait, 200/**
200 int prio) 201 * spu_add_to_rq - add a context to the runqueue
202 * @ctx: context to add
203 */
204static void spu_add_to_rq(struct spu_context *ctx)
201{ 205{
202 prepare_to_wait_exclusive(wq, wait, TASK_INTERRUPTIBLE); 206 spin_lock(&spu_prio->runq_lock);
203 set_bit(prio, spu_prio->bitmap); 207 list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]);
208 set_bit(ctx->prio, spu_prio->bitmap);
209 spin_unlock(&spu_prio->runq_lock);
204} 210}
205 211
206static inline void spu_del_wq(wait_queue_head_t * wq, wait_queue_t * wait, 212/**
207 int prio) 213 * spu_del_from_rq - remove a context from the runqueue
214 * @ctx: context to remove
215 */
216static void spu_del_from_rq(struct spu_context *ctx)
208{ 217{
209 u64 flags; 218 spin_lock(&spu_prio->runq_lock);
210 219 list_del_init(&ctx->rq);
211 __set_current_state(TASK_RUNNING); 220 if (list_empty(&spu_prio->runq[ctx->prio]))
212 221 clear_bit(ctx->prio, spu_prio->bitmap);
213 spin_lock_irqsave(&wq->lock, flags); 222 spin_unlock(&spu_prio->runq_lock);
223}
214 224
215 remove_wait_queue_locked(wq, wait); 225/**
216 if (list_empty(&wq->task_list)) 226 * spu_grab_context - remove one context from the runqueue
217 clear_bit(prio, spu_prio->bitmap); 227 * @prio: priority of the context to be removed
228 *
229 * This function removes one context from the runqueue for priority @prio.
230 * If there is more than one context with the given priority the first
231 * task on the runqueue will be taken.
232 *
233 * Returns the spu_context it just removed.
234 *
235 * Must be called with spu_prio->runq_lock held.
236 */
237static struct spu_context *spu_grab_context(int prio)
238{
239 struct list_head *rq = &spu_prio->runq[prio];
218 240
219 spin_unlock_irqrestore(&wq->lock, flags); 241 if (list_empty(rq))
242 return NULL;
243 return list_entry(rq->next, struct spu_context, rq);
220} 244}
221 245
222static void spu_prio_wait(struct spu_context *ctx, u64 flags) 246static void spu_prio_wait(struct spu_context *ctx)
223{ 247{
224 int prio = ctx->prio;
225 wait_queue_head_t *wq = &spu_prio->waitq[prio];
226 DEFINE_WAIT(wait); 248 DEFINE_WAIT(wait);
227 249
228 if (ctx->spu) 250 prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE);
229 return;
230
231 spu_add_wq(wq, &wait, prio);
232 251
233 if (!signal_pending(current)) { 252 if (!signal_pending(current)) {
234 mutex_unlock(&ctx->state_mutex); 253 mutex_unlock(&ctx->state_mutex);
235 pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
236 current->pid, current->prio);
237 schedule(); 254 schedule();
238 mutex_lock(&ctx->state_mutex); 255 mutex_lock(&ctx->state_mutex);
239 } 256 }
240 257 __set_current_state(TASK_RUNNING);
241 spu_del_wq(wq, &wait, prio); 258 remove_wait_queue(&ctx->stop_wq, &wait);
242} 259}
243 260
244static void spu_prio_wakeup(void) 261/**
262 * spu_reschedule - try to find a runnable context for a spu
263 * @spu: spu available
264 *
265 * This function is called whenever a spu becomes idle. It looks for the
266 * most suitable runnable spu context and schedules it for execution.
267 */
268static void spu_reschedule(struct spu *spu)
245{ 269{
246 int best = sched_find_first_bit(spu_prio->bitmap); 270 int best;
271
272 spu_free(spu);
273
274 spin_lock(&spu_prio->runq_lock);
275 best = sched_find_first_bit(spu_prio->bitmap);
247 if (best < MAX_PRIO) { 276 if (best < MAX_PRIO) {
248 wait_queue_head_t *wq = &spu_prio->waitq[best]; 277 struct spu_context *ctx = spu_grab_context(best);
249 wake_up_interruptible_nr(wq, 1); 278 if (ctx)
279 wake_up(&ctx->stop_wq);
250 } 280 }
281 spin_unlock(&spu_prio->runq_lock);
251} 282}
252 283
253static struct spu *spu_get_idle(struct spu_context *ctx, u64 flags) 284static struct spu *spu_get_idle(struct spu_context *ctx)
254{ 285{
255 struct spu *spu = NULL; 286 struct spu *spu = NULL;
256 int node = cpu_to_node(raw_smp_processor_id()); 287 int node = cpu_to_node(raw_smp_processor_id());
@@ -267,15 +298,6 @@ static struct spu *spu_get_idle(struct spu_context *ctx, u64 flags)
267 return spu; 298 return spu;
268} 299}
269 300
270static inline struct spu *spu_get(struct spu_context *ctx, u64 flags)
271{
272 /* Future: spu_get_idle() if possible,
273 * otherwise try to preempt an active
274 * context.
275 */
276 return spu_get_idle(ctx, flags);
277}
278
279/* The three externally callable interfaces 301/* The three externally callable interfaces
280 * for the scheduler begin here. 302 * for the scheduler begin here.
281 * 303 *
@@ -284,32 +306,36 @@ static inline struct spu *spu_get(struct spu_context *ctx, u64 flags)
284 * spu_yield - yield an SPU if others are waiting. 306 * spu_yield - yield an SPU if others are waiting.
285 */ 307 */
286 308
309/**
310 * spu_activate - find a free spu for a context and execute it
311 * @ctx: spu context to schedule
312 * @flags: flags (currently ignored)
313 *
314 * Tries to find a free spu to run @ctx. If no free spu is availble
315 * add the context to the runqueue so it gets woken up once an spu
316 * is available.
317 */
287int spu_activate(struct spu_context *ctx, u64 flags) 318int spu_activate(struct spu_context *ctx, u64 flags)
288{ 319{
289 struct spu *spu;
290 int ret = 0;
291 320
292 for (;;) { 321 if (ctx->spu)
293 if (ctx->spu) 322 return 0;
294 return 0; 323
295 spu = spu_get(ctx, flags); 324 do {
296 if (spu != NULL) { 325 struct spu *spu;
297 if (ctx->spu != NULL) { 326
298 spu_free(spu); 327 spu = spu_get_idle(ctx);
299 spu_prio_wakeup(); 328 if (spu) {
300 break;
301 }
302 spu_bind_context(spu, ctx); 329 spu_bind_context(spu, ctx);
303 break; 330 return 0;
304 }
305 spu_prio_wait(ctx, flags);
306 if (signal_pending(current)) {
307 ret = -ERESTARTSYS;
308 spu_prio_wakeup();
309 break;
310 } 331 }
311 } 332
312 return ret; 333 spu_add_to_rq(ctx);
334 spu_prio_wait(ctx);
335 spu_del_from_rq(ctx);
336 } while (!signal_pending(current));
337
338 return -ERESTARTSYS;
313} 339}
314 340
315void spu_deactivate(struct spu_context *ctx) 341void spu_deactivate(struct spu_context *ctx)
@@ -321,10 +347,8 @@ void spu_deactivate(struct spu_context *ctx)
321 if (!spu) 347 if (!spu)
322 return; 348 return;
323 was_active = spu_unbind_context(spu, ctx); 349 was_active = spu_unbind_context(spu, ctx);
324 if (was_active) { 350 if (was_active)
325 spu_free(spu); 351 spu_reschedule(spu);
326 spu_prio_wakeup();
327 }
328} 352}
329 353
330void spu_yield(struct spu_context *ctx) 354void spu_yield(struct spu_context *ctx)
@@ -359,7 +383,7 @@ int __init spu_sched_init(void)
359 return 1; 383 return 1;
360 } 384 }
361 for (i = 0; i < MAX_PRIO; i++) { 385 for (i = 0; i < MAX_PRIO; i++) {
362 init_waitqueue_head(&spu_prio->waitq[i]); 386 INIT_LIST_HEAD(&spu_prio->runq[i]);
363 __clear_bit(i, spu_prio->bitmap); 387 __clear_bit(i, spu_prio->bitmap);
364 } 388 }
365 __set_bit(MAX_PRIO, spu_prio->bitmap); 389 __set_bit(MAX_PRIO, spu_prio->bitmap);
@@ -367,6 +391,7 @@ int __init spu_sched_init(void)
367 mutex_init(&spu_prio->active_mutex[i]); 391 mutex_init(&spu_prio->active_mutex[i]);
368 INIT_LIST_HEAD(&spu_prio->active_list[i]); 392 INIT_LIST_HEAD(&spu_prio->active_list[i]);
369 } 393 }
394 spin_lock_init(&spu_prio->runq_lock);
370 return 0; 395 return 0;
371} 396}
372 397
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index b500e94188b5..7f5a4fc03c00 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -76,6 +76,7 @@ struct spu_context {
76 struct spu_gang *gang; 76 struct spu_gang *gang;
77 77
78 /* scheduler fields */ 78 /* scheduler fields */
79 struct list_head rq;
79 int prio; 80 int prio;
80}; 81};
81 82