aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/cell/spufs/file.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2008-04-30 02:53:17 -0400
committerPaul Mackerras <paulus@samba.org>2008-04-30 02:53:17 -0400
commit595f403c1af37b1339e64b89040528b8cd48c5a3 (patch)
tree8729b820299b8090f476c1fcdd8441b19f7e6c74 /arch/powerpc/platforms/cell/spufs/file.c
parent822252521651ad74a6d41e712d790e2f10838a67 (diff)
parentd0eb801c60c20c2fbfc70e677415122798c472d2 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jk/spufs
Diffstat (limited to 'arch/powerpc/platforms/cell/spufs/file.c')
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 08f44d1971ac..80911a373400 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -2386,6 +2386,171 @@ static const struct file_operations spufs_stat_fops = {
2386 .release = single_release, 2386 .release = single_release,
2387}; 2387};
2388 2388
2389static inline int spufs_switch_log_used(struct spu_context *ctx)
2390{
2391 return (ctx->switch_log->head - ctx->switch_log->tail) %
2392 SWITCH_LOG_BUFSIZE;
2393}
2394
2395static inline int spufs_switch_log_avail(struct spu_context *ctx)
2396{
2397 return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx);
2398}
2399
2400static int spufs_switch_log_open(struct inode *inode, struct file *file)
2401{
2402 struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
2403
2404 /*
2405 * We (ab-)use the mapping_lock here because it serves the similar
2406 * purpose for synchronizing open/close elsewhere. Maybe it should
2407 * be renamed eventually.
2408 */
2409 mutex_lock(&ctx->mapping_lock);
2410 if (ctx->switch_log) {
2411 spin_lock(&ctx->switch_log->lock);
2412 ctx->switch_log->head = 0;
2413 ctx->switch_log->tail = 0;
2414 spin_unlock(&ctx->switch_log->lock);
2415 } else {
2416 /*
2417 * We allocate the switch log data structures on first open.
2418 * They will never be free because we assume a context will
2419 * be traced until it goes away.
2420 */
2421 ctx->switch_log = kzalloc(sizeof(struct switch_log) +
2422 SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry),
2423 GFP_KERNEL);
2424 if (!ctx->switch_log)
2425 goto out;
2426 spin_lock_init(&ctx->switch_log->lock);
2427 init_waitqueue_head(&ctx->switch_log->wait);
2428 }
2429 mutex_unlock(&ctx->mapping_lock);
2430
2431 return 0;
2432 out:
2433 mutex_unlock(&ctx->mapping_lock);
2434 return -ENOMEM;
2435}
2436
2437static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n)
2438{
2439 struct switch_log_entry *p;
2440
2441 p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE;
2442
2443 return snprintf(tbuf, n, "%u.%09u %d %u %u %llu\n",
2444 (unsigned int) p->tstamp.tv_sec,
2445 (unsigned int) p->tstamp.tv_nsec,
2446 p->spu_id,
2447 (unsigned int) p->type,
2448 (unsigned int) p->val,
2449 (unsigned long long) p->timebase);
2450}
2451
2452static ssize_t spufs_switch_log_read(struct file *file, char __user *buf,
2453 size_t len, loff_t *ppos)
2454{
2455 struct inode *inode = file->f_path.dentry->d_inode;
2456 struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
2457 int error = 0, cnt = 0;
2458
2459 if (!buf || len < 0)
2460 return -EINVAL;
2461
2462 while (cnt < len) {
2463 char tbuf[128];
2464 int width;
2465
2466 if (file->f_flags & O_NONBLOCK) {
2467 if (spufs_switch_log_used(ctx) <= 0)
2468 return cnt ? cnt : -EAGAIN;
2469 } else {
2470 /* Wait for data in buffer */
2471 error = wait_event_interruptible(ctx->switch_log->wait,
2472 spufs_switch_log_used(ctx) > 0);
2473 if (error)
2474 break;
2475 }
2476
2477 spin_lock(&ctx->switch_log->lock);
2478 if (ctx->switch_log->head == ctx->switch_log->tail) {
2479 /* multiple readers race? */
2480 spin_unlock(&ctx->switch_log->lock);
2481 continue;
2482 }
2483
2484 width = switch_log_sprint(ctx, tbuf, sizeof(tbuf));
2485 if (width < len) {
2486 ctx->switch_log->tail =
2487 (ctx->switch_log->tail + 1) %
2488 SWITCH_LOG_BUFSIZE;
2489 }
2490
2491 spin_unlock(&ctx->switch_log->lock);
2492
2493 /*
2494 * If the record is greater than space available return
2495 * partial buffer (so far)
2496 */
2497 if (width >= len)
2498 break;
2499
2500 error = copy_to_user(buf + cnt, tbuf, width);
2501 if (error)
2502 break;
2503 cnt += width;
2504 }
2505
2506 return cnt == 0 ? error : cnt;
2507}
2508
2509static unsigned int spufs_switch_log_poll(struct file *file, poll_table *wait)
2510{
2511 struct inode *inode = file->f_path.dentry->d_inode;
2512 struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
2513 unsigned int mask = 0;
2514
2515 poll_wait(file, &ctx->switch_log->wait, wait);
2516
2517 if (spufs_switch_log_used(ctx) > 0)
2518 mask |= POLLIN;
2519
2520 return mask;
2521}
2522
2523static const struct file_operations spufs_switch_log_fops = {
2524 .owner = THIS_MODULE,
2525 .open = spufs_switch_log_open,
2526 .read = spufs_switch_log_read,
2527 .poll = spufs_switch_log_poll,
2528};
2529
2530void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx,
2531 u32 type, u32 val)
2532{
2533 if (!ctx->switch_log)
2534 return;
2535
2536 spin_lock(&ctx->switch_log->lock);
2537 if (spufs_switch_log_avail(ctx) > 1) {
2538 struct switch_log_entry *p;
2539
2540 p = ctx->switch_log->log + ctx->switch_log->head;
2541 ktime_get_ts(&p->tstamp);
2542 p->timebase = get_tb();
2543 p->spu_id = spu ? spu->number : -1;
2544 p->type = type;
2545 p->val = val;
2546
2547 ctx->switch_log->head =
2548 (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE;
2549 }
2550 spin_unlock(&ctx->switch_log->lock);
2551
2552 wake_up(&ctx->switch_log->wait);
2553}
2389 2554
2390struct tree_descr spufs_dir_contents[] = { 2555struct tree_descr spufs_dir_contents[] = {
2391 { "capabilities", &spufs_caps_fops, 0444, }, 2556 { "capabilities", &spufs_caps_fops, 0444, },
@@ -2422,6 +2587,7 @@ struct tree_descr spufs_dir_contents[] = {
2422 { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, 2587 { "proxydma_info", &spufs_proxydma_info_fops, 0444, },
2423 { "tid", &spufs_tid_fops, 0444, }, 2588 { "tid", &spufs_tid_fops, 0444, },
2424 { "stat", &spufs_stat_fops, 0444, }, 2589 { "stat", &spufs_stat_fops, 0444, },
2590 { "switch_log", &spufs_switch_log_fops, 0444 },
2425 {}, 2591 {},
2426}; 2592};
2427 2593