aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
parent822252521651ad74a6d41e712d790e2f10838a67 (diff)
parentd0eb801c60c20c2fbfc70e677415122798c472d2 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jk/spufs
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/cell/spufs/.gitignore2
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c166
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h33
-rw-r--r--arch/powerpc/platforms/cell/spufs/sputrace.c36
7 files changed, 226 insertions, 21 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/.gitignore b/arch/powerpc/platforms/cell/spufs/.gitignore
new file mode 100644
index 000000000000..a09ee8d84d6c
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/.gitignore
@@ -0,0 +1,2 @@
1spu_save_dump.h
2spu_restore_dump.h
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 0ad83aeb70b1..177735f79317 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -78,6 +78,7 @@ void destroy_spu_context(struct kref *kref)
78{ 78{
79 struct spu_context *ctx; 79 struct spu_context *ctx;
80 ctx = container_of(kref, struct spu_context, kref); 80 ctx = container_of(kref, struct spu_context, kref);
81 spu_context_nospu_trace(destroy_spu_context__enter, ctx);
81 mutex_lock(&ctx->state_mutex); 82 mutex_lock(&ctx->state_mutex);
82 spu_deactivate(ctx); 83 spu_deactivate(ctx);
83 mutex_unlock(&ctx->state_mutex); 84 mutex_unlock(&ctx->state_mutex);
@@ -88,6 +89,7 @@ void destroy_spu_context(struct kref *kref)
88 kref_put(ctx->prof_priv_kref, ctx->prof_priv_release); 89 kref_put(ctx->prof_priv_kref, ctx->prof_priv_release);
89 BUG_ON(!list_empty(&ctx->rq)); 90 BUG_ON(!list_empty(&ctx->rq));
90 atomic_dec(&nr_spu_contexts); 91 atomic_dec(&nr_spu_contexts);
92 kfree(ctx->switch_log);
91 kfree(ctx); 93 kfree(ctx);
92} 94}
93 95
@@ -150,6 +152,8 @@ int spu_acquire_saved(struct spu_context *ctx)
150{ 152{
151 int ret; 153 int ret;
152 154
155 spu_context_nospu_trace(spu_acquire_saved__enter, ctx);
156
153 ret = spu_acquire(ctx); 157 ret = spu_acquire(ctx);
154 if (ret) 158 if (ret)
155 return ret; 159 return ret;
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
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 96bf7c2b86fc..a9c35b7b719f 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -405,6 +405,8 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
405 ret = spu_run_fini(ctx, npc, &status); 405 ret = spu_run_fini(ctx, npc, &status);
406 spu_yield(ctx); 406 spu_yield(ctx);
407 407
408 spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, status);
409
408 if ((status & SPU_STATUS_STOPPED_BY_STOP) && 410 if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
409 (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) 411 (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100))
410 ctx->stats.libassist++; 412 ctx->stats.libassist++;
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 00528ef84ad2..62280c292aac 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -240,6 +240,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
240 spu->mfc_callback = spufs_mfc_callback; 240 spu->mfc_callback = spufs_mfc_callback;
241 mb(); 241 mb();
242 spu_unmap_mappings(ctx); 242 spu_unmap_mappings(ctx);
243 spu_switch_log_notify(spu, ctx, SWITCH_LOG_START, 0);
243 spu_restore(&ctx->csa, spu); 244 spu_restore(&ctx->csa, spu);
244 spu->timestamp = jiffies; 245 spu->timestamp = jiffies;
245 spu_cpu_affinity_set(spu, raw_smp_processor_id()); 246 spu_cpu_affinity_set(spu, raw_smp_processor_id());
@@ -419,6 +420,7 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
419 spu_switch_notify(spu, NULL); 420 spu_switch_notify(spu, NULL);
420 spu_unmap_mappings(ctx); 421 spu_unmap_mappings(ctx);
421 spu_save(&ctx->csa, spu); 422 spu_save(&ctx->csa, spu);
423 spu_switch_log_notify(spu, ctx, SWITCH_LOG_STOP, 0);
422 spu->timestamp = jiffies; 424 spu->timestamp = jiffies;
423 ctx->state = SPU_STATE_SAVED; 425 ctx->state = SPU_STATE_SAVED;
424 spu->ibox_callback = NULL; 426 spu->ibox_callback = NULL;
@@ -591,7 +593,7 @@ static struct spu *find_victim(struct spu_context *ctx)
591 struct spu *spu; 593 struct spu *spu;
592 int node, n; 594 int node, n;
593 595
594 spu_context_nospu_trace(spu_find_vitim__enter, ctx); 596 spu_context_nospu_trace(spu_find_victim__enter, ctx);
595 597
596 /* 598 /*
597 * Look for a possible preemption candidate on the local node first. 599 * Look for a possible preemption candidate on the local node first.
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index cdc515182f82..7312745b7540 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -47,6 +47,30 @@ enum {
47 SPU_SCHED_SPU_RUN, /* context is within spu_run */ 47 SPU_SCHED_SPU_RUN, /* context is within spu_run */
48}; 48};
49 49
50enum {
51 SWITCH_LOG_BUFSIZE = 4096,
52};
53
54enum {
55 SWITCH_LOG_START,
56 SWITCH_LOG_STOP,
57 SWITCH_LOG_EXIT,
58};
59
60struct switch_log {
61 spinlock_t lock;
62 wait_queue_head_t wait;
63 unsigned long head;
64 unsigned long tail;
65 struct switch_log_entry {
66 struct timespec tstamp;
67 s32 spu_id;
68 u32 type;
69 u32 val;
70 u64 timebase;
71 } log[];
72};
73
50struct spu_context { 74struct spu_context {
51 struct spu *spu; /* pointer to a physical SPU */ 75 struct spu *spu; /* pointer to a physical SPU */
52 struct spu_state csa; /* SPU context save area. */ 76 struct spu_state csa; /* SPU context save area. */
@@ -116,6 +140,9 @@ struct spu_context {
116 unsigned long long libassist; 140 unsigned long long libassist;
117 } stats; 141 } stats;
118 142
143 /* context switch log */
144 struct switch_log *switch_log;
145
119 struct list_head aff_list; 146 struct list_head aff_list;
120 int aff_head; 147 int aff_head;
121 int aff_offset; 148 int aff_offset;
@@ -256,6 +283,8 @@ int spu_activate(struct spu_context *ctx, unsigned long flags);
256void spu_deactivate(struct spu_context *ctx); 283void spu_deactivate(struct spu_context *ctx);
257void spu_yield(struct spu_context *ctx); 284void spu_yield(struct spu_context *ctx);
258void spu_switch_notify(struct spu *spu, struct spu_context *ctx); 285void spu_switch_notify(struct spu *spu, struct spu_context *ctx);
286void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx,
287 u32 type, u32 val);
259void spu_set_timeslice(struct spu_context *ctx); 288void spu_set_timeslice(struct spu_context *ctx);
260void spu_update_sched_info(struct spu_context *ctx); 289void spu_update_sched_info(struct spu_context *ctx);
261void __spu_update_sched_info(struct spu_context *ctx); 290void __spu_update_sched_info(struct spu_context *ctx);
@@ -330,8 +359,8 @@ extern void spuctx_switch_state(struct spu_context *ctx,
330 enum spu_utilization_state new_state); 359 enum spu_utilization_state new_state);
331 360
332#define spu_context_trace(name, ctx, spu) \ 361#define spu_context_trace(name, ctx, spu) \
333 trace_mark(name, "%p %p", ctx, spu); 362 trace_mark(name, "ctx %p spu %p", ctx, spu);
334#define spu_context_nospu_trace(name, ctx) \ 363#define spu_context_nospu_trace(name, ctx) \
335 trace_mark(name, "%p", ctx); 364 trace_mark(name, "ctx %p", ctx);
336 365
337#endif 366#endif
diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c
index 79aa773f3c99..b9c79eda3359 100644
--- a/arch/powerpc/platforms/cell/spufs/sputrace.c
+++ b/arch/powerpc/platforms/cell/spufs/sputrace.c
@@ -171,24 +171,24 @@ static void spu_context_nospu_event(void *probe_private, void *call_data,
171} 171}
172 172
173struct spu_probe spu_probes[] = { 173struct spu_probe spu_probes[] = {
174 { "spu_bind_context__enter", "%p %p", spu_context_event }, 174 { "spu_bind_context__enter", "ctx %p spu %p", spu_context_event },
175 { "spu_unbind_context__enter", "%p %p", spu_context_event }, 175 { "spu_unbind_context__enter", "ctx %p spu %p", spu_context_event },
176 { "spu_get_idle__enter", "%p", spu_context_nospu_event }, 176 { "spu_get_idle__enter", "ctx %p", spu_context_nospu_event },
177 { "spu_get_idle__found", "%p %p", spu_context_event }, 177 { "spu_get_idle__found", "ctx %p spu %p", spu_context_event },
178 { "spu_get_idle__not_found", "%p", spu_context_nospu_event }, 178 { "spu_get_idle__not_found", "ctx %p", spu_context_nospu_event },
179 { "spu_find_victim__enter", "%p", spu_context_nospu_event }, 179 { "spu_find_victim__enter", "ctx %p", spu_context_nospu_event },
180 { "spusched_tick__preempt", "%p %p", spu_context_event }, 180 { "spusched_tick__preempt", "ctx %p spu %p", spu_context_event },
181 { "spusched_tick__newslice", "%p", spu_context_nospu_event }, 181 { "spusched_tick__newslice", "ctx %p", spu_context_nospu_event },
182 { "spu_yield__enter", "%p", spu_context_nospu_event }, 182 { "spu_yield__enter", "ctx %p", spu_context_nospu_event },
183 { "spu_deactivate__enter", "%p", spu_context_nospu_event }, 183 { "spu_deactivate__enter", "ctx %p", spu_context_nospu_event },
184 { "__spu_deactivate__unload", "%p %p", spu_context_event }, 184 { "__spu_deactivate__unload", "ctx %p spu %p", spu_context_event },
185 { "spufs_ps_nopfn__enter", "%p", spu_context_nospu_event }, 185 { "spufs_ps_nopfn__enter", "ctx %p", spu_context_nospu_event },
186 { "spufs_ps_nopfn__sleep", "%p", spu_context_nospu_event }, 186 { "spufs_ps_nopfn__sleep", "ctx %p", spu_context_nospu_event },
187 { "spufs_ps_nopfn__wake", "%p %p", spu_context_event }, 187 { "spufs_ps_nopfn__wake", "ctx %p spu %p", spu_context_event },
188 { "spufs_ps_nopfn__insert", "%p %p", spu_context_event }, 188 { "spufs_ps_nopfn__insert", "ctx %p spu %p", spu_context_event },
189 { "spu_acquire_saved__enter", "%p", spu_context_nospu_event }, 189 { "spu_acquire_saved__enter", "ctx %p", spu_context_nospu_event },
190 { "destroy_spu_context__enter", "%p", spu_context_nospu_event }, 190 { "destroy_spu_context__enter", "ctx %p", spu_context_nospu_event },
191 { "spufs_stop_callback__enter", "%p %p", spu_context_event }, 191 { "spufs_stop_callback__enter", "ctx %p spu %p", spu_context_event },
192}; 192};
193 193
194static int __init sputrace_init(void) 194static int __init sputrace_init(void)