linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/22] Cell patches for 2.6.20
@ 2006-11-20 17:44 Arnd Bergmann
  2006-11-20 17:44 ` [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable() Arnd Bergmann
                   ` (21 more replies)
  0 siblings, 22 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:44 UTC (permalink / raw)
  To: cbe-oss-dev; +Cc: linuxppc-dev, linux-kernel, Paul Mackerras

I'm trying to flush my patch queue again for 2.6.20, this is
most of what has been coming in since the last submission
to powerpc.git. Please review for inclusion in powerpc.git.

As a quick overview, the patches contain:

* new spufs file interfaces to support more gdb functionality,
  to look into the state of various HW registers without changing
  data.
* core dump support for SPUs. When core dumping a task that has
  created SPU contexts, information about them will be included
  in the dump.
* A rework of the SPU HW isolation support. Reusing an isolated
  SPU for another program now doesn't require a new spufs interface
  any more, which simplifies the implementation significantly.
* A new oprofile model for using the profile event mechanism on
  the Cell Broadband Engine. This is only for PPE profiling so far,
  profiling SPU code is still work-in-progress.
* Lots of bug fixes.

I have some other patches in my cell kernel tree currently, which
I'm not submitting myself, because I assume they will find their own
way into the kernel:
* Patches to the spidernet driver, these go through netdev
* Support for the Playstation 3, the patches are currently under
  discussion, and I expect that Paul will take them directly once
  they are done.
* xmon add-ons for debugging with SPUs. Waiting for a new version
  to be submitted.

	Arnd <><


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable()
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
@ 2006-11-20 17:44 ` Arnd Bergmann
  2006-11-20 21:59   ` Paul Mackerras
  2006-11-21  0:53   ` Benjamin Herrenschmidt
  2006-11-20 17:44 ` [PATCH 02/22] powerpc: change ppc_rtas declaration to weak Arnd Bergmann
                   ` (20 subsequent siblings)
  21 siblings, 2 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:44 UTC (permalink / raw)
  To: cbe-oss-dev; +Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Arnd Bergmann

[-- Attachment #1: idle-hard-irq-disable.diff --]
[-- Type: text/plain, Size: 1266 bytes --]

I got a bug report that I believe might be fixed by this
patch. The problem seems to be that with soft-disabled
interrupts in power_save, we can still get external exceptions
on Cell, even if we are in pause(0) a.k.a. sleep state.

When the CPU really wakes up through the 0x100 (system reset)
vector, while we have already started processing the 0x500
(external) exception, we get a panic in unrecoverable_exception()
because of the lost state.

This occurred in Systemsim for Cell, but as far as I can see,
it can theoretically occur on any machine that uses the
system reset exception to get out of sleep state.

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/kernel/idle.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/idle.c
+++ linux-2.6/arch/powerpc/kernel/idle.c
@@ -66,13 +66,13 @@ void cpu_idle(void)
 				 * is ordered w.r.t. need_resched() test.
 				 */
 				smp_mb();
-				local_irq_disable();
+				hard_irq_disable();
 
 				/* check again after disabling irqs */
 				if (!need_resched() && !cpu_should_die())
 					ppc_md.power_save();
 
-				local_irq_enable();
+				hard_irq_enable();
 				set_thread_flag(TIF_POLLING_NRFLAG);
 
 			} else {

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 02/22] powerpc: change ppc_rtas declaration to weak
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
  2006-11-20 17:44 ` [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable() Arnd Bergmann
@ 2006-11-20 17:44 ` Arnd Bergmann
  2006-11-20 17:44 ` [PATCH 03/22] spufs: Change %llx to 0x%llx Arnd Bergmann
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:44 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Geoff Levand, Arnd Bergmann

[-- Attachment #1: spufs-fix-weak-symbols-3.diff --]
[-- Type: text/plain, Size: 1638 bytes --]

From: Geoff Levand <geoffrey.levand@am.sony.com>
Change the definition of powerpc's cond_syscall() to use the standard gcc
weak attribute specifier which provides proper support for C linkage as
needed by spu_syscall_table[].

Fixes this powerpc build error with CONFIG_SPU_FS=y, CONFIG_PPC_RTAS=n:

 arch/powerpc/platforms/built-in.o: undefined reference to `ppc_rtas'


Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---

 include/asm-powerpc/unistd.h |   12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

Index: linux-2.6/include/asm-powerpc/unistd.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/unistd.h
+++ linux-2.6/include/asm-powerpc/unistd.h
@@ -446,7 +446,6 @@ type name(type1 arg1, type2 arg2, type3 
 #include <linux/types.h>
 #include <linux/compiler.h>
 #include <linux/linkage.h>
-#include <asm/syscalls.h>
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
@@ -481,16 +480,9 @@ type name(type1 arg1, type2 arg2, type3 
 
 /*
  * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
  */
-#ifdef CONFIG_PPC32
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#else
-#define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",.sys_ni_syscall")
-#endif
-
+#define cond_syscall(x) \
+	asmlinkage long x (void) __attribute__((weak,alias("sys_ni_syscall")))
 
 #endif		/* __ASSEMBLY__ */
 #endif		/* __KERNEL__ */

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 03/22] spufs: Change %llx to 0x%llx.
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
  2006-11-20 17:44 ` [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable() Arnd Bergmann
  2006-11-20 17:44 ` [PATCH 02/22] powerpc: change ppc_rtas declaration to weak Arnd Bergmann
@ 2006-11-20 17:44 ` Arnd Bergmann
  2006-11-20 17:44 ` [PATCH 04/22] spufs: add /lslr, /dma_info and /proxydma files Arnd Bergmann
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:44 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras,
	Dwayne Grant McConnell, Arnd Bergmann

[-- Attachment #1: spufs-change-llx-to-0x-llx.diff --]
[-- Type: text/plain, Size: 2879 bytes --]

From: Dwayne Grant McConnell <decimal@us.ibm.com>
This patches changes /npc, /decr, /decr_status, /spu_tag_mask, 
/event_mask, /event_status, and /srr0 files to provide output according to 
the format string "0x%llx" instead of "%llx".

Before this patch some files used "0x%llx" and other used "%llx" which is 
inconsistent and potentially confusing. A user might assume "%llx" numbers 
were decimal if they happened to not contain any a-f digits. This change 
will break any code cannot tolerate a leading 0x in the file contents. The 
only known users of these files are the libspe but there might also be 
some scripts which access these files. This risk is deemed acceptable for 
future consistency.

Signed-off-by: Dwayne Grant McConnell <decimal@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---
Dwayne Grant McConnell <decimal@us.ibm.com>
Lotus Notes Mail: Dwayne McConnell [Mail]/Austin/IBM@IBMUS
Lotus Notes Calendar: Dwayne McConnell [Calendar]/Austin/IBM@IBMUS

Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -1391,7 +1391,8 @@ static u64 spufs_npc_get(void *data)
 	spu_release(ctx);
 	return ret;
 }
-DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
+DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set,
+			"0x%llx\n")
 
 static void spufs_decr_set(void *data, u64 val)
 {
@@ -1413,7 +1414,7 @@ static u64 spufs_decr_get(void *data)
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
-			"%llx\n")
+			"0x%llx\n")
 
 static void spufs_decr_status_set(void *data, u64 val)
 {
@@ -1435,7 +1436,7 @@ static u64 spufs_decr_status_get(void *d
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
-			spufs_decr_status_set, "%llx\n")
+			spufs_decr_status_set, "0x%llx\n")
 
 static void spufs_spu_tag_mask_set(void *data, u64 val)
 {
@@ -1457,7 +1458,7 @@ static u64 spufs_spu_tag_mask_get(void *
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
-			spufs_spu_tag_mask_set, "%llx\n")
+			spufs_spu_tag_mask_set, "0x%llx\n")
 
 static void spufs_event_mask_set(void *data, u64 val)
 {
@@ -1479,7 +1480,7 @@ static u64 spufs_event_mask_get(void *da
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
-			spufs_event_mask_set, "%llx\n")
+			spufs_event_mask_set, "0x%llx\n")
 
 static void spufs_srr0_set(void *data, u64 val)
 {
@@ -1501,7 +1502,7 @@ static u64 spufs_srr0_get(void *data)
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
-			"%llx\n")
+			"0x%llx\n")
 
 static u64 spufs_id_get(void *data)
 {

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 04/22] spufs: add /lslr, /dma_info and /proxydma files
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (2 preceding siblings ...)
  2006-11-20 17:44 ` [PATCH 03/22] spufs: Change %llx to 0x%llx Arnd Bergmann
@ 2006-11-20 17:44 ` Arnd Bergmann
  2006-11-20 17:44 ` [PATCH 05/22] spufs: Remove /spu_tag_mask file Arnd Bergmann
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:44 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras,
	Dwayne Grant McConnell, Arnd Bergmann

[-- Attachment #1: spufs-gdb-interfaces-addon-5.diff --]
[-- Type: text/plain, Size: 9463 bytes --]

From: Dwayne Grant McConnell <decimal@us.ibm.com>
The /lslr file gives read access to the SPU_LSLR register in hex; 0x3fff
for example The /dma_info file provides read access to the SPU Command
Queue in a binary format. The /proxydma_info files provides read access
access to the Proxy Command Queue in a binary format. The spu_info.h
file provides data structures for interpreting the binary format of
/dma_info and /proxydma_info.

Signed-off-by: Dwayne Grant McConnell <decimal@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/backing_ops.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -36,6 +36,7 @@
 #include <asm/io.h>
 #include <asm/spu.h>
 #include <asm/spu_csa.h>
+#include <asm/spu_info.h>
 #include <asm/mmu_context.h>
 #include "spufs.h"
 
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -32,6 +32,7 @@
 #include <asm/io.h>
 #include <asm/semaphore.h>
 #include <asm/spu.h>
+#include <asm/spu_info.h>
 #include <asm/uaccess.h>
 
 #include "spufs.h"
@@ -1482,6 +1483,23 @@ static u64 spufs_event_mask_get(void *da
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
 			spufs_event_mask_set, "0x%llx\n")
 
+static u64 spufs_event_status_get(void *data)
+{
+	struct spu_context *ctx = data;
+	struct spu_state *state = &ctx->csa;
+	u64 ret = 0;
+	u64 stat;
+
+	spu_acquire_saved(ctx);
+	stat = state->spu_chnlcnt_RW[0];
+	if (stat)
+		ret = state->spu_chnldata_RW[0];
+	spu_release(ctx);
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
+			NULL, "0x%llx\n")
+
 static void spufs_srr0_set(void *data, u64 val)
 {
 	struct spu_context *ctx = data;
@@ -1535,6 +1553,109 @@ static void spufs_object_id_set(void *da
 DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get,
 		spufs_object_id_set, "0x%llx\n");
 
+static u64 spufs_lslr_get(void *data)
+{
+	struct spu_context *ctx = data;
+	u64 ret;
+
+	spu_acquire_saved(ctx);
+	ret = ctx->csa.priv2.spu_lslr_RW;
+	spu_release(ctx);
+
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n")
+
+static int spufs_info_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+	file->private_data = ctx;
+	return 0;
+}
+
+static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
+			      size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	struct spu_dma_info info;
+	struct mfc_cq_sr *qp, *spuqp;
+	int i;
+
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+
+	spu_acquire_saved(ctx);
+	spin_lock(&ctx->csa.register_lock);
+	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
+	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
+	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
+	info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
+	info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
+	for (i = 0; i < 16; i++) {
+		qp = &info.dma_info_command_data[i];
+		spuqp = &ctx->csa.priv2.spuq[i];
+
+		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
+		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
+		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
+		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
+	}
+	spin_unlock(&ctx->csa.register_lock);
+	spu_release(ctx);
+
+	return simple_read_from_buffer(buf, len, pos, &info,
+				sizeof info);
+}
+
+static struct file_operations spufs_dma_info_fops = {
+	.open = spufs_info_open,
+	.read = spufs_dma_info_read,
+};
+
+static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
+				   size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	struct spu_proxydma_info info;
+	int ret = sizeof info;
+	struct mfc_cq_sr *qp, *puqp;
+	int i;
+
+	if (len < ret)
+		return -EINVAL;
+
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+
+	spu_acquire_saved(ctx);
+	spin_lock(&ctx->csa.register_lock);
+	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
+	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
+	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
+	for (i = 0; i < 8; i++) {
+		qp = &info.proxydma_info_command_data[i];
+		puqp = &ctx->csa.priv2.puq[i];
+
+		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
+		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
+		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
+		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
+	}
+	spin_unlock(&ctx->csa.register_lock);
+	spu_release(ctx);
+
+	if (copy_to_user(buf, &info, sizeof info))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static struct file_operations spufs_proxydma_info_fops = {
+	.open = spufs_info_open,
+	.read = spufs_proxydma_info_read,
+};
+
 struct tree_descr spufs_dir_contents[] = {
 	{ "mem",  &spufs_mem_fops,  0666, },
 	{ "regs", &spufs_regs_fops,  0666, },
@@ -1548,19 +1669,23 @@ struct tree_descr spufs_dir_contents[] =
 	{ "signal2", &spufs_signal2_fops, 0666, },
 	{ "signal1_type", &spufs_signal1_type, 0666, },
 	{ "signal2_type", &spufs_signal2_type, 0666, },
-	{ "mss", &spufs_mss_fops, 0666, },
-	{ "mfc", &spufs_mfc_fops, 0666, },
 	{ "cntl", &spufs_cntl_fops,  0666, },
-	{ "npc", &spufs_npc_ops, 0666, },
 	{ "fpcr", &spufs_fpcr_fops, 0666, },
+	{ "lslr", &spufs_lslr_ops, 0444, },
+	{ "mfc", &spufs_mfc_fops, 0666, },
+	{ "mss", &spufs_mss_fops, 0666, },
+	{ "npc", &spufs_npc_ops, 0666, },
+	{ "srr0", &spufs_srr0_ops, 0666, },
 	{ "decr", &spufs_decr_ops, 0666, },
 	{ "decr_status", &spufs_decr_status_ops, 0666, },
 	{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
 	{ "event_mask", &spufs_event_mask_ops, 0666, },
-	{ "srr0", &spufs_srr0_ops, 0666, },
+	{ "event_status", &spufs_event_status_ops, 0444, },
 	{ "psmap", &spufs_psmap_fops, 0666, },
 	{ "phys-id", &spufs_id_ops, 0666, },
 	{ "object-id", &spufs_object_id_ops, 0666, },
+	{ "dma_info", &spufs_dma_info_fops, 0444, },
+	{ "proxydma_info", &spufs_proxydma_info_fops, 0444, },
 	{},
 };
 
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -29,6 +29,7 @@
 
 #include <asm/spu.h>
 #include <asm/spu_csa.h>
+#include <asm/spu_info.h>
 
 /* The magic number for our file system */
 enum {
@@ -119,8 +120,12 @@ struct spu_context_ops {
 	int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode);
 	u32 (*read_mfc_tagstatus)(struct spu_context * ctx);
 	u32 (*get_mfc_free_elements)(struct spu_context *ctx);
-	int (*send_mfc_command)(struct spu_context *ctx,
-					struct mfc_dma_command *cmd);
+	int (*send_mfc_command)(struct spu_context * ctx,
+				struct mfc_dma_command * cmd);
+	void (*dma_info_read) (struct spu_context * ctx,
+			       struct spu_dma_info * info);
+	void (*proxydma_info_read) (struct spu_context * ctx,
+				    struct spu_proxydma_info * info);
 };
 
 extern struct spu_context_ops spu_hw_ops;
Index: linux-2.6/include/asm-powerpc/Kbuild
===================================================================
--- linux-2.6.orig/include/asm-powerpc/Kbuild
+++ linux-2.6/include/asm-powerpc/Kbuild
@@ -17,6 +17,7 @@ header-y += ipc.h
 header-y += poll.h
 header-y += shmparam.h
 header-y += sockios.h
+header-y += spu_info.h
 header-y += ucontext.h
 header-y += ioctl.h
 header-y += linkage.h
Index: linux-2.6/include/asm-powerpc/spu_info.h
===================================================================
--- /dev/null
+++ linux-2.6/include/asm-powerpc/spu_info.h
@@ -0,0 +1,54 @@
+/*
+ * SPU info structures
+ *
+ * (C) Copyright 2006 IBM Corp.
+ *
+ * Author: Dwayne Grant McConnell <decimal@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SPU_INFO_H
+#define _SPU_INFO_H
+
+#ifdef __KERNEL__
+#include <asm/spu.h>
+#include <linux/types.h>
+#else
+struct mfc_cq_sr {
+	__u64 mfc_cq_data0_RW;
+	__u64 mfc_cq_data1_RW;
+	__u64 mfc_cq_data2_RW;
+	__u64 mfc_cq_data3_RW;
+};
+#endif /* __KERNEL__ */
+
+struct spu_dma_info {
+	__u64 dma_info_type;
+	__u64 dma_info_mask;
+	__u64 dma_info_status;
+	__u64 dma_info_stall_and_notify;
+	__u64 dma_info_atomic_command_status;
+	struct mfc_cq_sr dma_info_command_data[16];
+};
+
+struct spu_proxydma_info {
+	__u64 proxydma_info_type;
+	__u64 proxydma_info_mask;
+	__u64 proxydma_info_status;
+	struct mfc_cq_sr proxydma_info_command_data[8];
+};
+
+#endif

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 05/22] spufs: Remove /spu_tag_mask file
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (3 preceding siblings ...)
  2006-11-20 17:44 ` [PATCH 04/22] spufs: add /lslr, /dma_info and /proxydma files Arnd Bergmann
@ 2006-11-20 17:44 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 06/22] spufs: implement /mbox_info, /ibox_info, and /wbox_info Arnd Bergmann
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:44 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras,
	Dwayne Grant McConnell, Arnd Bergmann

[-- Attachment #1: spufs-remove-spu_tag_mask.diff --]
[-- Type: text/plain, Size: 1961 bytes --]

From: Dwayne Grant McConnell <decimal@us.ibm.com>
This patch removes the /spu_tag_mask file from spufs. The data provided by
this file is also available from the /dma_info file in the dma_info_mask
of the spu_dma_info struct.

The file was intended to be used by gdb, but that never used it, and
now it has been replaced with the more verbose dma_info file.

Signed-off-by: Dwayne Grant McConnell <decimal@us.ibm.com>
Signed-off-by: Arnd Bergmann  <arnd.bergmann@de.ibm.com>
---
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -1439,28 +1439,6 @@ static u64 spufs_decr_status_get(void *d
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
 			spufs_decr_status_set, "0x%llx\n")
 
-static void spufs_spu_tag_mask_set(void *data, u64 val)
-{
-	struct spu_context *ctx = data;
-	struct spu_lscsa *lscsa = ctx->csa.lscsa;
-	spu_acquire_saved(ctx);
-	lscsa->tag_mask.slot[0] = (u32) val;
-	spu_release(ctx);
-}
-
-static u64 spufs_spu_tag_mask_get(void *data)
-{
-	struct spu_context *ctx = data;
-	struct spu_lscsa *lscsa = ctx->csa.lscsa;
-	u64 ret;
-	spu_acquire_saved(ctx);
-	ret = lscsa->tag_mask.slot[0];
-	spu_release(ctx);
-	return ret;
-}
-DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
-			spufs_spu_tag_mask_set, "0x%llx\n")
-
 static void spufs_event_mask_set(void *data, u64 val)
 {
 	struct spu_context *ctx = data;
@@ -1678,7 +1656,6 @@ struct tree_descr spufs_dir_contents[] =
 	{ "srr0", &spufs_srr0_ops, 0666, },
 	{ "decr", &spufs_decr_ops, 0666, },
 	{ "decr_status", &spufs_decr_status_ops, 0666, },
-	{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
 	{ "event_mask", &spufs_event_mask_ops, 0666, },
 	{ "event_status", &spufs_event_status_ops, 0444, },
 	{ "psmap", &spufs_psmap_fops, 0666, },

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 06/22] spufs: implement /mbox_info, /ibox_info, and /wbox_info.
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (4 preceding siblings ...)
  2006-11-20 17:44 ` [PATCH 05/22] spufs: Remove /spu_tag_mask file Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 07/22] spufs: read from signal files only if data is there Arnd Bergmann
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras,
	Dwayne Grant McConnell, Arnd Bergmann

[-- Attachment #1: spufs-mbox-info.diff --]
[-- Type: text/plain, Size: 3947 bytes --]

From: Dwayne Grant McConnell <decimal@us.ibm.com>
This patch implements read only access to

/mbox_info - SPU Write Outbound Mailbox
/ibox_info - SPU Write Outbound Interrupt Mailbox
/wbox_info - SPU Read Inbound Mailbox

These files are used by gdb in order to look into the current mailbox
queues without changing the contents at the same time. They are
not meant for general programming use, since the access requires
a context save and is therefore rather slow.

It would be good to complement this patch with one that adds
write support as well.

Signed-off-by: Dwayne Grant McConnell <decimal@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---
Dwayne Grant McConnell <decimal@us.ibm.com>
Lotus Notes Mail: Dwayne McConnell [Mail]/Austin/IBM@IBMUS
Lotus Notes Calendar: Dwayne McConnell [Calendar]/Austin/IBM@IBMUS

Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -1552,6 +1552,93 @@ static int spufs_info_open(struct inode 
 	return 0;
 }
 
+static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
+				   size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 mbox_stat;
+	u32 data;
+
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+
+	spu_acquire_saved(ctx);
+	spin_lock(&ctx->csa.register_lock);
+	mbox_stat = ctx->csa.prob.mb_stat_R;
+	if (mbox_stat & 0x0000ff) {
+		data = ctx->csa.prob.pu_mb_R;
+	}
+	spin_unlock(&ctx->csa.register_lock);
+	spu_release(ctx);
+
+	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
+}
+
+static struct file_operations spufs_mbox_info_fops = {
+	.open = spufs_info_open,
+	.read = spufs_mbox_info_read,
+	.llseek  = generic_file_llseek,
+};
+
+static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
+				   size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 ibox_stat;
+	u32 data;
+
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+
+	spu_acquire_saved(ctx);
+	spin_lock(&ctx->csa.register_lock);
+	ibox_stat = ctx->csa.prob.mb_stat_R;
+	if (ibox_stat & 0xff0000) {
+		data = ctx->csa.priv2.puint_mb_R;
+	}
+	spin_unlock(&ctx->csa.register_lock);
+	spu_release(ctx);
+
+	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
+}
+
+static struct file_operations spufs_ibox_info_fops = {
+	.open = spufs_info_open,
+	.read = spufs_ibox_info_read,
+	.llseek  = generic_file_llseek,
+};
+
+static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
+				   size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	int i, cnt;
+	u32 data[4];
+	u32 wbox_stat;
+
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+
+	spu_acquire_saved(ctx);
+	spin_lock(&ctx->csa.register_lock);
+	wbox_stat = ctx->csa.prob.mb_stat_R;
+	cnt = (wbox_stat & 0x00ff00) >> 8;
+	for (i = 0; i < cnt; i++) {
+		data[i] = ctx->csa.spu_mailbox_data[i];
+	}
+	spin_unlock(&ctx->csa.register_lock);
+	spu_release(ctx);
+
+	return simple_read_from_buffer(buf, len, pos, &data,
+				cnt * sizeof(u32));
+}
+
+static struct file_operations spufs_wbox_info_fops = {
+	.open = spufs_info_open,
+	.read = spufs_wbox_info_read,
+	.llseek  = generic_file_llseek,
+};
+
 static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
 			      size_t len, loff_t *pos)
 {
@@ -1661,6 +1748,9 @@ struct tree_descr spufs_dir_contents[] =
 	{ "psmap", &spufs_psmap_fops, 0666, },
 	{ "phys-id", &spufs_id_ops, 0666, },
 	{ "object-id", &spufs_object_id_ops, 0666, },
+	{ "mbox_info", &spufs_mbox_info_fops, 0444, },
+	{ "ibox_info", &spufs_ibox_info_fops, 0444, },
+	{ "wbox_info", &spufs_wbox_info_fops, 0444, },
 	{ "dma_info", &spufs_dma_info_fops, 0444, },
 	{ "proxydma_info", &spufs_proxydma_info_fops, 0444, },
 	{},

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 07/22] spufs: read from signal files only if data is there
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (5 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 06/22] spufs: implement /mbox_info, /ibox_info, and /wbox_info Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 08/22] spufs: replace spu.nid with spu.node Arnd Bergmann
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras,
	Dwayne Grant McConnell, Arnd Bergmann

[-- Attachment #1: spufs-require-context-save-for-signal-read-2.diff --]
[-- Type: text/plain, Size: 3664 bytes --]

From: Dwayne Grant McConnell <decimal@us.ibm.com>
We need to check the channel count of the signal notification registers
before reading them, because it can be undefined when the count is
zero. In order to read count and data atomically, we read from the
saved context.

This patch uses spu_acquire_saved() to force a context save before a
/signal1 or /signal2 read. Because of this it is no longer necessary to
have backing_ops and hw_ops versions of this function so they have been
removed.

Regular applications should not rely on reading this register
to be fast, as it's conceptually a write-only file from the PPE
perspective.

Signed-off-by: Dwayne Grant McConnell <decimal@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---
Dwayne Grant McConnell <decimal@us.ibm.com>
Lotus Notes Mail: Dwayne McConnell [Mail]/Austin/IBM@IBMUS
Lotus Notes Calendar: Dwayne McConnell [Calendar]/Austin/IBM@IBMUS

Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -723,19 +723,27 @@ static ssize_t spufs_signal1_read(struct
 			size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	int ret = 0;
 	u32 data;
 
 	if (len < 4)
 		return -EINVAL;
 
-	spu_acquire(ctx);
-	data = ctx->ops->signal1_read(ctx);
+	spu_acquire_saved(ctx);
+	if (ctx->csa.spu_chnlcnt_RW[3]) {
+		data = ctx->csa.spu_chnldata_RW[3];
+		ret = 4;
+	}
 	spu_release(ctx);
 
+	if (!ret)
+		goto out;
+
 	if (copy_to_user(buf, &data, 4))
 		return -EFAULT;
 
-	return 4;
+out:
+	return ret;
 }
 
 static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
@@ -811,21 +819,27 @@ static int spufs_signal2_open(struct ino
 static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
 			size_t len, loff_t *pos)
 {
-	struct spu_context *ctx;
+	struct spu_context *ctx = file->private_data;
+	int ret = 0;
 	u32 data;
 
-	ctx = file->private_data;
-
 	if (len < 4)
 		return -EINVAL;
 
-	spu_acquire(ctx);
-	data = ctx->ops->signal2_read(ctx);
+	spu_acquire_saved(ctx);
+	if (ctx->csa.spu_chnlcnt_RW[4]) {
+		data =  ctx->csa.spu_chnldata_RW[4];
+		ret = 4;
+	}
 	spu_release(ctx);
 
+	if (!ret)
+		goto out;
+
 	if (copy_to_user(buf, &data, 4))
 		return -EFAULT;
 
+out:
 	return 4;
 }
 
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/hw_ops.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -135,21 +135,11 @@ static int spu_hw_wbox_write(struct spu_
 	return ret;
 }
 
-static u32 spu_hw_signal1_read(struct spu_context *ctx)
-{
-	return in_be32(&ctx->spu->problem->signal_notify1);
-}
-
 static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
 {
 	out_be32(&ctx->spu->problem->signal_notify1, data);
 }
 
-static u32 spu_hw_signal2_read(struct spu_context *ctx)
-{
-	return in_be32(&ctx->spu->problem->signal_notify2);
-}
-
 static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
 {
 	out_be32(&ctx->spu->problem->signal_notify2, data);
@@ -294,9 +284,7 @@ struct spu_context_ops spu_hw_ops = {
 	.mbox_stat_poll = spu_hw_mbox_stat_poll,
 	.ibox_read = spu_hw_ibox_read,
 	.wbox_write = spu_hw_wbox_write,
-	.signal1_read = spu_hw_signal1_read,
 	.signal1_write = spu_hw_signal1_write,
-	.signal2_read = spu_hw_signal2_read,
 	.signal2_write = spu_hw_signal2_write,
 	.signal1_type_set = spu_hw_signal1_type_set,
 	.signal1_type_get = spu_hw_signal1_type_get,

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 08/22] spufs: replace spu.nid with spu.node
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (6 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 07/22] spufs: read from signal files only if data is there Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 09/22] spufs: return correct event for data storage interrupt Arnd Bergmann
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Geoff Levand, Arnd Bergmann

[-- Attachment #1: cell-replace-spu-nid-with-spu-node.diff --]
[-- Type: text/plain, Size: 932 bytes --]

From: Geoff Levand <geoffrey.levand@am.sony.com>
Replace the use of the platform specific variable spu.nid with the
platform independednt variable spu.node.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---
Index: linux-2.6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6/arch/powerpc/platforms/cell/spu_base.c
@@ -835,14 +835,14 @@ static int spu_create_sysdev(struct spu 
 		return ret;
 	}
 
-	sysfs_add_device_to_node(&spu->sysdev, spu->nid);
+	sysfs_add_device_to_node(&spu->sysdev, spu->node);
 
 	return 0;
 }
 
 static void spu_destroy_sysdev(struct spu *spu)
 {
-	sysfs_remove_device_from_node(&spu->sysdev, spu->nid);
+	sysfs_remove_device_from_node(&spu->sysdev, spu->node);
 	sysdev_unregister(&spu->sysdev);
 }
 

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 09/22] spufs: return correct event for data storage interrupt
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (7 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 08/22] spufs: replace spu.nid with spu.node Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 10/22] spufs: fix missing stop-and-signal Arnd Bergmann
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev; +Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Arnd Bergmann

[-- Attachment #1: spufs-dma-storage-error-return.diff --]
[-- Type: text/plain, Size: 1153 bytes --]

When we attempt an MFC DMA to an unmapped address, the event
returned from spu_run should be SPE_EVENT_SPE_DATA_STORAGE,
not SPE_EVENT_INVALID_DMA.

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
@@ -26,6 +26,7 @@ void spufs_dma_callback(struct spu *spu,
 	} else {
 		switch (type) {
 		case SPE_EVENT_DMA_ALIGNMENT:
+		case SPE_EVENT_SPE_DATA_STORAGE:
 		case SPE_EVENT_INVALID_DMA:
 			force_sig(SIGBUS, /* info, */ current);
 			break;
Index: linux-2.6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6/arch/powerpc/platforms/cell/spu_base.c
@@ -507,7 +507,7 @@ int spu_irq_class_1_bottom(struct spu *s
 	if (!error) {
 		spu_restart_dma(spu);
 	} else {
-		__spu_trap_invalid_dma(spu);
+		spu->dma_callback(spu, SPE_EVENT_SPE_DATA_STORAGE);
 	}
 	return ret;
 }

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 10/22] spufs: fix missing stop-and-signal
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (8 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 09/22] spufs: return correct event for data storage interrupt Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 11/22] spufs: avoid user-triggered oops in ptrace Arnd Bergmann
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Masato Noguchi,
	Arnd Bergmann

[-- Attachment #1: spufs-fix-missing-stop-and-signal.diff --]
[-- Type: text/plain, Size: 2223 bytes --]

From: Masato Noguchi <Masato.Noguchi@jp.sony.com>

When there is pending signals, current spufs_run_spu() always returns 
-ERESTARTSYS and it is called again automatically.
But, if spe already stopped by stop-and-signal or halt instruction,
returning -ERESTARTSYS makes stop-and-signal/halt lost and 
spu run over the end-point.

For your convenience, I attached a sample code to restage this bug.
If there is no bug, printed NPC will be 0x4000.

Signed-off-by: Masato Noguchi <Masato.Noguchi@jp.sony.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---

 run.c |   28 ++++++++++++++++++----------
 1 files changed, 18 insertions(+), 10 deletions(-)


Index: linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
@@ -79,13 +79,7 @@ static inline int spu_run_fini(struct sp
 
 	if (signal_pending(current))
 		ret = -ERESTARTSYS;
-	if (unlikely(current->ptrace & PT_PTRACED)) {
-		if ((*status & SPU_STATUS_STOPPED_BY_STOP)
-		    && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
-			force_sig(SIGTRAP, current);
-			ret = -ERESTARTSYS;
-		}
-	}
+
 	return ret;
 }
 
@@ -232,7 +226,7 @@ long spufs_run_spu(struct file *file, st
 		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
 			ret = spu_reacquire_runnable(ctx, npc, &status);
 			if (ret)
-				goto out;
+				goto out2;
 			continue;
 		}
 		ret = spu_process_events(ctx);
@@ -242,10 +236,24 @@ long spufs_run_spu(struct file *file, st
 
 	ctx->ops->runcntl_stop(ctx);
 	ret = spu_run_fini(ctx, npc, &status);
-	if (!ret)
-		ret = status;
 	spu_yield(ctx);
 
+out2:
+	if ((ret == 0) ||
+	    ((ret == -ERESTARTSYS) &&
+	     ((status & SPU_STATUS_STOPPED_BY_HALT) ||
+	      ((status & SPU_STATUS_STOPPED_BY_STOP) &&
+	       (status >> SPU_STOP_STATUS_SHIFT != 0x2104)))))
+		ret = status;
+
+	if (unlikely(current->ptrace & PT_PTRACED)) {
+		if ((status & SPU_STATUS_STOPPED_BY_STOP)
+		    && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
+			force_sig(SIGTRAP, current);
+			ret = -ERESTARTSYS;
+		}
+	}
+
 out:
 	*event = ctx->event_return;
 	up(&ctx->run_sema);

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 11/22] spufs: avoid user-triggered oops in ptrace
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (9 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 10/22] spufs: fix missing stop-and-signal Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 12/22] spufs: always map local store non-guarded Arnd Bergmann
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Arnd Bergmann,
	Christoph Hellwig

[-- Attachment #1: spufs-vm-io-mappings.diff --]
[-- Type: text/plain, Size: 2966 bytes --]

From: Christoph Hellwig <hch@infradead.org>
When one of the spufs files is mapped into a process address
space, regular users can use ptrace to attempt accessing
them with access_process_vm(). With the way that the
mappings currently work, this likely causes an oops.

Setting the vm_flags to VM_IO makes sure that ptrace can
not access them but returns an error code. This is not
the perfect solution in case of the local store mapping,
but it fixes the oops in a well-defined way.

Also remove leftover VM_RESERVED flags in spufs.  The
VM_RESERVED flag is on it's way out and not checked by
the memory managment code anymore.

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Christoph Hellwig <chellwig@de.ibm.com>

---

Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -132,7 +132,7 @@ spufs_mem_mmap(struct file *file, struct
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	/* FIXME: */
+	vma->vm_flags |= VM_IO;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE);
 
@@ -201,7 +201,7 @@ static int spufs_cntl_mmap(struct file *
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_IO;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
@@ -791,7 +791,7 @@ static int spufs_signal1_mmap(struct fil
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_IO;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
@@ -889,8 +889,7 @@ static int spufs_signal2_mmap(struct fil
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	/* FIXME: */
-	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_IO;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
@@ -973,7 +972,7 @@ static int spufs_mss_mmap(struct file *f
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_IO;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
@@ -1015,7 +1014,7 @@ static int spufs_psmap_mmap(struct file 
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_IO;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
@@ -1056,7 +1055,7 @@ static int spufs_mfc_mmap(struct file *f
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_IO;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
 

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 12/22] spufs: always map local store non-guarded
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (10 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 11/22] spufs: avoid user-triggered oops in ptrace Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 13/22] spufs: fix return value of spufs_mfc_write Arnd Bergmann
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev; +Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Arnd Bergmann

[-- Attachment #1: spufs-map-nonguarded.diff --]
[-- Type: text/plain, Size: 1091 bytes --]

When fixing spufs to map the 'mem' file backing store cacheable,
I incorrectly set the physical mapping to use both cache-inhibited
and guarded mapping, which resulted in a serious performance
degradation.

Debugged-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -105,11 +105,11 @@ spufs_mem_mmap_nopage(struct vm_area_str
 
 	if (ctx->state == SPU_STATE_SAVED) {
 		vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-					& ~(_PAGE_NO_CACHE | _PAGE_GUARDED));
+							& ~_PAGE_NO_CACHE);
 		page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
 	} else {
 		vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-					| _PAGE_NO_CACHE | _PAGE_GUARDED);
+							| _PAGE_NO_CACHE);
 		page = pfn_to_page((ctx->spu->local_store_phys + offset)
 				   >> PAGE_SHIFT);
 	}

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 13/22] spufs: fix return value of spufs_mfc_write
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (11 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 12/22] spufs: always map local store non-guarded Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution Arnd Bergmann
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Masato Noguchi,
	Arnd Bergmann

[-- Attachment #1: spufs-fix-return-value-of-spufs_mfc_write.diff --]
[-- Type: text/plain, Size: 905 bytes --]

From: Masato Noguchi <Masato.Noguchi@jp.sony.com>
This patch changes spufs_mfc_write() to return
correct size instead of 0.

Signed-off-by: Masato Noguchi <Masato.Noguchi@jp.sony.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
 arch/powerpc/platforms/cell/spufs/file.c |    1 +
 1 files changed, 1 insertion(+)

Index: linux-2.6.19-rc6-arnd1/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.19-rc6-arnd1.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6.19-rc6-arnd1/arch/powerpc/platforms/cell/spufs/file.c
@@ -1325,6 +1325,7 @@ static ssize_t spufs_mfc_write(struct fi
 		goto out;
 
 	ctx->tagwait |= 1 << cmd.tag;
+	ret = size;
 
 out:
 	return ret;

_______________________________________________
cbe-oss-dev mailing list
cbe-oss-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/cbe-oss-dev

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (12 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 13/22] spufs: fix return value of spufs_mfc_write Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2007-03-01  6:18   ` Michael Ellerman
  2006-11-20 17:45 ` [PATCH 15/22] spufs: Add runcntrl read accessors Arnd Bergmann
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev; +Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Arnd Bergmann

[-- Attachment #1: spufs-master-control.diff --]
[-- Type: text/plain, Size: 7907 bytes --]

When the user changes the runcontrol register, an SPU might be
running without a process being attached to it and waiting for
events. In order to prevent this, make sure we always disable
the priv1 master control when we're not inside of spu_run.

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/hw_ops.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -216,13 +216,26 @@ static void spu_hw_runcntl_write(struct 
 	spin_unlock_irq(&ctx->spu->register_lock);
 }
 
-static void spu_hw_runcntl_stop(struct spu_context *ctx)
+static void spu_hw_master_start(struct spu_context *ctx)
 {
-	spin_lock_irq(&ctx->spu->register_lock);
-	out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
-	while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
-		cpu_relax();
-	spin_unlock_irq(&ctx->spu->register_lock);
+	struct spu *spu = ctx->spu;
+	u64 sr1;
+
+	spin_lock_irq(&spu->register_lock);
+	sr1 = spu_mfc_sr1_get(spu) | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+	spu_mfc_sr1_set(spu, sr1);
+	spin_unlock_irq(&spu->register_lock);
+}
+
+static void spu_hw_master_stop(struct spu_context *ctx)
+{
+	struct spu *spu = ctx->spu;
+	u64 sr1;
+
+	spin_lock_irq(&spu->register_lock);
+	sr1 = spu_mfc_sr1_get(spu) & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+	spu_mfc_sr1_set(spu, sr1);
+	spin_unlock_irq(&spu->register_lock);
 }
 
 static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
@@ -295,7 +308,8 @@ struct spu_context_ops spu_hw_ops = {
 	.status_read = spu_hw_status_read,
 	.get_ls = spu_hw_get_ls,
 	.runcntl_write = spu_hw_runcntl_write,
-	.runcntl_stop = spu_hw_runcntl_stop,
+	.master_start = spu_hw_master_start,
+	.master_stop = spu_hw_master_stop,
 	.set_mfc_query = spu_hw_set_mfc_query,
 	.read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
 	.get_mfc_free_elements = spu_hw_get_mfc_free_elements,
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/backing_ops.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -280,9 +280,26 @@ static void spu_backing_runcntl_write(st
 	spin_unlock(&ctx->csa.register_lock);
 }
 
-static void spu_backing_runcntl_stop(struct spu_context *ctx)
+static void spu_backing_master_start(struct spu_context *ctx)
 {
-	spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
+	struct spu_state *csa = &ctx->csa;
+	u64 sr1;
+
+	spin_lock(&csa->register_lock);
+	sr1 = csa->priv1.mfc_sr1_RW | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+	csa->priv1.mfc_sr1_RW = sr1;
+	spin_unlock(&csa->register_lock);
+}
+
+static void spu_backing_master_stop(struct spu_context *ctx)
+{
+	struct spu_state *csa = &ctx->csa;
+	u64 sr1;
+
+	spin_lock(&csa->register_lock);
+	sr1 = csa->priv1.mfc_sr1_RW & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+	csa->priv1.mfc_sr1_RW = sr1;
+	spin_unlock(&csa->register_lock);
 }
 
 static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask,
@@ -347,7 +364,8 @@ struct spu_context_ops spu_backing_ops =
 	.status_read = spu_backing_status_read,
 	.get_ls = spu_backing_get_ls,
 	.runcntl_write = spu_backing_runcntl_write,
-	.runcntl_stop = spu_backing_runcntl_stop,
+	.master_start = spu_backing_master_start,
+	.master_stop = spu_backing_master_stop,
 	.set_mfc_query = spu_backing_set_mfc_query,
 	.read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
 	.get_mfc_free_elements = spu_backing_get_mfc_free_elements,
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -116,7 +116,8 @@ struct spu_context_ops {
 	 u32(*status_read) (struct spu_context * ctx);
 	char*(*get_ls) (struct spu_context * ctx);
 	void (*runcntl_write) (struct spu_context * ctx, u32 data);
-	void (*runcntl_stop) (struct spu_context * ctx);
+	void (*master_start) (struct spu_context * ctx);
+	void (*master_stop) (struct spu_context * ctx);
 	int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode);
 	u32 (*read_mfc_tagstatus)(struct spu_context * ctx);
 	u32 (*get_mfc_free_elements)(struct spu_context *ctx);
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/context.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/context.c
@@ -122,29 +122,29 @@ void spu_unmap_mappings(struct spu_conte
 
 int spu_acquire_exclusive(struct spu_context *ctx)
 {
-       int ret = 0;
+	int ret = 0;
 
-       down_write(&ctx->state_sema);
-       /* ctx is about to be freed, can't acquire any more */
-       if (!ctx->owner) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (ctx->state == SPU_STATE_SAVED) {
-               ret = spu_activate(ctx, 0);
-               if (ret)
-                       goto out;
-               ctx->state = SPU_STATE_RUNNABLE;
-       } else {
-               /* We need to exclude userspace access to the context. */
-               spu_unmap_mappings(ctx);
-       }
+	down_write(&ctx->state_sema);
+	/* ctx is about to be freed, can't acquire any more */
+	if (!ctx->owner) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (ctx->state == SPU_STATE_SAVED) {
+		ret = spu_activate(ctx, 0);
+		if (ret)
+			goto out;
+		ctx->state = SPU_STATE_RUNNABLE;
+	} else {
+		/* We need to exclude userspace access to the context. */
+		spu_unmap_mappings(ctx);
+	}
 
 out:
-       if (ret)
-               up_write(&ctx->state_sema);
-       return ret;
+	if (ret)
+		up_write(&ctx->state_sema);
+	return ret;
 }
 
 int spu_acquire_runnable(struct spu_context *ctx)
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
@@ -248,8 +248,13 @@ static int spu_setup_isolated(struct spu
 	if (!isolated_loader)
 		return -ENODEV;
 
-	if ((ret = spu_acquire_exclusive(ctx)) != 0)
-		return ret;
+	/* prevent concurrent operation with spu_run */
+	down(&ctx->run_sema);
+	ctx->ops->master_start(ctx);
+
+	ret = spu_acquire_exclusive(ctx);
+	if (ret)
+		goto out;
 
 	mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
 
@@ -315,12 +320,14 @@ out_drop_priv:
 
 out_unlock:
 	spu_release_exclusive(ctx);
+out:
+	ctx->ops->master_stop(ctx);
+	up(&ctx->run_sema);
 	return ret;
 }
 
 int spu_recycle_isolated(struct spu_context *ctx)
 {
-	ctx->ops->runcntl_stop(ctx);
 	return spu_setup_isolated(ctx);
 }
 
@@ -435,6 +442,8 @@ out:
 	if (ret >= 0 && (flags & SPU_CREATE_ISOLATE)) {
 		int setup_err = spu_setup_isolated(
 				SPUFS_I(dentry->d_inode)->i_ctx);
+		/* FIXME: clean up context again on failure to avoid
+		          leak. */
 		if (setup_err)
 			ret = setup_err;
 	}
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
@@ -207,6 +207,7 @@ long spufs_run_spu(struct file *file, st
 	if (down_interruptible(&ctx->run_sema))
 		return -ERESTARTSYS;
 
+	ctx->ops->master_start(ctx);
 	ctx->event_return = 0;
 	ret = spu_run_init(ctx, npc);
 	if (ret)
@@ -234,7 +235,7 @@ long spufs_run_spu(struct file *file, st
 	} while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
 				      SPU_STATUS_STOPPED_BY_HALT)));
 
-	ctx->ops->runcntl_stop(ctx);
+	ctx->ops->master_stop(ctx);
 	ret = spu_run_fini(ctx, npc, &status);
 	spu_yield(ctx);
 

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 15/22] spufs: Add runcntrl read accessors
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (13 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 16/22] spufs: load isolation kernel from spu_run Arnd Bergmann
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Jeremy Kerr, Arnd Bergmann

[-- Attachment #1: spufs-add-runcntrl-read-accessors.diff --]
[-- Type: text/plain, Size: 3158 bytes --]

From: Jeremy Kerr <jeremy@au1.ibm.com>
This change adds a read accessor for the SPE problem-state run control
register.

This is required for for applying (userspace) changes made to the run
control register while the SPE is stopped - simply asserting the master
run control bit is not sufficient. My next patch for isolated-mode
setup requires this.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---

 arch/powerpc/platforms/cell/spufs/backing_ops.c |    6 ++++++
 arch/powerpc/platforms/cell/spufs/hw_ops.c      |    6 ++++++
 arch/powerpc/platforms/cell/spufs/spufs.h       |    1 +
 3 files changed, 13 insertions(+)
 
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/backing_ops.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -268,6 +268,11 @@ static char *spu_backing_get_ls(struct s
 	return ctx->csa.lscsa->ls;
 }
 
+static u32 spu_backing_runcntl_read(struct spu_context *ctx)
+{
+	return ctx->csa.prob.spu_runcntl_RW;
+}
+
 static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val)
 {
 	spin_lock(&ctx->csa.register_lock);
@@ -363,6 +368,7 @@ struct spu_context_ops spu_backing_ops =
 	.npc_write = spu_backing_npc_write,
 	.status_read = spu_backing_status_read,
 	.get_ls = spu_backing_get_ls,
+	.runcntl_read = spu_backing_runcntl_read,
 	.runcntl_write = spu_backing_runcntl_write,
 	.master_start = spu_backing_master_start,
 	.master_stop = spu_backing_master_stop,
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/hw_ops.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -207,6 +207,11 @@ static char *spu_hw_get_ls(struct spu_co
 	return ctx->spu->local_store;
 }
 
+static u32 spu_hw_runcntl_read(struct spu_context *ctx)
+{
+	return in_be32(&ctx->spu->problem->spu_runcntl_RW);
+}
+
 static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
 {
 	spin_lock_irq(&ctx->spu->register_lock);
@@ -307,6 +312,7 @@ struct spu_context_ops spu_hw_ops = {
 	.npc_write = spu_hw_npc_write,
 	.status_read = spu_hw_status_read,
 	.get_ls = spu_hw_get_ls,
+	.runcntl_read = spu_hw_runcntl_read,
 	.runcntl_write = spu_hw_runcntl_write,
 	.master_start = spu_hw_master_start,
 	.master_stop = spu_hw_master_stop,
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -115,6 +115,7 @@ struct spu_context_ops {
 	void (*npc_write) (struct spu_context * ctx, u32 data);
 	 u32(*status_read) (struct spu_context * ctx);
 	char*(*get_ls) (struct spu_context * ctx);
+	 u32 (*runcntl_read) (struct spu_context * ctx);
 	void (*runcntl_write) (struct spu_context * ctx, u32 data);
 	void (*master_start) (struct spu_context * ctx);
 	void (*master_stop) (struct spu_context * ctx);

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 16/22] spufs: load isolation kernel from spu_run
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (14 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 15/22] spufs: Add runcntrl read accessors Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 17/22] coredump: Add SPU elf notes to coredump Arnd Bergmann
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Jeremy Kerr, Arnd Bergmann

[-- Attachment #1: spufs-autorecycle-isolated-2.diff --]
[-- Type: text/plain, Size: 10655 bytes --]

From: Jeremy Kerr <jeremy@au1.ibm.com>
In order to fit with the "don't-run-spus-outside-of-spu_run" model, this
patch starts the isolated-mode loader in spu_run, rather than
spu_create. If spu_run is passed an isolated-mode context that isn't in
isolated mode state, it will run the loader.

This fixes potential races with the isolated SPE app doing a
stop-and-signal before the PPE has called spu_run: bugzilla #29111.
Also (in conjunction with a mambo patch), this addresses #28565, as we
always set the runcntrl register when entering spu_run.

It is up to libspe to ensure that isolated-mode apps are cleaned up
after running to completion - ie, put the app through the "ISOLATE EXIT"
state (see Ch11 of the CBEA).

Signed-off-by: Jeremy Kerr <jeremy@au1.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -1358,37 +1358,6 @@ static struct file_operations spufs_mfc_
 	.mmap	 = spufs_mfc_mmap,
 };
 
-
-static int spufs_recycle_open(struct inode *inode, struct file *file)
-{
-	file->private_data = SPUFS_I(inode)->i_ctx;
-	return nonseekable_open(inode, file);
-}
-
-static ssize_t spufs_recycle_write(struct file *file,
-		const char __user *buffer, size_t size, loff_t *pos)
-{
-	struct spu_context *ctx = file->private_data;
-	int ret;
-
-	if (!(ctx->flags & SPU_CREATE_ISOLATE))
-		return -EINVAL;
-
-	if (size < 1)
-		return -EINVAL;
-
-	ret = spu_recycle_isolated(ctx);
-
-	if (ret)
-		return ret;
-	return size;
-}
-
-static struct file_operations spufs_recycle_fops = {
-	.open	 = spufs_recycle_open,
-	.write	 = spufs_recycle_write,
-};
-
 static void spufs_npc_set(void *data, u64 val)
 {
 	struct spu_context *ctx = data;
@@ -1789,6 +1758,5 @@ struct tree_descr spufs_dir_nosched_cont
 	{ "psmap", &spufs_psmap_fops, 0666, },
 	{ "phys-id", &spufs_id_ops, 0666, },
 	{ "object-id", &spufs_object_id_ops, 0666, },
-	{ "recycle", &spufs_recycle_fops, 0222, },
 	{},
 };
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
@@ -34,8 +34,6 @@
 #include <linux/parser.h>
 
 #include <asm/prom.h>
-#include <asm/spu_priv1.h>
-#include <asm/io.h>
 #include <asm/semaphore.h>
 #include <asm/spu.h>
 #include <asm/uaccess.h>
@@ -43,7 +41,7 @@
 #include "spufs.h"
 
 static kmem_cache_t *spufs_inode_cache;
-static char *isolated_loader;
+char *isolated_loader;
 
 static struct inode *
 spufs_alloc_inode(struct super_block *sb)
@@ -235,102 +233,6 @@ struct file_operations spufs_context_fop
 	.fsync		= simple_sync_file,
 };
 
-static int spu_setup_isolated(struct spu_context *ctx)
-{
-	int ret;
-	u64 __iomem *mfc_cntl;
-	u64 sr1;
-	u32 status;
-	unsigned long timeout;
-	const u32 status_loading = SPU_STATUS_RUNNING
-		| SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
-
-	if (!isolated_loader)
-		return -ENODEV;
-
-	/* prevent concurrent operation with spu_run */
-	down(&ctx->run_sema);
-	ctx->ops->master_start(ctx);
-
-	ret = spu_acquire_exclusive(ctx);
-	if (ret)
-		goto out;
-
-	mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
-
-	/* purge the MFC DMA queue to ensure no spurious accesses before we
-	 * enter kernel mode */
-	timeout = jiffies + HZ;
-	out_be64(mfc_cntl, MFC_CNTL_PURGE_DMA_REQUEST);
-	while ((in_be64(mfc_cntl) & MFC_CNTL_PURGE_DMA_STATUS_MASK)
-			!= MFC_CNTL_PURGE_DMA_COMPLETE) {
-		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
-					__FUNCTION__);
-			ret = -EIO;
-			goto out_unlock;
-		}
-		cond_resched();
-	}
-
-	/* put the SPE in kernel mode to allow access to the loader */
-	sr1 = spu_mfc_sr1_get(ctx->spu);
-	sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK;
-	spu_mfc_sr1_set(ctx->spu, sr1);
-
-	/* start the loader */
-	ctx->ops->signal1_write(ctx, (unsigned long)isolated_loader >> 32);
-	ctx->ops->signal2_write(ctx,
-			(unsigned long)isolated_loader & 0xffffffff);
-
-	ctx->ops->runcntl_write(ctx,
-			SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
-
-	ret = 0;
-	timeout = jiffies + HZ;
-	while (((status = ctx->ops->status_read(ctx)) & status_loading) ==
-				status_loading) {
-		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR "%s: timeout waiting for loader\n",
-					__FUNCTION__);
-			ret = -EIO;
-			goto out_drop_priv;
-		}
-		cond_resched();
-	}
-
-	if (!(status & SPU_STATUS_RUNNING)) {
-		/* If isolated LOAD has failed: run SPU, we will get a stop-and
-		 * signal later. */
-		pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
-		ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
-		ret = -EACCES;
-
-	} else if (!(status & SPU_STATUS_ISOLATED_STATE)) {
-		/* This isn't allowed by the CBEA, but check anyway */
-		pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
-		ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
-		ret = -EINVAL;
-	}
-
-out_drop_priv:
-	/* Finished accessing the loader. Drop kernel mode */
-	sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
-	spu_mfc_sr1_set(ctx->spu, sr1);
-
-out_unlock:
-	spu_release_exclusive(ctx);
-out:
-	ctx->ops->master_stop(ctx);
-	up(&ctx->run_sema);
-	return ret;
-}
-
-int spu_recycle_isolated(struct spu_context *ctx)
-{
-	return spu_setup_isolated(ctx);
-}
-
 static int
 spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
 		int mode)
@@ -439,15 +341,6 @@ static int spufs_create_context(struct i
 out_unlock:
 	mutex_unlock(&inode->i_mutex);
 out:
-	if (ret >= 0 && (flags & SPU_CREATE_ISOLATE)) {
-		int setup_err = spu_setup_isolated(
-				SPUFS_I(dentry->d_inode)->i_ctx);
-		/* FIXME: clean up context again on failure to avoid
-		          leak. */
-		if (setup_err)
-			ret = setup_err;
-	}
-
 	dput(dentry);
 	return ret;
 }
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
@@ -4,6 +4,8 @@
 #include <linux/ptrace.h>
 
 #include <asm/spu.h>
+#include <asm/spu_priv1.h>
+#include <asm/io.h>
 #include <asm/unistd.h>
 
 #include "spufs.h"
@@ -51,21 +53,122 @@ static inline int spu_stopped(struct spu
 	return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
 }
 
+static int spu_setup_isolated(struct spu_context *ctx)
+{
+	int ret;
+	u64 __iomem *mfc_cntl;
+	u64 sr1;
+	u32 status;
+	unsigned long timeout;
+	const u32 status_loading = SPU_STATUS_RUNNING
+		| SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
+
+	if (!isolated_loader)
+		return -ENODEV;
+
+	ret = spu_acquire_exclusive(ctx);
+	if (ret)
+		goto out;
+
+	mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
+
+	/* purge the MFC DMA queue to ensure no spurious accesses before we
+	 * enter kernel mode */
+	timeout = jiffies + HZ;
+	out_be64(mfc_cntl, MFC_CNTL_PURGE_DMA_REQUEST);
+	while ((in_be64(mfc_cntl) & MFC_CNTL_PURGE_DMA_STATUS_MASK)
+			!= MFC_CNTL_PURGE_DMA_COMPLETE) {
+		if (time_after(jiffies, timeout)) {
+			printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
+					__FUNCTION__);
+			ret = -EIO;
+			goto out_unlock;
+		}
+		cond_resched();
+	}
+
+	/* put the SPE in kernel mode to allow access to the loader */
+	sr1 = spu_mfc_sr1_get(ctx->spu);
+	sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK;
+	spu_mfc_sr1_set(ctx->spu, sr1);
+
+	/* start the loader */
+	ctx->ops->signal1_write(ctx, (unsigned long)isolated_loader >> 32);
+	ctx->ops->signal2_write(ctx,
+			(unsigned long)isolated_loader & 0xffffffff);
+
+	ctx->ops->runcntl_write(ctx,
+			SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
+
+	ret = 0;
+	timeout = jiffies + HZ;
+	while (((status = ctx->ops->status_read(ctx)) & status_loading) ==
+				status_loading) {
+		if (time_after(jiffies, timeout)) {
+			printk(KERN_ERR "%s: timeout waiting for loader\n",
+					__FUNCTION__);
+			ret = -EIO;
+			goto out_drop_priv;
+		}
+		cond_resched();
+	}
+
+	if (!(status & SPU_STATUS_RUNNING)) {
+		/* If isolated LOAD has failed: run SPU, we will get a stop-and
+		 * signal later. */
+		pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
+		ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+		ret = -EACCES;
+
+	} else if (!(status & SPU_STATUS_ISOLATED_STATE)) {
+		/* This isn't allowed by the CBEA, but check anyway */
+		pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
+		ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
+		ret = -EINVAL;
+	}
+
+out_drop_priv:
+	/* Finished accessing the loader. Drop kernel mode */
+	sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
+	spu_mfc_sr1_set(ctx->spu, sr1);
+
+out_unlock:
+	spu_release_exclusive(ctx);
+out:
+	return ret;
+}
+
 static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
 {
 	int ret;
 	unsigned long runcntl = SPU_RUNCNTL_RUNNABLE;
 
-	if ((ret = spu_acquire_runnable(ctx)) != 0)
+	ret = spu_acquire_runnable(ctx);
+	if (ret)
 		return ret;
 
-	/* if we're in isolated mode, we would have started the SPU
-	 * earlier, so don't do it again now. */
-	if (!(ctx->flags & SPU_CREATE_ISOLATE)) {
+	if (ctx->flags & SPU_CREATE_ISOLATE) {
+		if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) {
+			/* Need to release ctx, because spu_setup_isolated will
+			 * acquire it exclusively.
+			 */
+			spu_release(ctx);
+			ret = spu_setup_isolated(ctx);
+			if (!ret)
+				ret = spu_acquire_runnable(ctx);
+		}
+
+		/* if userspace has set the runcntrl register (eg, to issue an
+		 * isolated exit), we need to re-set it here */
+		runcntl = ctx->ops->runcntl_read(ctx) &
+			(SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
+		if (runcntl == 0)
+			runcntl = SPU_RUNCNTL_RUNNABLE;
+	} else
 		ctx->ops->npc_write(ctx, *npc);
-		ctx->ops->runcntl_write(ctx, runcntl);
-	}
-	return 0;
+
+	ctx->ops->runcntl_write(ctx, runcntl);
+	return ret;
 }
 
 static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -183,7 +183,8 @@ void spu_yield(struct spu_context *ctx);
 int __init spu_sched_init(void);
 void __exit spu_sched_exit(void);
 
-int spu_recycle_isolated(struct spu_context *ctx);
+extern char *isolated_loader;
+
 /*
  * spufs_wait
  * 	Same as wait_event_interruptible(), except that here

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 17/22] coredump: Add SPU elf notes to coredump.
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (15 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 16/22] spufs: load isolation kernel from spu_run Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-21  5:38   ` Michael Ellerman
  2006-11-20 17:45 ` [PATCH 18/22] cell: add symbol exports for oprofile Arnd Bergmann
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, linux-arch,
	Dwayne Grant McConnell, Arnd Bergmann

[-- Attachment #1: coredump-add-spu-elf-notes-to-coredump.diff --]
[-- Type: text/plain, Size: 33166 bytes --]

From: Dwayne Grant McConnell <decimal@us.ibm.com>
This patch adds SPU elf notes to the coredump. It creates a separate note
for each of /regs, /fpcr, /lslr, /decr, /decr_status, /mem, /signal1,
/signal1_type, /signal2, /signal2_type, /event_mask, /event_status,
/mbox_info, /ibox_info, /wbox_info, /dma_info, /proxydma_info, /object-id.

A new macro, ARCH_HAVE_EXTRA_NOTES, was created for architectures to 
specify they have extra elf core notes.

A new macro, ELF_CORE_EXTRA_NOTES_SIZE, was created so the size of the
additional notes could be calculated and added to the notes phdr entry.

A new macro, ELF_CORE_WRITE_EXTRA_NOTES, was created so the new notes
would be written after the existing notes.

The SPU coredump code resides in spufs. Stub functions are provided in the 
kernel which are hooked into the spufs code which does the actual work via 
register_arch_coredump_calls().

A new set of __spufs_<file>_read/get() functions was provided to allow the 
coredump code to read from the spufs files without having to lock the 
SPU context for each file read from.

Cc: <linux-arch@vger.kernel.org>
Signed-off-by: Dwayne Grant McConnell <decimal@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---

Cc'ing linux-arch because I couldn't find the right maintainer
for fs/binfmt_elf.c, and the patch adds architecture specific hooks.

Index: linux-2.6/arch/powerpc/platforms/cell/Makefile
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Makefile
+++ linux-2.6/arch/powerpc/platforms/cell/Makefile
@@ -15,5 +15,6 @@ spufs-modular-$(CONFIG_SPU_FS)		+= spu_s
 spu-priv1-$(CONFIG_PPC_CELL_NATIVE)	+= spu_priv1_mmio.o
 
 obj-$(CONFIG_SPU_BASE)			+= spu_callbacks.o spu_base.o \
+					   spu_coredump.o \
 					   $(spufs-modular-m) \
 					   $(spu-priv1-y) spufs/
Index: linux-2.6/arch/powerpc/platforms/cell/spu_coredump.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/spu_coredump.c
@@ -0,0 +1,81 @@
+/*
+ * SPU core dump code
+ *
+ * (C) Copyright 2006 IBM Corp.
+ *
+ * Author: Dwayne Grant McConnell <decimal@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+#include <asm/spu.h>
+
+static struct spu_coredump_calls spu_coredump_calls;
+static DEFINE_MUTEX(spu_coredump_mutex);
+
+int arch_notes_size(void)
+{
+	long ret;
+	struct module *owner = spu_coredump_calls.owner;
+
+	ret = -ENOSYS;
+	mutex_lock(&spu_coredump_mutex);
+	if (owner && try_module_get(owner)) {
+		ret = spu_coredump_calls.arch_notes_size();
+		module_put(owner);
+	}
+	mutex_unlock(&spu_coredump_mutex);
+	return ret;
+}
+
+void arch_write_notes(struct file *file)
+{
+	struct module *owner = spu_coredump_calls.owner;
+
+	mutex_lock(&spu_coredump_mutex);
+	if (owner && try_module_get(owner)) {
+		spu_coredump_calls.arch_write_notes(file);
+		module_put(owner);
+	}
+	mutex_unlock(&spu_coredump_mutex);
+}
+
+int register_arch_coredump_calls(struct spu_coredump_calls *calls)
+{
+	if (spu_coredump_calls.owner)
+		return -EBUSY;
+
+	mutex_lock(&spu_coredump_mutex);
+	spu_coredump_calls.arch_notes_size = calls->arch_notes_size;
+	spu_coredump_calls.arch_write_notes = calls->arch_write_notes;
+	spu_coredump_calls.owner = calls->owner;
+	mutex_unlock(&spu_coredump_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(register_arch_coredump_calls);
+
+void unregister_arch_coredump_calls(struct spu_coredump_calls *calls)
+{
+	BUG_ON(spu_coredump_calls.owner != calls->owner);
+
+	mutex_lock(&spu_coredump_mutex);
+	spu_coredump_calls.owner = NULL;
+	mutex_unlock(&spu_coredump_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls);
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/coredump.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -0,0 +1,238 @@
+/*
+ * SPU core dump code
+ *
+ * (C) Copyright 2006 IBM Corp.
+ *
+ * Author: Dwayne Grant McConnell <decimal@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/elf.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+struct spufs_ctx_info {
+	struct list_head list;
+	int dfd;
+	int memsize; /* in bytes */
+	struct spu_context *ctx;
+};
+
+static LIST_HEAD(ctx_info_list);
+
+static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer,
+				size_t size, loff_t *off)
+{
+	u64 data;
+	int ret;
+
+	if (spufs_coredump_read[num].read)
+		return spufs_coredump_read[num].read(ctx, buffer, size, off);
+
+	data = spufs_coredump_read[num].get(ctx);
+	ret = copy_to_user(buffer, &data, 8);
+	return ret ? -EFAULT : 8;
+}
+
+/*
+ * These are the only things you should do on a core-file: use only these
+ * functions to write out all the necessary info.
+ */
+static int spufs_dump_write(struct file *file, const void *addr, int nr)
+{
+	return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+}
+
+static int spufs_dump_seek(struct file *file, loff_t off)
+{
+	if (file->f_op->llseek) {
+		if (file->f_op->llseek(file, off, 0) != off)
+			return 0;
+	} else
+		file->f_pos = off;
+	return 1;
+}
+
+static void spufs_fill_memsize(struct spufs_ctx_info *ctx_info)
+{
+	struct spu_context *ctx;
+	unsigned long long lslr;
+
+	ctx = ctx_info->ctx;
+	lslr = ctx->csa.priv2.spu_lslr_RW;
+	ctx_info->memsize = lslr + 1;
+}
+
+static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info)
+{
+	int dfd, memsize, i, sz, total = 0;
+	char *name;
+	char fullname[80];
+
+	dfd = ctx_info->dfd;
+	memsize = ctx_info->memsize;
+
+	for (i = 0; spufs_coredump_read[i].name; i++) {
+		name = spufs_coredump_read[i].name;
+		sz = spufs_coredump_read[i].size;
+
+		sprintf(fullname, "SPU/%d/%s", dfd, name);
+
+		total += sizeof(struct elf_note);
+		total += roundup(strlen(fullname) + 1, 4);
+		if (!strcmp(name, "mem"))
+			total += roundup(memsize, 4);
+		else
+			total += roundup(sz, 4);
+	}
+
+	return total;
+}
+
+static int spufs_add_one_context(struct file *file, int dfd)
+{
+	struct spu_context *ctx;
+	struct spufs_ctx_info *ctx_info;
+	int size;
+
+	ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx;
+	if (ctx->flags & SPU_CREATE_NOSCHED)
+		return 0;
+
+	ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL);
+	if (unlikely(!ctx_info))
+		return -ENOMEM;
+
+	ctx_info->dfd = dfd;
+	ctx_info->ctx = ctx;
+
+	spufs_fill_memsize(ctx_info);
+
+	size = spufs_ctx_note_size(ctx_info);
+	list_add(&ctx_info->list, &ctx_info_list);
+	return size;
+}
+
+/*
+ * The additional architecture-specific notes for Cell are various
+ * context files in the spu context.
+ *
+ * This function iterates over all open file descriptors and sees
+ * if they are a directory in spufs.  In that case we use spufs
+ * internal functionality to dump them without needing to actually
+ * open the files.
+ */
+static int spufs_arch_notes_size(void)
+{
+	struct fdtable *fdt = files_fdtable(current->files);
+	int size = 0, fd;
+
+	for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) {
+		if (FD_ISSET(fd, fdt->open_fds)) {
+			struct file *file = fcheck(fd);
+
+			if (file && file->f_op == &spufs_context_fops) {
+				int rval = spufs_add_one_context(file, fd);
+				if (rval < 0)
+					break;
+				size += rval;
+			}
+		}
+	}
+
+	return size;
+}
+
+static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
+				struct file *file)
+{
+	struct spu_context *ctx;
+	loff_t pos = 0;
+	int sz, dfd, rc, total = 0;
+	const int bufsz = 4096;
+	char *name;
+	char fullname[80], *buf;
+	struct elf_note en;
+
+	buf = kmalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	dfd = ctx_info->dfd;
+	name = spufs_coredump_read[i].name;
+
+	if (!strcmp(name, "mem"))
+		sz = ctx_info->memsize;
+	else
+		sz = spufs_coredump_read[i].size;
+
+	ctx = ctx_info->ctx;
+	if (!ctx) {
+		return;
+	}
+
+	sprintf(fullname, "SPU/%d/%s", dfd, name);
+	en.n_namesz = strlen(fullname) + 1;
+	en.n_descsz = sz;
+	en.n_type = NT_SPU;
+
+	if (!spufs_dump_write(file, &en, sizeof(en)))
+		return;
+	if (!spufs_dump_write(file, fullname, en.n_namesz))
+		return;
+	if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4)))
+		return;
+
+	do {
+		rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
+		if (rc > 0) {
+			if (!spufs_dump_write(file, buf, rc))
+				return;
+			total += rc;
+		}
+	} while (rc == bufsz && total < sz);
+
+	spufs_dump_seek(file, roundup((unsigned long)file->f_pos
+						- total + sz, 4));
+}
+
+static void spufs_arch_write_notes(struct file *file)
+{
+	int j;
+	struct spufs_ctx_info *ctx_info, *next;
+
+	list_for_each_entry_safe(ctx_info, next, &ctx_info_list, list) {
+		spu_acquire_saved(ctx_info->ctx);
+		for (j = 0; j < spufs_coredump_num_notes; j++)
+			spufs_arch_write_note(ctx_info, j, file);
+		spu_release(ctx_info->ctx);
+		list_del(&ctx_info->list);
+		kfree(ctx_info);
+	}
+}
+
+struct spu_coredump_calls spufs_coredump_calls = {
+	.arch_notes_size = spufs_arch_notes_size,
+	.arch_write_notes = spufs_arch_write_notes,
+	.owner = THIS_MODULE,
+};
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -39,7 +39,6 @@
 
 #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
 
-
 static int
 spufs_mem_open(struct inode *inode, struct file *file)
 {
@@ -52,18 +51,23 @@ spufs_mem_open(struct inode *inode, stru
 }
 
 static ssize_t
+__spufs_mem_read(struct spu_context *ctx, char __user *buffer,
+			size_t size, loff_t *pos)
+{
+	char *local_store = ctx->ops->get_ls(ctx);
+	return simple_read_from_buffer(buffer, size, pos, local_store,
+					LS_SIZE);
+}
+
+static ssize_t
 spufs_mem_read(struct file *file, char __user *buffer,
 				size_t size, loff_t *pos)
 {
-	struct spu_context *ctx = file->private_data;
-	char *local_store;
 	int ret;
+	struct spu_context *ctx = file->private_data;
 
 	spu_acquire(ctx);
-
-	local_store = ctx->ops->get_ls(ctx);
-	ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
-
+	ret = __spufs_mem_read(ctx, buffer, size, pos);
 	spu_release(ctx);
 	return ret;
 }
@@ -262,18 +266,23 @@ spufs_regs_open(struct inode *inode, str
 }
 
 static ssize_t
+__spufs_regs_read(struct spu_context *ctx, char __user *buffer,
+			size_t size, loff_t *pos)
+{
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	return simple_read_from_buffer(buffer, size, pos,
+				      lscsa->gprs, sizeof lscsa->gprs);
+}
+
+static ssize_t
 spufs_regs_read(struct file *file, char __user *buffer,
 		size_t size, loff_t *pos)
 {
-	struct spu_context *ctx = file->private_data;
-	struct spu_lscsa *lscsa = ctx->csa.lscsa;
 	int ret;
+	struct spu_context *ctx = file->private_data;
 
 	spu_acquire_saved(ctx);
-
-	ret = simple_read_from_buffer(buffer, size, pos,
-				      lscsa->gprs, sizeof lscsa->gprs);
-
+	ret = __spufs_regs_read(ctx, buffer, size, pos);
 	spu_release(ctx);
 	return ret;
 }
@@ -308,18 +317,23 @@ static struct file_operations spufs_regs
 };
 
 static ssize_t
+__spufs_fpcr_read(struct spu_context *ctx, char __user * buffer,
+			size_t size, loff_t * pos)
+{
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	return simple_read_from_buffer(buffer, size, pos,
+				      &lscsa->fpcr, sizeof(lscsa->fpcr));
+}
+
+static ssize_t
 spufs_fpcr_read(struct file *file, char __user * buffer,
 		size_t size, loff_t * pos)
 {
-	struct spu_context *ctx = file->private_data;
-	struct spu_lscsa *lscsa = ctx->csa.lscsa;
 	int ret;
+	struct spu_context *ctx = file->private_data;
 
 	spu_acquire_saved(ctx);
-
-	ret = simple_read_from_buffer(buffer, size, pos,
-				      &lscsa->fpcr, sizeof(lscsa->fpcr));
-
+	ret = __spufs_fpcr_read(ctx, buffer, size, pos);
 	spu_release(ctx);
 	return ret;
 }
@@ -719,22 +733,19 @@ static int spufs_signal1_open(struct ino
 	return nonseekable_open(inode, file);
 }
 
-static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
+static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
 			size_t len, loff_t *pos)
 {
-	struct spu_context *ctx = file->private_data;
 	int ret = 0;
 	u32 data;
 
 	if (len < 4)
 		return -EINVAL;
 
-	spu_acquire_saved(ctx);
 	if (ctx->csa.spu_chnlcnt_RW[3]) {
 		data = ctx->csa.spu_chnldata_RW[3];
 		ret = 4;
 	}
-	spu_release(ctx);
 
 	if (!ret)
 		goto out;
@@ -746,6 +757,19 @@ out:
 	return ret;
 }
 
+static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	int ret;
+	struct spu_context *ctx = file->private_data;
+
+	spu_acquire_saved(ctx);
+	ret = __spufs_signal1_read(ctx, buf, len, pos);
+	spu_release(ctx);
+
+	return ret;
+}
+
 static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
 			size_t len, loff_t *pos)
 {
@@ -816,22 +840,19 @@ static int spufs_signal2_open(struct ino
 	return nonseekable_open(inode, file);
 }
 
-static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
+static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
 			size_t len, loff_t *pos)
 {
-	struct spu_context *ctx = file->private_data;
 	int ret = 0;
 	u32 data;
 
 	if (len < 4)
 		return -EINVAL;
 
-	spu_acquire_saved(ctx);
 	if (ctx->csa.spu_chnlcnt_RW[4]) {
 		data =  ctx->csa.spu_chnldata_RW[4];
 		ret = 4;
 	}
-	spu_release(ctx);
 
 	if (!ret)
 		goto out;
@@ -840,7 +861,20 @@ static ssize_t spufs_signal2_read(struct
 		return -EFAULT;
 
 out:
-	return 4;
+	return ret;
+}
+
+static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	int ret;
+
+	spu_acquire_saved(ctx);
+	ret = __spufs_signal2_read(ctx, buf, len, pos);
+	spu_release(ctx);
+
+	return ret;
 }
 
 static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
@@ -916,13 +950,19 @@ static void spufs_signal1_type_set(void 
 	spu_release(ctx);
 }
 
+static u64 __spufs_signal1_type_get(void *data)
+{
+	struct spu_context *ctx = data;
+	return ctx->ops->signal1_type_get(ctx);
+}
+
 static u64 spufs_signal1_type_get(void *data)
 {
 	struct spu_context *ctx = data;
 	u64 ret;
 
 	spu_acquire(ctx);
-	ret = ctx->ops->signal1_type_get(ctx);
+	ret = __spufs_signal1_type_get(data);
 	spu_release(ctx);
 
 	return ret;
@@ -939,13 +979,19 @@ static void spufs_signal2_type_set(void 
 	spu_release(ctx);
 }
 
+static u64 __spufs_signal2_type_get(void *data)
+{
+	struct spu_context *ctx = data;
+	return ctx->ops->signal2_type_get(ctx);
+}
+
 static u64 spufs_signal2_type_get(void *data)
 {
 	struct spu_context *ctx = data;
 	u64 ret;
 
 	spu_acquire(ctx);
-	ret = ctx->ops->signal2_type_get(ctx);
+	ret = __spufs_signal2_type_get(data);
 	spu_release(ctx);
 
 	return ret;
@@ -1387,13 +1433,19 @@ static void spufs_decr_set(void *data, u
 	spu_release(ctx);
 }
 
-static u64 spufs_decr_get(void *data)
+static u64 __spufs_decr_get(void *data)
 {
 	struct spu_context *ctx = data;
 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	return lscsa->decr.slot[0];
+}
+
+static u64 spufs_decr_get(void *data)
+{
+	struct spu_context *ctx = data;
 	u64 ret;
 	spu_acquire_saved(ctx);
-	ret = lscsa->decr.slot[0];
+	ret = __spufs_decr_get(data);
 	spu_release(ctx);
 	return ret;
 }
@@ -1409,13 +1461,19 @@ static void spufs_decr_status_set(void *
 	spu_release(ctx);
 }
 
-static u64 spufs_decr_status_get(void *data)
+static u64 __spufs_decr_status_get(void *data)
 {
 	struct spu_context *ctx = data;
 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	return lscsa->decr_status.slot[0];
+}
+
+static u64 spufs_decr_status_get(void *data)
+{
+	struct spu_context *ctx = data;
 	u64 ret;
 	spu_acquire_saved(ctx);
-	ret = lscsa->decr_status.slot[0];
+	ret = __spufs_decr_status_get(data);
 	spu_release(ctx);
 	return ret;
 }
@@ -1431,30 +1489,43 @@ static void spufs_event_mask_set(void *d
 	spu_release(ctx);
 }
 
-static u64 spufs_event_mask_get(void *data)
+static u64 __spufs_event_mask_get(void *data)
 {
 	struct spu_context *ctx = data;
 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	return lscsa->event_mask.slot[0];
+}
+
+static u64 spufs_event_mask_get(void *data)
+{
+	struct spu_context *ctx = data;
 	u64 ret;
 	spu_acquire_saved(ctx);
-	ret = lscsa->event_mask.slot[0];
+	ret = __spufs_event_mask_get(data);
 	spu_release(ctx);
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
 			spufs_event_mask_set, "0x%llx\n")
 
-static u64 spufs_event_status_get(void *data)
+static u64 __spufs_event_status_get(void *data)
 {
 	struct spu_context *ctx = data;
 	struct spu_state *state = &ctx->csa;
-	u64 ret = 0;
 	u64 stat;
-
-	spu_acquire_saved(ctx);
 	stat = state->spu_chnlcnt_RW[0];
 	if (stat)
-		ret = state->spu_chnldata_RW[0];
+		return state->spu_chnldata_RW[0];
+	return 0;
+}
+
+static u64 spufs_event_status_get(void *data)
+{
+	struct spu_context *ctx = data;
+	u64 ret = 0;
+
+	spu_acquire_saved(ctx);
+	ret = __spufs_event_status_get(data);
 	spu_release(ctx);
 	return ret;
 }
@@ -1499,12 +1570,18 @@ 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)
+static u64 __spufs_object_id_get(void *data)
 {
 	struct spu_context *ctx = data;
 	return ctx->object_id;
 }
 
+static u64 spufs_object_id_get(void *data)
+{
+	/* FIXME: Should there really be no locking here? */
+	return __spufs_object_id_get(data);
+}
+
 static void spufs_object_id_set(void *data, u64 id)
 {
 	struct spu_context *ctx = data;
@@ -1514,13 +1591,19 @@ static void spufs_object_id_set(void *da
 DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get,
 		spufs_object_id_set, "0x%llx\n");
 
+static u64 __spufs_lslr_get(void *data)
+{
+	struct spu_context *ctx = data;
+	return ctx->csa.priv2.spu_lslr_RW;
+}
+
 static u64 spufs_lslr_get(void *data)
 {
 	struct spu_context *ctx = data;
 	u64 ret;
 
 	spu_acquire_saved(ctx);
-	ret = ctx->csa.priv2.spu_lslr_RW;
+	ret = __spufs_lslr_get(data);
 	spu_release(ctx);
 
 	return ret;
@@ -1535,26 +1618,36 @@ static int spufs_info_open(struct inode 
 	return 0;
 }
 
+static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
+			char __user *buf, size_t len, loff_t *pos)
+{
+	u32 mbox_stat;
+	u32 data;
+
+	mbox_stat = ctx->csa.prob.mb_stat_R;
+	if (mbox_stat & 0x0000ff) {
+		data = ctx->csa.prob.pu_mb_R;
+	}
+
+	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
+}
+
 static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
 				   size_t len, loff_t *pos)
 {
+	int ret;
 	struct spu_context *ctx = file->private_data;
-	u32 mbox_stat;
-	u32 data;
 
 	if (!access_ok(VERIFY_WRITE, buf, len))
 		return -EFAULT;
 
 	spu_acquire_saved(ctx);
 	spin_lock(&ctx->csa.register_lock);
-	mbox_stat = ctx->csa.prob.mb_stat_R;
-	if (mbox_stat & 0x0000ff) {
-		data = ctx->csa.prob.pu_mb_R;
-	}
+	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release(ctx);
 
-	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
+	return ret;
 }
 
 static struct file_operations spufs_mbox_info_fops = {
@@ -1563,26 +1656,36 @@ static struct file_operations spufs_mbox
 	.llseek  = generic_file_llseek,
 };
 
+static ssize_t __spufs_ibox_info_read(struct spu_context *ctx,
+				char __user *buf, size_t len, loff_t *pos)
+{
+	u32 ibox_stat;
+	u32 data;
+
+	ibox_stat = ctx->csa.prob.mb_stat_R;
+	if (ibox_stat & 0xff0000) {
+		data = ctx->csa.priv2.puint_mb_R;
+	}
+
+	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
+}
+
 static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
-	u32 ibox_stat;
-	u32 data;
+	int ret;
 
 	if (!access_ok(VERIFY_WRITE, buf, len))
 		return -EFAULT;
 
 	spu_acquire_saved(ctx);
 	spin_lock(&ctx->csa.register_lock);
-	ibox_stat = ctx->csa.prob.mb_stat_R;
-	if (ibox_stat & 0xff0000) {
-		data = ctx->csa.priv2.puint_mb_R;
-	}
+	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release(ctx);
 
-	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
+	return ret;
 }
 
 static struct file_operations spufs_ibox_info_fops = {
@@ -1591,29 +1694,39 @@ static struct file_operations spufs_ibox
 	.llseek  = generic_file_llseek,
 };
 
-static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
-				   size_t len, loff_t *pos)
+static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
+			char __user *buf, size_t len, loff_t *pos)
 {
-	struct spu_context *ctx = file->private_data;
 	int i, cnt;
 	u32 data[4];
 	u32 wbox_stat;
 
+	wbox_stat = ctx->csa.prob.mb_stat_R;
+	cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
+	for (i = 0; i < cnt; i++) {
+		data[i] = ctx->csa.spu_mailbox_data[i];
+	}
+
+	return simple_read_from_buffer(buf, len, pos, &data,
+				cnt * sizeof(u32));
+}
+
+static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
+				   size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	int ret;
+
 	if (!access_ok(VERIFY_WRITE, buf, len))
 		return -EFAULT;
 
 	spu_acquire_saved(ctx);
 	spin_lock(&ctx->csa.register_lock);
-	wbox_stat = ctx->csa.prob.mb_stat_R;
-	cnt = (wbox_stat & 0x00ff00) >> 8;
-	for (i = 0; i < cnt; i++) {
-		data[i] = ctx->csa.spu_mailbox_data[i];
-	}
+	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release(ctx);
 
-	return simple_read_from_buffer(buf, len, pos, &data,
-				cnt * sizeof(u32));
+	return ret;
 }
 
 static struct file_operations spufs_wbox_info_fops = {
@@ -1622,19 +1735,13 @@ static struct file_operations spufs_wbox
 	.llseek  = generic_file_llseek,
 };
 
-static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
-			      size_t len, loff_t *pos)
+static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
+			char __user *buf, size_t len, loff_t *pos)
 {
-	struct spu_context *ctx = file->private_data;
 	struct spu_dma_info info;
 	struct mfc_cq_sr *qp, *spuqp;
 	int i;
 
-	if (!access_ok(VERIFY_WRITE, buf, len))
-		return -EFAULT;
-
-	spu_acquire_saved(ctx);
-	spin_lock(&ctx->csa.register_lock);
 	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
 	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
 	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
@@ -1649,25 +1756,40 @@ static ssize_t spufs_dma_info_read(struc
 		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
 		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
 	}
-	spin_unlock(&ctx->csa.register_lock);
-	spu_release(ctx);
 
 	return simple_read_from_buffer(buf, len, pos, &info,
 				sizeof info);
 }
 
+static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
+			      size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	int ret;
+
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+
+	spu_acquire_saved(ctx);
+	spin_lock(&ctx->csa.register_lock);
+	ret = __spufs_dma_info_read(ctx, buf, len, pos);
+	spin_unlock(&ctx->csa.register_lock);
+	spu_release(ctx);
+
+	return ret;
+}
+
 static struct file_operations spufs_dma_info_fops = {
 	.open = spufs_info_open,
 	.read = spufs_dma_info_read,
 };
 
-static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
-				   size_t len, loff_t *pos)
+static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
+			char __user *buf, size_t len, loff_t *pos)
 {
-	struct spu_context *ctx = file->private_data;
 	struct spu_proxydma_info info;
-	int ret = sizeof info;
 	struct mfc_cq_sr *qp, *puqp;
+	int ret = sizeof info;
 	int i;
 
 	if (len < ret)
@@ -1676,8 +1798,6 @@ static ssize_t spufs_proxydma_info_read(
 	if (!access_ok(VERIFY_WRITE, buf, len))
 		return -EFAULT;
 
-	spu_acquire_saved(ctx);
-	spin_lock(&ctx->csa.register_lock);
 	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
 	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
 	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
@@ -1690,12 +1810,23 @@ static ssize_t spufs_proxydma_info_read(
 		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
 		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
 	}
+
+	return simple_read_from_buffer(buf, len, pos, &info,
+				sizeof info);
+}
+
+static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
+				   size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	int ret;
+
+	spu_acquire_saved(ctx);
+	spin_lock(&ctx->csa.register_lock);
+	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release(ctx);
 
-	if (copy_to_user(buf, &info, sizeof info))
-		ret = -EFAULT;
-
 	return ret;
 }
 
@@ -1760,3 +1891,27 @@ struct tree_descr spufs_dir_nosched_cont
 	{ "object-id", &spufs_object_id_ops, 0666, },
 	{},
 };
+
+struct spufs_coredump_reader spufs_coredump_read[] = {
+	{ "regs", __spufs_regs_read, NULL, 128 * 16 },
+	{ "fpcr", __spufs_fpcr_read, NULL, 16 },
+	{ "lslr", NULL, __spufs_lslr_get, 11 },
+	{ "decr", NULL, __spufs_decr_get, 11 },
+	{ "decr_status", NULL, __spufs_decr_status_get, 11 },
+	{ "mem", __spufs_mem_read, NULL, 256 * 1024, },
+	{ "signal1", __spufs_signal1_read, NULL, 4 },
+	{ "signal1_type", NULL, __spufs_signal1_type_get, 2 },
+	{ "signal2", __spufs_signal2_read, NULL, 4 },
+	{ "signal2_type", NULL, __spufs_signal2_type_get, 2 },
+	{ "event_mask", NULL, __spufs_event_mask_get, 8 },
+	{ "event_status", NULL, __spufs_event_status_get, 8 },
+	{ "mbox_info", __spufs_mbox_info_read, NULL, 4 },
+	{ "ibox_info", __spufs_ibox_info_read, NULL, 4 },
+	{ "wbox_info", __spufs_wbox_info_read, NULL, 16 },
+	{ "dma_info", __spufs_dma_info_read, NULL, 69 * 8 },
+	{ "proxydma_info", __spufs_proxydma_info_read, NULL, 35 * 8 },
+	{ "object-id", NULL, __spufs_object_id_get, 19 },
+	{ },
+};
+int spufs_coredump_num_notes = ARRAY_SIZE(spufs_coredump_read) - 1;
+
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
@@ -232,6 +232,7 @@ struct file_operations spufs_context_fop
 	.readdir	= dcache_readdir,
 	.fsync		= simple_sync_file,
 };
+EXPORT_SYMBOL_GPL(spufs_context_fops);
 
 static int
 spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
@@ -647,6 +648,7 @@ static struct file_system_type spufs_typ
 static int __init spufs_init(void)
 {
 	int ret;
+
 	ret = -ENOMEM;
 	spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
 			sizeof(struct spufs_inode_info), 0,
@@ -664,8 +666,12 @@ static int __init spufs_init(void)
 	ret = register_spu_syscalls(&spufs_calls);
 	if (ret)
 		goto out_fs;
+	ret = register_arch_coredump_calls(&spufs_coredump_calls);
+	if (ret)
+		goto out_fs;
 
 	spufs_init_isolated_loader();
+
 	return 0;
 out_fs:
 	unregister_filesystem(&spufs_type);
@@ -679,6 +685,7 @@ module_init(spufs_init);
 static void __exit spufs_exit(void)
 {
 	spu_sched_exit();
+	unregister_arch_coredump_calls(&spufs_coredump_calls);
 	unregister_spu_syscalls(&spufs_calls);
 	unregister_filesystem(&spufs_type);
 	kmem_cache_destroy(spufs_inode_cache);
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/Makefile
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/Makefile
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/Makefile
@@ -1,7 +1,7 @@
 obj-y += switch.o
 
 obj-$(CONFIG_SPU_FS) += spufs.o
-spufs-y += inode.o file.o context.o syscalls.o
+spufs-y += inode.o file.o context.o syscalls.o coredump.o
 spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
 
 # Rules to build switch.o with the help of SPU tool chain
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -223,4 +223,15 @@ void spufs_stop_callback(struct spu *spu
 void spufs_mfc_callback(struct spu *spu);
 void spufs_dma_callback(struct spu *spu, int type);
 
+extern struct spu_coredump_calls spufs_coredump_calls;
+struct spufs_coredump_reader {
+	char *name;
+	ssize_t (*read)(struct spu_context *ctx,
+			char __user *buffer, size_t size, loff_t *pos);
+	u64 (*get)(void *data);
+	size_t size;
+};
+extern struct spufs_coredump_reader spufs_coredump_read[];
+extern int spufs_coredump_num_notes;
+
 #endif
Index: linux-2.6/fs/binfmt_elf.c
===================================================================
--- linux-2.6.orig/fs/binfmt_elf.c
+++ linux-2.6/fs/binfmt_elf.c
@@ -1582,6 +1582,10 @@ static int elf_core_dump(long signr, str
 		
 		sz += thread_status_size;
 
+#ifdef ELF_CORE_WRITE_EXTRA_NOTES
+		sz += ELF_CORE_EXTRA_NOTES_SIZE;
+#endif
+
 		fill_elf_note_phdr(&phdr, sz, offset);
 		offset += sz;
 		DUMP_WRITE(&phdr, sizeof(phdr));
@@ -1622,6 +1626,10 @@ static int elf_core_dump(long signr, str
 		if (!writenote(notes + i, file, &foffset))
 			goto end_coredump;
 
+#ifdef ELF_CORE_WRITE_EXTRA_NOTES
+	ELF_CORE_WRITE_EXTRA_NOTES;
+#endif
+
 	/* write out the thread status notes section */
 	list_for_each(t, &thread_list) {
 		struct elf_thread_status *tmp =
Index: linux-2.6/include/asm-powerpc/elf.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/elf.h
+++ linux-2.6/include/asm-powerpc/elf.h
@@ -411,4 +411,17 @@ do {									\
 /* Keep this the last entry.  */
 #define R_PPC64_NUM		107
 
+#ifdef CONFIG_PPC_CELL
+/* Notes used in ET_CORE. Note name is "SPU/<fd>/<filename>". */
+#define NT_SPU		1
+
+extern int arch_notes_size(void);
+extern void arch_write_notes(struct file *file);
+
+#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size()
+#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file)
+
+#define ARCH_HAVE_EXTRA_ELF_NOTES
+#endif /* CONFIG_PPC_CELL */
+
 #endif /* _ASM_POWERPC_ELF_H */
Index: linux-2.6/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/spu.h
+++ linux-2.6/include/asm-powerpc/spu.h
@@ -172,6 +172,13 @@ extern struct spufs_calls {
 	struct module *owner;
 } spufs_calls;
 
+/* coredump calls implemented in spufs */
+struct spu_coredump_calls {
+	asmlinkage int (*arch_notes_size)(void);
+	asmlinkage void (*arch_write_notes)(struct file *file);
+	struct module *owner;
+};
+
 /* return status from spu_run, same as in libspe */
 #define SPE_EVENT_DMA_ALIGNMENT		0x0008	/*A DMA alignment error */
 #define SPE_EVENT_SPE_ERROR		0x0010	/*An illegal instruction error*/
@@ -203,6 +210,9 @@ static inline void unregister_spu_syscal
 }
 #endif /* MODULE */
 
+int register_arch_coredump_calls(struct spu_coredump_calls *calls);
+void unregister_arch_coredump_calls(struct spu_coredump_calls *calls);
+
 int spu_add_sysdev_attr(struct sysdev_attribute *attr);
 void spu_remove_sysdev_attr(struct sysdev_attribute *attr);
 
Index: linux-2.6/include/linux/elf.h
===================================================================
--- linux-2.6.orig/include/linux/elf.h
+++ linux-2.6/include/linux/elf.h
@@ -368,5 +368,12 @@ extern Elf64_Dyn _DYNAMIC [];
 
 #endif
 
+#ifndef ARCH_HAVE_EXTRA_ELF_NOTES
+static inline int arch_notes_size(void) { return 0; }
+static inline int arch_write_notes(void) { return 0; }
+
+#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size()
+#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file)
+#endif /* ARCH_HAVE_EXTRA_ELF_NOTES */
 
 #endif /* _LINUX_ELF_H */

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 18/22] cell: add symbol exports for oprofile
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (16 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 17/22] coredump: Add SPU elf notes to coredump Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 19/22] cell: PMU register macros Arnd Bergmann
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Kevin Corry, Arnd Bergmann

[-- Attachment #1: cell-pmu-exports.diff --]
[-- Type: text/plain, Size: 2990 bytes --]

Add symbol-exports for the new routines in arch/powerpc/platforms/cell/pmu.c.
They are needed for Oprofile, which can be built as a module.

Patch is against 2.6.18-arnd5.

Signed-Off-By: Kevin Corry <kevcorry@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

Index: linux-2.6/arch/powerpc/platforms/cell/pmu.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pmu.c
+++ linux-2.6/arch/powerpc/platforms/cell/pmu.c
@@ -85,6 +85,7 @@ u32 cbe_read_phys_ctr(u32 cpu, u32 phys_
 
 	return val;
 }
+EXPORT_SYMBOL_GPL(cbe_read_phys_ctr);
 
 void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
 {
@@ -111,6 +112,7 @@ void cbe_write_phys_ctr(u32 cpu, u32 phy
 		}
 	}
 }
+EXPORT_SYMBOL_GPL(cbe_write_phys_ctr);
 
 /*
  * "Logical" counter registers.
@@ -130,6 +132,7 @@ u32 cbe_read_ctr(u32 cpu, u32 ctr)
 
 	return val;
 }
+EXPORT_SYMBOL_GPL(cbe_read_ctr);
 
 void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
 {
@@ -149,6 +152,7 @@ void cbe_write_ctr(u32 cpu, u32 ctr, u32
 
 	cbe_write_phys_ctr(cpu, phys_ctr, val);
 }
+EXPORT_SYMBOL_GPL(cbe_write_ctr);
 
 /*
  * Counter-control registers.
@@ -164,12 +168,14 @@ u32 cbe_read_pm07_control(u32 cpu, u32 c
 
 	return pm07_control;
 }
+EXPORT_SYMBOL_GPL(cbe_read_pm07_control);
 
 void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val)
 {
 	if (ctr < NR_CTRS)
 		WRITE_WO_MMIO(pm07_control[ctr], val);
 }
+EXPORT_SYMBOL_GPL(cbe_write_pm07_control);
 
 /*
  * Other PMU control registers. Most of these are write-only.
@@ -215,6 +221,7 @@ u32 cbe_read_pm(u32 cpu, enum pm_reg_nam
 
 	return val;
 }
+EXPORT_SYMBOL_GPL(cbe_read_pm);
 
 void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
 {
@@ -252,6 +259,7 @@ void cbe_write_pm(u32 cpu, enum pm_reg_n
 		break;
 	}
 }
+EXPORT_SYMBOL_GPL(cbe_write_pm);
 
 /*
  * Get/set the size of a physical counter to either 16 or 32 bits.
@@ -268,6 +276,7 @@ u32 cbe_get_ctr_size(u32 cpu, u32 phys_c
 
 	return size;
 }
+EXPORT_SYMBOL_GPL(cbe_get_ctr_size);
 
 void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
 {
@@ -287,6 +296,7 @@ void cbe_set_ctr_size(u32 cpu, u32 phys_
 		cbe_write_pm(cpu, pm_control, pm_ctrl);
 	}
 }
+EXPORT_SYMBOL_GPL(cbe_set_ctr_size);
 
 /*
  * Enable/disable the entire performance monitoring unit.
@@ -304,6 +314,7 @@ void cbe_enable_pm(u32 cpu)
 	pm_ctrl = cbe_read_pm(cpu, pm_control) | CBE_PM_ENABLE_PERF_MON;
 	cbe_write_pm(cpu, pm_control, pm_ctrl);
 }
+EXPORT_SYMBOL_GPL(cbe_enable_pm);
 
 void cbe_disable_pm(u32 cpu)
 {
@@ -311,6 +322,7 @@ void cbe_disable_pm(u32 cpu)
 	pm_ctrl = cbe_read_pm(cpu, pm_control) & ~CBE_PM_ENABLE_PERF_MON;
 	cbe_write_pm(cpu, pm_control, pm_ctrl);
 }
+EXPORT_SYMBOL_GPL(cbe_disable_pm);
 
 /*
  * Reading from the trace_buffer.
@@ -325,4 +337,5 @@ void cbe_read_trace_buffer(u32 cpu, u64 
 	*buf++ = in_be64(&pmd_regs->trace_buffer_0_63);
 	*buf++ = in_be64(&pmd_regs->trace_buffer_64_127);
 }
+EXPORT_SYMBOL_GPL(cbe_read_trace_buffer);
 

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 19/22] cell: PMU register macros
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (17 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 18/22] cell: add symbol exports for oprofile Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 20/22] cell: Move PMU-related stuff to include/asm-powerpc/cell-pmu.h Arnd Bergmann
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Kevin Corry,
	Carl Love, Arnd Bergmann

[-- Attachment #1: cell-pmu-register-macros.diff --]
[-- Type: text/plain, Size: 1687 bytes --]

From: Kevin Corry <kevcorry@us.ibm.com>
More macros for manipulating bits in the Cell PMU control registers.

Signed-off-by: Kevin Corry <kevcorry@us.ibm.com>
Signed-off-by: Carl Love <carll@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.h
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
@@ -38,7 +38,28 @@
 /* Macros for the pm_control register. */
 #define CBE_PM_16BIT_CTR(ctr)			(1 << (24 - ((ctr) & (NR_PHYS_CTRS - 1))))
 #define CBE_PM_ENABLE_PERF_MON			0x80000000
+#define CBE_PM_STOP_AT_MAX			0x40000000
+#define CBE_PM_TRACE_MODE_GET(pm_control)	(((pm_control) >> 28) & 0x3)
+#define CBE_PM_TRACE_MODE_SET(mode)		(((mode)  & 0x3) << 28)
+#define CBE_PM_COUNT_MODE_SET(count)		(((count) & 0x3) << 18)
+#define CBE_PM_FREEZE_ALL_CTRS			0x00100000
+#define CBE_PM_ENABLE_EXT_TRACE			0x00008000
+
+/* Macros for the trace_address register. */
+#define CBE_PM_TRACE_BUF_FULL			0x00000800
+#define CBE_PM_TRACE_BUF_EMPTY			0x00000400
+#define CBE_PM_TRACE_BUF_DATA_COUNT(ta)		((ta) & 0x3ff)
+#define CBE_PM_TRACE_BUF_MAX_COUNT		0x400
+
+/* Macros for the pm07_control registers. */
+#define CBE_PM_CTR_INPUT_MUX(pm07_control)	(((pm07_control) >> 26) & 0x3f)
+#define CBE_PM_CTR_INPUT_CONTROL		0x02000000
+#define CBE_PM_CTR_POLARITY			0x01000000
+#define CBE_PM_CTR_COUNT_CYCLES			0x00800000
+#define CBE_PM_CTR_ENABLE			0x00400000
 
+/* Macros for the pm_status register. */
+#define CBE_PM_CTR_OVERFLOW_INTR(ctr)		(1 << (31 - ((ctr) & 7)))
 
 union spe_reg {
 	u64 val;

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 20/22] cell: Move PMU-related stuff to include/asm-powerpc/cell-pmu.h
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (18 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 19/22] cell: PMU register macros Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 21/22] cell: add routines for managing PMU interrupts Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 22/22] cell: add oprofile support Arnd Bergmann
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Kevin Corry, Arnd Bergmann

[-- Attachment #1: cell-move-PMU-related-stuff-to-include_asm-powerpc_cell-pmu-h.diff --]
[-- Type: text/plain, Size: 8307 bytes --]

From: Kevin Corry <kevcorry@us.ibm.com>
Move some PMU-related macros and function prototypes from cbe_regs.h
and pmu.h in arch/powerpc/platforms/cell/ to a new header at
include/asm-powerpc/cell-pmu.h

This is cleaner to use from the oprofile code, since that sits in
arch/powerpc/oprofile, not in the cell platform directory.

Signed-off-by: Kevin Corry <kevcorry@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.h
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
@@ -15,6 +15,8 @@
 #ifndef CBE_REGS_H
 #define CBE_REGS_H
 
+#include <asm/cell-pmu.h>
+
 /*
  *
  * Some HID register definitions
@@ -35,32 +37,6 @@
  *
  */
 
-/* Macros for the pm_control register. */
-#define CBE_PM_16BIT_CTR(ctr)			(1 << (24 - ((ctr) & (NR_PHYS_CTRS - 1))))
-#define CBE_PM_ENABLE_PERF_MON			0x80000000
-#define CBE_PM_STOP_AT_MAX			0x40000000
-#define CBE_PM_TRACE_MODE_GET(pm_control)	(((pm_control) >> 28) & 0x3)
-#define CBE_PM_TRACE_MODE_SET(mode)		(((mode)  & 0x3) << 28)
-#define CBE_PM_COUNT_MODE_SET(count)		(((count) & 0x3) << 18)
-#define CBE_PM_FREEZE_ALL_CTRS			0x00100000
-#define CBE_PM_ENABLE_EXT_TRACE			0x00008000
-
-/* Macros for the trace_address register. */
-#define CBE_PM_TRACE_BUF_FULL			0x00000800
-#define CBE_PM_TRACE_BUF_EMPTY			0x00000400
-#define CBE_PM_TRACE_BUF_DATA_COUNT(ta)		((ta) & 0x3ff)
-#define CBE_PM_TRACE_BUF_MAX_COUNT		0x400
-
-/* Macros for the pm07_control registers. */
-#define CBE_PM_CTR_INPUT_MUX(pm07_control)	(((pm07_control) >> 26) & 0x3f)
-#define CBE_PM_CTR_INPUT_CONTROL		0x02000000
-#define CBE_PM_CTR_POLARITY			0x01000000
-#define CBE_PM_CTR_COUNT_CYCLES			0x00800000
-#define CBE_PM_CTR_ENABLE			0x00400000
-
-/* Macros for the pm_status register. */
-#define CBE_PM_CTR_OVERFLOW_INTR(ctr)		(1 << (31 - ((ctr) & 7)))
-
 union spe_reg {
 	u64 val;
 	u8 spe[8];
@@ -160,9 +136,6 @@ extern struct cbe_pmd_regs __iomem *cbe_
  * counters currently have a value waiting to be written.
  */
 
-#define NR_PHYS_CTRS	4
-#define NR_CTRS		(NR_PHYS_CTRS * 2)
-
 struct cbe_pmd_shadow_regs {
 	u32 group_control;
 	u32 debug_bus_control;
Index: linux-2.6/arch/powerpc/platforms/cell/pmu.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pmu.c
+++ linux-2.6/arch/powerpc/platforms/cell/pmu.c
@@ -30,7 +30,6 @@
 
 #include "cbe_regs.h"
 #include "interrupt.h"
-#include "pmu.h"
 
 /*
  * When writing to write-only mmio addresses, save a shadow copy. All of the
Index: linux-2.6/arch/powerpc/platforms/cell/pmu.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pmu.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Cell Broadband Engine Performance Monitor
- *
- * (C) Copyright IBM Corporation 2001,2006
- *
- * Author:
- *   David Erb (djerb@us.ibm.com)
- *   Kevin Corry (kevcorry@us.ibm.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __PERFMON_H__
-#define __PERFMON_H__
-
-enum pm_reg_name {
-	group_control,
-	debug_bus_control,
-	trace_address,
-	ext_tr_timer,
-	pm_status,
-	pm_control,
-	pm_interval,
-	pm_start_stop,
-};
-
-extern u32  cbe_read_phys_ctr(u32 cpu, u32 phys_ctr);
-extern void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val);
-extern u32  cbe_read_ctr(u32 cpu, u32 ctr);
-extern void cbe_write_ctr(u32 cpu, u32 ctr, u32 val);
-
-extern u32  cbe_read_pm07_control(u32 cpu, u32 ctr);
-extern void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val);
-extern u32  cbe_read_pm (u32 cpu, enum pm_reg_name reg);
-extern void cbe_write_pm (u32 cpu, enum pm_reg_name reg, u32 val);
-
-extern u32  cbe_get_ctr_size(u32 cpu, u32 phys_ctr);
-extern void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size);
-
-extern void cbe_enable_pm(u32 cpu);
-extern void cbe_disable_pm(u32 cpu);
-
-extern void cbe_read_trace_buffer(u32 cpu, u64 *buf);
-
-#endif
Index: linux-2.6/include/asm-powerpc/cell-pmu.h
===================================================================
--- /dev/null
+++ linux-2.6/include/asm-powerpc/cell-pmu.h
@@ -0,0 +1,90 @@
+/*
+ * Cell Broadband Engine Performance Monitor
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author:
+ *   David Erb (djerb@us.ibm.com)
+ *   Kevin Corry (kevcorry@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_CELL_PMU_H__
+#define __ASM_CELL_PMU_H__
+
+/* The Cell PMU has four hardware performance counters, which can be
+ * configured as four 32-bit counters or eight 16-bit counters.
+ */
+#define NR_PHYS_CTRS 4
+#define NR_CTRS      (NR_PHYS_CTRS * 2)
+
+/* Macros for the pm_control register. */
+#define CBE_PM_16BIT_CTR(ctr)              (1 << (24 - ((ctr) & (NR_PHYS_CTRS - 1))))
+#define CBE_PM_ENABLE_PERF_MON             0x80000000
+#define CBE_PM_STOP_AT_MAX                 0x40000000
+#define CBE_PM_TRACE_MODE_GET(pm_control)  (((pm_control) >> 28) & 0x3)
+#define CBE_PM_TRACE_MODE_SET(mode)        (((mode)  & 0x3) << 28)
+#define CBE_PM_COUNT_MODE_SET(count)       (((count) & 0x3) << 18)
+#define CBE_PM_FREEZE_ALL_CTRS             0x00100000
+#define CBE_PM_ENABLE_EXT_TRACE            0x00008000
+
+/* Macros for the trace_address register. */
+#define CBE_PM_TRACE_BUF_FULL              0x00000800
+#define CBE_PM_TRACE_BUF_EMPTY             0x00000400
+#define CBE_PM_TRACE_BUF_DATA_COUNT(ta)    ((ta) & 0x3ff)
+#define CBE_PM_TRACE_BUF_MAX_COUNT         0x400
+
+/* Macros for the pm07_control registers. */
+#define CBE_PM_CTR_INPUT_MUX(pm07_control) (((pm07_control) >> 26) & 0x3f)
+#define CBE_PM_CTR_INPUT_CONTROL           0x02000000
+#define CBE_PM_CTR_POLARITY                0x01000000
+#define CBE_PM_CTR_COUNT_CYCLES            0x00800000
+#define CBE_PM_CTR_ENABLE                  0x00400000
+
+/* Macros for the pm_status register. */
+#define CBE_PM_CTR_OVERFLOW_INTR(ctr)      (1 << (31 - ((ctr) & 7)))
+
+enum pm_reg_name {
+	group_control,
+	debug_bus_control,
+	trace_address,
+	ext_tr_timer,
+	pm_status,
+	pm_control,
+	pm_interval,
+	pm_start_stop,
+};
+
+/* Routines for reading/writing the PMU registers. */
+extern u32  cbe_read_phys_ctr(u32 cpu, u32 phys_ctr);
+extern void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val);
+extern u32  cbe_read_ctr(u32 cpu, u32 ctr);
+extern void cbe_write_ctr(u32 cpu, u32 ctr, u32 val);
+
+extern u32  cbe_read_pm07_control(u32 cpu, u32 ctr);
+extern void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val);
+extern u32  cbe_read_pm(u32 cpu, enum pm_reg_name reg);
+extern void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val);
+
+extern u32  cbe_get_ctr_size(u32 cpu, u32 phys_ctr);
+extern void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size);
+
+extern void cbe_enable_pm(u32 cpu);
+extern void cbe_disable_pm(u32 cpu);
+
+extern void cbe_read_trace_buffer(u32 cpu, u64 *buf);
+
+#endif /* __ASM_CELL_PMU_H__ */

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 21/22] cell: add routines for managing PMU interrupts
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (19 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 20/22] cell: Move PMU-related stuff to include/asm-powerpc/cell-pmu.h Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  2006-11-20 17:45 ` [PATCH 22/22] cell: add oprofile support Arnd Bergmann
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Kevin Corry,
	Carl Love, Arnd Bergmann

[-- Attachment #1: oprofile-for-cell-prereqs-new-routines-for-managing-pmu-interrupts.diff --]
[-- Type: text/plain, Size: 5344 bytes --]

From: Kevin Corry <kevcorry@us.ibm.com>

The following routines are added to arch/powerpc/platforms/cell/pmu.c:
 cbe_clear_pm_interrupts()
 cbe_enable_pm_interrupts()
 cbe_disable_pm_interrupts()
 cbe_query_pm_interrupts()
 cbe_pm_irq()
 cbe_init_pm_irq()

This also adds a routine in arch/powerpc/platforms/cell/interrupt.c and
some macros in cbe_regs.h to manipulate the IIC_IR register:
 iic_set_interrupt_routing()

Signed-off-by: Kevin Corry <kevcorry@us.ibm.com>
Signed-off-by: Carl Love <carll@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/platforms/cell/pmu.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pmu.c
+++ linux-2.6/arch/powerpc/platforms/cell/pmu.c
@@ -22,9 +22,11 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/interrupt.h>
 #include <linux/types.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
+#include <asm/pmc.h>
 #include <asm/reg.h>
 #include <asm/spu.h>
 
@@ -338,3 +340,71 @@ void cbe_read_trace_buffer(u32 cpu, u64 
 }
 EXPORT_SYMBOL_GPL(cbe_read_trace_buffer);
 
+/*
+ * Enabling/disabling interrupts for the entire performance monitoring unit.
+ */
+
+u32 cbe_query_pm_interrupts(u32 cpu)
+{
+	return cbe_read_pm(cpu, pm_status);
+}
+EXPORT_SYMBOL_GPL(cbe_query_pm_interrupts);
+
+u32 cbe_clear_pm_interrupts(u32 cpu)
+{
+	/* Reading pm_status clears the interrupt bits. */
+	return cbe_query_pm_interrupts(cpu);
+}
+EXPORT_SYMBOL_GPL(cbe_clear_pm_interrupts);
+
+void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
+{
+	/* Set which node and thread will handle the next interrupt. */
+	iic_set_interrupt_routing(cpu, thread, 0);
+
+	/* Enable the interrupt bits in the pm_status register. */
+	if (mask)
+		cbe_write_pm(cpu, pm_status, mask);
+}
+EXPORT_SYMBOL_GPL(cbe_enable_pm_interrupts);
+
+void cbe_disable_pm_interrupts(u32 cpu)
+{
+	cbe_clear_pm_interrupts(cpu);
+	cbe_write_pm(cpu, pm_status, 0);
+}
+EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts);
+
+static irqreturn_t cbe_pm_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	perf_irq(regs);
+	return IRQ_HANDLED;
+}
+
+int __init cbe_init_pm_irq(void)
+{
+	unsigned int irq;
+	int rc, node;
+
+	for_each_node(node) {
+		irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
+					       (node << IIC_IRQ_NODE_SHIFT));
+		if (irq == NO_IRQ) {
+			printk("ERROR: Unable to allocate irq for node %d\n",
+			       node);
+			return -EINVAL;
+		}
+
+		rc = request_irq(irq, cbe_pm_irq,
+				 IRQF_DISABLED, "cbe-pmu-0", NULL);
+		if (rc) {
+			printk("ERROR: Request for irq on node %d failed\n",
+			       node);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+arch_initcall(cbe_init_pm_irq);
+
Index: linux-2.6/arch/powerpc/platforms/cell/interrupt.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/interrupt.c
+++ linux-2.6/arch/powerpc/platforms/cell/interrupt.c
@@ -396,3 +396,19 @@ void __init iic_init_IRQ(void)
 	/* Enable on current CPU */
 	iic_setup_cpu();
 }
+
+void iic_set_interrupt_routing(int cpu, int thread, int priority)
+{
+	struct cbe_iic_regs __iomem *iic_regs = cbe_get_cpu_iic_regs(cpu);
+	u64 iic_ir = 0;
+	int node = cpu >> 1;
+
+	/* Set which node and thread will handle the next interrupt */
+	iic_ir |= CBE_IIC_IR_PRIO(priority) |
+		  CBE_IIC_IR_DEST_NODE(node);
+	if (thread == 0)
+		iic_ir |= CBE_IIC_IR_DEST_UNIT(CBE_IIC_IR_PT_0);
+	else
+		iic_ir |= CBE_IIC_IR_DEST_UNIT(CBE_IIC_IR_PT_1);
+	out_be64(&iic_regs->iic_ir, iic_ir);
+}
Index: linux-2.6/arch/powerpc/platforms/cell/interrupt.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/interrupt.h
+++ linux-2.6/arch/powerpc/platforms/cell/interrupt.h
@@ -83,5 +83,7 @@ extern u8 iic_get_target_id(int cpu);
 
 extern void spider_init_IRQ(void);
 
+extern void iic_set_interrupt_routing(int cpu, int thread, int priority);
+
 #endif
 #endif /* ASM_CELL_PIC_H */
Index: linux-2.6/include/asm-powerpc/cell-pmu.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/cell-pmu.h
+++ linux-2.6/include/asm-powerpc/cell-pmu.h
@@ -87,4 +87,9 @@ extern void cbe_disable_pm(u32 cpu);
 
 extern void cbe_read_trace_buffer(u32 cpu, u64 *buf);
 
+extern void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask);
+extern void cbe_disable_pm_interrupts(u32 cpu);
+extern u32  cbe_query_pm_interrupts(u32 cpu);
+extern u32  cbe_clear_pm_interrupts(u32 cpu);
+
 #endif /* __ASM_CELL_PMU_H__ */
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.h
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
@@ -185,6 +185,14 @@ struct cbe_iic_regs {
 	struct	cbe_iic_thread_regs thread[2];			/* 0x0400 */
 
 	u64	iic_ir;						/* 0x0440 */
+#define CBE_IIC_IR_PRIO(x)      (((x) & 0xf) << 12)
+#define CBE_IIC_IR_DEST_NODE(x) (((x) & 0xf) << 4)
+#define CBE_IIC_IR_DEST_UNIT(x) ((x) & 0xf)
+#define CBE_IIC_IR_IOC_0        0x0
+#define CBE_IIC_IR_IOC_1S       0xb
+#define CBE_IIC_IR_PT_0         0xe
+#define CBE_IIC_IR_PT_1         0xf
+
 	u64	iic_is;						/* 0x0448 */
 #define CBE_IIC_IS_PMI		0x2
 

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 22/22] cell: add oprofile support
  2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
                   ` (20 preceding siblings ...)
  2006-11-20 17:45 ` [PATCH 21/22] cell: add routines for managing PMU interrupts Arnd Bergmann
@ 2006-11-20 17:45 ` Arnd Bergmann
  21 siblings, 0 replies; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-20 17:45 UTC (permalink / raw)
  To: cbe-oss-dev
  Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Carl Love,
	Maynard Johnson, Arnd Bergmann

[-- Attachment #1: oprofile-for-cell-initial-profiling-support-updated-patch.diff --]
[-- Type: text/plain, Size: 29487 bytes --]

From: Maynard Johnson <maynardj@us.ibm.com>
Add PPU event-based and cycle-based profiling support to Oprofile for Cell.

Oprofile is expected to collect data on all CPUs simultaneously.
However, there is one set of performance counters per node.  There are
two hardware threads or virtual CPUs on each node.  Hence, OProfile must
multiplex in time the performance counter collection on the two virtual
CPUs.

The multiplexing of the performance counters is done by a virtual
counter routine.  Initially, the counters are configured to collect data
on the even CPUs in the system, one CPU per node.  In order to capture
the PC for the virtual CPU when the performance counter interrupt occurs
(the specified number of events between samples has occurred), the even
processors are configured to handle the performance counter interrupts
for their node.  The virtual counter routine is called via a kernel
timer after the virtual sample time.  The routine stops the counters,
saves the current counts, loads the last counts for the other virtual
CPU on the node, sets interrupts to be handled by the other virtual CPU
and restarts the counters, the virtual timer routine is scheduled to run
again.  The virtual sample time is kept relatively small to make sure
sampling occurs on both CPUs on the node with a relatively small
granularity.  Whenever the counters overflow, the performance counter
interrupt is called to collect the PC for the CPU where data is being
collected.

The oprofile driver relies on a firmware RTAS call to setup the debug bus
to route the desired signals to the performance counter hardware to be
counted.  The RTAS call must set the routing registers appropriately in
each of the islands to pass the signals down the debug bus as well as
routing the signals from a particular island onto the bus.  There is a
second firmware RTAS call to reset the debug bus to the non pass thru
state when the counters are not in use.

Signed-off-by: Carl Love <carll@us.ibm.com>
Signed-off-by: Maynard Johnson <mpjohn@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/configs/cell_defconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/configs/cell_defconfig
+++ linux-2.6/arch/powerpc/configs/cell_defconfig
@@ -1121,7 +1121,8 @@ CONFIG_PLIST=y
 #
 # Instrumentation Support
 #
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
 # CONFIG_KPROBES is not set
 
 #
Index: linux-2.6/arch/powerpc/kernel/cputable.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/cputable.c
+++ linux-2.6/arch/powerpc/kernel/cputable.c
@@ -304,6 +304,9 @@ static struct cpu_spec cpu_specs[] = {
 			PPC_FEATURE_SMT,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
+		.num_pmcs		= 4,
+		.oprofile_cpu_type	= "ppc64/cell-be",
+		.oprofile_type		= PPC_OPROFILE_CELL,
 		.platform		= "ppc-cell-be",
 	},
 	{	/* PA Semi PA6T */
Index: linux-2.6/arch/powerpc/oprofile/common.c
===================================================================
--- linux-2.6.orig/arch/powerpc/oprofile/common.c
+++ linux-2.6/arch/powerpc/oprofile/common.c
@@ -69,7 +69,10 @@ static void op_powerpc_cpu_start(void *d
 
 static int op_powerpc_start(void)
 {
-	on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
+	if (model->global_start)
+		model->global_start(ctr);
+	if (model->start)
+		on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
 	return 0;
 }
 
@@ -80,7 +83,10 @@ static inline void op_powerpc_cpu_stop(v
 
 static void op_powerpc_stop(void)
 {
-	on_each_cpu(op_powerpc_cpu_stop, NULL, 0, 1);
+	if (model->stop)
+		on_each_cpu(op_powerpc_cpu_stop, NULL, 0, 1);
+        if (model->global_stop)
+                model->global_stop();
 }
 
 static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
@@ -141,6 +147,11 @@ int __init oprofile_arch_init(struct opr
 
 	switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_CELL
+		case PPC_OPROFILE_CELL:
+			model = &op_model_cell;
+			break;
+#endif
 		case PPC_OPROFILE_RS64:
 			model = &op_model_rs64;
 			break;
Index: linux-2.6/arch/powerpc/oprofile/Makefile
===================================================================
--- linux-2.6.orig/arch/powerpc/oprofile/Makefile
+++ linux-2.6/arch/powerpc/oprofile/Makefile
@@ -11,6 +11,7 @@ DRIVER_OBJS := $(addprefix ../../../driv
 		timer_int.o )
 
 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
+oprofile-$(CONFIG_PPC_CELL) += op_model_cell.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
Index: linux-2.6/arch/powerpc/oprofile/op_model_cell.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/oprofile/op_model_cell.c
@@ -0,0 +1,724 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: David Erb (djerb@us.ibm.com)
+ * Modifications:
+ *         Carl Love <carll@us.ibm.com>
+ *         Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <linux/oprofile.h>
+#include <linux/percpu.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <asm/cell-pmu.h>
+#include <asm/cputable.h>
+#include <asm/firmware.h>
+#include <asm/io.h>
+#include <asm/oprofile_impl.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/ptrace.h>
+#include <asm/reg.h>
+#include <asm/rtas.h>
+#include <asm/system.h>
+
+#include "../platforms/cell/interrupt.h"
+
+#define PPU_CYCLES_EVENT_NUM 1	/*  event number for CYCLES */
+#define CBE_COUNT_ALL_CYCLES 0x42800000	/* PPU cycle event specifier */
+
+#define NUM_THREADS 2
+#define VIRT_CNTR_SW_TIME_NS 100000000	// 0.5 seconds
+
+struct pmc_cntrl_data {
+	unsigned long vcntr;
+	unsigned long evnts;
+	unsigned long masks;
+	unsigned long enabled;
+};
+
+/*
+ * ibm,cbe-perftools rtas parameters
+ */
+
+struct pm_signal {
+	u16 cpu;		/* Processor to modify */
+	u16 sub_unit;		/* hw subunit this applies to (if applicable) */
+	u16 signal_group;	/* Signal Group to Enable/Disable */
+	u8 bus_word;		/* Enable/Disable on this Trace/Trigger/Event
+				 * Bus Word(s) (bitmask)
+				 */
+	u8 bit;			/* Trigger/Event bit (if applicable) */
+};
+
+/*
+ * rtas call arguments
+ */
+enum {
+	SUBFUNC_RESET = 1,
+	SUBFUNC_ACTIVATE = 2,
+	SUBFUNC_DEACTIVATE = 3,
+
+	PASSTHRU_IGNORE = 0,
+	PASSTHRU_ENABLE = 1,
+	PASSTHRU_DISABLE = 2,
+};
+
+struct pm_cntrl {
+	u16 enable;
+	u16 stop_at_max;
+	u16 trace_mode;
+	u16 freeze;
+	u16 count_mode;
+};
+
+static struct {
+	u32 group_control;
+	u32 debug_bus_control;
+	struct pm_cntrl pm_cntrl;
+	u32 pm07_cntrl[NR_PHYS_CTRS];
+} pm_regs;
+
+
+#define GET_SUB_UNIT(x) ((x & 0x0000f000) >> 12)
+#define GET_BUS_WORD(x) ((x & 0x000000f0) >> 4)
+#define GET_BUS_TYPE(x) ((x & 0x00000300) >> 8)
+#define GET_POLARITY(x) ((x & 0x00000002) >> 1)
+#define GET_COUNT_CYCLES(x) (x & 0x00000001)
+#define GET_INPUT_CONTROL(x) ((x & 0x00000004) >> 2)
+
+
+static DEFINE_PER_CPU(unsigned long[NR_PHYS_CTRS], pmc_values);
+
+static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS];
+
+/* Interpetation of hdw_thread:
+ * 0 - even virtual cpus 0, 2, 4,...
+ * 1 - odd virtual cpus 1, 3, 5, ...
+ */
+static u32 hdw_thread;
+
+static u32 virt_cntr_inter_mask;
+static struct timer_list timer_virt_cntr;
+
+/* pm_signal needs to be global since it is initialized in
+ * cell_reg_setup at the time when the necessary information
+ * is available.
+ */
+static struct pm_signal pm_signal[NR_PHYS_CTRS];
+static int pm_rtas_token;
+
+static u32 reset_value[NR_PHYS_CTRS];
+static int num_counters;
+static int oprofile_running;
+static spinlock_t virt_cntr_lock = SPIN_LOCK_UNLOCKED;
+
+static u32 ctr_enabled;
+
+static unsigned char trace_bus[4];
+static unsigned char input_bus[2];
+
+/*
+ * Firmware interface functions
+ */
+static int
+rtas_ibm_cbe_perftools(int subfunc, int passthru,
+		       void *address, unsigned long length)
+{
+	u64 paddr = __pa(address);
+
+	return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, passthru,
+			 paddr >> 32, paddr & 0xffffffff, length);
+}
+
+static void pm_rtas_reset_signals(u32 node)
+{
+	int ret;
+	struct pm_signal pm_signal_local;
+
+	/*  The debug bus is being set to the passthru disable state.
+	 *  However, the FW still expects atleast one legal signal routing
+	 *  entry or it will return an error on the arguments.  If we don't
+	 *  supply a valid entry, we must ignore all return values.  Ignoring
+	 *  all return values means we might miss an error we should be
+	 *  concerned about.
+	 */
+
+	/*  fw expects physical cpu #. */
+	pm_signal_local.cpu = node;
+	pm_signal_local.signal_group = 21;
+	pm_signal_local.bus_word = 1;
+	pm_signal_local.sub_unit = 0;
+	pm_signal_local.bit = 0;
+
+	ret = rtas_ibm_cbe_perftools(SUBFUNC_RESET, PASSTHRU_DISABLE,
+				     &pm_signal_local,
+				     sizeof(struct pm_signal));
+
+	if (ret)
+		printk(KERN_WARNING "%s: rtas returned: %d\n",
+		       __FUNCTION__, ret);
+}
+
+static void pm_rtas_activate_signals(u32 node, u32 count)
+{
+	int ret;
+	int j;
+	struct pm_signal pm_signal_local[NR_PHYS_CTRS];
+
+	for (j = 0; j < count; j++) {
+		/* fw expects physical cpu # */
+		pm_signal_local[j].cpu = node;
+		pm_signal_local[j].signal_group = pm_signal[j].signal_group;
+		pm_signal_local[j].bus_word = pm_signal[j].bus_word;
+		pm_signal_local[j].sub_unit = pm_signal[j].sub_unit;
+		pm_signal_local[j].bit = pm_signal[j].bit;
+	}
+
+	ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE, PASSTHRU_ENABLE,
+				     pm_signal_local,
+				     count * sizeof(struct pm_signal));
+
+	if (ret)
+		printk(KERN_WARNING "%s: rtas returned: %d\n",
+		       __FUNCTION__, ret);
+}
+
+/*
+ * PM Signal functions
+ */
+static void set_pm_event(u32 ctr, int event, u32 unit_mask)
+{
+	struct pm_signal *p;
+	u32 signal_bit;
+	u32 bus_word, bus_type, count_cycles, polarity, input_control;
+	int j, i;
+
+	if (event == PPU_CYCLES_EVENT_NUM) {
+		/* Special Event: Count all cpu cycles */
+		pm_regs.pm07_cntrl[ctr] = CBE_COUNT_ALL_CYCLES;
+		p = &(pm_signal[ctr]);
+		p->signal_group = 21;
+		p->bus_word = 1;
+		p->sub_unit = 0;
+		p->bit = 0;
+		goto out;
+	} else {
+		pm_regs.pm07_cntrl[ctr] = 0;
+	}
+
+	bus_word = GET_BUS_WORD(unit_mask);
+	bus_type = GET_BUS_TYPE(unit_mask);
+	count_cycles = GET_COUNT_CYCLES(unit_mask);
+	polarity = GET_POLARITY(unit_mask);
+	input_control = GET_INPUT_CONTROL(unit_mask);
+	signal_bit = (event % 100);
+
+	p = &(pm_signal[ctr]);
+
+	p->signal_group = event / 100;
+	p->bus_word = bus_word;
+	p->sub_unit = unit_mask & 0x0000f000;
+
+	pm_regs.pm07_cntrl[ctr] = 0;
+	pm_regs.pm07_cntrl[ctr] |= PM07_CTR_COUNT_CYCLES(count_cycles);
+	pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity);
+	pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control);
+
+	if (input_control == 0) {
+		if (signal_bit > 31) {
+			signal_bit -= 32;
+			if (bus_word == 0x3)
+				bus_word = 0x2;
+			else if (bus_word == 0xc)
+				bus_word = 0x8;
+		}
+
+		if ((bus_type == 0) && p->signal_group >= 60)
+			bus_type = 2;
+		if ((bus_type == 1) && p->signal_group >= 50)
+			bus_type = 0;
+
+		pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_MUX(signal_bit);
+	} else {
+		pm_regs.pm07_cntrl[ctr] = 0;
+		p->bit = signal_bit;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (bus_word & (1 << i)) {
+			pm_regs.debug_bus_control |=
+			    (bus_type << (31 - (2 * i) + 1));
+
+			for (j = 0; j < 2; j++) {
+				if (input_bus[j] == 0xff) {
+					input_bus[j] = i;
+					pm_regs.group_control |=
+					    (i << (31 - i));
+					break;
+				}
+			}
+		}
+	}
+out:
+	;
+}
+
+static void write_pm_cntrl(int cpu, struct pm_cntrl *pm_cntrl)
+{
+	/* Oprofile will use 32 bit counters, set bits 7:10 to 0 */
+	u32 val = 0;
+	if (pm_cntrl->enable == 1)
+		val |= CBE_PM_ENABLE_PERF_MON;
+
+	if (pm_cntrl->stop_at_max == 1)
+		val |= CBE_PM_STOP_AT_MAX;
+
+	if (pm_cntrl->trace_mode == 1)
+		val |= CBE_PM_TRACE_MODE_SET(pm_cntrl->trace_mode);
+
+	if (pm_cntrl->freeze == 1)
+		val |= CBE_PM_FREEZE_ALL_CTRS;
+
+	/* Routine set_count_mode must be called previously to set
+	 * the count mode based on the user selection of user and kernel.
+	 */
+	val |= CBE_PM_COUNT_MODE_SET(pm_cntrl->count_mode);
+	cbe_write_pm(cpu, pm_control, val);
+}
+
+static inline void
+set_count_mode(u32 kernel, u32 user, struct pm_cntrl *pm_cntrl)
+{
+	/* The user must specify user and kernel if they want them. If
+	 *  neither is specified, OProfile will count in hypervisor mode
+	 */
+	if (kernel) {
+		if (user)
+			pm_cntrl->count_mode = CBE_COUNT_ALL_MODES;
+		else
+			pm_cntrl->count_mode = CBE_COUNT_SUPERVISOR_MODE;
+	} else {
+		if (user)
+			pm_cntrl->count_mode = CBE_COUNT_PROBLEM_MODE;
+		else
+			pm_cntrl->count_mode = CBE_COUNT_HYPERVISOR_MODE;
+	}
+}
+
+static inline void enable_ctr(u32 cpu, u32 ctr, u32 * pm07_cntrl)
+{
+
+	pm07_cntrl[ctr] |= PM07_CTR_ENABLE(1);
+	cbe_write_pm07_control(cpu, ctr, pm07_cntrl[ctr]);
+}
+
+/*
+ * Oprofile is expected to collect data on all CPUs simultaneously.
+ * However, there is one set of performance counters per node.  There are
+ * two hardware threads or virtual CPUs on each node.  Hence, OProfile must
+ * multiplex in time the performance counter collection on the two virtual
+ * CPUs.  The multiplexing of the performance counters is done by this
+ * virtual counter routine.
+ *
+ * The pmc_values used below is defined as 'per-cpu' but its use is
+ * more akin to 'per-node'.  We need to store two sets of counter
+ * values per node -- one for the previous run and one for the next.
+ * The per-cpu[NR_PHYS_CTRS] gives us the storage we need.  Each odd/even
+ * pair of per-cpu arrays is used for storing the previous and next
+ * pmc values for a given node.
+ * NOTE: We use the per-cpu variable to improve cache performance.
+ */
+static void cell_virtual_cntr(unsigned long data)
+{
+	/* This routine will alternate loading the virtual counters for
+	 * virtual CPUs
+	 */
+	int i, prev_hdw_thread, next_hdw_thread;
+	u32 cpu;
+	unsigned long flags;
+
+	/* Make sure that the interrupt_hander and
+	 * the virt counter are not both playing with
+	 * the counters on the same node.
+	 */
+
+	spin_lock_irqsave(&virt_cntr_lock, flags);
+
+	prev_hdw_thread = hdw_thread;
+
+	/* switch the cpu handling the interrupts */
+	hdw_thread = 1 ^ hdw_thread;
+	next_hdw_thread = hdw_thread;
+
+	/* The following is done only once per each node, but
+	 * we need cpu #, not node #, to pass to the cbe_xxx functions.
+	 */
+	for_each_online_cpu(cpu) {
+		if (cbe_get_hw_thread_id(cpu))
+			continue;
+
+		/* stop counters, save counter values, restore counts
+		 * for previous thread
+		 */
+		cbe_disable_pm(cpu);
+		cbe_disable_pm_interrupts(cpu);
+		for (i = 0; i < num_counters; i++) {
+			per_cpu(pmc_values, cpu + prev_hdw_thread)[i]
+			    = cbe_read_ctr(cpu, i);
+
+			if (per_cpu(pmc_values, cpu + next_hdw_thread)[i]
+			    == 0xFFFFFFFF)
+				/* If the cntr value is 0xffffffff, we must
+				 * reset that to 0xfffffff0 when the current
+				 * thread is restarted.  This will generate a new
+				 * interrupt and make sure that we never restore
+				 * the counters to the max value.  If the counters
+				 * were restored to the max value, they do not
+				 * increment and no interrupts are generated.  Hence
+				 * no more samples will be collected on that cpu.
+				 */
+				cbe_write_ctr(cpu, i, 0xFFFFFFF0);
+			else
+				cbe_write_ctr(cpu, i,
+					      per_cpu(pmc_values,
+						      cpu +
+						      next_hdw_thread)[i]);
+		}
+
+		/* Switch to the other thread. Change the interrupt
+		 * and control regs to be scheduled on the CPU
+		 * corresponding to the thread to execute.
+		 */
+		for (i = 0; i < num_counters; i++) {
+			if (pmc_cntrl[next_hdw_thread][i].enabled) {
+				/* There are some per thread events.
+				 * Must do the set event, enable_cntr
+				 * for each cpu.
+				 */
+				set_pm_event(i,
+				     pmc_cntrl[next_hdw_thread][i].evnts,
+				     pmc_cntrl[next_hdw_thread][i].masks);
+				enable_ctr(cpu, i,
+					   pm_regs.pm07_cntrl);
+			} else {
+				cbe_write_pm07_control(cpu, i, 0);
+			}
+		}
+
+		/* Enable interrupts on the CPU thread that is starting */
+		cbe_enable_pm_interrupts(cpu, next_hdw_thread,
+					 virt_cntr_inter_mask);
+		cbe_enable_pm(cpu);
+	}
+
+	spin_unlock_irqrestore(&virt_cntr_lock, flags);
+
+	mod_timer(&timer_virt_cntr, jiffies + HZ / 10);
+}
+
+static void start_virt_cntrs(void)
+{
+	init_timer(&timer_virt_cntr);
+	timer_virt_cntr.function = cell_virtual_cntr;
+	timer_virt_cntr.data = 0UL;
+	timer_virt_cntr.expires = jiffies + HZ / 10;
+	add_timer(&timer_virt_cntr);
+}
+
+/* This function is called once for all cpus combined */
+static void
+cell_reg_setup(struct op_counter_config *ctr,
+	       struct op_system_config *sys, int num_ctrs)
+{
+	int i, j, cpu;
+
+	pm_rtas_token = rtas_token("ibm,cbe-perftools");
+	if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
+		       __FUNCTION__);
+		goto out;
+	}
+
+	num_counters = num_ctrs;
+
+	pm_regs.group_control = 0;
+	pm_regs.debug_bus_control = 0;
+
+	/* setup the pm_control register */
+	memset(&pm_regs.pm_cntrl, 0, sizeof(struct pm_cntrl));
+	pm_regs.pm_cntrl.stop_at_max = 1;
+	pm_regs.pm_cntrl.trace_mode = 0;
+	pm_regs.pm_cntrl.freeze = 1;
+
+	set_count_mode(sys->enable_kernel, sys->enable_user,
+		       &pm_regs.pm_cntrl);
+
+	/* Setup the thread 0 events */
+	for (i = 0; i < num_ctrs; ++i) {
+
+		pmc_cntrl[0][i].evnts = ctr[i].event;
+		pmc_cntrl[0][i].masks = ctr[i].unit_mask;
+		pmc_cntrl[0][i].enabled = ctr[i].enabled;
+		pmc_cntrl[0][i].vcntr = i;
+
+		for_each_possible_cpu(j)
+			per_cpu(pmc_values, j)[i] = 0;
+	}
+
+	/* Setup the thread 1 events, map the thread 0 event to the
+	 * equivalent thread 1 event.
+	 */
+	for (i = 0; i < num_ctrs; ++i) {
+		if ((ctr[i].event >= 2100) && (ctr[i].event <= 2111))
+			pmc_cntrl[1][i].evnts = ctr[i].event + 19;
+		else if (ctr[i].event == 2203)
+			pmc_cntrl[1][i].evnts = ctr[i].event;
+		else if ((ctr[i].event >= 2200) && (ctr[i].event <= 2215))
+			pmc_cntrl[1][i].evnts = ctr[i].event + 16;
+		else
+			pmc_cntrl[1][i].evnts = ctr[i].event;
+
+		pmc_cntrl[1][i].masks = ctr[i].unit_mask;
+		pmc_cntrl[1][i].enabled = ctr[i].enabled;
+		pmc_cntrl[1][i].vcntr = i;
+	}
+
+	for (i = 0; i < 4; i++)
+		trace_bus[i] = 0xff;
+
+	for (i = 0; i < 2; i++)
+		input_bus[i] = 0xff;
+
+	/* Our counters count up, and "count" refers to
+	 * how much before the next interrupt, and we interrupt
+	 * on overflow.  So we calculate the starting value
+	 * which will give us "count" until overflow.
+	 * Then we set the events on the enabled counters.
+	 */
+	for (i = 0; i < num_counters; ++i) {
+		/* start with virtual counter set 0 */
+		if (pmc_cntrl[0][i].enabled) {
+			/* Using 32bit counters, reset max - count */
+			reset_value[i] = 0xFFFFFFFF - ctr[i].count;
+			set_pm_event(i,
+				     pmc_cntrl[0][i].evnts,
+				     pmc_cntrl[0][i].masks);
+
+			/* global, used by cell_cpu_setup */
+			ctr_enabled |= (1 << i);
+		}
+	}
+
+	/* initialize the previous counts for the virtual cntrs */
+	for_each_online_cpu(cpu)
+		for (i = 0; i < num_counters; ++i) {
+			per_cpu(pmc_values, cpu)[i] = reset_value[i];
+		}
+out:
+	;
+}
+
+/* This function is called once for each cpu */
+static void cell_cpu_setup(struct op_counter_config *cntr)
+{
+	u32 cpu = smp_processor_id();
+	u32 num_enabled = 0;
+	int i;
+
+	/* There is one performance monitor per processor chip (i.e. node),
+	 * so we only need to perform this function once per node.
+	 */
+	if (cbe_get_hw_thread_id(cpu))
+		goto out;
+
+	if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
+		       __FUNCTION__);
+		goto out;
+	}
+
+	/* Stop all counters */
+	cbe_disable_pm(cpu);
+	cbe_disable_pm_interrupts(cpu);
+
+	cbe_write_pm(cpu, pm_interval, 0);
+	cbe_write_pm(cpu, pm_start_stop, 0);
+	cbe_write_pm(cpu, group_control, pm_regs.group_control);
+	cbe_write_pm(cpu, debug_bus_control, pm_regs.debug_bus_control);
+	write_pm_cntrl(cpu, &pm_regs.pm_cntrl);
+
+	for (i = 0; i < num_counters; ++i) {
+		if (ctr_enabled & (1 << i)) {
+			pm_signal[num_enabled].cpu = cbe_cpu_to_node(cpu);
+			num_enabled++;
+		}
+	}
+
+	pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+out:
+	;
+}
+
+static void cell_global_start(struct op_counter_config *ctr)
+{
+	u32 cpu;
+	u32 interrupt_mask = 0;
+	u32 i;
+
+	/* This routine gets called once for the system.
+	 * There is one performance monitor per node, so we
+	 * only need to perform this function once per node.
+	 */
+	for_each_online_cpu(cpu) {
+		if (cbe_get_hw_thread_id(cpu))
+			continue;
+
+		interrupt_mask = 0;
+
+		for (i = 0; i < num_counters; ++i) {
+			if (ctr_enabled & (1 << i)) {
+				cbe_write_ctr(cpu, i, reset_value[i]);
+				enable_ctr(cpu, i, pm_regs.pm07_cntrl);
+				interrupt_mask |=
+				    CBE_PM_CTR_OVERFLOW_INTR(i);
+			} else {
+				/* Disable counter */
+				cbe_write_pm07_control(cpu, i, 0);
+			}
+		}
+
+		cbe_clear_pm_interrupts(cpu);
+		cbe_enable_pm_interrupts(cpu, hdw_thread, interrupt_mask);
+		cbe_enable_pm(cpu);
+	}
+
+	virt_cntr_inter_mask = interrupt_mask;
+	oprofile_running = 1;
+	smp_wmb();
+
+	/* NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
+	 * executed which manipulates the PMU.  We start the "virtual counter"
+	 * here so that we do not need to synchronize access to the PMU in
+	 * the above for-loop.
+	 */
+	start_virt_cntrs();
+}
+
+static void cell_global_stop(void)
+{
+	int cpu;
+
+	/* This routine will be called once for the system.
+	 * There is one performance monitor per node, so we
+	 * only need to perform this function once per node.
+	 */
+	del_timer_sync(&timer_virt_cntr);
+	oprofile_running = 0;
+	smp_wmb();
+
+	for_each_online_cpu(cpu) {
+		if (cbe_get_hw_thread_id(cpu))
+			continue;
+
+		cbe_sync_irq(cbe_cpu_to_node(cpu));
+		/* Stop the counters */
+		cbe_disable_pm(cpu);
+
+		/* Deactivate the signals */
+		pm_rtas_reset_signals(cbe_cpu_to_node(cpu));
+
+		/* Deactivate interrupts */
+		cbe_disable_pm_interrupts(cpu);
+	}
+}
+
+static void
+cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
+{
+	u32 cpu;
+	u64 pc;
+	int is_kernel;
+	unsigned long flags = 0;
+	u32 interrupt_mask;
+	int i;
+
+	cpu = smp_processor_id();
+
+	/* Need to make sure the interrupt handler and the virt counter
+	 * routine are not running at the same time. See the
+	 * cell_virtual_cntr() routine for additional comments.
+	 */
+	spin_lock_irqsave(&virt_cntr_lock, flags);
+
+	/* Need to disable and reenable the performance counters
+	 * to get the desired behavior from the hardware.  This
+	 * is hardware specific.
+	 */
+
+	cbe_disable_pm(cpu);
+
+	interrupt_mask = cbe_clear_pm_interrupts(cpu);
+
+	/* If the interrupt mask has been cleared, then the virt cntr
+	 * has cleared the interrupt.  When the thread that generated
+	 * the interrupt is restored, the data count will be restored to
+	 * 0xffffff0 to cause the interrupt to be regenerated.
+	 */
+
+	if ((oprofile_running == 1) && (interrupt_mask != 0)) {
+		pc = regs->nip;
+		is_kernel = is_kernel_addr(pc);
+
+		for (i = 0; i < num_counters; ++i) {
+			if ((interrupt_mask & CBE_PM_CTR_OVERFLOW_INTR(i))
+			    && ctr[i].enabled) {
+				oprofile_add_pc(pc, is_kernel, i);
+				cbe_write_ctr(cpu, i, reset_value[i]);
+			}
+		}
+
+		/* The counters were frozen by the interrupt.
+		 * Reenable the interrupt and restart the counters.
+		 * If there was a race between the interrupt handler and
+		 * the virtual counter routine.  The virutal counter
+		 * routine may have cleared the interrupts.  Hence must
+		 * use the virt_cntr_inter_mask to re-enable the interrupts.
+		 */
+		cbe_enable_pm_interrupts(cpu, hdw_thread,
+					 virt_cntr_inter_mask);
+
+		/* The writes to the various performance counters only writes
+		 * to a latch.  The new values (interrupt setting bits, reset
+		 * counter value etc.) are not copied to the actual registers
+		 * until the performance monitor is enabled.  In order to get
+		 * this to work as desired, the permormance monitor needs to
+		 * be disabled while writting to the latches.  This is a
+		 * HW design issue.
+		 */
+		cbe_enable_pm(cpu);
+	}
+	spin_unlock_irqrestore(&virt_cntr_lock, flags);
+}
+
+struct op_powerpc_model op_model_cell = {
+	.reg_setup = cell_reg_setup,
+	.cpu_setup = cell_cpu_setup,
+	.global_start = cell_global_start,
+	.global_stop = cell_global_stop,
+	.handle_interrupt = cell_handle_interrupt,
+};
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.c
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.c
@@ -130,6 +130,18 @@ struct cbe_mic_tm_regs __iomem *cbe_get_
 }
 EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
 
+/* FIXME
+ * This is little more than a stub at the moment.  It should be
+ * fleshed out so that it works for both SMT and non-SMT, no
+ * matter if the passed cpu is odd or even.
+ * For SMT enabled, returns 0 for even-numbered cpu; otherwise 1.
+ * For SMT disabled, returns 0 for all cpus.
+ */
+u32 cbe_get_hw_thread_id(int cpu)
+{
+	return (cpu & 1);
+}
+EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id);
 
 void __init cbe_regs_init(void)
 {
Index: linux-2.6/include/asm-powerpc/cell-pmu.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/cell-pmu.h
+++ linux-2.6/include/asm-powerpc/cell-pmu.h
@@ -91,5 +91,23 @@ extern void cbe_enable_pm_interrupts(u32
 extern void cbe_disable_pm_interrupts(u32 cpu);
 extern u32  cbe_query_pm_interrupts(u32 cpu);
 extern u32  cbe_clear_pm_interrupts(u32 cpu);
+extern void cbe_sync_irq(int node);
+
+/* Utility functions, macros */
+extern u32 cbe_get_hw_thread_id(int cpu);
+
+#define cbe_cpu_to_node(cpu) ((cpu) >> 1)
+
+#define CBE_COUNT_SUPERVISOR_MODE       0
+#define CBE_COUNT_HYPERVISOR_MODE       1
+#define CBE_COUNT_PROBLEM_MODE          2
+#define CBE_COUNT_ALL_MODES             3
+
+/* Macros for the pm07_control registers. */
+#define PM07_CTR_INPUT_MUX(x)                    (((x) & 0x3F) << 26)
+#define PM07_CTR_INPUT_CONTROL(x)                (((x) & 1) << 25)
+#define PM07_CTR_POLARITY(x)                     (((x) & 1) << 24)
+#define PM07_CTR_COUNT_CYCLES(x)                 (((x) & 1) << 23)
+#define PM07_CTR_ENABLE(x)                       (((x) & 1) << 22)
 
 #endif /* __ASM_CELL_PMU_H__ */
Index: linux-2.6/include/asm-powerpc/cputable.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/cputable.h
+++ linux-2.6/include/asm-powerpc/cputable.h
@@ -45,6 +45,7 @@ enum powerpc_oprofile_type {
 	PPC_OPROFILE_POWER4 = 2,
 	PPC_OPROFILE_G4 = 3,
 	PPC_OPROFILE_BOOKE = 4,
+	PPC_OPROFILE_CELL = 5,
 };
 
 struct cpu_spec {
Index: linux-2.6/include/asm-powerpc/oprofile_impl.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/oprofile_impl.h
+++ linux-2.6/include/asm-powerpc/oprofile_impl.h
@@ -44,7 +44,9 @@ struct op_powerpc_model {
 			   int num_counters);
 	void (*cpu_setup) (struct op_counter_config *);
 	void (*start) (struct op_counter_config *);
+        void (*global_start) (struct op_counter_config *);
 	void (*stop) (void);
+	void (*global_stop) (void);
 	void (*handle_interrupt) (struct pt_regs *,
 				  struct op_counter_config *);
 	int num_counters;
@@ -54,6 +56,7 @@ extern struct op_powerpc_model op_model_
 extern struct op_powerpc_model op_model_rs64;
 extern struct op_powerpc_model op_model_power4;
 extern struct op_powerpc_model op_model_7450;
+extern struct op_powerpc_model op_model_cell;
 
 #ifndef CONFIG_FSL_BOOKE
 
Index: linux-2.6/arch/powerpc/platforms/cell/pmu.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pmu.c
+++ linux-2.6/arch/powerpc/platforms/cell/pmu.c
@@ -25,6 +25,7 @@
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <asm/io.h>
+#include <asm/irq_regs.h>
 #include <asm/machdep.h>
 #include <asm/pmc.h>
 #include <asm/reg.h>
@@ -375,9 +376,9 @@ void cbe_disable_pm_interrupts(u32 cpu)
 }
 EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts);
 
-static irqreturn_t cbe_pm_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cbe_pm_irq(int irq, void *dev_id)
 {
-	perf_irq(regs);
+	perf_irq(get_irq_regs());
 	return IRQ_HANDLED;
 }
 
@@ -408,3 +409,21 @@ int __init cbe_init_pm_irq(void)
 }
 arch_initcall(cbe_init_pm_irq);
 
+void cbe_sync_irq(int node)
+{
+	unsigned int irq;
+
+	irq = irq_find_mapping(NULL,
+			       IIC_IRQ_IOEX_PMI
+			       | (node << IIC_IRQ_NODE_SHIFT));
+
+	if (irq == NO_IRQ) {
+		printk(KERN_WARNING "ERROR, unable to get existing irq %d " \
+		"for node %d\n", irq, node);
+		return;
+	}
+
+	synchronize_irq(irq);
+}
+EXPORT_SYMBOL_GPL(cbe_sync_irq);
+

--


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable()
  2006-11-20 17:44 ` [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable() Arnd Bergmann
@ 2006-11-20 21:59   ` Paul Mackerras
  2006-11-21  0:53   ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 33+ messages in thread
From: Paul Mackerras @ 2006-11-20 21:59 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: cbe-oss-dev, linuxppc-dev, linux-kernel, Arnd Bergmann

Arnd Bergmann writes:

> I got a bug report that I believe might be fixed by this
> patch. The problem seems to be that with soft-disabled
> interrupts in power_save, we can still get external exceptions
> on Cell, even if we are in pause(0) a.k.a. sleep state.

[snip]

> -				local_irq_disable();
> +				hard_irq_disable();

This would mean that any platform-specific power_save function that
wants to re-enable interrupts (as the pseries ones do) would have to
do hard_irq_enable instead of local_irq_enable.  Also, I don't think
this change will be good on iSeries.

What we want is an irq-disable function that is like local_irq_disable
but also clears MSR_EE and the hard irq enabled flag (provided we
aren't running on iSeries).

Paul.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable()
  2006-11-20 17:44 ` [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable() Arnd Bergmann
  2006-11-20 21:59   ` Paul Mackerras
@ 2006-11-21  0:53   ` Benjamin Herrenschmidt
  2006-11-21 10:14     ` Arnd Bergmann
  1 sibling, 1 reply; 33+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-21  0:53 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: cbe-oss-dev, linuxppc-dev, Paul Mackerras, linux-kernel, Arnd Bergmann

I got a bug report that I believe might be fixed by this
patch. The problem seems to be that with soft-disabled
interrupts in power_save, we can still get external exceptions
on Cell, even if we are in pause(0) a.k.a. sleep state.

When the CPU really wakes up through the 0x100 (system reset)
vector, while we have already started processing the 0x500
(external) exception, we get a panic in unrecoverable_exception()
because of the lost state.

This occurred in Systemsim for Cell, but as far as I can see,
it can theoretically occur on any machine that uses the
system reset exception to get out of sleep state.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
What about that patch instead ?

Index: linux-cell/arch/powerpc/platforms/cell/pervasive.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/pervasive.c	2006-11-21 11:01:12.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/pervasive.c	2006-11-21 11:48:12.000000000 +1100
@@ -41,6 +41,15 @@
 static void cbe_power_save(void)
 {
 	unsigned long ctrl, thread_switch_control;
+
+	/*
+	 * We need to hard disable interrupts, but we also need to mark them
+	 * hard disabled in the PACA so that the local_irq_enable() done by
+	 * our caller upon return propertly hard enables.
+	 */
+	hard_irq_disable();
+	get_paca()->hard_enabled = 0;
+
 	ctrl = mfspr(SPRN_CTRLF);
 
 	/* Enable DEC and EE interrupt request */



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 17/22] coredump: Add SPU elf notes to coredump.
  2006-11-20 17:45 ` [PATCH 17/22] coredump: Add SPU elf notes to coredump Arnd Bergmann
@ 2006-11-21  5:38   ` Michael Ellerman
  0 siblings, 0 replies; 33+ messages in thread
From: Michael Ellerman @ 2006-11-21  5:38 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: cbe-oss-dev, linux-arch, Arnd Bergmann, linux-kernel,
	linuxppc-dev, Paul Mackerras, Dwayne Grant McConnell

[-- Attachment #1: Type: text/plain, Size: 1000 bytes --]

On Mon, 2006-11-20 at 18:45 +0100, Arnd Bergmann wrote:
> Index: linux-2.6/include/linux/elf.h
> ===================================================================
> --- linux-2.6.orig/include/linux/elf.h
> +++ linux-2.6/include/linux/elf.h
> @@ -368,5 +368,12 @@ extern Elf64_Dyn _DYNAMIC [];
>  
>  #endif
>  
> +#ifndef ARCH_HAVE_EXTRA_ELF_NOTES
> +static inline int arch_notes_size(void) { return 0; }
> +static inline int arch_write_notes(void) { return 0; }
> +
> +#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size()
> +#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file)
> +#endif /* ARCH_HAVE_EXTRA_ELF_NOTES */

This is broken for !CELL. arch_write_notes(void) can't be called as
arch_write_notes(file).

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable()
  2006-11-21  0:53   ` Benjamin Herrenschmidt
@ 2006-11-21 10:14     ` Arnd Bergmann
  2006-11-21 16:58       ` Olof Johansson
  0 siblings, 1 reply; 33+ messages in thread
From: Arnd Bergmann @ 2006-11-21 10:14 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: cbe-oss-dev, linuxppc-dev, Paul Mackerras, linux-kernel

On Tuesday 21 November 2006 01:53, Benjamin Herrenschmidt wrote:
> +
> +       /*
> +        * We need to hard disable interrupts, but we also need to mark them
> +        * hard disabled in the PACA so that the local_irq_enable() done by
> +        * our caller upon return propertly hard enables.
> +        */
> +       hard_irq_disable();
> +       get_paca()->hard_enabled = 0;
> +

Yes, this looks good. Paul, please use this patch instead of mine.
Do we need to do the same thing for any of the other power_save functions?
IIRC, all new CPUs are supposed to use the same mechanism based on the
0x100 vector.

	Arnd <><

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable()
  2006-11-21 10:14     ` Arnd Bergmann
@ 2006-11-21 16:58       ` Olof Johansson
  0 siblings, 0 replies; 33+ messages in thread
From: Olof Johansson @ 2006-11-21 16:58 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Benjamin Herrenschmidt, linuxppc-dev, Paul Mackerras,
	cbe-oss-dev, linux-kernel

On Tue, 21 Nov 2006 11:14:45 +0100 Arnd Bergmann <arnd@arndb.de> wrote:

> IIRC, all new CPUs are supposed to use the same mechanism based on the
> 0x100 vector.

It's only really affecting platforms without hypervisors though, which
aren't all that many (yet).

I don't have a problem dealing with it locally in my platform.


-Olof

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution
  2006-11-20 17:45 ` [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution Arnd Bergmann
@ 2007-03-01  6:18   ` Michael Ellerman
  2007-03-01 13:50     ` [Cbe-oss-dev] " Arnd Bergmann
  0 siblings, 1 reply; 33+ messages in thread
From: Michael Ellerman @ 2007-03-01  6:18 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: cbe-oss-dev, linuxppc-dev, Paul Mackerras, linux-kernel,
	Arnd Bergmann, Jeremy Kerr

[-- Attachment #1: Type: text/plain, Size: 1304 bytes --]

On Mon, 2006-11-20 at 18:45 +0100, Arnd Bergmann wrote:
> plain text document attachment (spufs-master-control.diff)
> When the user changes the runcontrol register, an SPU might be
> running without a process being attached to it and waiting for
> events. In order to prevent this, make sure we always disable
> the priv1 master control when we're not inside of spu_run.

Hi Arnd,

Sorry I didn't comment on this when you sent it, I wasn't paying enough
attention. This patch confuses me, you say we should make sure we always
disable the master control when we're not inside spu_run, but I see
several exit paths where we leave the master run bit enabled - or maybe
I'm reading it wrong.

I think I've also seen it happen:

[root@localhost dma5]# ./put-test 
10963.13
[root@localhost dma5]# find /spu
/spu
[root@localhost dma5]# echo x > /proc/sysrq-trigger 
SysRq : Entering xmon

0:mon> ss
..
Stopped spu 06, was running (mfc_sr1: 0x32 runcntl: 0x1)
Stopped spu 07, was running (mfc_sr1: 0x32 runcntl: 0x1)
..

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Cbe-oss-dev] [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution
  2007-03-01  6:18   ` Michael Ellerman
@ 2007-03-01 13:50     ` Arnd Bergmann
  2007-03-02 10:13       ` Michael Ellerman
  0 siblings, 1 reply; 33+ messages in thread
From: Arnd Bergmann @ 2007-03-01 13:50 UTC (permalink / raw)
  To: cbe-oss-dev, michael; +Cc: linux-kernel, linuxppc-dev

On Thursday 01 March 2007, Michael Ellerman wrote:
> On Mon, 2006-11-20 at 18:45 +0100, Arnd Bergmann wrote:
> > plain text document attachment (spufs-master-control.diff)
> > When the user changes the runcontrol register, an SPU might be
> > running without a process being attached to it and waiting for
> > events. In order to prevent this, make sure we always disable
> > the priv1 master control when we're not inside of spu_run.
> 
> Hi Arnd,
> 
> Sorry I didn't comment on this when you sent it, I wasn't paying enough
> attention. This patch confuses me, you say we should make sure we always
> disable the master control when we're not inside spu_run, but I see
> several exit paths where we leave the master run bit enabled - or maybe
> I'm reading it wrong.

I think you're right, there is at least one path that I now saw
getting out of spufs_run_spu incorrectly. In particular, when
spu_reacquire_runnable() fails, we never call the master stop,
which is a bug, but should happen very infrequently in practice.
Do you see another case where we end up with the same problem?

If not, I'll prepare a patch to fix this one case.

	Arnd <><


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Cbe-oss-dev] [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution
  2007-03-01 13:50     ` [Cbe-oss-dev] " Arnd Bergmann
@ 2007-03-02 10:13       ` Michael Ellerman
  2007-03-05  1:02         ` Arnd Bergmann
  0 siblings, 1 reply; 33+ messages in thread
From: Michael Ellerman @ 2007-03-02 10:13 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: cbe-oss-dev, linux-kernel, linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 3747 bytes --]

On Thu, 2007-03-01 at 14:50 +0100, Arnd Bergmann wrote: 
> On Thursday 01 March 2007, Michael Ellerman wrote:
> > On Mon, 2006-11-20 at 18:45 +0100, Arnd Bergmann wrote:
> > > plain text document attachment (spufs-master-control.diff)
> > > When the user changes the runcontrol register, an SPU might be
> > > running without a process being attached to it and waiting for
> > > events. In order to prevent this, make sure we always disable
> > > the priv1 master control when we're not inside of spu_run.
> > 
> > Hi Arnd,
> > 
> > Sorry I didn't comment on this when you sent it, I wasn't paying enough
> > attention. This patch confuses me, you say we should make sure we always
> > disable the master control when we're not inside spu_run, but I see
> > several exit paths where we leave the master run bit enabled - or maybe
> > I'm reading it wrong.
> 
> I think you're right, there is at least one path that I now saw
> getting out of spufs_run_spu incorrectly. In particular, when
> spu_reacquire_runnable() fails, we never call the master stop,
> which is a bug, but should happen very infrequently in practice.
> Do you see another case where we end up with the same problem?

That was the first one that caught my eye, but I wasn't sure about the
semantics of the error case.

There's also the error case for spu_run_init() which skips the master
stop. I guess that's ok because we've only set the master control in the
backing store, and the only way that will ever get propagated to an
actual spu is by coming back thorough spufs_run_spu().

What originally caught my eye on this was the output from xmon. When we
drop into xmon with no spu programs running and stop the spus, it
reports that they _all_ have the master run enabled, and some of them
have the runcntl enabled (those that have had spu programs run on them
since boot it seems).

It looks like the save/restore code sets the master bit in several
places, but never sets/clears the runcntl, which seems bogus to me.

So when we leave spufs_spu_run we do the master stop call:

spu_mfc_sr1_set: spu: c00000007ffdfc80 (15) sr1: 0x1b runcntl: 0x1
Call Trace:
[C00000000196BAA0] [C00000000000F920] .show_stack+0x68/0x1b0 (unreliable)
[C00000000196BB40] [D0000000001475C0] .spu_hw_master_stop+0xa8/0x170 [spufs]
[C00000000196BBE0] [D000000000148598] .spufs_run_spu+0x5ec/0x770 [spufs]
[C00000000196BCC0] [D000000000144BA0] .do_spu_run+0xb4/0x180 [spufs]
[C00000000196BD80] [C00000000003905C] .sys_spu_run+0xb0/0x108
[C00000000196BE30] [C000000000008634] syscall_exit+0x0/0x40


But then the save/restore code sets it back on?

spu_mfc_sr1_set: spu: c00000007ffdfc80 (15) sr1: 0x32 runcntl: 0x1
Call Trace:
[C00000000FF9B790] [C00000000000F920] .show_stack+0x68/0x1b0 (unreliable)
[C00000000FF9B830] [C00000000003B310] .spu_save+0x9b0/0x156c
[C00000000FF9B950] [D0000000001457FC] .spu_unbind_context+0x124/0x1a4 [spufs]
[C00000000FF9B9F0] [D0000000001458B0] .spu_deactivate+0x34/0x138 [spufs]
[C00000000FF9BA80] [D00000000014448C] .spu_acquire_saved+0x34/0x4c [spufs]
[C00000000FF9BB10] [D00000000014493C] .spu_forget+0x18/0x4c [spufs]
[C00000000FF9BBA0] [D00000000014030C] .spufs_dir_close+0x78/0xb4 [spufs]
[C00000000FF9BC50] [C0000000000B8594] .__fput+0x110/0x200
[C00000000FF9BD00] [C0000000000B4F38] .filp_close+0xac/0xd4
[C00000000FF9BD90] [C0000000000B68BC] .sys_close+0xc4/0x130
[C00000000FF9BE30] [C000000000008634] syscall_exit+0x0/0x40


cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Cbe-oss-dev] [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution
  2007-03-02 10:13       ` Michael Ellerman
@ 2007-03-05  1:02         ` Arnd Bergmann
  2007-03-07  8:58           ` Michael Ellerman
  0 siblings, 1 reply; 33+ messages in thread
From: Arnd Bergmann @ 2007-03-05  1:02 UTC (permalink / raw)
  To: cbe-oss-dev, michael; +Cc: linuxppc-dev, linux-kernel

On Friday 02 March 2007, Michael Ellerman wrote:
> There's also the error case for spu_run_init() which skips the master
> stop. I guess that's ok because we've only set the master control in the
> backing store, and the only way that will ever get propagated to an
> actual spu is by coming back thorough spufs_run_spu().

Hmm, the correct way would be to switch off the master control in there,
afaics. Fixing it only in spu_run_init would mean that we also handle
the case of spu_reacquire_runnable along with it.

> What originally caught my eye on this was the output from xmon. When we
> drop into xmon with no spu programs running and stop the spus, it
> reports that they _all_ have the master run enabled,

That looks right, there is no problem to have master control enabled,
as long as user space can't access the spu through a context that is
bound to it.

> and some of them 
> have the runcntl enabled (those that have had spu programs run on them
> since boot it seems).

While this sounds wrong. Maybe the runcntl is active on those that have
_not_ run since boot, which would make more sense. We should investigate
this.

> It looks like the save/restore code sets the master bit in several
> places, but never sets/clears the runcntl, which seems bogus to me.
> 
> So when we leave spufs_spu_run we do the master stop call:
> 
> spu_mfc_sr1_set: spu: c00000007ffdfc80 (15) sr1: 0x1b runcntl: 0x1
> Call Trace:
> [C00000000196BAA0] [C00000000000F920] .show_stack+0x68/0x1b0 (unreliable)
> [C00000000196BB40] [D0000000001475C0] .spu_hw_master_stop+0xa8/0x170 [spufs]
> [C00000000196BBE0] [D000000000148598] .spufs_run_spu+0x5ec/0x770 [spufs]
> [C00000000196BCC0] [D000000000144BA0] .do_spu_run+0xb4/0x180 [spufs]
> [C00000000196BD80] [C00000000003905C] .sys_spu_run+0xb0/0x108
> [C00000000196BE30] [C000000000008634] syscall_exit+0x0/0x40
> 
> 
> But then the save/restore code sets it back on?

Right, the context save code needs to enable master control in order to
run on the spu. However, that should be after all mappings to user space
have been discarded.

	Arnd <><

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Cbe-oss-dev] [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution
  2007-03-05  1:02         ` Arnd Bergmann
@ 2007-03-07  8:58           ` Michael Ellerman
  0 siblings, 0 replies; 33+ messages in thread
From: Michael Ellerman @ 2007-03-07  8:58 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: cbe-oss-dev, linuxppc-dev, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1709 bytes --]

On Mon, 2007-03-05 at 02:02 +0100, Arnd Bergmann wrote:
> On Friday 02 March 2007, Michael Ellerman wrote:
> > There's also the error case for spu_run_init() which skips the master
> > stop. I guess that's ok because we've only set the master control in the
> > backing store, and the only way that will ever get propagated to an
> > actual spu is by coming back thorough spufs_run_spu().
> 
> Hmm, the correct way would be to switch off the master control in there,
> afaics. Fixing it only in spu_run_init would mean that we also handle
> the case of spu_reacquire_runnable along with it.
> 
> > What originally caught my eye on this was the output from xmon. When we
> > drop into xmon with no spu programs running and stop the spus, it
> > reports that they _all_ have the master run enabled,
> 
> That looks right, there is no problem to have master control enabled,
> as long as user space can't access the spu through a context that is
> bound to it.
> 
> > and some of them 
> > have the runcntl enabled (those that have had spu programs run on them
> > since boot it seems).
> 
> While this sounds wrong. Maybe the runcntl is active on those that have
> _not_ run since boot, which would make more sense. We should investigate
> this.

No I'm pretty sure it's enabled on the ones that _have_ run since boot.
I'm booting up fresh, running two spu programs, and then I see two spus
with master and runcntl set.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2007-03-07  8:58 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-11-20 17:44 [PATCH 00/22] Cell patches for 2.6.20 Arnd Bergmann
2006-11-20 17:44 ` [PATCH 01/22] powerpc: convert idle_loop to use hard_irq_disable() Arnd Bergmann
2006-11-20 21:59   ` Paul Mackerras
2006-11-21  0:53   ` Benjamin Herrenschmidt
2006-11-21 10:14     ` Arnd Bergmann
2006-11-21 16:58       ` Olof Johansson
2006-11-20 17:44 ` [PATCH 02/22] powerpc: change ppc_rtas declaration to weak Arnd Bergmann
2006-11-20 17:44 ` [PATCH 03/22] spufs: Change %llx to 0x%llx Arnd Bergmann
2006-11-20 17:44 ` [PATCH 04/22] spufs: add /lslr, /dma_info and /proxydma files Arnd Bergmann
2006-11-20 17:44 ` [PATCH 05/22] spufs: Remove /spu_tag_mask file Arnd Bergmann
2006-11-20 17:45 ` [PATCH 06/22] spufs: implement /mbox_info, /ibox_info, and /wbox_info Arnd Bergmann
2006-11-20 17:45 ` [PATCH 07/22] spufs: read from signal files only if data is there Arnd Bergmann
2006-11-20 17:45 ` [PATCH 08/22] spufs: replace spu.nid with spu.node Arnd Bergmann
2006-11-20 17:45 ` [PATCH 09/22] spufs: return correct event for data storage interrupt Arnd Bergmann
2006-11-20 17:45 ` [PATCH 10/22] spufs: fix missing stop-and-signal Arnd Bergmann
2006-11-20 17:45 ` [PATCH 11/22] spufs: avoid user-triggered oops in ptrace Arnd Bergmann
2006-11-20 17:45 ` [PATCH 12/22] spufs: always map local store non-guarded Arnd Bergmann
2006-11-20 17:45 ` [PATCH 13/22] spufs: fix return value of spufs_mfc_write Arnd Bergmann
2006-11-20 17:45 ` [PATCH 14/22] spufs: use SPU master control to prevent wild SPU execution Arnd Bergmann
2007-03-01  6:18   ` Michael Ellerman
2007-03-01 13:50     ` [Cbe-oss-dev] " Arnd Bergmann
2007-03-02 10:13       ` Michael Ellerman
2007-03-05  1:02         ` Arnd Bergmann
2007-03-07  8:58           ` Michael Ellerman
2006-11-20 17:45 ` [PATCH 15/22] spufs: Add runcntrl read accessors Arnd Bergmann
2006-11-20 17:45 ` [PATCH 16/22] spufs: load isolation kernel from spu_run Arnd Bergmann
2006-11-20 17:45 ` [PATCH 17/22] coredump: Add SPU elf notes to coredump Arnd Bergmann
2006-11-21  5:38   ` Michael Ellerman
2006-11-20 17:45 ` [PATCH 18/22] cell: add symbol exports for oprofile Arnd Bergmann
2006-11-20 17:45 ` [PATCH 19/22] cell: PMU register macros Arnd Bergmann
2006-11-20 17:45 ` [PATCH 20/22] cell: Move PMU-related stuff to include/asm-powerpc/cell-pmu.h Arnd Bergmann
2006-11-20 17:45 ` [PATCH 21/22] cell: add routines for managing PMU interrupts Arnd Bergmann
2006-11-20 17:45 ` [PATCH 22/22] cell: add oprofile support Arnd Bergmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).