linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/16] cell patches for 2.6.20
@ 2006-10-24 16:31 arnd
  2006-10-24 16:31 ` [PATCH 01/16] spufs: wrap mfc sdr access arnd
                   ` (15 more replies)
  0 siblings, 16 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus

These are the patches I have queued for 2.6.20 for cell,
as I got them after the merge window closed.

They apply on the current powerpc.git with the bug fixes
applied that I sent earlier.

Please review for inclusion.

	Arnd <><

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

* [PATCH 01/16] spufs: wrap mfc sdr access
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 02/16] cell: remove unused struct spu variable arnd
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
  Cc: Masato Noguchi, Arnd Bergmann

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

SPRN_SDR1 and the SPE's MFC SDR are hypervisor resources and
are not accessible from a logical partition.  This change adds an
access wrapper.

When running on bare H/W, the spufs needs to only set the SPE's MFC SDR
to the value of the PPE's SPRN_SDR1 once at SPE initialization, so this
change renames mfc_sdr_set() to mfc_sdr_setup() and moves the
access of SPRN_SDR1 into the mmio wrapper.  It also removes the now
unneeded member mfc_sdr_RW from struct spu_priv1_collapsed.

Signed-off-by: Masato Noguchi <Masato.Noguchi@jp.sony.com>
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
@@ -805,7 +805,7 @@ static int __init create_spu(struct devi
 	if (ret)
 		goto out_unmap;
 	spin_lock_init(&spu->register_lock);
-	spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
+	spu_mfc_sdr_setup(spu);
 	spu_mfc_sr1_set(spu, 0x33);
 	mutex_lock(&spu_mutex);
 
Index: linux-2.6/arch/powerpc/platforms/cell/spu_priv1_mmio.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spu_priv1_mmio.c
+++ linux-2.6/arch/powerpc/platforms/cell/spu_priv1_mmio.c
@@ -84,9 +84,9 @@ static void mfc_dsisr_set(struct spu *sp
 	out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
 }
 
-static void mfc_sdr_set(struct spu *spu, u64 sdr)
+static void mfc_sdr_setup(struct spu *spu)
 {
-	out_be64(&spu->priv1->mfc_sdr_RW, sdr);
+	out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
 }
 
 static void mfc_sr1_set(struct spu *spu, u64 sr1)
@@ -146,7 +146,7 @@ const struct spu_priv1_ops spu_priv1_mmi
 	.mfc_dar_get = mfc_dar_get,
 	.mfc_dsisr_get = mfc_dsisr_get,
 	.mfc_dsisr_set = mfc_dsisr_set,
-	.mfc_sdr_set = mfc_sdr_set,
+	.mfc_sdr_setup = mfc_sdr_setup,
 	.mfc_sr1_set = mfc_sr1_set,
 	.mfc_sr1_get = mfc_sr1_get,
 	.mfc_tclass_id_set = mfc_tclass_id_set,
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/switch.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/switch.c
@@ -2165,9 +2165,6 @@ static void init_priv1(struct spu_state 
 	    MFC_STATE1_PROBLEM_STATE_MASK |
 	    MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK;
 
-	/* Set storage description.  */
-	csa->priv1.mfc_sdr_RW = mfspr(SPRN_SDR1);
-
 	/* Enable OS-specific set of interrupts. */
 	csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR |
 	    CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR |
Index: linux-2.6/include/asm-powerpc/spu_csa.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/spu_csa.h
+++ linux-2.6/include/asm-powerpc/spu_csa.h
@@ -151,7 +151,6 @@ struct spu_priv1_collapsed {
 	u64 mfc_fir_chkstp_enable_RW;
 	u64 smf_sbi_signal_sel;
 	u64 smf_ato_signal_sel;
-	u64 mfc_sdr_RW;
 	u64 tlb_index_hint_RO;
 	u64 tlb_index_W;
 	u64 tlb_vpn_RW;
Index: linux-2.6/include/asm-powerpc/spu_priv1.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/spu_priv1.h
+++ linux-2.6/include/asm-powerpc/spu_priv1.h
@@ -37,7 +37,7 @@ struct spu_priv1_ops
 	u64 (*mfc_dar_get) (struct spu *spu);
 	u64 (*mfc_dsisr_get) (struct spu *spu);
 	void (*mfc_dsisr_set) (struct spu *spu, u64 dsisr);
-	void (*mfc_sdr_set) (struct spu *spu, u64 sdr);
+	void (*mfc_sdr_setup) (struct spu *spu);
 	void (*mfc_sr1_set) (struct spu *spu, u64 sr1);
 	u64 (*mfc_sr1_get) (struct spu *spu);
 	void (*mfc_tclass_id_set) (struct spu *spu, u64 tclass_id);
@@ -112,9 +112,9 @@ spu_mfc_dsisr_set (struct spu *spu, u64 
 }
 
 static inline void
-spu_mfc_sdr_set (struct spu *spu, u64 sdr)
+spu_mfc_sdr_setup (struct spu *spu)
 {
-	spu_priv1_ops->mfc_sdr_set(spu, sdr);
+	spu_priv1_ops->mfc_sdr_setup(spu);
 }
 
 static inline void

--

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

* [PATCH 02/16] cell: remove unused struct spu variable
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
  2006-10-24 16:31 ` [PATCH 01/16] spufs: wrap mfc sdr access arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 03/16] spufs: add support for nonschedulable contexts arnd
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann

From: Geoff Levand <geoffrey.levand@am.sony.com>

Remove the mostly unused variable isrc from struct spu and a forgotten
function declaration.

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
@@ -364,8 +364,7 @@ struct spu *spu_alloc_node(int node)
 	if (!list_empty(&spu_list[node])) {
 		spu = list_entry(spu_list[node].next, struct spu, list);
 		list_del_init(&spu->list);
-		pr_debug("Got SPU %x %d %d\n",
-			 spu->isrc, spu->number, spu->node);
+		pr_debug("Got SPU %d %d\n", spu->number, spu->node);
 		spu_init_channels(spu);
 	}
 	mutex_unlock(&spu_mutex);
@@ -591,7 +590,6 @@ static int __init spu_map_interrupts_old
 
 	/* Add the node number */
 	isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
-	spu->isrc = isrc;
 
 	/* Now map interrupts of all 3 classes */
 	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
@@ -733,16 +731,6 @@ struct sysdev_class spu_sysdev_class = {
 	set_kset_name("spu")
 };
 
-static ssize_t spu_show_isrc(struct sys_device *sysdev, char *buf)
-{
-	struct spu *spu = container_of(sysdev, struct spu, sysdev);
-	return sprintf(buf, "%d\n", spu->isrc);
-
-}
-static SYSDEV_ATTR(isrc, 0400, spu_show_isrc, NULL);
-
-extern int attach_sysdev_to_node(struct sys_device *dev, int nid);
-
 static int spu_create_sysdev(struct spu *spu)
 {
 	int ret;
@@ -756,8 +744,6 @@ static int spu_create_sysdev(struct spu 
 		return ret;
 	}
 
-	if (spu->isrc != 0)
-		sysdev_create_file(&spu->sysdev, &attr_isrc);
 	sysfs_add_device_to_node(&spu->sysdev, spu->nid);
 
 	return 0;
@@ -765,7 +751,6 @@ static int spu_create_sysdev(struct spu 
 
 static void spu_destroy_sysdev(struct spu *spu)
 {
-	sysdev_remove_file(&spu->sysdev, &attr_isrc);
 	sysfs_remove_device_from_node(&spu->sysdev, spu->nid);
 	sysdev_unregister(&spu->sysdev);
 }
@@ -821,8 +806,8 @@ static int __init create_spu(struct devi
 	list_add(&spu->list, &spu_list[spu->node]);
 	mutex_unlock(&spu_mutex);
 
-	pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
-		spu->name, spu->isrc, spu->local_store,
+	pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n",
+		spu->name, spu->local_store,
 		spu->problem, spu->priv1, spu->priv2, spu->number);
 	goto out;
 
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
@@ -118,7 +118,6 @@ struct spu {
 	int number;
 	int nid;
 	unsigned int irqs[3];
-	u32 isrc;
 	u32 node;
 	u64 flags;
 	u64 dar;

--

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

* [PATCH 03/16] spufs: add support for nonschedulable contexts
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
  2006-10-24 16:31 ` [PATCH 01/16] spufs: wrap mfc sdr access arnd
  2006-10-24 16:31 ` [PATCH 02/16] cell: remove unused struct spu variable arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 04/16] spufs: "stataus" isnt a word arnd
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann

From: Mark Nutter <mnutter@us.ibm.com>

This adds two new flags to spu_create:

SPU_CREATE_NONSCHED: create a context that is never moved
away from an SPE once it has started running. This flag
can only be used by tasks with the CAP_SYS_NICE capability.

SPU_CREATE_ISOLATED: create a nonschedulable context that
enters isolation mode upon first run. This requires the
SPU_CREATE_NONSCHED flag.

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

---

Update: add psmap file.

 arch/powerpc/platforms/cell/spufs/file.c   |   22 ++++++++++++
 arch/powerpc/platforms/cell/spufs/hw_ops.c |    5 ++
 arch/powerpc/platforms/cell/spufs/inode.c  |   17 +++++++++
 arch/powerpc/platforms/cell/spufs/run.c    |   10 ++++-
 arch/powerpc/platforms/cell/spufs/spufs.h  |    1 
 arch/powerpc/platforms/cell/spufs/switch.c |   50 +++++++++++++++++++++++++++--
 include/asm-powerpc/spu.h                  |    5 ++
 7 files changed, 103 insertions(+), 7 deletions(-)

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
@@ -1531,3 +1531,25 @@ struct tree_descr spufs_dir_contents[] =
 	{ "object-id", &spufs_object_id_ops, 0666, },
 	{},
 };
+
+struct tree_descr spufs_dir_nosched_contents[] = {
+	{ "mem",  &spufs_mem_fops,  0666, },
+	{ "mbox", &spufs_mbox_fops, 0444, },
+	{ "ibox", &spufs_ibox_fops, 0444, },
+	{ "wbox", &spufs_wbox_fops, 0222, },
+	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
+	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
+	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
+	{ "signal1", &spufs_signal1_fops, 0666, },
+	{ "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, },
+	{ "psmap", &spufs_psmap_fops, 0666, },
+	{ "phys-id", &spufs_id_ops, 0666, },
+	{ "object-id", &spufs_object_id_ops, 0666, },
+	{},
+};
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
@@ -219,8 +219,11 @@ static char *spu_hw_get_ls(struct spu_co
 
 static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
 {
-	eieio();
+	spin_lock_irq(&ctx->spu->register_lock);
+	if (val & SPU_RUNCNTL_ISOLATE)
+		out_be64(&ctx->spu->priv2->spu_privcntl_RW, 4LL);
 	out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
+	spin_unlock_irq(&ctx->spu->register_lock);
 }
 
 static void spu_hw_runcntl_stop(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
@@ -258,7 +258,12 @@ spufs_mkdir(struct inode *dir, struct de
 
 	inode->i_op = &spufs_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
-	ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
+	if (flags & SPU_CREATE_NOSCHED)
+		ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
+					 mode, ctx);
+	else
+		ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
+
 	if (ret)
 		goto out_free_ctx;
 
@@ -307,6 +312,16 @@ static int spufs_create_context(struct i
 {
 	int ret;
 
+	ret = -EPERM;
+	if ((flags & SPU_CREATE_NOSCHED) &&
+	    !capable(CAP_SYS_NICE))
+		goto out_unlock;
+
+	ret = -EINVAL;
+	if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
+	    == SPU_CREATE_ISOLATE)
+		goto out_unlock;
+
 	ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
 	if (ret)
 		goto out_unlock;
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
@@ -51,11 +51,17 @@ static inline int spu_stopped(struct spu
 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)
 		return ret;
-	ctx->ops->npc_write(ctx, *npc);
-	ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+
+	if (ctx->flags & SPU_CREATE_ISOLATE)
+		runcntl |= SPU_RUNCNTL_ISOLATE;
+	else
+		ctx->ops->npc_write(ctx, *npc);
+
+	ctx->ops->runcntl_write(ctx, runcntl);
 	return 0;
 }
 
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
@@ -135,6 +135,7 @@ struct spufs_inode_info {
 	container_of(inode, struct spufs_inode_info, vfs_inode)
 
 extern struct tree_descr spufs_dir_contents[];
+extern struct tree_descr spufs_dir_nosched_contents[];
 
 /* system call implementation */
 long spufs_run_spu(struct file *file,
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/switch.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/switch.c
@@ -1916,6 +1916,51 @@ static void save_lscsa(struct spu_state 
 	wait_spu_stopped(prev, spu);	/* Step 57. */
 }
 
+static void force_spu_isolate_exit(struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Stop SPE execution and wait for completion. */
+	out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+	iobarrier_rw();
+	POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
+
+	/* Restart SPE master runcntl. */
+	spu_mfc_sr1_set(spu, MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+	iobarrier_w();
+
+	/* Initiate isolate exit request and wait for completion. */
+	out_be64(&priv2->spu_privcntl_RW, 4LL);
+	iobarrier_w();
+	out_be32(&prob->spu_runcntl_RW, 2);
+	iobarrier_rw();
+	POLL_WHILE_FALSE((in_be32(&prob->spu_status_R)
+				& SPU_STATUS_STOPPED_BY_STOP));
+
+	/* Reset load request to normal. */
+	out_be64(&priv2->spu_privcntl_RW, SPU_PRIVCNT_LOAD_REQUEST_NORMAL);
+	iobarrier_w();
+}
+
+/**
+ * stop_spu_isolate
+ *	Check SPU run-control state and force isolated
+ *	exit function as necessary.
+ */
+static void stop_spu_isolate(struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	if (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_STATE) {
+		/* The SPU is in isolated state; the only way
+		 * to get it out is to perform an isolated
+		 * exit (clean) operation.
+		 */
+		force_spu_isolate_exit(spu);
+	}
+}
+
 static void harvest(struct spu_state *prev, struct spu *spu)
 {
 	/*
@@ -1928,6 +1973,7 @@ static void harvest(struct spu_state *pr
 	inhibit_user_access(prev, spu);	        /* Step 3.  */
 	terminate_spu_app(prev, spu);	        /* Step 4.  */
 	set_switch_pending(prev, spu);	        /* Step 5.  */
+	stop_spu_isolate(spu);			/* NEW.     */
 	remove_other_spu_access(prev, spu);	/* Step 6.  */
 	suspend_mfc(prev, spu);	                /* Step 7.  */
 	wait_suspend_mfc_complete(prev, spu);	/* Step 8.  */
@@ -2096,11 +2142,11 @@ int spu_save(struct spu_state *prev, str
 	acquire_spu_lock(spu);	        /* Step 1.     */
 	rc = __do_spu_save(prev, spu);	/* Steps 2-53. */
 	release_spu_lock(spu);
-	if (rc) {
+	if (rc != 0 && rc != 2 && rc != 6) {
 		panic("%s failed on SPU[%d], rc=%d.\n",
 		      __func__, spu->number, rc);
 	}
-	return rc;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(spu_save);
 
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
@@ -181,8 +181,10 @@ extern struct spufs_calls {
  */
 #define SPU_CREATE_EVENTS_ENABLED	0x0001
 #define SPU_CREATE_GANG			0x0002
+#define SPU_CREATE_NOSCHED		0x0004
+#define SPU_CREATE_ISOLATE		0x0008
 
-#define SPU_CREATE_FLAG_ALL		0x0003 /* mask of all valid flags */
+#define SPU_CREATE_FLAG_ALL		0x000f /* mask of all valid flags */
 
 
 #ifdef CONFIG_SPU_FS_MODULE
@@ -276,6 +278,7 @@ struct spu_problem {
 	u32 spu_runcntl_RW;					/* 0x401c */
 #define SPU_RUNCNTL_STOP	0L
 #define SPU_RUNCNTL_RUNNABLE	1L
+#define SPU_RUNCNTL_ISOLATE	2L
 	u8  pad_0x4020_0x4024[0x4];				/* 0x4020 */
 	u32 spu_status_R;					/* 0x4024 */
 #define SPU_STOP_STATUS_SHIFT           16

--

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

* [PATCH 04/16] spufs: "stataus" isnt a word.
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (2 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 03/16] spufs: add support for nonschedulable contexts arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 05/16] spufs: allow isolated mode apps by starting the SPE loader arnd
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann

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

Index: linux-2.6/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/switch.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/switch.c
@@ -102,7 +102,7 @@ static inline int check_spu_isolate(stru
 	 *     saved at this time.
 	 */
 	isolate_state = SPU_STATUS_ISOLATED_STATE |
-	    SPU_STATUS_ISOLATED_LOAD_STAUTUS | SPU_STATUS_ISOLATED_EXIT_STAUTUS;
+	    SPU_STATUS_ISOLATED_LOAD_STATUS | SPU_STATUS_ISOLATED_EXIT_STATUS;
 	return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0;
 }
 
@@ -1046,12 +1046,12 @@ static inline int suspend_spe(struct spu
 	 */
 	if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) {
 		if (in_be32(&prob->spu_status_R) &
-		    SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+		    SPU_STATUS_ISOLATED_EXIT_STATUS) {
 			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
 					SPU_STATUS_RUNNING);
 		}
 		if ((in_be32(&prob->spu_status_R) &
-		     SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+		     SPU_STATUS_ISOLATED_LOAD_STATUS)
 		    || (in_be32(&prob->spu_status_R) &
 			SPU_STATUS_ISOLATED_STATE)) {
 			out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
@@ -1085,7 +1085,7 @@ static inline void clear_spu_status(stru
 	 */
 	if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) {
 		if (in_be32(&prob->spu_status_R) &
-		    SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+		    SPU_STATUS_ISOLATED_EXIT_STATUS) {
 			spu_mfc_sr1_set(spu,
 					MFC_STATE1_MASTER_RUN_CONTROL_MASK);
 			eieio();
@@ -1095,7 +1095,7 @@ static inline void clear_spu_status(stru
 					SPU_STATUS_RUNNING);
 		}
 		if ((in_be32(&prob->spu_status_R) &
-		     SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+		     SPU_STATUS_ISOLATED_LOAD_STATUS)
 		    || (in_be32(&prob->spu_status_R) &
 			SPU_STATUS_ISOLATED_STATE)) {
 			spu_mfc_sr1_set(spu,
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
@@ -291,8 +291,8 @@ struct spu_problem {
 #define SPU_STATUS_INVALID_INSTR        0x20
 #define SPU_STATUS_INVALID_CH           0x40
 #define SPU_STATUS_ISOLATED_STATE       0x80
-#define SPU_STATUS_ISOLATED_LOAD_STAUTUS 0x200
-#define SPU_STATUS_ISOLATED_EXIT_STAUTUS 0x400
+#define SPU_STATUS_ISOLATED_LOAD_STATUS 0x200
+#define SPU_STATUS_ISOLATED_EXIT_STATUS 0x400
 	u8  pad_0x4028_0x402c[0x4];				/* 0x4028 */
 	u32 spu_spe_R;						/* 0x402c */
 	u8  pad_0x4030_0x4034[0x4];				/* 0x4030 */

--

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

* [PATCH 05/16] spufs: allow isolated mode apps by starting the SPE loader
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (3 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 04/16] spufs: "stataus" isnt a word arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 06/16] spufs: Add isolated-mode SPE recycling support arnd
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann

This patch adds general support for isolated mode SPE apps.

Isolated apps are started indirectly, by a dedicated loader "kernel".
This patch starts the loader when spe_create is invoked with the
ISOLATE flag. We do this at spe_create time to allow libspe to pass the
isolated app in before calling spe_run.

The loader is read from the device tree, at the location
"/spu-isolation/loader". If the loader is not present, an attempt to
start an isolated SPE binary will fail with -ENODEV.

Update: loader needs to be correctly aligned - copy to a kmalloced buf.
Update: remove workaround for systemsim/spurom 'L-bit' bug, which has
        been fixed.
Update: don't write to runcntl on spu_run_init: SPU is already running.
Update: do spu_setup_isolated earlier

Tested on systemsim.

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

---

 arch/powerpc/platforms/cell/spu_base.c    |   35 ++++++--
 arch/powerpc/platforms/cell/spufs/inode.c |  117 ++++++++++++++++++++++++++++++
 arch/powerpc/platforms/cell/spufs/run.c   |   12 +--
 3 files changed, 148 insertions(+), 16 deletions(-)

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
@@ -89,7 +89,30 @@ static int __spu_trap_data_seg(struct sp
 		printk("%s: invalid access during switch!\n", __func__);
 		return 1;
 	}
-	if (!mm || (REGION_ID(ea) != USER_REGION_ID)) {
+	esid = (ea & ESID_MASK) | SLB_ESID_V;
+
+	switch(REGION_ID(ea)) {
+	case USER_REGION_ID:
+#ifdef CONFIG_HUGETLB_PAGE
+		if (in_hugepage_area(mm->context, ea))
+			llp = mmu_psize_defs[mmu_huge_psize].sllp;
+		else
+#endif
+			llp = mmu_psize_defs[mmu_virtual_psize].sllp;
+		vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
+				SLB_VSID_USER | llp;
+		break;
+	case VMALLOC_REGION_ID:
+		llp = mmu_psize_defs[mmu_virtual_psize].sllp;
+		vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
+			SLB_VSID_KERNEL | llp;
+		break;
+	case KERNEL_REGION_ID:
+		llp = mmu_psize_defs[mmu_linear_psize].sllp;
+		vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
+			SLB_VSID_KERNEL | llp;
+		break;
+	default:
 		/* Future: support kernel segments so that drivers
 		 * can use SPUs.
 		 */
@@ -97,16 +120,6 @@ static int __spu_trap_data_seg(struct sp
 		return 1;
 	}
 
-	esid = (ea & ESID_MASK) | SLB_ESID_V;
-#ifdef CONFIG_HUGETLB_PAGE
-	if (in_hugepage_area(mm->context, ea))
-		llp = mmu_psize_defs[mmu_huge_psize].sllp;
-	else
-#endif
-		llp = mmu_psize_defs[mmu_virtual_psize].sllp;
-	vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
-			SLB_VSID_USER | llp;
-
 	out_be64(&priv2->slb_index_W, spu->slb_replace);
 	out_be64(&priv2->slb_vsid_RW, vsid);
 	out_be64(&priv2->slb_esid_RW, esid);
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
@@ -33,6 +33,8 @@
 #include <linux/slab.h>
 #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>
@@ -41,6 +43,7 @@
 #include "spufs.h"
 
 static kmem_cache_t *spufs_inode_cache;
+static char *isolated_loader;
 
 static struct inode *
 spufs_alloc_inode(struct super_block *sb)
@@ -232,6 +235,89 @@ 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;
+
+	if ((ret = spu_acquire_runnable(ctx)) != 0)
+		return ret;
+
+	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:
+	up_write(&ctx->state_sema);
+	return ret;
+}
+
 static int
 spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
 		int mode)
@@ -255,6 +341,11 @@ spufs_mkdir(struct inode *dir, struct de
 		goto out_iput;
 
 	ctx->flags = flags;
+	if (flags & SPU_CREATE_ISOLATE) {
+		ret = spu_setup_isolated(ctx);
+		if (ret)
+			goto out_iput;
+	}
 
 	inode->i_op = &spufs_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
@@ -555,6 +646,30 @@ spufs_parse_options(char *options, struc
 	return 1;
 }
 
+static void
+spufs_init_isolated_loader(void)
+{
+	struct device_node *dn;
+	const char *loader;
+	int size;
+
+	dn = of_find_node_by_path("/spu-isolation");
+	if (!dn)
+		return;
+
+	loader = get_property(dn, "loader", &size);
+	if (!loader)
+		return;
+
+	/* kmalloc should align on a 16 byte boundary..* */
+	isolated_loader = kmalloc(size, GFP_KERNEL);
+	if (!isolated_loader)
+		return;
+
+	memcpy(isolated_loader, loader, size);
+	printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
+}
+
 static int
 spufs_create_root(struct super_block *sb, void *data)
 {
@@ -640,6 +755,8 @@ static int __init spufs_init(void)
 	ret = register_spu_syscalls(&spufs_calls);
 	if (ret)
 		goto out_fs;
+
+	spufs_init_isolated_loader();
 	return 0;
 out_fs:
 	unregister_filesystem(&spufs_type);
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
@@ -1,3 +1,5 @@
+#define DEBUG
+
 #include <linux/wait.h>
 #include <linux/ptrace.h>
 
@@ -56,12 +58,12 @@ static inline int spu_run_init(struct sp
 	if ((ret = spu_acquire_runnable(ctx)) != 0)
 		return ret;
 
-	if (ctx->flags & SPU_CREATE_ISOLATE)
-		runcntl |= SPU_RUNCNTL_ISOLATE;
-	else
+	/* 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)) {
 		ctx->ops->npc_write(ctx, *npc);
-
-	ctx->ops->runcntl_write(ctx, runcntl);
+		ctx->ops->runcntl_write(ctx, runcntl);
+	}
 	return 0;
 }
 

--

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

* [PATCH 06/16] spufs: Add isolated-mode SPE recycling support
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (4 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 05/16] spufs: allow isolated mode apps by starting the SPE loader arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 07/16] cell: update cell be register definitions arnd
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann

From: Jeremy Kerr <jeremy@au1.ibm.com>

When in isolated mode, SPEs have access to an area of persistent
storage, which is per-SPE. In order for isolated-mode apps to
communicate arbitrary data through this storage, we need to ensure that
isolated physical SPEs can be reused for subsequent applications.

Add a file ("recycle") in a spethread dir to enable isolated-mode
recycling. By writing to this file, the kernel will reload the
isolated-mode loader kernel, allowing a new app to be run on the same
physical SPE.

This requires the spu_acquire_exclusive function to enforce exclusive
access to the SPE while the loader is initialised.

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

---
Update: clarify locking, remove unnecessary yield, require >0 bytes
        when writing to recycle file.

 arch/powerpc/platforms/cell/spufs/context.c |   27 +++++++++++++++++++++++
 arch/powerpc/platforms/cell/spufs/file.c    |   32 ++++++++++++++++++++++++++++
 arch/powerpc/platforms/cell/spufs/inode.c   |   23 +++++++++++++-------
 arch/powerpc/platforms/cell/spufs/spufs.h   |    7 ++++++
 4 files changed, 81 insertions(+), 8 deletions(-)

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
@@ -120,6 +120,33 @@ void spu_unmap_mappings(struct spu_conte
 		unmap_mapping_range(ctx->signal2, 0, 0x4000, 1);
 }
 
+int spu_acquire_exclusive(struct spu_context *ctx)
+{
+       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);
+       }
+
+out:
+       if (ret)
+               up_write(&ctx->state_sema);
+       return ret;
+}
+
 int spu_acquire_runnable(struct spu_context *ctx)
 {
 	int ret = 0;
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
@@ -1343,6 +1343,37 @@ 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;
@@ -1551,5 +1582,6 @@ 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
@@ -248,7 +248,7 @@ static int spu_setup_isolated(struct spu
 	if (!isolated_loader)
 		return -ENODEV;
 
-	if ((ret = spu_acquire_runnable(ctx)) != 0)
+	if ((ret = spu_acquire_exclusive(ctx)) != 0)
 		return ret;
 
 	mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
@@ -314,10 +314,16 @@ out_drop_priv:
 	spu_mfc_sr1_set(ctx->spu, sr1);
 
 out_unlock:
-	up_write(&ctx->state_sema);
+	spu_release_exclusive(ctx);
 	return ret;
 }
 
+int spu_recycle_isolated(struct spu_context *ctx)
+{
+	ctx->ops->runcntl_stop(ctx);
+	return spu_setup_isolated(ctx);
+}
+
 static int
 spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
 		int mode)
@@ -341,12 +347,6 @@ spufs_mkdir(struct inode *dir, struct de
 		goto out_iput;
 
 	ctx->flags = flags;
-	if (flags & SPU_CREATE_ISOLATE) {
-		ret = spu_setup_isolated(ctx);
-		if (ret)
-			goto out_iput;
-	}
-
 	inode->i_op = &spufs_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
 	if (flags & SPU_CREATE_NOSCHED)
@@ -432,6 +432,13 @@ 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);
+		if (setup_err)
+			ret = setup_err;
+	}
+
 	dput(dentry);
 	return ret;
 }
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
@@ -163,6 +163,12 @@ void spu_acquire(struct spu_context *ctx
 void spu_release(struct spu_context *ctx);
 int spu_acquire_runnable(struct spu_context *ctx);
 void spu_acquire_saved(struct spu_context *ctx);
+int spu_acquire_exclusive(struct spu_context *ctx);
+
+static inline void spu_release_exclusive(struct spu_context *ctx)
+{
+	up_write(&ctx->state_sema);
+}
 
 int spu_activate(struct spu_context *ctx, u64 flags);
 void spu_deactivate(struct spu_context *ctx);
@@ -170,6 +176,7 @@ 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);
 /*
  * spufs_wait
  * 	Same as wait_event_interruptible(), except that here

--

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

* [PATCH 07/16] cell: update cell be register definitions
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (5 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 06/16] spufs: Add isolated-mode SPE recycling support arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 08/16] cell: add shadow registers for pmd_reg arnd
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
  Cc: Kevin Corry, Arnd Bergmann

From: David Erb <djerb@us.ibm.com>

There are a few definitions that are required by subsequent patches,
so add them here.

The original patch is from David Erb, but is significantly cleaned
up by Kevon Corry.

Cc: 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
@@ -4,6 +4,11 @@
  * This file is intended to hold the various register definitions for CBE
  * on-chip system devices (memory controller, IO controller, etc...)
  *
+ * (C) Copyright IBM Corporation 2001,2006
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ *          David J. Erb (djerb@us.ibm.com)
+ *
  * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
  */
 
@@ -22,6 +27,7 @@
 #define HID0_CBE_THERM_INT_EN	0x0000000400000000ul
 #define HID0_CBE_SYSERR_INT_EN	0x0000000200000000ul
 
+#define MAX_CBE		2
 
 /*
  *
@@ -29,45 +35,86 @@
  *
  */
 
+union spe_reg {
+	u64 val;
+	u8 spe[8];
+};
+
+union ppe_spe_reg {
+	u64 val;
+	struct {
+		u32 ppe;
+		u32 spe;
+	};
+};
+
+
 struct cbe_pmd_regs {
-	u8 pad_0x0000_0x0800[0x0800 - 0x0000];			/* 0x0000 */
+	/* Debug Bus Control */
+	u64	pad_0x0000;					/* 0x0000 */
+
+	u64	group_control;					/* 0x0008 */
+
+	u8	pad_0x0010_0x00a8 [0x00a8 - 0x0010];		/* 0x0010 */
+
+	u64	debug_bus_control;				/* 0x00a8 */
+
+	u8	pad_0x00b0_0x0100 [0x0100 - 0x00b0];		/* 0x00b0 */
+
+	u64	trace_aux_data;					/* 0x0100 */
+	u64	trace_buffer_0_63;				/* 0x0108 */
+	u64	trace_buffer_64_127;				/* 0x0110 */
+	u64	trace_address;					/* 0x0118 */
+	u64	ext_tr_timer;					/* 0x0120 */
+
+	u8	pad_0x0128_0x0400 [0x0400 - 0x0128];		/* 0x0128 */
+
+	/* Performance Monitor */
+	u64	pm_status;					/* 0x0400 */
+	u64	pm_control;					/* 0x0408 */
+	u64	pm_interval;					/* 0x0410 */
+	u64	pm_ctr[4];					/* 0x0418 */
+	u64	pm_start_stop;					/* 0x0438 */
+	u64	pm07_control[8];				/* 0x0440 */
+
+	u8	pad_0x0480_0x0800 [0x0800 - 0x0480];		/* 0x0480 */
 
 	/* Thermal Sensor Registers */
-	u64  ts_ctsr1;						/* 0x0800 */
-	u64  ts_ctsr2;						/* 0x0808 */
-	u64  ts_mtsr1;						/* 0x0810 */
-	u64  ts_mtsr2;						/* 0x0818 */
-	u64  ts_itr1;						/* 0x0820 */
-	u64  ts_itr2;						/* 0x0828 */
-	u64  ts_gitr;						/* 0x0830 */
-	u64  ts_isr;						/* 0x0838 */
-	u64  ts_imr;						/* 0x0840 */
-	u64  tm_cr1;						/* 0x0848 */
-	u64  tm_cr2;						/* 0x0850 */
-	u64  tm_simr;						/* 0x0858 */
-	u64  tm_tpr;						/* 0x0860 */
-	u64  tm_str1;						/* 0x0868 */
-	u64  tm_str2;						/* 0x0870 */
-	u64  tm_tsr;						/* 0x0878 */
+	union	spe_reg	ts_ctsr1;				/* 0x0800 */
+	u64	ts_ctsr2;					/* 0x0808 */
+	union	spe_reg	ts_mtsr1;				/* 0x0810 */
+	u64	ts_mtsr2;					/* 0x0818 */
+	union	spe_reg	ts_itr1;				/* 0x0820 */
+	u64	ts_itr2;					/* 0x0828 */
+	u64	ts_gitr;					/* 0x0830 */
+	u64	ts_isr;						/* 0x0838 */
+	u64	ts_imr;						/* 0x0840 */
+	union	spe_reg	tm_cr1;					/* 0x0848 */
+	u64	tm_cr2;						/* 0x0850 */
+	u64	tm_simr;					/* 0x0858 */
+	union	ppe_spe_reg tm_tpr;				/* 0x0860 */
+	union	spe_reg	tm_str1;				/* 0x0868 */
+	u64	tm_str2;					/* 0x0870 */
+	union	ppe_spe_reg tm_tsr;				/* 0x0878 */
 
 	/* Power Management */
-	u64  pm_control;					/* 0x0880 */
-#define CBE_PMD_PAUSE_ZERO_CONTROL		0x10000
-	u64  pm_status;						/* 0x0888 */
+	u64	pmcr;						/* 0x0880 */
+#define CBE_PMD_PAUSE_ZERO_CONTROL	0x10000
+	u64	pmsr;						/* 0x0888 */
 
 	/* Time Base Register */
-	u64  tbr;						/* 0x0890 */
+	u64	tbr;						/* 0x0890 */
 
-	u8   pad_0x0898_0x0c00 [0x0c00 - 0x0898];		/* 0x0898 */
+	u8	pad_0x0898_0x0c00 [0x0c00 - 0x0898];		/* 0x0898 */
 
 	/* Fault Isolation Registers */
-	u64  checkstop_fir;					/* 0x0c00 */
-	u64  recoverable_fir;
-	u64  spec_att_mchk_fir;
-	u64  fir_mode_reg;
-	u64  fir_enable_mask;
+	u64	checkstop_fir;					/* 0x0c00 */
+	u64	recoverable_fir;				/* 0x0c08 */
+	u64	spec_att_mchk_fir;				/* 0x0c10 */
+	u64	fir_mode_reg;					/* 0x0c18 */
+	u64	fir_enable_mask;				/* 0x0c20 */
 
-	u8   pad_0x0c28_0x1000 [0x1000 - 0x0c28];		/* 0x0c28 */
+	u8	pad_0x0c28_0x1000 [0x1000 - 0x0c28];		/* 0x0c28 */
 };
 
 extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np);
@@ -102,18 +149,20 @@ struct cbe_iic_regs {
 
 	/* IIC interrupt registers */
 	struct	cbe_iic_thread_regs thread[2];			/* 0x0400 */
-	u64     iic_ir;						/* 0x0440 */
-	u64     iic_is;						/* 0x0448 */
+
+	u64	iic_ir;						/* 0x0440 */
+	u64	iic_is;						/* 0x0448 */
+#define CBE_IIC_IS_PMI		0x2
 
 	u8	pad_0x0450_0x0500[0x0500 - 0x0450];		/* 0x0450 */
 
 	/* IOC FIR */
 	u64	ioc_fir_reset;					/* 0x0500 */
-	u64	ioc_fir_set;
-	u64	ioc_checkstop_enable;
-	u64	ioc_fir_error_mask;
-	u64	ioc_syserr_enable;
-	u64	ioc_fir;
+	u64	ioc_fir_set;					/* 0x0508 */
+	u64	ioc_checkstop_enable;				/* 0x0510 */
+	u64	ioc_fir_error_mask;				/* 0x0518 */
+	u64	ioc_syserr_enable;				/* 0x0520 */
+	u64	ioc_fir;					/* 0x0528 */
 
 	u8	pad_0x0530_0x1000[0x1000 - 0x0530];		/* 0x0530 */
 };
@@ -122,6 +171,48 @@ extern struct cbe_iic_regs __iomem *cbe_
 extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu);
 
 
+struct cbe_mic_tm_regs {
+	u8	pad_0x0000_0x0040[0x0040 - 0x0000];		/* 0x0000 */
+
+	u64	mic_ctl_cnfg2;					/* 0x0040 */
+#define CBE_MIC_ENABLE_AUX_TRC		0x8000000000000000LL
+#define CBE_MIC_DISABLE_PWR_SAV_2	0x0200000000000000LL
+#define CBE_MIC_DISABLE_AUX_TRC_WRAP	0x0100000000000000LL
+#define CBE_MIC_ENABLE_AUX_TRC_INT	0x0080000000000000LL
+
+	u64	pad_0x0048;					/* 0x0048 */
+
+	u64	mic_aux_trc_base;				/* 0x0050 */
+	u64	mic_aux_trc_max_addr;				/* 0x0058 */
+	u64	mic_aux_trc_cur_addr;				/* 0x0060 */
+	u64	mic_aux_trc_grf_addr;				/* 0x0068 */
+	u64	mic_aux_trc_grf_data;				/* 0x0070 */
+
+	u64	pad_0x0078;					/* 0x0078 */
+
+	u64	mic_ctl_cnfg_0;					/* 0x0080 */
+#define CBE_MIC_DISABLE_PWR_SAV_0	0x8000000000000000LL
+
+	u64	pad_0x0088;					/* 0x0088 */
+
+	u64	slow_fast_timer_0;				/* 0x0090 */
+	u64	slow_next_timer_0;				/* 0x0098 */
+
+	u8	pad_0x00a0_0x01c0[0x01c0 - 0x0a0];		/* 0x00a0 */
+
+	u64	mic_ctl_cnfg_1;					/* 0x01c0 */
+#define CBE_MIC_DISABLE_PWR_SAV_1	0x8000000000000000LL
+	u64	pad_0x01c8;					/* 0x01c8 */
+
+	u64	slow_fast_timer_1;				/* 0x01d0 */
+	u64	slow_next_timer_1;				/* 0x01d8 */
+
+	u8	pad_0x01e0_0x1000[0x1000 - 0x01e0];		/* 0x01e0 */
+};
+
+extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
+extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
+
 /* Init this module early */
 extern void cbe_regs_init(void);
 
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
@@ -8,6 +8,7 @@
 
 #include <linux/percpu.h>
 #include <linux/types.h>
+#include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -16,8 +17,6 @@
 
 #include "cbe_regs.h"
 
-#define MAX_CBE		2
-
 /*
  * Current implementation uses "cpu" nodes. We build our own mapping
  * array of cpu numbers to cpu nodes locally for now to allow interrupt
@@ -30,6 +29,7 @@ static struct cbe_regs_map
 	struct device_node *cpu_node;
 	struct cbe_pmd_regs __iomem *pmd_regs;
 	struct cbe_iic_regs __iomem *iic_regs;
+	struct cbe_mic_tm_regs __iomem *mic_tm_regs;
 } cbe_regs_maps[MAX_CBE];
 static int cbe_regs_map_count;
 
@@ -42,6 +42,19 @@ static struct cbe_thread_map
 static struct cbe_regs_map *cbe_find_map(struct device_node *np)
 {
 	int i;
+	struct device_node *tmp_np;
+
+	if (strcasecmp(np->type, "spe") == 0) {
+		if (np->data == NULL) {
+			/* walk up path until cpu node was found */
+			tmp_np = np->parent;
+			while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0)
+				tmp_np = tmp_np->parent;
+
+			np->data = cbe_find_map(tmp_np);
+		}
+		return np->data;
+	}
 
 	for (i = 0; i < cbe_regs_map_count; i++)
 		if (cbe_regs_maps[i].cpu_node == np)
@@ -56,6 +69,7 @@ struct cbe_pmd_regs __iomem *cbe_get_pmd
 		return NULL;
 	return map->pmd_regs;
 }
+EXPORT_SYMBOL_GPL(cbe_get_pmd_regs);
 
 struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu)
 {
@@ -64,7 +78,7 @@ struct cbe_pmd_regs __iomem *cbe_get_cpu
 		return NULL;
 	return map->pmd_regs;
 }
-
+EXPORT_SYMBOL_GPL(cbe_get_cpu_pmd_regs);
 
 struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
 {
@@ -73,6 +87,7 @@ struct cbe_iic_regs __iomem *cbe_get_iic
 		return NULL;
 	return map->iic_regs;
 }
+
 struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu)
 {
 	struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
@@ -81,6 +96,24 @@ struct cbe_iic_regs __iomem *cbe_get_cpu
 	return map->iic_regs;
 }
 
+struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np)
+{
+	struct cbe_regs_map *map = cbe_find_map(np);
+	if (map == NULL)
+		return NULL;
+	return map->mic_tm_regs;
+}
+
+struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu)
+{
+	struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
+	if (map == NULL)
+		return NULL;
+	return map->mic_tm_regs;
+}
+EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
+
+
 void __init cbe_regs_init(void)
 {
 	int i;
@@ -119,6 +152,11 @@ void __init cbe_regs_init(void)
 		prop = get_property(cpu, "iic", NULL);
 		if (prop != NULL)
 			map->iic_regs = ioremap(prop->address, prop->len);
+
+		prop = (struct address_prop *)get_property(cpu, "mic-tm",
+							   NULL);
+		if (prop != NULL)
+			map->mic_tm_regs = ioremap(prop->address, prop->len);
 	}
 }
 
Index: linux-2.6/arch/powerpc/platforms/cell/pervasive.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pervasive.c
+++ linux-2.6/arch/powerpc/platforms/cell/pervasive.c
@@ -54,9 +54,9 @@ static void __init cbe_enable_pause_zero
 	pr_debug("Power Management: CPU %d\n", smp_processor_id());
 
 	 /* Enable Pause(0) control bit */
-	temp_register = in_be64(&pregs->pm_control);
+	temp_register = in_be64(&pregs->pmcr);
 
-	out_be64(&pregs->pm_control,
+	out_be64(&pregs->pmcr,
 		 temp_register | CBE_PMD_PAUSE_ZERO_CONTROL);
 
 	/* Enable DEC and EE interrupt request */
@@ -87,7 +87,7 @@ static void cbe_idle(void)
 	unsigned long ctrl;
 
 	/* Why do we do that on every idle ? Couldn't that be done once for
-	 * all or do we lose the state some way ? Also, the pm_control
+	 * all or do we lose the state some way ? Also, the pmcr
 	 * register setting, that can't be set once at boot ? We really want
 	 * to move that away in order to implement a simple powersave
 	 */

--

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

* [PATCH 08/16] cell: add shadow registers for pmd_reg
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (6 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 07/16] cell: update cell be register definitions arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 09/16] cell: add low-level performance monitoring code arnd
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
  Cc: Kevin Corry, Arnd Bergmann

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

Many of the registers in the performance monitoring unit are write-only.
We need to save a "shadow" copy when we write to those registers so we
can retrieve the values if we need them later.

The new cbe_pmd_shadow_regs structure is added to the cbe_regs_map structure
so we have the appropriate per-node copies of these shadow values.

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.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.c
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.c
@@ -30,6 +30,7 @@ static struct cbe_regs_map
 	struct cbe_pmd_regs __iomem *pmd_regs;
 	struct cbe_iic_regs __iomem *iic_regs;
 	struct cbe_mic_tm_regs __iomem *mic_tm_regs;
+	struct cbe_pmd_shadow_regs pmd_shadow_regs;
 } cbe_regs_maps[MAX_CBE];
 static int cbe_regs_map_count;
 
@@ -80,6 +81,22 @@ struct cbe_pmd_regs __iomem *cbe_get_cpu
 }
 EXPORT_SYMBOL_GPL(cbe_get_cpu_pmd_regs);
 
+struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np)
+{
+	struct cbe_regs_map *map = cbe_find_map(np);
+	if (map == NULL)
+		return NULL;
+	return &map->pmd_shadow_regs;
+}
+
+struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu)
+{
+	struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
+	if (map == NULL)
+		return NULL;
+	return &map->pmd_shadow_regs;
+}
+
 struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
 {
 	struct cbe_regs_map *map = cbe_find_map(np);
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
@@ -121,6 +121,41 @@ extern struct cbe_pmd_regs __iomem *cbe_
 extern struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu);
 
 /*
+ * PMU shadow registers
+ *
+ * Many of the registers in the performance monitoring unit are write-only,
+ * so we need to save a copy of what we write to those registers.
+ *
+ * The actual data counters are read/write. However, writing to the counters
+ * only takes effect if the PMU is enabled. Otherwise the value is stored in
+ * a hardware latch until the next time the PMU is enabled. So we save a copy
+ * of the counter values if we need to read them back while the PMU is
+ * disabled. The counter_value_in_latch field is a bitmap indicating which
+ * 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;
+	u32 trace_address;
+	u32 ext_tr_timer;
+	u32 pm_status;
+	u32 pm_control;
+	u32 pm_interval;
+	u32 pm_start_stop;
+	u32 pm07_control[NR_CTRS];
+
+	u32 pm_ctr[NR_PHYS_CTRS];
+	u32 counter_value_in_latch;
+};
+
+extern struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np);
+extern struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu);
+
+/*
  *
  * IIC unit register definitions
  *

--

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

* [PATCH 09/16] cell: add low-level performance monitoring code
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (7 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 08/16] cell: add shadow registers for pmd_reg arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 10/16] cell: add support for registering sysfs attributes to spus arnd
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
  Cc: Kevin Corry, Arnd Bergmann

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

Add routines for accessing the registers and counters in the performance
monitoring unit.

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/Makefile
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Makefile
+++ linux-2.6/arch/powerpc/platforms/cell/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_PPC_CELL_NATIVE)		+= interrupt.o iommu.o setup.o \
-					   cbe_regs.o spider-pic.o pervasive.o
+					   cbe_regs.o spider-pic.o pervasive.o \
+					   pmu.o
 obj-$(CONFIG_CBE_RAS)			+= ras.o
 
 ifeq ($(CONFIG_SMP),y)
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
@@ -35,6 +35,11 @@
  *
  */
 
+/* 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
+
+
 union spe_reg {
 	u64 val;
 	u8 spe[8];
Index: linux-2.6/arch/powerpc/platforms/cell/pmu.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/pmu.c
@@ -0,0 +1,328 @@
+/*
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/reg.h>
+#include <asm/spu.h>
+
+#include "cbe_regs.h"
+#include "interrupt.h"
+#include "pmu.h"
+
+/*
+ * When writing to write-only mmio addresses, save a shadow copy. All of the
+ * registers are 32-bit, but stored in the upper-half of a 64-bit field in
+ * pmd_regs.
+ */
+
+#define WRITE_WO_MMIO(reg, x)					\
+	do {							\
+		u32 _x = (x);					\
+		struct cbe_pmd_regs __iomem *pmd_regs;		\
+		struct cbe_pmd_shadow_regs *shadow_regs;	\
+		pmd_regs = cbe_get_cpu_pmd_regs(cpu);		\
+		shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);	\
+		out_be64(&(pmd_regs->reg), (((u64)_x) << 32));	\
+		shadow_regs->reg = _x;				\
+	} while (0)
+
+#define READ_SHADOW_REG(val, reg)				\
+	do {							\
+		struct cbe_pmd_shadow_regs *shadow_regs;	\
+		shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);	\
+		(val) = shadow_regs->reg;			\
+	} while (0)
+
+#define READ_MMIO_UPPER32(val, reg)				\
+	do {							\
+		struct cbe_pmd_regs __iomem *pmd_regs;		\
+		pmd_regs = cbe_get_cpu_pmd_regs(cpu);		\
+		(val) = (u32)(in_be64(&pmd_regs->reg) >> 32);	\
+	} while (0)
+
+/*
+ * Physical counter registers.
+ * Each physical counter can act as one 32-bit counter or two 16-bit counters.
+ */
+
+u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr)
+{
+	u32 val_in_latch, val = 0;
+
+	if (phys_ctr < NR_PHYS_CTRS) {
+		READ_SHADOW_REG(val_in_latch, counter_value_in_latch);
+
+		/* Read the latch or the actual counter, whichever is newer. */
+		if (val_in_latch & (1 << phys_ctr)) {
+			READ_SHADOW_REG(val, pm_ctr[phys_ctr]);
+		} else {
+			READ_MMIO_UPPER32(val, pm_ctr[phys_ctr]);
+		}
+	}
+
+	return val;
+}
+
+void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
+{
+	struct cbe_pmd_shadow_regs *shadow_regs;
+	u32 pm_ctrl;
+
+	if (phys_ctr < NR_PHYS_CTRS) {
+		/* Writing to a counter only writes to a hardware latch.
+		 * The new value is not propagated to the actual counter
+		 * until the performance monitor is enabled.
+		 */
+		WRITE_WO_MMIO(pm_ctr[phys_ctr], val);
+
+		pm_ctrl = cbe_read_pm(cpu, pm_control);
+		if (pm_ctrl & CBE_PM_ENABLE_PERF_MON) {
+			/* The counters are already active, so we need to
+			 * rewrite the pm_control register to "re-enable"
+			 * the PMU.
+			 */
+			cbe_write_pm(cpu, pm_control, pm_ctrl);
+		} else {
+			shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
+			shadow_regs->counter_value_in_latch |= (1 << phys_ctr);
+		}
+	}
+}
+
+/*
+ * "Logical" counter registers.
+ * These will read/write 16-bits or 32-bits depending on the
+ * current size of the counter. Counters 4 - 7 are always 16-bit.
+ */
+
+u32 cbe_read_ctr(u32 cpu, u32 ctr)
+{
+	u32 val;
+	u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+	val = cbe_read_phys_ctr(cpu, phys_ctr);
+
+	if (cbe_get_ctr_size(cpu, phys_ctr) == 16)
+		val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
+
+	return val;
+}
+
+void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
+{
+	u32 phys_ctr;
+	u32 phys_val;
+
+	phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+	if (cbe_get_ctr_size(cpu, phys_ctr) == 16) {
+		phys_val = cbe_read_phys_ctr(cpu, phys_ctr);
+
+		if (ctr < NR_PHYS_CTRS)
+			val = (val << 16) | (phys_val & 0xffff);
+		else
+			val = (val & 0xffff) | (phys_val & 0xffff0000);
+	}
+
+	cbe_write_phys_ctr(cpu, phys_ctr, val);
+}
+
+/*
+ * Counter-control registers.
+ * Each "logical" counter has a corresponding control register.
+ */
+
+u32 cbe_read_pm07_control(u32 cpu, u32 ctr)
+{
+	u32 pm07_control = 0;
+
+	if (ctr < NR_CTRS)
+		READ_SHADOW_REG(pm07_control, pm07_control[ctr]);
+
+	return pm07_control;
+}
+
+void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val)
+{
+	if (ctr < NR_CTRS)
+		WRITE_WO_MMIO(pm07_control[ctr], val);
+}
+
+/*
+ * Other PMU control registers. Most of these are write-only.
+ */
+
+u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
+{
+	u32 val = 0;
+
+	switch (reg) {
+	case group_control:
+		READ_SHADOW_REG(val, group_control);
+		break;
+
+	case debug_bus_control:
+		READ_SHADOW_REG(val, debug_bus_control);
+		break;
+
+	case trace_address:
+		READ_MMIO_UPPER32(val, trace_address);
+		break;
+
+	case ext_tr_timer:
+		READ_SHADOW_REG(val, ext_tr_timer);
+		break;
+
+	case pm_status:
+		READ_MMIO_UPPER32(val, pm_status);
+		break;
+
+	case pm_control:
+		READ_SHADOW_REG(val, pm_control);
+		break;
+
+	case pm_interval:
+		READ_SHADOW_REG(val, pm_interval);
+		break;
+
+	case pm_start_stop:
+		READ_SHADOW_REG(val, pm_start_stop);
+		break;
+	}
+
+	return val;
+}
+
+void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
+{
+	switch (reg) {
+	case group_control:
+		WRITE_WO_MMIO(group_control, val);
+		break;
+
+	case debug_bus_control:
+		WRITE_WO_MMIO(debug_bus_control, val);
+		break;
+
+	case trace_address:
+		WRITE_WO_MMIO(trace_address, val);
+		break;
+
+	case ext_tr_timer:
+		WRITE_WO_MMIO(ext_tr_timer, val);
+		break;
+
+	case pm_status:
+		WRITE_WO_MMIO(pm_status, val);
+		break;
+
+	case pm_control:
+		WRITE_WO_MMIO(pm_control, val);
+		break;
+
+	case pm_interval:
+		WRITE_WO_MMIO(pm_interval, val);
+		break;
+
+	case pm_start_stop:
+		WRITE_WO_MMIO(pm_start_stop, val);
+		break;
+	}
+}
+
+/*
+ * Get/set the size of a physical counter to either 16 or 32 bits.
+ */
+
+u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr)
+{
+	u32 pm_ctrl, size = 0;
+
+	if (phys_ctr < NR_PHYS_CTRS) {
+		pm_ctrl = cbe_read_pm(cpu, pm_control);
+		size = (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
+	}
+
+	return size;
+}
+
+void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
+{
+	u32 pm_ctrl;
+
+	if (phys_ctr < NR_PHYS_CTRS) {
+		pm_ctrl = cbe_read_pm(cpu, pm_control);
+		switch (ctr_size) {
+		case 16:
+			pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
+			break;
+
+		case 32:
+			pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
+			break;
+		}
+		cbe_write_pm(cpu, pm_control, pm_ctrl);
+	}
+}
+
+/*
+ * Enable/disable the entire performance monitoring unit.
+ * When we enable the PMU, all pending writes to counters get committed.
+ */
+
+void cbe_enable_pm(u32 cpu)
+{
+	struct cbe_pmd_shadow_regs *shadow_regs;
+	u32 pm_ctrl;
+
+	shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
+	shadow_regs->counter_value_in_latch = 0;
+
+	pm_ctrl = cbe_read_pm(cpu, pm_control) | CBE_PM_ENABLE_PERF_MON;
+	cbe_write_pm(cpu, pm_control, pm_ctrl);
+}
+
+void cbe_disable_pm(u32 cpu)
+{
+	u32 pm_ctrl;
+	pm_ctrl = cbe_read_pm(cpu, pm_control) & ~CBE_PM_ENABLE_PERF_MON;
+	cbe_write_pm(cpu, pm_control, pm_ctrl);
+}
+
+/*
+ * Reading from the trace_buffer.
+ * The trace buffer is two 64-bit registers. Reading from
+ * the second half automatically increments the trace_address.
+ */
+
+void cbe_read_trace_buffer(u32 cpu, u64 *buf)
+{
+	struct cbe_pmd_regs __iomem *pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+
+	*buf++ = in_be64(&pmd_regs->trace_buffer_0_63);
+	*buf++ = in_be64(&pmd_regs->trace_buffer_64_127);
+}
+
Index: linux-2.6/arch/powerpc/platforms/cell/pmu.h
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/pmu.h
@@ -0,0 +1,57 @@
+/*
+ * 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

--

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

* [PATCH 10/16] cell: add support for registering sysfs attributes to spus
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (8 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 09/16] cell: add low-level performance monitoring code arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 11/16] sysfs: add support for adding/removing spu sysfs attributes arnd
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
  Cc: Christian Krafft, Arnd Bergmann

From: Christian Krafft <krafft@de.ibm.com>

In order to add sysfs attributes to all spu's, there is a
need for a list of all available spu's. Adding the device_node
makes also sense, as it is needed for proper register access.
This patch also adds two functions to create and remove sysfs
attributes and attribute_groups to all spus.
That allows to group spu attributes in a subdirectory like:
/sys/devices/system/spu/spuX/group_name/what_ever
This will be used by cbe_thermal to group all attributes dealing with
thermal support in one directory.

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

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
@@ -115,6 +115,7 @@ struct spu {
 	struct spu_priv2 __iomem *priv2;
 	struct list_head list;
 	struct list_head sched_list;
+	struct list_head full_list;
 	int number;
 	int nid;
 	unsigned int irqs[3];
@@ -143,6 +144,8 @@ struct spu {
 	char irq_c1[8];
 	char irq_c2[8];
 
+	struct device_node *devnode;
+
 	struct sys_device sysdev;
 };
 
@@ -200,6 +203,12 @@ static inline void unregister_spu_syscal
 }
 #endif /* MODULE */
 
+int spu_add_sysdev_attr(struct sysdev_attribute *attr);
+void spu_remove_sysdev_attr(struct sysdev_attribute *attr);
+
+int spu_add_sysdev_attr_group(struct attribute_group *attrs);
+void spu_remove_sysdev_attr_group(struct attribute_group *attrs);
+
 
 /*
  * Notifier blocks:
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
@@ -333,6 +333,7 @@ static void spu_free_irqs(struct spu *sp
 }
 
 static struct list_head spu_list[MAX_NUMNODES];
+static LIST_HEAD(spu_full_list);
 static DEFINE_MUTEX(spu_mutex);
 
 static void spu_init_channels(struct spu *spu)
@@ -744,6 +745,57 @@ struct sysdev_class spu_sysdev_class = {
 	set_kset_name("spu")
 };
 
+int spu_add_sysdev_attr(struct sysdev_attribute *attr)
+{
+	struct spu *spu;
+	mutex_lock(&spu_mutex);
+
+	list_for_each_entry(spu, &spu_full_list, full_list)
+		sysdev_create_file(&spu->sysdev, attr);
+
+	mutex_unlock(&spu_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
+
+int spu_add_sysdev_attr_group(struct attribute_group *attrs)
+{
+	struct spu *spu;
+	mutex_lock(&spu_mutex);
+
+	list_for_each_entry(spu, &spu_full_list, full_list)
+		sysfs_create_group(&spu->sysdev.kobj, attrs);
+
+	mutex_unlock(&spu_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
+
+
+void spu_remove_sysdev_attr(struct sysdev_attribute *attr)
+{
+	struct spu *spu;
+	mutex_lock(&spu_mutex);
+
+	list_for_each_entry(spu, &spu_full_list, full_list)
+		sysdev_remove_file(&spu->sysdev, attr);
+
+	mutex_unlock(&spu_mutex);
+}
+EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);
+
+void spu_remove_sysdev_attr_group(struct attribute_group *attrs)
+{
+	struct spu *spu;
+	mutex_lock(&spu_mutex);
+
+	list_for_each_entry(spu, &spu_full_list, full_list)
+		sysfs_remove_group(&spu->sysdev.kobj, attrs);
+
+	mutex_unlock(&spu_mutex);
+}
+EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);
+
 static int spu_create_sysdev(struct spu *spu)
 {
 	int ret;
@@ -817,6 +869,9 @@ static int __init create_spu(struct devi
 		goto out_free_irqs;
 
 	list_add(&spu->list, &spu_list[spu->node]);
+	list_add(&spu->full_list, &spu_full_list);
+	spu->devnode = of_node_get(spe);
+
 	mutex_unlock(&spu_mutex);
 
 	pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n",
@@ -839,6 +894,9 @@ out:
 static void destroy_spu(struct spu *spu)
 {
 	list_del_init(&spu->list);
+	list_del_init(&spu->full_list);
+
+	of_node_put(spu->devnode);
 
 	spu_destroy_sysdev(spu);
 	spu_free_irqs(spu);

--

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

* [PATCH 11/16] sysfs: add support for adding/removing spu sysfs attributes
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (9 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 10/16] cell: add support for registering sysfs attributes to spus arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-25  7:52   ` Heiko Carstens
  2006-10-24 16:31 ` [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries arnd
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus

From: Christian Krafft <krafft@de.ibm.com>

This patch adds two functions to create and remove sysfs attributes and
attribute_group to all cpus.  That allows to register sysfs attributes in
a subdirectory like: /sys/devices/system/cpu/cpuX/group_name/what_ever
This will be used by cbe_thermal to group all attributes dealing with
thermal support in one directory.

Signed-of-by: Christian Krafft <krafft@de.ibm.com>

Index: linux-2.6/arch/powerpc/kernel/sysfs.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/sysfs.c
+++ linux-2.6/arch/powerpc/kernel/sysfs.c
@@ -299,6 +299,72 @@ static struct notifier_block __cpuinitda
 	.notifier_call	= sysfs_cpu_notify,
 };
 
+static DEFINE_MUTEX(cpu_mutex);
+
+int cpu_add_sysdev_attr(struct sysdev_attribute *attr)
+{
+	int cpu;
+
+	mutex_lock(&cpu_mutex);
+
+	for_each_possible_cpu(cpu) {
+		sysdev_create_file(get_cpu_sysdev(cpu), attr);
+	}
+
+	mutex_unlock(&cpu_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr);
+
+int cpu_add_sysdev_attr_group(struct attribute_group *attrs)
+{
+	int cpu;
+	struct sys_device *sysdev;
+
+	mutex_lock(&cpu_mutex);
+
+	for_each_possible_cpu(cpu) {
+		sysdev = get_cpu_sysdev(cpu);
+		sysfs_create_group(&sysdev->kobj, attrs);
+	}
+
+	mutex_unlock(&cpu_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr_group);
+
+
+void cpu_remove_sysdev_attr(struct sysdev_attribute *attr)
+{
+	int cpu;
+
+	mutex_lock(&cpu_mutex);
+
+	for_each_possible_cpu(cpu) {
+		sysdev_remove_file(get_cpu_sysdev(cpu), attr);
+	}
+
+	mutex_unlock(&cpu_mutex);
+}
+EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr);
+
+void cpu_remove_sysdev_attr_group(struct attribute_group *attrs)
+{
+	int cpu;
+	struct sys_device *sysdev;
+
+	mutex_lock(&cpu_mutex);
+
+	for_each_possible_cpu(cpu) {
+		sysdev = get_cpu_sysdev(cpu);
+		sysfs_remove_group(&sysdev->kobj, attrs);
+	}
+
+	mutex_unlock(&cpu_mutex);
+}
+EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr_group);
+
+
 /* NUMA stuff */
 
 #ifdef CONFIG_NUMA
Index: linux-2.6/include/linux/cpu.h
===================================================================
--- linux-2.6.orig/include/linux/cpu.h
+++ linux-2.6/include/linux/cpu.h
@@ -33,6 +33,14 @@ struct cpu {
 
 extern int register_cpu(struct cpu *cpu, int num);
 extern struct sys_device *get_cpu_sysdev(unsigned cpu);
+
+extern int cpu_add_sysdev_attr(struct sysdev_attribute *attr);
+extern void cpu_remove_sysdev_attr(struct sysdev_attribute *attr);
+
+extern int cpu_add_sysdev_attr_group(struct attribute_group *attrs);
+extern void cpu_remove_sysdev_attr_group(struct attribute_group *attrs);
+
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);
 #endif

--

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

* [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (10 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 11/16] sysfs: add support for adding/removing spu sysfs attributes arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-25  8:00   ` Heiko Carstens
  2006-10-24 16:31 ` [PATCH 13/16] cell: use ppc_md->power_save instead of cbe_idle_loop arnd
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
  Cc: Christian Krafft, Arnd Bergmann

From: Christian Krafft <krafft@de.ibm.com>

This patch adds a module that registers sysfs attributes to CPU and SPU
containing the temperature of the CBE.

They can be found under
/sys/devices/system/spu/cpuX/thermal/temperature[0|1]
/sys/devices/system/spu/spuX/thermal/temperature

The temperature is read from the on-chip temperature sensors.

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

Index: linux-2.6/arch/powerpc/platforms/cell/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Kconfig
+++ linux-2.6/arch/powerpc/platforms/cell/Kconfig
@@ -20,4 +20,9 @@ config CBE_RAS
 	bool "RAS features for bare metal Cell BE"
 	default y
 
+config CBE_THERM
+	tristate "CBE thermal support"
+	default m
+	depends on CBE_RAS
+
 endmenu
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
@@ -3,6 +3,8 @@ obj-$(CONFIG_PPC_CELL_NATIVE)		+= interr
 					   pmu.o
 obj-$(CONFIG_CBE_RAS)			+= ras.o
 
+obj-$(CONFIG_CBE_THERM)			+= cbe_thermal.o
+
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_CELL_NATIVE)		+= smp.o
 endif
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
@@ -149,6 +149,7 @@ CONFIG_MMIO_NVRAM=y
 CONFIG_SPU_FS=m
 CONFIG_SPU_BASE=y
 CONFIG_CBE_RAS=y
+CONFIG_CBE_THERM=m
 
 #
 # Kernel options
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_thermal.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -0,0 +1,225 @@
+/*
+ * thermal support for the cell processor
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Christian Krafft <krafft@de.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/module.h>
+#include <linux/sysdev.h>
+#include <linux/kernel.h>
+#include <linux/cpu.h>
+#include <asm/spu.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+
+#include "cbe_regs.h"
+
+static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
+{
+	struct spu *spu;
+
+	spu = container_of(sysdev, struct spu, sysdev);
+
+	return cbe_get_pmd_regs(spu->devnode);
+}
+
+/* returns the value for a given spu in a given register */
+static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg)
+{
+	unsigned int *id;
+	union spe_reg value;
+	struct spu *spu;
+
+	/* getting the id from the reg attribute will not work on future device-tree layouts
+	 * in future we should store the id to the spu struct and use it here */
+	spu = container_of(sysdev, struct spu, sysdev);
+	id = (unsigned int *)get_property(spu->devnode, "reg", NULL);
+	value.val = in_be64(&reg->val);
+
+	return value.spe[*id];
+}
+
+static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf)
+{
+	int value;
+	struct cbe_pmd_regs __iomem *pmd_regs;
+
+	pmd_regs = get_pmd_regs(sysdev);
+
+	value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1);
+	/* clear all other bits */
+	value &= 0x3F;
+	/* temp is stored in steps of 2 degrees */
+	value *= 2;
+	/* base temp is 65 degrees */
+	value += 65;
+
+	return sprintf(buf, "%d\n", (int) value);
+}
+
+static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
+{
+	struct cbe_pmd_regs __iomem *pmd_regs;
+	u64 value;
+
+	pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
+	value = in_be64(&pmd_regs->ts_ctsr2);
+
+	/* access the corresponding byte */
+	value >>= pos;
+	/* clear all other bits */
+	value &= 0x3F;
+	/* temp is stored in steps of 2 degrees */
+	value *= 2;
+	/* base temp is 65 degrees */
+	value += 65;
+
+	return sprintf(buf, "%d\n", (int) value);
+}
+
+
+/* shows the temperature of the DTS on the PPE,
+ * located near the linear thermal sensor */
+static ssize_t ppe_show_temp0(struct sys_device *sysdev, char *buf)
+{
+	return ppe_show_temp(sysdev, buf, 32);
+}
+
+/* shows the temperature of the second DTS on the PPE */
+static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf)
+{
+	return ppe_show_temp(sysdev, buf, 0);
+}
+
+static struct sysdev_attribute attr_spu_temperature = {
+	.attr = {.name = "temperature", .mode = 0400 },
+	.show = spu_show_temp,
+};
+
+static struct attribute *spu_attributes[] = {
+	&attr_spu_temperature.attr,
+};
+
+static struct attribute_group spu_attribute_group = {
+	.name	= "thermal",
+	.attrs	= spu_attributes,
+};
+
+static struct sysdev_attribute attr_ppe_temperature0 = {
+	.attr = {.name = "temperature0", .mode = 0400 },
+	.show = ppe_show_temp0,
+};
+
+static struct sysdev_attribute attr_ppe_temperature1 = {
+	.attr = {.name = "temperature1", .mode = 0400 },
+	.show = ppe_show_temp1,
+};
+
+static struct attribute *ppe_attributes[] = {
+	&attr_ppe_temperature0.attr,
+	&attr_ppe_temperature1.attr,
+};
+
+static struct attribute_group ppe_attribute_group = {
+	.name	= "thermal",
+	.attrs	= ppe_attributes,
+};
+
+/*
+ * initialize throttling with default values
+ */
+static void __init init_default_values(void)
+{
+	int cpu;
+	struct cbe_pmd_regs __iomem *pmd_regs;
+	struct sys_device *sysdev;
+	union ppe_spe_reg tpr;
+	union spe_reg str1;
+	u64 str2;
+	union spe_reg cr1;
+	u64 cr2;
+
+	/* TPR defaults */
+	/* ppe
+	 *	1F - no full stop
+	 *	08 - dynamic throttling starts if over 80 degrees
+	 *	03 - dynamic throttling ceases if below 70 degrees */
+	tpr.ppe = 0x1F0803;
+	/* spe
+	 *	10 - full stopped when over 96 degrees
+	 *	08 - dynamic throttling starts if over 80 degrees
+	 *	03 - dynamic throttling ceases if below 70 degrees
+	 */
+	tpr.spe = 0x100803;
+
+	/* STR defaults */
+	/* str1
+	 *	10 - stop 16 of 32 cycles
+	 */
+	str1.val = 0x1010101010101010ull;
+	/* str2
+	 *	10 - stop 16 of 32 cycles
+	 */
+	str2 = 0x10;
+
+	/* CR defaults */
+	/* cr1
+	 *	4 - normal operation
+	 */
+	cr1.val = 0x0404040404040404ull;
+	/* cr2
+	 *	4 - normal operation
+	 */
+	cr2 = 0x04;
+
+	for_each_possible_cpu (cpu) {
+		pr_debug("processing cpu %d\n", cpu);
+		sysdev = get_cpu_sysdev(cpu);
+		pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
+
+		out_be64(&pmd_regs->tm_str2, str2);
+		out_be64(&pmd_regs->tm_str1.val, str1.val);
+		out_be64(&pmd_regs->tm_tpr.val, tpr.val);
+		out_be64(&pmd_regs->tm_cr1.val, cr1.val);
+		out_be64(&pmd_regs->tm_cr2, cr2);
+	}
+}
+
+
+static int __init thermal_init(void)
+{
+	init_default_values();
+
+	spu_add_sysdev_attr_group(&spu_attribute_group);
+	cpu_add_sysdev_attr_group(&ppe_attribute_group);
+
+	return 0;
+}
+module_init(thermal_init);
+
+static void __exit thermal_exit(void)
+{
+	spu_remove_sysdev_attr_group(&spu_attribute_group);
+	cpu_remove_sysdev_attr_group(&ppe_attribute_group);
+}
+module_exit(thermal_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
+

--

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

* [PATCH 13/16] cell: use ppc_md->power_save instead of cbe_idle_loop
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (11 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 14/16] add support for stopping spus from xmon arnd
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann

This moves the cell idle function to use the default cpu_idle
with a special power_save callback, like all other platforms
except iSeries already do.

It also makes it possible to disable this power_save function
with a new powerpc-specific boot option "powersave=off".

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
@@ -39,6 +39,13 @@
 #define cpu_should_die()	0
 #endif
 
+static int __init powersave_off(char *arg)
+{
+	ppc_md.power_save = NULL;
+	return 0;
+}
+__setup("powersave=off", powersave_off);
+
 /*
  * The body of the idle task.
  */
Index: linux-2.6/arch/powerpc/platforms/cell/pervasive.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pervasive.c
+++ linux-2.6/arch/powerpc/platforms/cell/pervasive.c
@@ -38,32 +38,16 @@
 #include "pervasive.h"
 #include "cbe_regs.h"
 
-static DEFINE_SPINLOCK(cbe_pervasive_lock);
-
-static void __init cbe_enable_pause_zero(void)
+static void cbe_power_save(void)
 {
-	unsigned long thread_switch_control;
-	unsigned long temp_register;
-	struct cbe_pmd_regs __iomem *pregs;
-
-	spin_lock_irq(&cbe_pervasive_lock);
-	pregs = cbe_get_cpu_pmd_regs(smp_processor_id());
-	if (pregs == NULL)
-		goto out;
-
-	pr_debug("Power Management: CPU %d\n", smp_processor_id());
-
-	 /* Enable Pause(0) control bit */
-	temp_register = in_be64(&pregs->pmcr);
-
-	out_be64(&pregs->pmcr,
-		 temp_register | CBE_PMD_PAUSE_ZERO_CONTROL);
+	unsigned long ctrl, thread_switch_control;
+	ctrl = mfspr(SPRN_CTRLF);
 
 	/* Enable DEC and EE interrupt request */
 	thread_switch_control  = mfspr(SPRN_TSC_CELL);
 	thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
 
-	switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
+	switch (ctrl & CTRL_CT) {
 	case CTRL_CT0:
 		thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
 		break;
@@ -75,58 +59,21 @@ static void __init cbe_enable_pause_zero
 			__FUNCTION__);
 		break;
 	}
-
 	mtspr(SPRN_TSC_CELL, thread_switch_control);
 
-out:
-	spin_unlock_irq(&cbe_pervasive_lock);
-}
-
-static void cbe_idle(void)
-{
-	unsigned long ctrl;
-
-	/* Why do we do that on every idle ? Couldn't that be done once for
-	 * all or do we lose the state some way ? Also, the pmcr
-	 * register setting, that can't be set once at boot ? We really want
-	 * to move that away in order to implement a simple powersave
+	/*
+	 * go into low thread priority, medium priority will be
+	 * restored for us after wake-up.
 	 */
-	cbe_enable_pause_zero();
+	HMT_low();
 
-	while (1) {
-		if (!need_resched()) {
-			local_irq_disable();
-			while (!need_resched()) {
-				/* go into low thread priority */
-				HMT_low();
-
-				/*
-				 * atomically disable thread execution
-				 * and runlatch.
-				 * External and Decrementer exceptions
-				 * are still handled when the thread
-				 * is disabled but now enter in
-				 * cbe_system_reset_exception()
-				 */
-				ctrl = mfspr(SPRN_CTRLF);
-				ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
-				mtspr(SPRN_CTRLT, ctrl);
-			}
-			/* restore thread prio */
-			HMT_medium();
-			local_irq_enable();
-		}
-
-		/*
-		 * turn runlatch on again before scheduling the
-		 * process we just woke up
-		 */
-		ppc64_runlatch_on();
-
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
-	}
+	/*
+	 * atomically disable thread execution and runlatch.
+	 * External and Decrementer exceptions are still handled when the
+	 * thread is disabled but now enter in cbe_system_reset_exception()
+	 */
+	ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
+	mtspr(SPRN_CTRLT, ctrl);
 }
 
 static int cbe_system_reset_exception(struct pt_regs *regs)
@@ -158,9 +105,20 @@ static int cbe_system_reset_exception(st
 
 void __init cbe_pervasive_init(void)
 {
+	int cpu;
 	if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
 		return;
 
-	ppc_md.idle_loop = cbe_idle;
+	for_each_possible_cpu(cpu) {
+		struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu);
+		if (!regs)
+			continue;
+
+		 /* Enable Pause(0) control bit */
+		out_be64(&regs->pmcr, in_be64(&regs->pmcr) |
+					    CBE_PMD_PAUSE_ZERO_CONTROL);
+	}
+
+	ppc_md.power_save = cbe_power_save;
 	ppc_md.system_reset_exception = cbe_system_reset_exception;
 }

--

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

* [PATCH 14/16] add support for stopping spus from xmon
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (12 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 13/16] cell: use ppc_md->power_save instead of cbe_idle_loop arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:31 ` [PATCH 15/16] add support for dumping spu info " arnd
  2006-10-24 16:39 ` [PATCH 16/16] cell: add cpufreq driver for Cell BE processor arnd
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann

From: Michael Ellerman <michael@ellerman.id.au>

This patch adds support for stopping, and restarting, spus
from xmon. We use the spu master runcntl bit to stop execution,
this is apparently the "right" way to control spu execution and
spufs will be changed in the future to use this bit.

Testing has shown that to restart execution we have to turn the
master runcntl bit on and also rewrite the spu runcntl bit, even
if it is already set to 1 (running).

Stopping spus is triggered by the xmon command 'ss' - "spus stop"
perhaps. Restarting them is triggered via 'sr'. Restart doesn't
start execution on spus unless they were running prior to being
stopped by xmon.

Walking the spu->full_list in xmon after a panic, would mean
corruption of any spu struct would make all the others
inaccessible. To avoid this, and also to make the next patch
easier, we cache pointers to all spus during boot.

We attempt to catch and recover from errors while stopping and
restarting the spus, but as with most xmon functionality there are
no guarantees that performing these operations won't crash xmon
itself.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---

 arch/powerpc/platforms/cell/spu_base.c |    4 
 arch/powerpc/xmon/xmon.c               |  142 ++++++++++++++++++++++++++++++++-
 include/asm-powerpc/xmon.h             |    2 
 3 files changed, 146 insertions(+), 2 deletions(-)

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
@@ -38,6 +38,7 @@
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
 #include <asm/mmu_context.h>
+#include <asm/xmon.h>
 
 #include "interrupt.h"
 
@@ -943,6 +944,9 @@ static int __init init_spu_base(void)
 			break;
 		}
 	}
+
+	xmon_register_spus(&spu_full_list);
+
 	return ret;
 }
 module_init(init_spu_base);
Index: linux-2.6/arch/powerpc/xmon/xmon.c
===================================================================
--- linux-2.6.orig/arch/powerpc/xmon/xmon.c
+++ linux-2.6/arch/powerpc/xmon/xmon.c
@@ -37,6 +37,8 @@
 #include <asm/sstep.h>
 #include <asm/bug.h>
 #include <asm/irq_regs.h>
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
 
 #ifdef CONFIG_PPC64
 #include <asm/hvcall.h>
@@ -147,6 +149,8 @@ static void xmon_print_symbol(unsigned l
 			      const char *after);
 static const char *getvecname(unsigned long vec);
 
+static int do_spu_cmd(void);
+
 int xmon_no_auto_backtrace;
 
 extern int print_insn_powerpc(unsigned long, unsigned long, int);
@@ -209,8 +213,12 @@ Commands:\n\
   mi	show information about memory allocation\n\
   p 	call a procedure\n\
   r	print registers\n\
-  s	single step\n\
-  S	print special registers\n\
+  s	single step\n"
+#ifdef CONFIG_PPC_CELL
+"  ss	stop execution on all spus\n\
+  sr	restore execution on stopped spus\n"
+#endif
+"  S	print special registers\n\
   t	print backtrace\n\
   x	exit monitor and recover\n\
   X	exit monitor and dont recover\n"
@@ -518,6 +526,7 @@ int xmon(struct pt_regs *excp)
 		xmon_save_regs(&regs);
 		excp = &regs;
 	}
+
 	return xmon_core(excp, 0);
 }
 EXPORT_SYMBOL(xmon);
@@ -809,6 +818,8 @@ cmds(struct pt_regs *excp)
 			cacheflush();
 			break;
 		case 's':
+			if (do_spu_cmd() == 0)
+				break;
 			if (do_step(excp))
 				return cmd;
 			break;
@@ -2630,3 +2641,130 @@ void __init xmon_setup(void)
 	if (xmon_early)
 		debugger(NULL);
 }
+
+#ifdef CONFIG_PPC_CELL
+
+struct spu_info {
+	struct spu *spu;
+	u64 saved_mfc_sr1_RW;
+	u32 saved_spu_runcntl_RW;
+	u8 stopped_ok;
+};
+
+#define XMON_NUM_SPUS	16	/* Enough for current hardware */
+
+static struct spu_info spu_info[XMON_NUM_SPUS];
+
+void xmon_register_spus(struct list_head *list)
+{
+	struct spu *spu;
+
+	list_for_each_entry(spu, list, full_list) {
+		if (spu->number >= XMON_NUM_SPUS) {
+			WARN_ON(1);
+			continue;
+		}
+
+		spu_info[spu->number].spu = spu;
+		spu_info[spu->number].stopped_ok = 0;
+	}
+}
+
+static void stop_spus(void)
+{
+	struct spu *spu;
+	int i;
+	u64 tmp;
+
+	for (i = 0; i < XMON_NUM_SPUS; i++) {
+		if (!spu_info[i].spu)
+			continue;
+
+		if (setjmp(bus_error_jmp) == 0) {
+			catch_memory_errors = 1;
+			sync();
+
+			spu = spu_info[i].spu;
+
+			spu_info[i].saved_spu_runcntl_RW =
+				in_be32(&spu->problem->spu_runcntl_RW);
+
+			tmp = spu_mfc_sr1_get(spu);
+			spu_info[i].saved_mfc_sr1_RW = tmp;
+
+			tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+			spu_mfc_sr1_set(spu, tmp);
+
+			sync();
+			__delay(200);
+
+			spu_info[i].stopped_ok = 1;
+			printf("Stopped spu %.2d\n", i);
+		} else {
+			catch_memory_errors = 0;
+			printf("*** Error stopping spu %.2d\n", i);
+		}
+		catch_memory_errors = 0;
+	}
+}
+
+static void restart_spus(void)
+{
+	struct spu *spu;
+	int i;
+
+	for (i = 0; i < XMON_NUM_SPUS; i++) {
+		if (!spu_info[i].spu)
+			continue;
+
+		if (!spu_info[i].stopped_ok) {
+			printf("*** Error, spu %d was not successfully stopped"
+					", not restarting\n", i);
+			continue;
+		}
+
+		if (setjmp(bus_error_jmp) == 0) {
+			catch_memory_errors = 1;
+			sync();
+
+			spu = spu_info[i].spu;
+			spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
+			out_be32(&spu->problem->spu_runcntl_RW,
+					spu_info[i].saved_spu_runcntl_RW);
+
+			sync();
+			__delay(200);
+
+			printf("Restarted spu %.2d\n", i);
+		} else {
+			catch_memory_errors = 0;
+			printf("*** Error restarting spu %.2d\n", i);
+		}
+		catch_memory_errors = 0;
+	}
+}
+
+static int do_spu_cmd(void)
+{
+	int cmd;
+
+	cmd = inchar();
+	switch (cmd) {
+	case 's':
+		stop_spus();
+		break;
+	case 'r':
+		restart_spus();
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+#else /* ! CONFIG_PPC_CELL */
+static int do_spu_cmd(void)
+{
+	return -1;
+}
+#endif
Index: linux-2.6/include/asm-powerpc/xmon.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/xmon.h
+++ linux-2.6/include/asm-powerpc/xmon.h
@@ -14,8 +14,10 @@
 
 #ifdef CONFIG_XMON
 extern void xmon_setup(void);
+extern void xmon_register_spus(struct list_head *list);
 #else
 static inline void xmon_setup(void) { };
+static inline void xmon_register_spus(struct list_head *list) { };
 #endif
 
 #endif /* __KERNEL __ */

--

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

* [PATCH 15/16] add support for dumping spu info from xmon
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (13 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 14/16] add support for stopping spus from xmon arnd
@ 2006-10-24 16:31 ` arnd
  2006-10-24 16:39 ` [PATCH 16/16] cell: add cpufreq driver for Cell BE processor arnd
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann

From: Michael Ellerman <michael@ellerman.id.au>

This patch adds a command to xmon for dumping information about
spu structs. The command is 'sf' for "spu fields" perhaps, and
takes the spu number as an argument. This is the same value as the
spu->number field, or the "phys-id" value of a context when it is
bound to a physical spu.

We try to catch memory errors as we dump each field, hopefully this
will make the command reasonably robust, but YMMV. If people see a
need we can easily add more fields to the dump in future.

Output looks something like this:

0:mon> sf 0
Dumping spu fields at address c00000001ffd9e80:
  number                  = 0x0
  name                    = spe
  devnode->full_name      = /cpus/PowerPC,BE@0/spes/spe@0
  nid                     = 0x0
  local_store_phys        = 0x20000000000
  local_store             = 0xd0000800801e0000
  ls_size                 = 0x0
  isrc                    = 0x4
  node                    = 0x0
  flags                   = 0x0
  dar                     = 0x0
  dsisr                   = 0x0
  class_0_pending         = 0
  irqs[0]                 = 0x16
  irqs[1]                 = 0x17
  irqs[2]                 = 0x24
  slb_replace             = 0x0
  pid                     = 0
  prio                    = 0
  mm                      = 0x0000000000000000
  ctx                     = 0x0000000000000000
  rq                      = 0x0000000000000000
  timestamp               = 0x0000000000000000
  problem_phys            = 0x20000040000
  problem                 = 0xd000080080220000
  problem->spu_runcntl_RW = 0x0
  problem->spu_status_R   = 0x0
  problem->spu_npc_RW     = 0x0
  priv1                   = 0xd000080080240000
  priv1->mfc_sr1_RW       = 0x33
  priv2                   = 0xd000080080250000


Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---

 arch/powerpc/xmon/xmon.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

Index: linux-2.6/arch/powerpc/xmon/xmon.c
===================================================================
--- linux-2.6.orig/arch/powerpc/xmon/xmon.c
+++ linux-2.6/arch/powerpc/xmon/xmon.c
@@ -216,7 +216,8 @@ Commands:\n\
   s	single step\n"
 #ifdef CONFIG_PPC_CELL
 "  ss	stop execution on all spus\n\
-  sr	restore execution on stopped spus\n"
+  sr	restore execution on stopped spus\n\
+  sf #	dump spu fields for spu # (in hex)\n"
 #endif
 "  S	print special registers\n\
   t	print backtrace\n\
@@ -2744,8 +2745,66 @@ static void restart_spus(void)
 	}
 }
 
+#define DUMP_WIDTH	23
+#define DUMP_FIELD(obj, format, field)					\
+do {									\
+	if (setjmp(bus_error_jmp) == 0) {				\
+		catch_memory_errors = 1;				\
+		sync();							\
+		printf("  %-*s = "format"\n", DUMP_WIDTH,		\
+				#field, obj->field);			\
+		sync();							\
+		__delay(200);						\
+	} else {							\
+		catch_memory_errors = 0;				\
+		printf("  %-*s = *** Error reading field.\n",		\
+					DUMP_WIDTH, #field);		\
+	}								\
+	catch_memory_errors = 0;					\
+} while (0)
+
+static void dump_spu_fields(struct spu *spu)
+{
+	printf("Dumping spu fields at address %p:\n", spu);
+
+	DUMP_FIELD(spu, "0x%x", number);
+	DUMP_FIELD(spu, "%s", name);
+	DUMP_FIELD(spu, "%s", devnode->full_name);
+	DUMP_FIELD(spu, "0x%x", nid);
+	DUMP_FIELD(spu, "0x%lx", local_store_phys);
+	DUMP_FIELD(spu, "0x%p", local_store);
+	DUMP_FIELD(spu, "0x%lx", ls_size);
+	DUMP_FIELD(spu, "0x%x", node);
+	DUMP_FIELD(spu, "0x%lx", flags);
+	DUMP_FIELD(spu, "0x%lx", dar);
+	DUMP_FIELD(spu, "0x%lx", dsisr);
+	DUMP_FIELD(spu, "%d", class_0_pending);
+	DUMP_FIELD(spu, "0x%lx", irqs[0]);
+	DUMP_FIELD(spu, "0x%lx", irqs[1]);
+	DUMP_FIELD(spu, "0x%lx", irqs[2]);
+	DUMP_FIELD(spu, "0x%x", slb_replace);
+	DUMP_FIELD(spu, "%d", pid);
+	DUMP_FIELD(spu, "%d", prio);
+	DUMP_FIELD(spu, "0x%p", mm);
+	DUMP_FIELD(spu, "0x%p", ctx);
+	DUMP_FIELD(spu, "0x%p", rq);
+	DUMP_FIELD(spu, "0x%p", timestamp);
+	DUMP_FIELD(spu, "0x%lx", problem_phys);
+	DUMP_FIELD(spu, "0x%p", problem);
+	DUMP_FIELD(spu, "0x%x", problem->spu_runcntl_RW);
+	DUMP_FIELD(spu, "0x%x", problem->spu_status_R);
+	DUMP_FIELD(spu, "0x%x", problem->spu_npc_RW);
+	DUMP_FIELD(spu, "0x%p", priv1);
+
+	if (spu->priv1)
+		DUMP_FIELD(spu, "0x%lx", priv1->mfc_sr1_RW);
+
+	DUMP_FIELD(spu, "0x%p", priv2);
+}
+
 static int do_spu_cmd(void)
 {
+	unsigned long num = 0;
 	int cmd;
 
 	cmd = inchar();
@@ -2756,6 +2815,12 @@ static int do_spu_cmd(void)
 	case 'r':
 		restart_spus();
 		break;
+	case 'f':
+		if (scanhex(&num) && num < XMON_NUM_SPUS && spu_info[num].spu)
+			dump_spu_fields(spu_info[num].spu);
+		else
+			printf("*** Error: invalid spu number\n");
+		break;
 	default:
 		return -1;
 	}

--

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

* [PATCH 16/16] cell: add cpufreq driver for Cell BE processor
  2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
                   ` (14 preceding siblings ...)
  2006-10-24 16:31 ` [PATCH 15/16] add support for dumping spu info " arnd
@ 2006-10-24 16:39 ` arnd
  15 siblings, 0 replies; 23+ messages in thread
From: arnd @ 2006-10-24 16:39 UTC (permalink / raw)
  To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
  Cc: Christian Krafft, Arnd Bergmann

From: Christian Krafft <krafft@de.ibm.com>

This patch adds a cpufreq backend driver to enable frequency scaling on cell.

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

Index: linux-2.6/arch/powerpc/platforms/cell/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Kconfig
+++ linux-2.6/arch/powerpc/platforms/cell/Kconfig
@@ -25,4 +25,13 @@ config CBE_THERM
 	default m
 	depends on CBE_RAS
 
+config CBE_CPUFREQ
+	tristate "CBE frequency scaling"
+	depends on CBE_RAS && CPU_FREQ
+	default m
+	help
+	  This adds the cpufreq driver for Cell BE processors.
+	  For details, take a look at <file:Documentation/cpu-freq/>.
+	  If you don't have such processor, say N
+
 endmenu
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
@@ -4,6 +4,7 @@ obj-$(CONFIG_PPC_CELL_NATIVE)		+= interr
 obj-$(CONFIG_CBE_RAS)			+= ras.o
 
 obj-$(CONFIG_CBE_THERM)			+= cbe_thermal.o
+obj-$(CONFIG_CBE_CPUFREQ)		+= cbe_cpufreq.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_CELL_NATIVE)		+= smp.o
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_cpufreq.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -0,0 +1,248 @@
+/*
+ * cpufreq driver for the cell processor
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Christian Krafft <krafft@de.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/cpufreq.h>
+#include <linux/timer.h>
+
+#include <asm/hw_irq.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+
+#include "cbe_regs.h"
+
+static DEFINE_MUTEX(cbe_switch_mutex);
+
+
+/* the CBE supports an 8 step frequency scaling */
+static struct cpufreq_frequency_table cbe_freqs[] = {
+	{1,	0},
+	{2,	0},
+	{3,	0},
+	{4,	0},
+	{5,	0},
+	{6,	0},
+	{8,	0},
+	{10,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+/* to write to MIC register */
+static u64 MIC_Slow_Fast_Timer_table[] = {
+	[0 ... 7] = 0x007fc00000000000ull,
+};
+
+/* more values for the MIC */
+static u64 MIC_Slow_Next_Timer_table[] = {
+	0x0000240000000000ull,
+	0x0000268000000000ull,
+	0x000029C000000000ull,
+	0x00002D0000000000ull,
+	0x0000300000000000ull,
+	0x0000334000000000ull,
+	0x000039C000000000ull,
+	0x00003FC000000000ull,
+};
+
+/*
+ * hardware specific functions
+ */
+
+static int get_pmode(int cpu)
+{
+	int ret;
+	struct cbe_pmd_regs __iomem *pmd_regs;
+
+	pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+	ret = in_be64(&pmd_regs->pmsr) & 0x07;
+
+	return ret;
+}
+
+static int set_pmode(int cpu, unsigned int pmode)
+{
+	struct cbe_pmd_regs __iomem *pmd_regs;
+	struct cbe_mic_tm_regs __iomem *mic_tm_regs;
+	u64 flags;
+	u64 value;
+
+	local_irq_save(flags);
+
+	mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
+	pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+
+	pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr);
+	pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0);
+
+	out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
+	out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
+
+	out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
+	out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
+
+	value = in_be64(&pmd_regs->pmcr);
+	/* set bits to zero */
+	value &= 0xFFFFFFFFFFFFFFF8ull;
+	/* set bits to next pmode */
+	value |= pmode;
+
+	out_be64(&pmd_regs->pmcr, value);
+
+	/* wait until new pmode appears in status register */
+	value = in_be64(&pmd_regs->pmsr) & 0x07;
+	while(value != pmode) {
+		cpu_relax();
+		value = in_be64(&pmd_regs->pmsr) & 0x07;
+	}
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+/*
+ * cpufreq functions
+ */
+
+static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
+{
+	u32 *max_freq;
+	int i, cur_pmode;
+	struct device_node *cpu;
+
+	cpu = of_get_cpu_node(policy->cpu, NULL);
+
+	if(!cpu)
+		return -ENODEV;
+
+	pr_debug("init cpufreq on CPU %d\n", policy->cpu);
+
+	max_freq = (u32*) get_property(cpu, "clock-frequency", NULL);
+
+	if(!max_freq)
+		return -EINVAL;
+
+	// we need the freq in kHz
+	*max_freq /= 1000;
+
+	pr_debug("max clock-frequency is at %u kHz\n", *max_freq);
+	pr_debug("initializing frequency table\n");
+
+	// initialize frequency table
+	for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
+		cbe_freqs[i].frequency = *max_freq / cbe_freqs[i].index;
+		pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
+	}
+
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	/* if DEBUG is enabled set_pmode() measures the correct latency of a transition */
+	policy->cpuinfo.transition_latency = 25000;
+
+	cur_pmode = get_pmode(policy->cpu);
+	pr_debug("current pmode is at %d\n",cur_pmode);
+
+	policy->cur = cbe_freqs[cur_pmode].frequency;
+
+#ifdef CONFIG_SMP
+	policy->cpus = cpu_sibling_map[policy->cpu];
+#endif
+
+	cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu);
+
+	/* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
+	return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs);
+}
+
+static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, cbe_freqs);
+}
+
+
+static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq,
+			    unsigned int relation)
+{
+	int rc;
+	struct cpufreq_freqs freqs;
+	int cbe_pmode_new;
+
+	cpufreq_frequency_table_target(policy,
+				       cbe_freqs,
+				       target_freq,
+				       relation,
+				       &cbe_pmode_new);
+
+	freqs.old = policy->cur;
+	freqs.new = cbe_freqs[cbe_pmode_new].frequency;
+	freqs.cpu = policy->cpu;
+
+	mutex_lock (&cbe_switch_mutex);
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+		 policy->cpu,
+		 cbe_freqs[cbe_pmode_new].frequency,
+		 cbe_freqs[cbe_pmode_new].index);
+
+	rc = set_pmode(policy->cpu, cbe_pmode_new);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	mutex_unlock(&cbe_switch_mutex);
+
+	return rc;
+}
+
+static struct cpufreq_driver cbe_cpufreq_driver = {
+	.verify		= cbe_cpufreq_verify,
+	.target		= cbe_cpufreq_target,
+	.init		= cbe_cpufreq_cpu_init,
+	.exit		= cbe_cpufreq_cpu_exit,
+	.name		= "cbe-cpufreq",
+	.owner		= THIS_MODULE,
+	.flags		= CPUFREQ_CONST_LOOPS,
+};
+
+/*
+ * module init and destoy
+ */
+
+static int __init cbe_cpufreq_init(void)
+{
+	return cpufreq_register_driver(&cbe_cpufreq_driver);
+}
+
+static void __exit cbe_cpufreq_exit(void)
+{
+	cpufreq_unregister_driver(&cbe_cpufreq_driver);
+}
+
+module_init(cbe_cpufreq_init);
+module_exit(cbe_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Krafft <krafft@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
@@ -139,7 +139,19 @@ CONFIG_RTAS_FLASH=y
 CONFIG_MMIO_NVRAM=y
 # CONFIG_PPC_MPC106 is not set
 # CONFIG_PPC_970_NAP is not set
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_DEBUG=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+# CONFIG_CPU_FREQ_PMAC64 is not set
 # CONFIG_WANT_EARLY_SERIAL is not set
 # CONFIG_MPIC is not set
 
@@ -150,6 +162,7 @@ CONFIG_SPU_FS=m
 CONFIG_SPU_BASE=y
 CONFIG_CBE_RAS=y
 CONFIG_CBE_THERM=m
+CONFIG_CBE_CPUFREQ=m
 
 #
 # Kernel options
Index: linux-2.6/arch/powerpc/kernel/prom.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/prom.c
+++ linux-2.6/arch/powerpc/kernel/prom.c
@@ -1672,6 +1672,7 @@ struct device_node *of_get_cpu_node(int 
 	}
 	return NULL;
 }
+EXPORT_SYMBOL(of_get_cpu_node);
 
 #ifdef DEBUG
 static struct debugfs_blob_wrapper flat_dt_blob;
Index: linux-2.6/arch/powerpc/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/smp.c
+++ linux-2.6/arch/powerpc/kernel/smp.c
@@ -65,6 +65,7 @@ cpumask_t cpu_sibling_map[NR_CPUS] = { [
 
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(cpu_possible_map);
+EXPORT_SYMBOL(cpu_sibling_map);
 
 /* SMP operations for this machine */
 struct smp_ops_t *smp_ops;

--

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

* Re: [PATCH 11/16] sysfs: add support for adding/removing spu sysfs attributes
  2006-10-24 16:31 ` [PATCH 11/16] sysfs: add support for adding/removing spu sysfs attributes arnd
@ 2006-10-25  7:52   ` Heiko Carstens
  2006-10-25 12:27     ` Arnd Bergmann
  0 siblings, 1 reply; 23+ messages in thread
From: Heiko Carstens @ 2006-10-25  7:52 UTC (permalink / raw)
  To: arnd; +Cc: linuxppc-dev, paulus, cbe-oss-dev, linux-kernel

> +int cpu_add_sysdev_attr(struct sysdev_attribute *attr)
> +{
> +	int cpu;
> +
> +	mutex_lock(&cpu_mutex);
> +
> +	for_each_possible_cpu(cpu) {
> +		sysdev_create_file(get_cpu_sysdev(cpu), attr);
> +	}
> +
> +	mutex_unlock(&cpu_mutex);
> +	return 0;
> +}

You probably should check for errors on sysdev_create_file, clean up and
return an error number instead of always 0.
This is true for all the new functions here.

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

* Re: [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries
  2006-10-24 16:31 ` [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries arnd
@ 2006-10-25  8:00   ` Heiko Carstens
  2006-10-25 23:19     ` [Cbe-oss-dev] " Benjamin Herrenschmidt
  0 siblings, 1 reply; 23+ messages in thread
From: Heiko Carstens @ 2006-10-25  8:00 UTC (permalink / raw)
  To: arnd
  Cc: Arnd Bergmann, linux-kernel, linuxppc-dev, paulus,
	Christian Krafft, cbe-oss-dev

On Tue, Oct 24, 2006 at 06:31:25PM +0200, arnd@arndb.de wrote:

> + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005

IBM Corp. instead of IBM DE? 2006?

> +static int __init thermal_init(void)
> +{
> +	init_default_values();
> +
> +	spu_add_sysdev_attr_group(&spu_attribute_group);
> +	cpu_add_sysdev_attr_group(&ppe_attribute_group);
> +
> +	return 0;
> +}

Same here: check for errors on spu_add_sysdev_attr_group and
cpu_add_sysdev_attr_group.

> +static void __exit thermal_exit(void)
> +{
> +	spu_remove_sysdev_attr_group(&spu_attribute_group);
> +	cpu_remove_sysdev_attr_group(&ppe_attribute_group);

Will crash if cpu_add_sysdev_attr_group failed...

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

* Re: [PATCH 11/16] sysfs: add support for adding/removing spu sysfs attributes
  2006-10-25  7:52   ` Heiko Carstens
@ 2006-10-25 12:27     ` Arnd Bergmann
  0 siblings, 0 replies; 23+ messages in thread
From: Arnd Bergmann @ 2006-10-25 12:27 UTC (permalink / raw)
  To: Heiko Carstens
  Cc: linuxppc-dev, paulus, cbe-oss-dev, Christian Krafft, linux-kernel

On Wednesday 25 October 2006 09:52, Heiko Carstens wrote:
> You probably should check for errors on sysdev_create_file, clean up and
> return an error number instead of always 0.
> This is true for all the new functions here.

Right, thanks for the review.

Christian or I will take care of this.

	Arnd <><

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

* Re: [Cbe-oss-dev] [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries
  2006-10-25  8:00   ` Heiko Carstens
@ 2006-10-25 23:19     ` Benjamin Herrenschmidt
  2006-10-26  7:35       ` Arnd Bergmann
  0 siblings, 1 reply; 23+ messages in thread
From: Benjamin Herrenschmidt @ 2006-10-25 23:19 UTC (permalink / raw)
  To: Heiko Carstens
  Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann, arnd, linux-kernel

On Wed, 2006-10-25 at 10:00 +0200, Heiko Carstens wrote:
> On Tue, Oct 24, 2006 at 06:31:25PM +0200, arnd@arndb.de wrote:
> 
> > + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
> 
> IBM Corp. instead of IBM DE? 2006?
> 
> > +static int __init thermal_init(void)
> > +{
> > +	init_default_values();
> > +
> > +	spu_add_sysdev_attr_group(&spu_attribute_group);
> > +	cpu_add_sysdev_attr_group(&ppe_attribute_group);
> > +
> > +	return 0;
> > +}
> 
> Same here: check for errors on spu_add_sysdev_attr_group and
> cpu_add_sysdev_attr_group.
> 
> > +static void __exit thermal_exit(void)
> > +{
> > +	spu_remove_sysdev_attr_group(&spu_attribute_group);
> > +	cpu_remove_sysdev_attr_group(&ppe_attribute_group);
> 
> Will crash if cpu_add_sysdev_attr_group failed...


Which is a total PITA. If this is the case, then we should modify the
add calls to at least initialize enough fields before they can fail for
the remove calls not to crash. You don't want to keep track precisely of
what file was added and what not and test all of that in your exit code
path, it's just insane.

Ben.

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

* Re: [Cbe-oss-dev] [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries
  2006-10-25 23:19     ` [Cbe-oss-dev] " Benjamin Herrenschmidt
@ 2006-10-26  7:35       ` Arnd Bergmann
  2006-10-26  9:19         ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 23+ messages in thread
From: Arnd Bergmann @ 2006-10-26  7:35 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Andrew Morton, linuxppc-dev, Heiko Carstens, linux-kernel,
	cbe-oss-dev

On Thursday 26 October 2006 01:19, Benjamin Herrenschmidt wrote:
> > 
> > Will crash if cpu_add_sysdev_attr_group failed...
> 
> 
> Which is a total PITA. If this is the case, then we should modify the
> add calls to at least initialize enough fields before they can fail for
> the remove calls not to crash. You don't want to keep track precisely of
> what file was added and what not and test all of that in your exit code
> path, it's just insane.

Heiko suggested that earlied in http://lkml.org/lkml/2006/10/9/22,
but Andrew didn't like it.

Currently, the worst is that sysfs_remove_file can be used
on a nonexisting file,  but sysfs_remove_group cannot, which is
inconsistent. Either sysfs_remove_file should WARN_ON or
sysfs_remove_group should silently return, and I'd prefer the
latter, as it makes users simpler.

	Arnd <><

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

* Re: [Cbe-oss-dev] [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries
  2006-10-26  7:35       ` Arnd Bergmann
@ 2006-10-26  9:19         ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 23+ messages in thread
From: Benjamin Herrenschmidt @ 2006-10-26  9:19 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andrew Morton, linuxppc-dev, Heiko Carstens, linux-kernel,
	cbe-oss-dev

On Thu, 2006-10-26 at 09:35 +0200, Arnd Bergmann wrote:
> On Thursday 26 October 2006 01:19, Benjamin Herrenschmidt wrote:
> > > 
> > > Will crash if cpu_add_sysdev_attr_group failed...
> > 
> > 
> > Which is a total PITA. If this is the case, then we should modify the
> > add calls to at least initialize enough fields before they can fail for
> > the remove calls not to crash. You don't want to keep track precisely of
> > what file was added and what not and test all of that in your exit code
> > path, it's just insane.
> 
> Heiko suggested that earlied in http://lkml.org/lkml/2006/10/9/22,
> but Andrew didn't like it.
> 
> Currently, the worst is that sysfs_remove_file can be used
> on a nonexisting file,  but sysfs_remove_group cannot, which is
> inconsistent. Either sysfs_remove_file should WARN_ON or
> sysfs_remove_group should silently return, and I'd prefer the
> latter, as it makes users simpler.

We need to argue with Andrew then. I'll have a go tomorrow

Ben.

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

end of thread, other threads:[~2006-10-26  9:19 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-24 16:31 [PATCH 00/16] cell patches for 2.6.20 arnd
2006-10-24 16:31 ` [PATCH 01/16] spufs: wrap mfc sdr access arnd
2006-10-24 16:31 ` [PATCH 02/16] cell: remove unused struct spu variable arnd
2006-10-24 16:31 ` [PATCH 03/16] spufs: add support for nonschedulable contexts arnd
2006-10-24 16:31 ` [PATCH 04/16] spufs: "stataus" isnt a word arnd
2006-10-24 16:31 ` [PATCH 05/16] spufs: allow isolated mode apps by starting the SPE loader arnd
2006-10-24 16:31 ` [PATCH 06/16] spufs: Add isolated-mode SPE recycling support arnd
2006-10-24 16:31 ` [PATCH 07/16] cell: update cell be register definitions arnd
2006-10-24 16:31 ` [PATCH 08/16] cell: add shadow registers for pmd_reg arnd
2006-10-24 16:31 ` [PATCH 09/16] cell: add low-level performance monitoring code arnd
2006-10-24 16:31 ` [PATCH 10/16] cell: add support for registering sysfs attributes to spus arnd
2006-10-24 16:31 ` [PATCH 11/16] sysfs: add support for adding/removing spu sysfs attributes arnd
2006-10-25  7:52   ` Heiko Carstens
2006-10-25 12:27     ` Arnd Bergmann
2006-10-24 16:31 ` [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries arnd
2006-10-25  8:00   ` Heiko Carstens
2006-10-25 23:19     ` [Cbe-oss-dev] " Benjamin Herrenschmidt
2006-10-26  7:35       ` Arnd Bergmann
2006-10-26  9:19         ` Benjamin Herrenschmidt
2006-10-24 16:31 ` [PATCH 13/16] cell: use ppc_md->power_save instead of cbe_idle_loop arnd
2006-10-24 16:31 ` [PATCH 14/16] add support for stopping spus from xmon arnd
2006-10-24 16:31 ` [PATCH 15/16] add support for dumping spu info " arnd
2006-10-24 16:39 ` [PATCH 16/16] cell: add cpufreq driver for Cell BE processor arnd

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).