diff options
author | Paul Mackerras <paulus@samba.org> | 2008-04-30 02:53:17 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-04-30 02:53:17 -0400 |
commit | 595f403c1af37b1339e64b89040528b8cd48c5a3 (patch) | |
tree | 8729b820299b8090f476c1fcdd8441b19f7e6c74 /arch/powerpc/platforms/cell/spufs/file.c | |
parent | 822252521651ad74a6d41e712d790e2f10838a67 (diff) | |
parent | d0eb801c60c20c2fbfc70e677415122798c472d2 (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.c | 166 |
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 | ||
2389 | static 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 | |||
2395 | static inline int spufs_switch_log_avail(struct spu_context *ctx) | ||
2396 | { | ||
2397 | return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx); | ||
2398 | } | ||
2399 | |||
2400 | static 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 | |||
2437 | static 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 | |||
2452 | static 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 | |||
2509 | static 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 | |||
2523 | static 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 | |||
2530 | void 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 | ||
2390 | struct tree_descr spufs_dir_contents[] = { | 2555 | struct 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 | ||