diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 133 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/run.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 1 |
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) | |||
2426 | static int spufs_switch_log_open(struct inode *inode, struct file *file) | 2426 | static 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 | |||
2452 | out: | ||
2453 | spu_release(ctx); | ||
2454 | return rc; | ||
2455 | } | ||
2456 | |||
2457 | static 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 | ||
2463 | static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) | 2473 | static 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 | ||
2549 | static const struct file_operations spufs_switch_log_fops = { | 2572 | static 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 | */ | ||
2556 | void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, | 2585 | void 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 | ||
67 | struct switch_log { | 67 | struct 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; |