aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c133
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c3
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h1
3 files changed, 81 insertions, 56 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 010a51f59796..adb5abb9af5d 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -2426,38 +2426,48 @@ static inline int spufs_switch_log_avail(struct spu_context *ctx)
2426static int spufs_switch_log_open(struct inode *inode, struct file *file) 2426static int spufs_switch_log_open(struct inode *inode, struct file *file)
2427{ 2427{
2428 struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 2428 struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
2429 int rc;
2430
2431 rc = spu_acquire(ctx);
2432 if (rc)
2433 return rc;
2429 2434
2430 /*
2431 * We (ab-)use the mapping_lock here because it serves the similar
2432 * purpose for synchronizing open/close elsewhere. Maybe it should
2433 * be renamed eventually.
2434 */
2435 mutex_lock(&ctx->mapping_lock);
2436 if (ctx->switch_log) { 2435 if (ctx->switch_log) {
2437 spin_lock(&ctx->switch_log->lock); 2436 rc = -EBUSY;
2438 ctx->switch_log->head = 0; 2437 goto out;
2439 ctx->switch_log->tail = 0;
2440 spin_unlock(&ctx->switch_log->lock);
2441 } else {
2442 /*
2443 * We allocate the switch log data structures on first open.
2444 * They will never be free because we assume a context will
2445 * be traced until it goes away.
2446 */
2447 ctx->switch_log = kzalloc(sizeof(struct switch_log) +
2448 SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry),
2449 GFP_KERNEL);
2450 if (!ctx->switch_log)
2451 goto out;
2452 spin_lock_init(&ctx->switch_log->lock);
2453 init_waitqueue_head(&ctx->switch_log->wait);
2454 } 2438 }
2455 mutex_unlock(&ctx->mapping_lock); 2439
2440 ctx->switch_log = kzalloc(sizeof(struct switch_log) +
2441 SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry),
2442 GFP_KERNEL);
2443
2444 if (!ctx->switch_log) {
2445 rc = -ENOMEM;
2446 goto out;
2447 }
2448
2449 init_waitqueue_head(&ctx->switch_log->wait);
2450 rc = 0;
2451
2452out:
2453 spu_release(ctx);
2454 return rc;
2455}
2456
2457static int spufs_switch_log_release(struct inode *inode, struct file *file)
2458{
2459 struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
2460 int rc;
2461
2462 rc = spu_acquire(ctx);
2463 if (rc)
2464 return rc;
2465
2466 kfree(ctx->switch_log);
2467 ctx->switch_log = NULL;
2468 spu_release(ctx);
2456 2469
2457 return 0; 2470 return 0;
2458 out:
2459 mutex_unlock(&ctx->mapping_lock);
2460 return -ENOMEM;
2461} 2471}
2462 2472
2463static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) 2473static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n)
@@ -2485,42 +2495,46 @@ static ssize_t spufs_switch_log_read(struct file *file, char __user *buf,
2485 if (!buf || len < 0) 2495 if (!buf || len < 0)
2486 return -EINVAL; 2496 return -EINVAL;
2487 2497
2498 error = spu_acquire(ctx);
2499 if (error)
2500 return error;
2501
2488 while (cnt < len) { 2502 while (cnt < len) {
2489 char tbuf[128]; 2503 char tbuf[128];
2490 int width; 2504 int width;
2491 2505
2492 if (file->f_flags & O_NONBLOCK) { 2506 if (file->f_flags & O_NONBLOCK) {
2493 if (spufs_switch_log_used(ctx) <= 0) 2507 if (spufs_switch_log_used(ctx) == 0) {
2494 return cnt ? cnt : -EAGAIN; 2508 error = -EAGAIN;
2509 break;
2510 }
2495 } else { 2511 } else {
2496 /* Wait for data in buffer */ 2512 /* spufs_wait will drop the mutex and re-acquire,
2497 error = wait_event_interruptible(ctx->switch_log->wait, 2513 * but since we're in read(), the file cannot be
2514 * _released (and so ctx->switch_log is stable).
2515 */
2516 error = spufs_wait(ctx->switch_log->wait,
2498 spufs_switch_log_used(ctx) > 0); 2517 spufs_switch_log_used(ctx) > 0);
2518
2519 /* On error, spufs_wait returns without the
2520 * state mutex held */
2499 if (error) 2521 if (error)
2500 break; 2522 return error;
2501 } 2523 }
2502 2524
2503 spin_lock(&ctx->switch_log->lock); 2525 /* We may have had entries read from underneath us while we
2504 if (ctx->switch_log->head == ctx->switch_log->tail) { 2526 * dropped the mutex in spufs_wait, so re-check */
2505 /* multiple readers race? */ 2527 if (ctx->switch_log->head == ctx->switch_log->tail)
2506 spin_unlock(&ctx->switch_log->lock);
2507 continue; 2528 continue;
2508 }
2509 2529
2510 width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); 2530 width = switch_log_sprint(ctx, tbuf, sizeof(tbuf));
2511 if (width < len) { 2531 if (width < len)
2512 ctx->switch_log->tail = 2532 ctx->switch_log->tail =
2513 (ctx->switch_log->tail + 1) % 2533 (ctx->switch_log->tail + 1) %
2514 SWITCH_LOG_BUFSIZE; 2534 SWITCH_LOG_BUFSIZE;
2515 } 2535 else
2516 2536 /* If the record is greater than space available return
2517 spin_unlock(&ctx->switch_log->lock); 2537 * partial buffer (so far) */
2518
2519 /*
2520 * If the record is greater than space available return
2521 * partial buffer (so far)
2522 */
2523 if (width >= len)
2524 break; 2538 break;
2525 2539
2526 error = copy_to_user(buf + cnt, tbuf, width); 2540 error = copy_to_user(buf + cnt, tbuf, width);
@@ -2529,6 +2543,8 @@ static ssize_t spufs_switch_log_read(struct file *file, char __user *buf,
2529 cnt += width; 2543 cnt += width;
2530 } 2544 }
2531 2545
2546 spu_release(ctx);
2547
2532 return cnt == 0 ? error : cnt; 2548 return cnt == 0 ? error : cnt;
2533} 2549}
2534 2550
@@ -2537,29 +2553,41 @@ static unsigned int spufs_switch_log_poll(struct file *file, poll_table *wait)
2537 struct inode *inode = file->f_path.dentry->d_inode; 2553 struct inode *inode = file->f_path.dentry->d_inode;
2538 struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 2554 struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
2539 unsigned int mask = 0; 2555 unsigned int mask = 0;
2556 int rc;
2540 2557
2541 poll_wait(file, &ctx->switch_log->wait, wait); 2558 poll_wait(file, &ctx->switch_log->wait, wait);
2542 2559
2560 rc = spu_acquire(ctx);
2561 if (rc)
2562 return rc;
2563
2543 if (spufs_switch_log_used(ctx) > 0) 2564 if (spufs_switch_log_used(ctx) > 0)
2544 mask |= POLLIN; 2565 mask |= POLLIN;
2545 2566
2567 spu_release(ctx);
2568
2546 return mask; 2569 return mask;
2547} 2570}
2548 2571
2549static const struct file_operations spufs_switch_log_fops = { 2572static const struct file_operations spufs_switch_log_fops = {
2550 .owner = THIS_MODULE, 2573 .owner = THIS_MODULE,
2551 .open = spufs_switch_log_open, 2574 .open = spufs_switch_log_open,
2552 .read = spufs_switch_log_read, 2575 .read = spufs_switch_log_read,
2553 .poll = spufs_switch_log_poll, 2576 .poll = spufs_switch_log_poll,
2577 .release = spufs_switch_log_release,
2554}; 2578};
2555 2579
2580/**
2581 * Log a context switch event to a switch log reader.
2582 *
2583 * Must be called with ctx->state_mutex held.
2584 */
2556void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, 2585void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx,
2557 u32 type, u32 val) 2586 u32 type, u32 val)
2558{ 2587{
2559 if (!ctx->switch_log) 2588 if (!ctx->switch_log)
2560 return; 2589 return;
2561 2590
2562 spin_lock(&ctx->switch_log->lock);
2563 if (spufs_switch_log_avail(ctx) > 1) { 2591 if (spufs_switch_log_avail(ctx) > 1) {
2564 struct switch_log_entry *p; 2592 struct switch_log_entry *p;
2565 2593
@@ -2573,7 +2601,6 @@ void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx,
2573 ctx->switch_log->head = 2601 ctx->switch_log->head =
2574 (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE; 2602 (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE;
2575 } 2603 }
2576 spin_unlock(&ctx->switch_log->lock);
2577 2604
2578 wake_up(&ctx->switch_log->wait); 2605 wake_up(&ctx->switch_log->wait);
2579} 2606}
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index c9bb7cfd3dca..c58bd36b0c5b 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -249,6 +249,7 @@ static int spu_run_fini(struct spu_context *ctx, u32 *npc,
249 249
250 spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); 250 spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
251 clear_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags); 251 clear_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags);
252 spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, *status);
252 spu_release(ctx); 253 spu_release(ctx);
253 254
254 if (signal_pending(current)) 255 if (signal_pending(current))
@@ -417,8 +418,6 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
417 ret = spu_run_fini(ctx, npc, &status); 418 ret = spu_run_fini(ctx, npc, &status);
418 spu_yield(ctx); 419 spu_yield(ctx);
419 420
420 spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, status);
421
422 if ((status & SPU_STATUS_STOPPED_BY_STOP) && 421 if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
423 (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) 422 (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100))
424 ctx->stats.libassist++; 423 ctx->stats.libassist++;
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 8ae8ef9dfc22..15c62d3ca129 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -65,7 +65,6 @@ enum {
65}; 65};
66 66
67struct switch_log { 67struct switch_log {
68 spinlock_t lock;
69 wait_queue_head_t wait; 68 wait_queue_head_t wait;
70 unsigned long head; 69 unsigned long head;
71 unsigned long tail; 70 unsigned long tail;