[POWERPC] spufs: add infrastructure for finding elf objects
authorArnd Bergmann <arnd@arndb.de>
Wed, 4 Oct 2006 15:26:21 +0000 (17:26 +0200)
committerPaul Mackerras <paulus@samba.org>
Wed, 4 Oct 2006 23:21:02 +0000 (09:21 +1000)
This adds an 'object-id' file that the spe library can
use to store a pointer to its ELF object. This was
originally meant for use by oprofile, but is now
also used by the GNU debugger, if available.

In order for oprofile to find the location in an spu-elf
binary where an event counter triggered, we need a way
to identify the binary in the first place.

Unfortunately, that binary itself can be embedded in a
powerpc ELF binary. Since we can assume it is mapped into
the effective address space of the running process,
have that one write the pointer value into a new spufs
file.

When a context switch occurs, pass the user value to
the profiler so that can look at the mapped file (with
some care).

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spufs.h
include/asm-powerpc/spu.h

index e2c9d48a68047730a4039748916fdd6adda55bdc..e0d730045260aeb00e399024485af2197fb39bd2 100644 (file)
@@ -1487,6 +1487,21 @@ static u64 spufs_id_get(void *data)
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n")
 
+static u64 spufs_object_id_get(void *data)
+{
+       struct spu_context *ctx = data;
+       return ctx->object_id;
+}
+
+static void spufs_object_id_set(void *data, u64 id)
+{
+       struct spu_context *ctx = data;
+       ctx->object_id = id;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get,
+               spufs_object_id_set, "0x%llx\n");
+
 struct tree_descr spufs_dir_contents[] = {
        { "mem",  &spufs_mem_fops,  0666, },
        { "regs", &spufs_regs_fops,  0666, },
@@ -1510,7 +1525,8 @@ struct tree_descr spufs_dir_contents[] = {
        { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
        { "event_mask", &spufs_event_mask_ops, 0666, },
        { "srr0", &spufs_srr0_ops, 0666, },
-       { "phys-id", &spufs_id_ops, 0666, },
        { "psmap", &spufs_psmap_fops, 0666, },
+       { "phys-id", &spufs_id_ops, 0666, },
+       { "object-id", &spufs_object_id_ops, 0666, },
        {},
 };
index a824b605116431402aa1ba6f38d68bb6436b656b..bd6fe4b7a84baab84face56b2d8ca5f5c263db2e 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/unistd.h>
 #include <linux/numa.h>
 #include <linux/mutex.h>
+#include <linux/notifier.h>
 
 #include <asm/io.h>
 #include <asm/mmu_context.h>
@@ -75,6 +76,25 @@ static inline void mm_needs_global_tlbie(struct mm_struct *mm)
        __cpus_setall(&mm->cpu_vm_mask, nr);
 }
 
+static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
+
+static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
+{
+       blocking_notifier_call_chain(&spu_switch_notifier,
+                           ctx ? ctx->object_id : 0, spu);
+}
+
+int spu_switch_event_register(struct notifier_block * n)
+{
+       return blocking_notifier_chain_register(&spu_switch_notifier, n);
+}
+
+int spu_switch_event_unregister(struct notifier_block * n)
+{
+       return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
+}
+
+
 static inline void bind_context(struct spu *spu, struct spu_context *ctx)
 {
        pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
@@ -97,12 +117,14 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
        spu_restore(&ctx->csa, spu);
        spu->timestamp = jiffies;
        spu_cpu_affinity_set(spu, raw_smp_processor_id());
+       spu_switch_notify(spu, ctx);
 }
 
 static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
 {
        pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
                 spu->pid, spu->number, spu->node);
+       spu_switch_notify(spu, NULL);
        spu_unmap_mappings(ctx);
        spu_save(&ctx->csa, spu);
        spu->timestamp = jiffies;
index f6624ceedf70c4ee0a387d58222daf621ca5a5a0..a0f55ca2d488322c1165a82b647eb4196a13d872 100644 (file)
@@ -50,6 +50,7 @@ struct spu_context {
        struct address_space *cntl;        /* 'control' area mappings. */
        struct address_space *signal1;     /* 'signal1' area mappings. */
        struct address_space *signal2;     /* 'signal2' area mappings. */
+       u64 object_id;             /* user space pointer for oprofile */
 
        enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
        struct rw_semaphore state_sema;
index 83b6dae48efcad514b34aa6ab6d44949944509c9..e73ea00efd8b2ea7917a9820edbd94225b695cb6 100644 (file)
@@ -200,6 +200,24 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls)
 #endif /* MODULE */
 
 
+/*
+ * Notifier blocks:
+ *
+ * oprofile can get notified when a context switch is performed
+ * on an spe. The notifer function that gets called is passed
+ * a pointer to the SPU structure as well as the object-id that
+ * identifies the binary running on that SPU now.
+ *
+ * For a context save, the object-id that is passed is zero,
+ * identifying that the kernel will run from that moment on.
+ *
+ * For a context restore, the object-id is the value written
+ * to object-id spufs file from user space and the notifer
+ * function can assume that spu->ctx is valid.
+ */
+int spu_switch_event_register(struct notifier_block * n);
+int spu_switch_event_unregister(struct notifier_block * n);
+
 /*
  * This defines the Local Store, Problem Area and Privlege Area of an SPU.
  */