[Cbe-oss-dev] [PATCH 02/02][RFC] spufs: try to work without master run bit

Masato Noguchi Masato.Noguchi at jp.sony.com
Mon Feb 5 20:47:42 EST 2007


 [ note: This patch is a hot-fix and RFC. ]

Current kernel uses the master run control bit (MFC_SR1[S]) to
control SPE execution in spufs_run_spu(). PS3 hypervisor does not
permit to change this bit.
This cause Oops that Gerhard pointed out before.

I know, oldtime kernel used run control register in priv2, and
it was replaced by master run bit to avoid vulnerability.
But, for now, I made a patch closing my eyes to it.
I want to fix it witout using master run bit, if possible.
Does anyone have comments?


BTW, in current implementation, if spe was running at disabled
by master run, it seems to be failed at next spu_run syscall.
Is it correct?


Signed-off-by: Masato Noguchi <Masato.Noguchi at jp.sony.com>
---
 arch/powerpc/platforms/cell/spu_base.c          |    1 +
 arch/powerpc/platforms/cell/spu_priv1_mmio.c    |   15 +++++++++++++++
 arch/powerpc/platforms/cell/spufs/backing_ops.c |    6 ++++++
 arch/powerpc/platforms/cell/spufs/hw_ops.c      |   10 ++++++++++
 arch/powerpc/platforms/cell/spufs/run.c         |    4 ++--
 arch/powerpc/platforms/cell/spufs/spufs.h       |    1 +
 arch/powerpc/platforms/ps3/spu.c                |   14 ++++++++++++++
 include/asm-powerpc/spu_priv1.h                 |   14 ++++++++++++++
 8 files changed, 63 insertions(+), 2 deletions(-)

Index: ps3-linux/arch/powerpc/platforms/cell/spu_priv1_mmio.c
===================================================================
--- ps3-linux.orig/arch/powerpc/platforms/cell/spu_priv1_mmio.c
+++ ps3-linux/arch/powerpc/platforms/cell/spu_priv1_mmio.c
@@ -34,6 +34,7 @@
 #include <asm/firmware.h>
 #include <asm/prom.h>
 
+#include "spufs/spufs.h"
 #include "interrupt.h"
 #include "spu_priv1_mmio.h"
 
@@ -405,10 +406,24 @@ static int of_destroy_spu(struct spu *sp
 	return 0;
 }
 
+static int enable_spu_by_master_run(struct spu_context *ctx)
+{
+	ctx->ops->master_start(ctx);
+	return 0;
+}
+
+static int disable_spu_by_master_run(struct spu_context *ctx)
+{
+	ctx->ops->master_stop(ctx);
+	return 0;
+}
+
 const struct spu_management_ops spu_management_of_ops = {
 	.enumerate_spus = of_enumerate_spus,
 	.create_spu = of_create_spu,
 	.destroy_spu = of_destroy_spu,
+	.enable_spu = enable_spu_by_master_run,
+	.disable_spu = disable_spu_by_master_run,
 };
 
 static void int_mask_and(struct spu *spu, int class, u64 mask)
Index: ps3-linux/arch/powerpc/platforms/cell/spufs/backing_ops.c
===================================================================
--- ps3-linux.orig/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ ps3-linux/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -285,6 +285,11 @@ static void spu_backing_runcntl_write(st
 	spin_unlock(&ctx->csa.register_lock);
 }
 
+static void spu_backing_runcntl_stop(struct spu_context *ctx)
+{
+	spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
+}
+
 static void spu_backing_master_start(struct spu_context *ctx)
 {
 	struct spu_state *csa = &ctx->csa;
@@ -370,6 +375,7 @@ struct spu_context_ops spu_backing_ops =
 	.get_ls = spu_backing_get_ls,
 	.runcntl_read = spu_backing_runcntl_read,
 	.runcntl_write = spu_backing_runcntl_write,
+	.runcntl_stop = spu_backing_runcntl_stop,
 	.master_start = spu_backing_master_start,
 	.master_stop = spu_backing_master_stop,
 	.set_mfc_query = spu_backing_set_mfc_query,
Index: ps3-linux/arch/powerpc/platforms/cell/spufs/hw_ops.c
===================================================================
--- ps3-linux.orig/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ ps3-linux/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -221,6 +221,15 @@ static void spu_hw_runcntl_write(struct 
 	spin_unlock_irq(&ctx->spu->register_lock);
 }
 
+static void spu_hw_runcntl_stop(struct spu_context *ctx)
+{
+	spin_lock_irq(&ctx->spu->register_lock);
+	out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+	while(in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
+		cpu_relax();
+	spin_unlock_irq(&ctx->spu->register_lock);
+}
+
 static void spu_hw_master_start(struct spu_context *ctx)
 {
 	struct spu *spu = ctx->spu;
@@ -314,6 +323,7 @@ struct spu_context_ops spu_hw_ops = {
 	.get_ls = spu_hw_get_ls,
 	.runcntl_read = spu_hw_runcntl_read,
 	.runcntl_write = spu_hw_runcntl_write,
+	.runcntl_stop = spu_hw_runcntl_stop,
 	.master_start = spu_hw_master_start,
 	.master_stop = spu_hw_master_stop,
 	.set_mfc_query = spu_hw_set_mfc_query,
Index: ps3-linux/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- ps3-linux.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ ps3-linux/arch/powerpc/platforms/cell/spufs/run.c
@@ -310,7 +310,7 @@ long spufs_run_spu(struct file *file, st
 	if (down_interruptible(&ctx->run_sema))
 		return -ERESTARTSYS;
 
-	ctx->ops->master_start(ctx);
+	spu_enable_spu(ctx);
 	ctx->event_return = 0;
 	ret = spu_run_init(ctx, npc);
 	if (ret)
@@ -338,7 +338,7 @@ long spufs_run_spu(struct file *file, st
 	} while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
 				      SPU_STATUS_STOPPED_BY_HALT)));
 
-	ctx->ops->master_stop(ctx);
+	spu_disable_spu(ctx);
 	ret = spu_run_fini(ctx, npc, &status);
 	spu_yield(ctx);
 
Index: ps3-linux/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- ps3-linux.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ ps3-linux/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -117,6 +117,7 @@ struct spu_context_ops {
 	char*(*get_ls) (struct spu_context * ctx);
 	 u32 (*runcntl_read) (struct spu_context * ctx);
 	void (*runcntl_write) (struct spu_context * ctx, u32 data);
+	void (*runcntl_stop) (struct spu_context * ctx);
 	void (*master_start) (struct spu_context * ctx);
 	void (*master_stop) (struct spu_context * ctx);
 	int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode);
Index: ps3-linux/arch/powerpc/platforms/ps3/spu.c
===================================================================
--- ps3-linux.orig/arch/powerpc/platforms/ps3/spu.c
+++ ps3-linux/arch/powerpc/platforms/ps3/spu.c
@@ -28,6 +28,7 @@
 #include <asm/spu_priv1.h>
 #include <asm/lv1call.h>
 
+#include "../cell/spufs/spufs.h"
 #include "platform.h"
 
 /* spu_management_ops */
@@ -447,10 +448,23 @@ static int __init ps3_enumerate_spus(int
 	return num_resource_id;
 }
 
+static int ps3_enable_spu(struct spu_context *ctx)
+{
+	return -ENOSYS;
+}
+
+static int ps3_disable_spu(struct spu_context *ctx)
+{
+	ctx->ops->runcntl_stop(ctx);
+	return -ENOSYS;
+}
+
 const struct spu_management_ops spu_management_ps3_ops = {
 	.enumerate_spus = ps3_enumerate_spus,
 	.create_spu = ps3_create_spu,
 	.destroy_spu = ps3_destroy_spu,
+	.enable_spu = ps3_enable_spu,
+	.disable_spu = ps3_disable_spu,
 };
 
 /* spu_priv1_ops */
Index: ps3-linux/include/asm-powerpc/spu_priv1.h
===================================================================
--- ps3-linux.orig/include/asm-powerpc/spu_priv1.h
+++ ps3-linux/include/asm-powerpc/spu_priv1.h
@@ -178,6 +178,8 @@ struct spu_management_ops {
 	int (*enumerate_spus)(int (*fn)(void *data));
 	int (*create_spu)(struct spu *spu, void *data);
 	int (*destroy_spu)(struct spu *spu);
+	int (*enable_spu)(struct spu_context *ctx);
+	int (*disable_spu)(struct spu_context *ctx);
 };
 
 extern const struct spu_management_ops* spu_management_ops;
@@ -200,6 +202,18 @@ spu_destroy_spu (struct spu *spu)
 	return spu_management_ops->destroy_spu(spu);
 }
 
+static inline int
+spu_enable_spu (struct spu_context *ctx)
+{
+	return spu_management_ops->enable_spu(ctx);
+}
+
+static inline int
+spu_disable_spu (struct spu_context *ctx)
+{
+	return spu_management_ops->disable_spu(ctx);
+}
+
 /*
  * The declarations folowing are put here for convenience
  * and only intended to be used by the platform setup code.
Index: ps3-linux/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- ps3-linux.orig/arch/powerpc/platforms/cell/spu_base.c
+++ ps3-linux/arch/powerpc/platforms/cell/spu_base.c
@@ -40,6 +40,7 @@ const struct spu_management_ops *spu_man
 const struct spu_priv1_ops *spu_priv1_ops;
 
 EXPORT_SYMBOL_GPL(spu_priv1_ops);
+EXPORT_SYMBOL_GPL(spu_management_ops);
 
 static int __spu_trap_invalid_dma(struct spu *spu)
 {




More information about the cbe-oss-dev mailing list