public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/13] spufs fixes and cleanups
@ 2006-01-04 19:31 Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 01/13] spufs: fix locking in spu_acquire_runnable Arnd Bergmann
                   ` (12 more replies)
  0 siblings, 13 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter

In a review almost a month ago, Al Viro found numerous
problems in the current spufs code. I now finally found
some time to go through those and attempt to fix them.

There are also a few other changes in this series that
should also help, in particular improved interrupt
sending and an abstraction for priviledged register
access (as suggested by  Masato Noguchi and Geoff Levand).

Please apply to powerpc.git before sending spufs upstream.

Al, could you have a look over this to see if it addresses
all the concerns you had and if I broke it in new ways?

	Arnd <><

 arch/powerpc/platforms/cell/Makefile         |    5
 arch/powerpc/platforms/cell/interrupt.c      |   42 ++--
 arch/powerpc/platforms/cell/interrupt.h      |    1
 arch/powerpc/platforms/cell/spu_base.c       |   67 +++----
 arch/powerpc/platforms/cell/spu_priv1.c      |  133 ++++++++++++++
 arch/powerpc/platforms/cell/spufs/Makefile   |    2
 arch/powerpc/platforms/cell/spufs/file.c     |  167 +----------------
 arch/powerpc/platforms/cell/spufs/hw_ops.c   |   19 --
 arch/powerpc/platforms/cell/spufs/inode.c    |  156 ++++++++-------
 arch/powerpc/platforms/cell/spufs/run.c      |  131 ++++++++++++++
 arch/powerpc/platforms/cell/spufs/sched.c    |   13 +
 arch/powerpc/platforms/cell/spufs/spufs.h    |   35 +++
 arch/powerpc/platforms/cell/spufs/switch.c   |  139 +++++----------
 arch/powerpc/platforms/cell/spufs/syscalls.c |    5
 arch/powerpc/platforms/cell/spufs/context.c  |   11 -
 include/asm-powerpc/spu.h                    |   42 +++-
  20 files changed, 565 insertions(+), 407 deletions(-)



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

* [PATCH 01/13] spufs: fix locking in spu_acquire_runnable
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 02/13] spufs: dont hold root->isem in spu_forget Arnd Bergmann
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-lock.diff --]
[-- Type: text/plain, Size: 1195 bytes --]

We need to check for validity of owner under down_write,
down_read is not enough.

Noticed by Al Viro.

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

Index: linux-cg/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
--- linux-cg.orig/arch/powerpc/platforms/cell/spufs/context.c	2005-12-22 12:10:15.000000000 +0000
+++ linux-cg/arch/powerpc/platforms/cell/spufs/context.c	2005-12-22 12:10:20.000000000 +0000
@@ -120,27 +120,29 @@
 		ctx->spu->prio = current->prio;
 		return 0;
 	}
+	up_read(&ctx->state_sema);
+
+	down_write(&ctx->state_sema);
 	/* ctx is about to be freed, can't acquire any more */
 	if (!ctx->owner) {
 		ret = -EINVAL;
 		goto out;
 	}
-	up_read(&ctx->state_sema);
 
-	down_write(&ctx->state_sema);
 	if (ctx->state == SPU_STATE_SAVED) {
 		ret = spu_activate(ctx, 0);
 		ctx->state = SPU_STATE_RUNNABLE;
 	}
-	downgrade_write(&ctx->state_sema);
 	if (ret)
 		goto out;
 
+	downgrade_write(&ctx->state_sema);
 	/* On success, we return holding the lock */
+
 	return ret;
 out:
 	/* Release here, to simplify calling code. */
-	up_read(&ctx->state_sema);
+	up_write(&ctx->state_sema);
 
 	return ret;
 }

--


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

* [PATCH 02/13] spufs: dont hold root->isem in spu_forget
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 01/13] spufs: fix locking in spu_acquire_runnable Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 03/13] spufs: check for proper file pointer in sys_spu_run Arnd Bergmann
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-final-iput.diff --]
[-- Type: text/plain, Size: 1692 bytes --]

spu_forget will do mmput on the DMA address space,
which can lead to lots of other stuff getting triggered.
We better not hold a semaphore here that we might
need in the process.

Noticed by Al Viro.

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

Index: linux-cg/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-cg.orig/arch/powerpc/platforms/cell/spufs/inode.c	2005-12-22 12:26:03.000000000 +0000
+++ linux-cg/arch/powerpc/platforms/cell/spufs/inode.c	2005-12-22 13:25:19.000000000 +0000
@@ -162,10 +162,10 @@
 {
 	struct dentry *dentry, *tmp;
 	struct spu_context *ctx;
-	int err;
 
 	/* remove all entries */
-	err = 0;
+	down(&root->i_sem);
+	down(&dir_dentry->d_inode->i_sem);
 	list_for_each_entry_safe(dentry, tmp, &dir_dentry->d_subdirs, d_child) {
 		spin_lock(&dcache_lock);
 		spin_lock(&dentry->d_lock);
@@ -181,16 +181,16 @@
 			spin_unlock(&dcache_lock);
 		}
 	}
+	shrink_dcache_parent(dir_dentry);
+	up(&dir_dentry->d_inode->i_sem);
+	up(&root->i_sem);
 
 	/* We have to give up the mm_struct */
 	ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx;
 	spu_forget(ctx);
 
-	if (!err) {
-		shrink_dcache_parent(dir_dentry);
-		err = simple_rmdir(root, dir_dentry);
-	}
-	return err;
+	/* XXX Do we need to hold i_sem here ? */
+	return simple_rmdir(root, dir_dentry);
 }
 
 static int spufs_dir_close(struct inode *inode, struct file *file)
@@ -201,10 +201,10 @@
 
 	dentry = file->f_dentry;
 	dir = dentry->d_parent->d_inode;
-	down(&dir->i_sem);
-	ret = spufs_rmdir(dir, file->f_dentry);
+
+	ret = spufs_rmdir(dir, dentry);
 	WARN_ON(ret);
-	up(&dir->i_sem);
+
 	return dcache_dir_close(inode, file);
 }
 

--


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

* [PATCH 03/13] spufs: check for proper file pointer in sys_spu_run
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 01/13] spufs: fix locking in spu_acquire_runnable Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 02/13] spufs: dont hold root->isem in spu_forget Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 04/13] spufs: serialize sys_spu_run per spu Arnd Bergmann
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-run-check-fd.diff --]
[-- Type: text/plain, Size: 2349 bytes --]

Only checking for SPUFS_MAGIC is not reliable, because
it might not be unique in theory. Worse than that,
we accidentally allow spu_run to be performed on
any file in spufs, not just those returned from
spu_create as intended.

Noticed by Al Viro.

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

Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/inode.c
@@ -212,7 +212,7 @@ struct inode_operations spufs_dir_inode_
 	.lookup = simple_lookup,
 };
 
-struct file_operations spufs_autodelete_dir_operations = {
+struct file_operations spufs_context_fops = {
 	.open		= dcache_dir_open,
 	.release	= spufs_dir_close,
 	.llseek		= dcache_dir_lseek,
@@ -301,7 +301,7 @@ spufs_create_thread(struct nameidata *nd
 		put_unused_fd(ret);
 		ret = PTR_ERR(filp);
 	} else {
-		filp->f_op = &spufs_autodelete_dir_operations;
+		filp->f_op = &spufs_context_fops;
 		fd_install(ret, filp);
 	}
 
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -103,6 +103,7 @@ long spufs_run_spu(struct file *file,
 		   struct spu_context *ctx, u32 *npc, u32 *status);
 long spufs_create_thread(struct nameidata *nd, const char *name,
 			 unsigned int flags, mode_t mode);
+extern struct file_operations spufs_context_fops;
 
 /* context management */
 struct spu_context * alloc_spu_context(struct address_space *local_store);
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/syscalls.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -39,8 +39,9 @@ long do_spu_run(struct file *filp, __u32
 	if (get_user(npc, unpc) || get_user(status, ustatus))
 		goto out;
 
+	/* check if this file was created by spu_create */
 	ret = -EINVAL;
-	if (filp->f_vfsmnt->mnt_sb->s_magic != SPUFS_MAGIC)
+	if (filp->f_op != &spufs_context_fops)
 		goto out;
 
 	i = SPUFS_I(filp->f_dentry->d_inode);

--


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

* [PATCH 04/13] spufs: serialize sys_spu_run per spu
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (2 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 03/13] spufs: check for proper file pointer in sys_spu_run Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 05/13] spufs fix spu_acquire_runnable error path Arnd Bergmann
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-serialize-spu-run.diff --]
[-- Type: text/plain, Size: 2315 bytes --]

During an earlier cleanup, we lost the serialization
of multiple spu_run calls performed on the same
spu_context. In order to get this back, introduce a
mutex in the spu_context that is held inside of spu_run.

Noticed by Al Viro.

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

Index: linux-cg/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
--- linux-cg.orig/arch/powerpc/platforms/cell/spufs/context.c	2005-12-22 13:25:12.000000000 +0000
+++ linux-cg/arch/powerpc/platforms/cell/spufs/context.c	2005-12-22 13:36:37.000000000 +0000
@@ -43,6 +43,7 @@
 	spin_lock_init(&ctx->mmio_lock);
 	kref_init(&ctx->kref);
 	init_rwsem(&ctx->state_sema);
+	init_MUTEX(&ctx->run_sema);
 	init_waitqueue_head(&ctx->ibox_wq);
 	init_waitqueue_head(&ctx->wbox_wq);
 	init_waitqueue_head(&ctx->stop_wq);
Index: linux-cg/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-cg.orig/arch/powerpc/platforms/cell/spufs/file.c	2005-12-22 13:25:12.000000000 +0000
+++ linux-cg/arch/powerpc/platforms/cell/spufs/file.c	2005-12-22 13:37:14.000000000 +0000
@@ -620,8 +620,12 @@
 {
 	int ret;
 
-	if ((ret = spu_run_init(ctx, npc, status)) != 0)
-		return ret;
+	if (down_interruptible(&ctx->run_sema))
+		return -ERESTARTSYS;
+
+	ret = spu_run_init(ctx, npc, status);
+	if (ret)
+		goto out;
 
 	do {
 		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
@@ -629,9 +633,8 @@
 			break;
 		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
 			ret = spu_reacquire_runnable(ctx, npc, status);
-			if (ret) {
-				return ret;
-			}
+			if (ret)
+				goto out;
 			continue;
 		}
 		ret = spu_process_events(ctx);
@@ -645,6 +648,8 @@
 		ret = *status;
 	spu_yield(ctx);
 
+out:
+	up(&ctx->run_sema);
 	return ret;
 }
 
Index: linux-cg/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-cg.orig/arch/powerpc/platforms/cell/spufs/spufs.h	2005-12-22 13:25:26.000000000 +0000
+++ linux-cg/arch/powerpc/platforms/cell/spufs/spufs.h	2005-12-22 13:34:38.000000000 +0000
@@ -48,6 +48,7 @@
 
 	enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
 	struct rw_semaphore state_sema;
+	struct semaphore run_sema;
 
 	struct mm_struct *owner;
 

--


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

* [PATCH 05/13] spufs fix spu_acquire_runnable error path
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (3 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 04/13] spufs: serialize sys_spu_run per spu Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 06/13] spufs: dont leak directories in failed spu_create Arnd Bergmann
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-aquire-runnable-fix.diff --]
[-- Type: text/plain, Size: 778 bytes --]

When spu_activate fails in spu_acquire_runnable, the
state must still be SPU_STATE_SAVED, we were
incorrectly setting it to SPU_STATE_RUNNABLE.

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

Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/context.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/context.c
@@ -132,10 +132,10 @@ int spu_acquire_runnable(struct spu_cont
 
 	if (ctx->state == SPU_STATE_SAVED) {
 		ret = spu_activate(ctx, 0);
+		if (ret)
+			goto out;
 		ctx->state = SPU_STATE_RUNNABLE;
 	}
-	if (ret)
-		goto out;
 
 	downgrade_write(&ctx->state_sema);
 	/* On success, we return holding the lock */

--


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

* [PATCH 06/13] spufs: dont leak directories in failed spu_create
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (4 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 05/13] spufs fix spu_acquire_runnable error path Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 07/13] spufs: fix spufs_fill_dir error path Arnd Bergmann
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-create-fix-leak.diff --]
[-- Type: text/plain, Size: 2475 bytes --]

If get_unused_fd failed in sys_spu_create, we never cleaned
up the created directory. Fix that by restructuring the
error path.

Noticed by Al Viro.

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

Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/inode.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/ioctl.h>
 #include <linux/module.h>
+#include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/pagemap.h>
 #include <linux/poll.h>
@@ -251,6 +252,7 @@ spufs_mkdir(struct inode *dir, struct de
 	d_instantiate(dentry, inode);
 	dget(dentry);
 	dir->i_nlink++;
+	dentry->d_inode->i_nlink++;
 	goto out;
 
 out_free_ctx:
@@ -261,18 +263,44 @@ out:
 	return ret;
 }
 
+static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt)
+{
+	int ret;
+	struct file *filp;
+
+	ret = get_unused_fd();
+	if (ret < 0) {
+		dput(dentry);
+		mntput(mnt);
+		goto out;
+	}
+
+	filp = dentry_open(dentry, mnt, O_RDONLY);
+	if (IS_ERR(filp)) {
+		put_unused_fd(ret);
+		ret = PTR_ERR(filp);
+		goto out;
+	}
+
+	filp->f_op = &spufs_context_fops;
+	fd_install(ret, filp);
+out:
+	return ret;
+}
+
+static struct file_system_type spufs_type;
+
 long
 spufs_create_thread(struct nameidata *nd, const char *name,
 			unsigned int flags, mode_t mode)
 {
 	struct dentry *dentry;
-	struct file *filp;
 	int ret;
 
 	/* need to be at the root of spufs */
 	ret = -EINVAL;
-	if (nd->dentry->d_sb->s_magic != SPUFS_MAGIC ||
-		nd->dentry != nd->dentry->d_sb->s_root)
+	if (nd->dentry->d_sb->s_type != &spufs_type ||
+	    nd->dentry != nd->dentry->d_sb->s_root)
 		goto out;
 
 	dentry = lookup_create(nd, 1);
@@ -289,21 +317,13 @@ spufs_create_thread(struct nameidata *nd
 	if (ret)
 		goto out_dput;
 
-	ret = get_unused_fd();
+	/*
+	 * get references for dget and mntget, will be released
+	 * in error path of *_open().
+	 */
+	ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
 	if (ret < 0)
-		goto out_dput;
-
-	dentry->d_inode->i_nlink++;
-
-	filp = filp_open(name, O_RDONLY, mode);
-	if (IS_ERR(filp)) {
-		// FIXME: remove directory again
-		put_unused_fd(ret);
-		ret = PTR_ERR(filp);
-	} else {
-		filp->f_op = &spufs_context_fops;
-		fd_install(ret, filp);
-	}
+		spufs_rmdir(nd->dentry->d_inode, dentry);
 
 out_dput:
 	dput(dentry);

--


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

* [PATCH 07/13] spufs: fix spufs_fill_dir error path
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (5 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 06/13] spufs: dont leak directories in failed spu_create Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 08/13] spufs: clean up use of bitops Arnd Bergmann
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-fill-dir-leak.diff --]
[-- Type: text/plain, Size: 3016 bytes --]

If creating one entry failed in spufs_fill_dir,
we never cleaned up the freshly created entries.
Fix this by calling the cleanup function on error.

Noticed by Al Viro.

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

Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/inode.c
@@ -134,47 +134,18 @@ spufs_delete_inode(struct inode *inode)
 	clear_inode(inode);
 }
 
-static int
-spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
-		int mode, struct spu_context *ctx)
-{
-	struct dentry *dentry;
-	int ret;
-
-	while (files->name && files->name[0]) {
-		ret = -ENOMEM;
-		dentry = d_alloc_name(dir, files->name);
-		if (!dentry)
-			goto out;
-		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
-					files->mode & mode, ctx);
-		if (ret)
-			goto out;
-		files++;
-	}
-	return 0;
-out:
-	// FIXME: remove all files that are left
-
-	return ret;
-}
-
-static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+static void spufs_prune_dir(struct dentry *dir)
 {
 	struct dentry *dentry, *tmp;
-	struct spu_context *ctx;
-
-	/* remove all entries */
-	down(&root->i_sem);
-	down(&dir_dentry->d_inode->i_sem);
-	list_for_each_entry_safe(dentry, tmp, &dir_dentry->d_subdirs, d_child) {
+	down(&dir->d_inode->i_sem);
+	list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
 		spin_lock(&dcache_lock);
 		spin_lock(&dentry->d_lock);
 		if (!(d_unhashed(dentry)) && dentry->d_inode) {
 			dget_locked(dentry);
 			__d_drop(dentry);
 			spin_unlock(&dentry->d_lock);
-			simple_unlink(dir_dentry->d_inode, dentry);
+			simple_unlink(dir->d_inode, dentry);
 			spin_unlock(&dcache_lock);
 			dput(dentry);
 		} else {
@@ -182,8 +153,17 @@ static int spufs_rmdir(struct inode *roo
 			spin_unlock(&dcache_lock);
 		}
 	}
-	shrink_dcache_parent(dir_dentry);
-	up(&dir_dentry->d_inode->i_sem);
+	shrink_dcache_parent(dir);
+	up(&dir->d_inode->i_sem);
+}
+
+static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+{
+	struct spu_context *ctx;
+
+	/* remove all entries */
+	down(&root->i_sem);
+	spufs_prune_dir(dir_dentry);
 	up(&root->i_sem);
 
 	/* We have to give up the mm_struct */
@@ -194,6 +174,29 @@ static int spufs_rmdir(struct inode *roo
 	return simple_rmdir(root, dir_dentry);
 }
 
+static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
+			  int mode, struct spu_context *ctx)
+{
+	struct dentry *dentry;
+	int ret;
+
+	while (files->name && files->name[0]) {
+		ret = -ENOMEM;
+		dentry = d_alloc_name(dir, files->name);
+		if (!dentry)
+			goto out;
+		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
+					files->mode & mode, ctx);
+		if (ret)
+			goto out;
+		files++;
+	}
+	return 0;
+out:
+	spufs_prune_dir(dir);
+	return ret;
+}
+
 static int spufs_dir_close(struct inode *inode, struct file *file)
 {
 	struct inode *dir;

--


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

* [PATCH 08/13] spufs: clean up use of bitops
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (6 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 07/13] spufs: fix spufs_fill_dir error path Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 09/13] spufs: move spu_run call to its own file Arnd Bergmann
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-test-bit-cleanup.diff --]
[-- Type: text/plain, Size: 5352 bytes --]

checking bits manually might not be synchonized with
the use of set_bit/clear_bit. Make sure we always use
the correct bitops by removing the unnecessary
identifiers.

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

Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/sched.c
@@ -214,14 +214,14 @@ static void spu_reaper(void *data)
 
 	down_write(&ctx->state_sema);
 	spu = ctx->spu;
-	if (spu && (ctx->flags & SPU_CONTEXT_PREEMPT)) {
+	if (spu && test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
 		if (atomic_read(&spu->rq->prio.nr_blocked)) {
 			pr_debug("%s: spu=%d\n", __func__, spu->number);
 			ctx->ops->runcntl_stop(ctx);
 			spu_deactivate(ctx);
 			wake_up_all(&ctx->stop_wq);
 		} else {
-			clear_bit(SPU_CONTEXT_PREEMPT_nr, &ctx->flags);
+			clear_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
 		}
 	}
 	up_write(&ctx->state_sema);
@@ -234,7 +234,7 @@ static void schedule_spu_reaper(struct s
 	unsigned long now = jiffies;
 	unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE;
 
-	set_bit(SPU_CONTEXT_PREEMPT_nr, &ctx->flags);
+	set_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
 	INIT_WORK(&ctx->reap_work, spu_reaper, ctx);
 	if (time_after(now, expire))
 		schedule_work(&ctx->reap_work);
@@ -250,7 +250,7 @@ static void check_preempt_active(struct 
 	list_for_each(p, &rq->active_list) {
 		struct spu *spu = list_entry(p, struct spu, sched_list);
 		struct spu_context *ctx = spu->ctx;
-		if (!(ctx->flags & SPU_CONTEXT_PREEMPT)) {
+		if (!test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
 			if (!worst || (spu->prio > worst->prio)) {
 				worst = spu;
 			}
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -37,8 +37,7 @@ enum {
 
 struct spu_context_ops;
 
-#define SPU_CONTEXT_PREEMPT_nr          0UL
-#define SPU_CONTEXT_PREEMPT             (1UL << SPU_CONTEXT_PREEMPT_nr)
+#define SPU_CONTEXT_PREEMPT          0UL
 
 struct spu_context {
 	struct spu *spu;		  /* pointer to a physical SPU */
Index: linux-2.6.15-rc/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.15-rc.orig/include/asm-powerpc/spu.h
+++ linux-2.6.15-rc/include/asm-powerpc/spu.h
@@ -102,10 +102,8 @@
 #define MFC_MULTI_SRC_EVENT                 0x00001000
 
 /* Flags indicating progress during context switch. */
-#define SPU_CONTEXT_SWITCH_PENDING_nr	0UL
-#define SPU_CONTEXT_SWITCH_ACTIVE_nr	1UL
-#define SPU_CONTEXT_SWITCH_PENDING	(1UL << SPU_CONTEXT_SWITCH_PENDING_nr)
-#define SPU_CONTEXT_SWITCH_ACTIVE	(1UL << SPU_CONTEXT_SWITCH_ACTIVE_nr)
+#define SPU_CONTEXT_SWITCH_PENDING	0UL
+#define SPU_CONTEXT_SWITCH_ACTIVE	1UL
 
 struct spu_context;
 struct spu_runqueue;
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
@@ -63,7 +63,7 @@ static void spu_restart_dma(struct spu *
 {
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
 
-	if (!test_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags))
+	if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
 		out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
 }
 
@@ -75,7 +75,7 @@ static int __spu_trap_data_seg(struct sp
 
 	pr_debug("%s\n", __FUNCTION__);
 
-	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
+	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
 		/* SLBs are pre-loaded for context switch, so
 		 * we should never get here!
 		 */
@@ -122,7 +122,7 @@ static int __spu_trap_data_map(struct sp
 		return 0;
 	}
 
-	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
+	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
 		printk("%s: invalid access during switch!\n", __func__);
 		return 1;
 	}
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/switch.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/switch.c
@@ -165,7 +165,7 @@ static inline void set_switch_pending(st
 	 * Restore, Step 5:
 	 *     Set a software context switch pending flag.
 	 */
-	set_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags);
+	set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
 	mb();
 }
 
@@ -767,8 +767,8 @@ static inline void set_switch_active(str
 	 *     Change the software context switch pending flag
 	 *     to context switch active.
 	 */
-	set_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags);
-	clear_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags);
+	set_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
+	clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
 	mb();
 }
 
@@ -1786,7 +1786,7 @@ static inline void reset_switch_active(s
 	/* Restore, Step 74:
 	 *     Reset the "context switch active" flag.
 	 */
-	clear_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags);
+	clear_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
 	mb();
 }
 

--


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

* [PATCH 09/13] spufs: move spu_run call to its own file
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (7 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 08/13] spufs: clean up use of bitops Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 10/13] spufs: abstract priv1 register access Arnd Bergmann
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-run-c-2.diff --]
[-- Type: text/plain, Size: 9480 bytes --]

The logic for sys_spu_run keeps growing and it does
not really belong into file.c any more since we
moved away from using regular file operations to our
own syscall.

No functional change in here.

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

Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/Makefile
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/Makefile
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_SPU_FS) += spufs.o
 spufs-y += inode.o file.o context.o switch.o syscalls.o
-spufs-y += sched.o backing_ops.o hw_ops.o
+spufs-y += sched.o backing_ops.o hw_ops.o run.o
 
 # Rules to build switch.o with the help of SPU tool chain
 SPU_CROSS	:= spu-
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/file.c
@@ -304,34 +304,6 @@ static struct file_operations spufs_mbox
 	.read	= spufs_mbox_stat_read,
 };
 
-/*
- * spufs_wait
- * 	Same as wait_event_interruptible(), except that here
- *	we need to call spu_release(ctx) before sleeping, and
- *	then spu_acquire(ctx) when awoken.
- */
-
-#define spufs_wait(wq, condition)					\
-({									\
-	int __ret = 0;							\
-	DEFINE_WAIT(__wait);						\
-	for (;;) {							\
-		prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);	\
-		if (condition)						\
-			break;						\
-		if (!signal_pending(current)) {				\
-			spu_release(ctx);				\
-			schedule();					\
-			spu_acquire(ctx);				\
-			continue;					\
-		}							\
-		__ret = -ERESTARTSYS;					\
-		break;							\
-	}								\
-	finish_wait(&(wq), &__wait);					\
-	__ret;								\
-})
-
 /* low-level ibox access function */
 size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
 {
@@ -529,130 +501,6 @@ static struct file_operations spufs_wbox
 	.read	= spufs_wbox_stat_read,
 };
 
-/* interrupt-level stop callback function. */
-void spufs_stop_callback(struct spu *spu)
-{
-	struct spu_context *ctx = spu->ctx;
-
-	wake_up_all(&ctx->stop_wq);
-}
-
-static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
-{
-	struct spu *spu;
-	u64 pte_fault;
-
-	*stat = ctx->ops->status_read(ctx);
-	if (ctx->state != SPU_STATE_RUNNABLE)
-		return 1;
-	spu = ctx->spu;
-	pte_fault = spu->dsisr &
-	    (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
-	return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
-}
-
-static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
-			       u32 * status)
-{
-	int ret;
-
-	if ((ret = spu_acquire_runnable(ctx)) != 0)
-		return ret;
-	ctx->ops->npc_write(ctx, *npc);
-	ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
-	return 0;
-}
-
-static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
-			       u32 * status)
-{
-	int ret = 0;
-
-	*status = ctx->ops->status_read(ctx);
-	*npc = ctx->ops->npc_read(ctx);
-	spu_release(ctx);
-
-	if (signal_pending(current))
-		ret = -ERESTARTSYS;
-	if (unlikely(current->ptrace & PT_PTRACED)) {
-		if ((*status & SPU_STATUS_STOPPED_BY_STOP)
-		    && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
-			force_sig(SIGTRAP, current);
-			ret = -ERESTARTSYS;
-		}
-	}
-	return ret;
-}
-
-static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
-				         u32 *status)
-{
-	int ret;
-
-	if ((ret = spu_run_fini(ctx, npc, status)) != 0)
-		return ret;
-	if (*status & (SPU_STATUS_STOPPED_BY_STOP |
-		       SPU_STATUS_STOPPED_BY_HALT)) {
-		return *status;
-	}
-	if ((ret = spu_run_init(ctx, npc, status)) != 0)
-		return ret;
-	return 0;
-}
-
-static inline int spu_process_events(struct spu_context *ctx)
-{
-	struct spu *spu = ctx->spu;
-	u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
-	int ret = 0;
-
-	if (spu->dsisr & pte_fault)
-		ret = spu_irq_class_1_bottom(spu);
-	if (spu->class_0_pending)
-		ret = spu_irq_class_0_bottom(spu);
-	if (!ret && signal_pending(current))
-		ret = -ERESTARTSYS;
-	return ret;
-}
-
-long spufs_run_spu(struct file *file, struct spu_context *ctx,
-		   u32 * npc, u32 * status)
-{
-	int ret;
-
-	if (down_interruptible(&ctx->run_sema))
-		return -ERESTARTSYS;
-
-	ret = spu_run_init(ctx, npc, status);
-	if (ret)
-		goto out;
-
-	do {
-		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
-		if (unlikely(ret))
-			break;
-		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
-			ret = spu_reacquire_runnable(ctx, npc, status);
-			if (ret)
-				goto out;
-			continue;
-		}
-		ret = spu_process_events(ctx);
-
-	} while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
-				      SPU_STATUS_STOPPED_BY_HALT)));
-
-	ctx->ops->runcntl_stop(ctx);
-	ret = spu_run_fini(ctx, npc, status);
-	if (!ret)
-		ret = *status;
-	spu_yield(ctx);
-
-out:
-	up(&ctx->run_sema);
-	return ret;
-}
-
 static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
 			size_t len, loff_t *pos)
 {
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- /dev/null
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/run.c
@@ -0,0 +1,131 @@
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+
+#include <asm/spu.h>
+
+#include "spufs.h"
+
+/* interrupt-level stop callback function. */
+void spufs_stop_callback(struct spu *spu)
+{
+	struct spu_context *ctx = spu->ctx;
+
+	wake_up_all(&ctx->stop_wq);
+}
+
+static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+{
+	struct spu *spu;
+	u64 pte_fault;
+
+	*stat = ctx->ops->status_read(ctx);
+	if (ctx->state != SPU_STATE_RUNNABLE)
+		return 1;
+	spu = ctx->spu;
+	pte_fault = spu->dsisr &
+	    (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
+	return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
+}
+
+static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
+			       u32 * status)
+{
+	int ret;
+
+	if ((ret = spu_acquire_runnable(ctx)) != 0)
+		return ret;
+	ctx->ops->npc_write(ctx, *npc);
+	ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+	return 0;
+}
+
+static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
+			       u32 * status)
+{
+	int ret = 0;
+
+	*status = ctx->ops->status_read(ctx);
+	*npc = ctx->ops->npc_read(ctx);
+	spu_release(ctx);
+
+	if (signal_pending(current))
+		ret = -ERESTARTSYS;
+	if (unlikely(current->ptrace & PT_PTRACED)) {
+		if ((*status & SPU_STATUS_STOPPED_BY_STOP)
+		    && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
+			force_sig(SIGTRAP, current);
+			ret = -ERESTARTSYS;
+		}
+	}
+	return ret;
+}
+
+static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
+				         u32 *status)
+{
+	int ret;
+
+	if ((ret = spu_run_fini(ctx, npc, status)) != 0)
+		return ret;
+	if (*status & (SPU_STATUS_STOPPED_BY_STOP |
+		       SPU_STATUS_STOPPED_BY_HALT)) {
+		return *status;
+	}
+	if ((ret = spu_run_init(ctx, npc, status)) != 0)
+		return ret;
+	return 0;
+}
+
+static inline int spu_process_events(struct spu_context *ctx)
+{
+	struct spu *spu = ctx->spu;
+	u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
+	int ret = 0;
+
+	if (spu->dsisr & pte_fault)
+		ret = spu_irq_class_1_bottom(spu);
+	if (spu->class_0_pending)
+		ret = spu_irq_class_0_bottom(spu);
+	if (!ret && signal_pending(current))
+		ret = -ERESTARTSYS;
+	return ret;
+}
+
+long spufs_run_spu(struct file *file, struct spu_context *ctx,
+		   u32 * npc, u32 * status)
+{
+	int ret;
+
+	if (down_interruptible(&ctx->run_sema))
+		return -ERESTARTSYS;
+
+	ret = spu_run_init(ctx, npc, status);
+	if (ret)
+		goto out;
+
+	do {
+		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
+		if (unlikely(ret))
+			break;
+		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
+			ret = spu_reacquire_runnable(ctx, npc, status);
+			if (ret)
+				goto out;
+			continue;
+		}
+		ret = spu_process_events(ctx);
+
+	} while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
+				      SPU_STATUS_STOPPED_BY_HALT)));
+
+	ctx->ops->runcntl_stop(ctx);
+	ret = spu_run_fini(ctx, npc, status);
+	if (!ret)
+		ret = *status;
+	spu_yield(ctx);
+
+out:
+	up(&ctx->run_sema);
+	return ret;
+}
+
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -124,6 +124,34 @@ void spu_yield(struct spu_context *ctx);
 int __init spu_sched_init(void);
 void __exit spu_sched_exit(void);
 
+/*
+ * spufs_wait
+ * 	Same as wait_event_interruptible(), except that here
+ *	we need to call spu_release(ctx) before sleeping, and
+ *	then spu_acquire(ctx) when awoken.
+ */
+
+#define spufs_wait(wq, condition)					\
+({									\
+	int __ret = 0;							\
+	DEFINE_WAIT(__wait);						\
+	for (;;) {							\
+		prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);	\
+		if (condition)						\
+			break;						\
+		if (!signal_pending(current)) {				\
+			spu_release(ctx);				\
+			schedule();					\
+			spu_acquire(ctx);				\
+			continue;					\
+		}							\
+		__ret = -ERESTARTSYS;					\
+		break;							\
+	}								\
+	finish_wait(&(wq), &__wait);					\
+	__ret;								\
+})
+
 size_t spu_wbox_write(struct spu_context *ctx, u32 data);
 size_t spu_ibox_read(struct spu_context *ctx, u32 *data);
 

--


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

* [PATCH 10/13] spufs: abstract priv1 register access.
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (8 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 09/13] spufs: move spu_run call to its own file Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 11/13] spufs: fix sparse warnings Arnd Bergmann
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter,
	Masato Noguchi, Geoff Levand, Arnd Bergmann

[-- Attachment #1: spufs-priv1-hvcall.diff --]
[-- Type: text/plain, Size: 27183 bytes --]

In a hypervisor based setup, direct access to the first
priviledged register space can typically not be allowed
to the kernel and has to be implemented through hypervisor
calls.

As suggested by Masato Noguchi, let's abstract the register
access trough a number of function calls. Since there is
currently no public specification of actual hypervisor
calls to implement this, I only provide a place that
makes it easier to hook into.

Cc: Masato Noguchi <Masato.Noguchi@jp.sony.com>
Cc: Geoff Levand <geoff.levand@am.sony.com>
Signed-off-by: Arnd Bergmann <arndb@de.ibm.com>

Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
@@ -142,8 +142,7 @@ static int __spu_trap_mailbox(struct spu
 
 	/* atomically disable SPU mailbox interrupts */
 	spin_lock(&spu->register_lock);
-	out_be64(&spu->priv1->int_mask_class2_RW,
-		in_be64(&spu->priv1->int_mask_class2_RW) & ~0x1);
+	spu_int_mask_and(spu, 2, ~0x1);
 	spin_unlock(&spu->register_lock);
 	return 0;
 }
@@ -180,8 +179,7 @@ static int __spu_trap_spubox(struct spu 
 
 	/* atomically disable SPU mailbox interrupts */
 	spin_lock(&spu->register_lock);
-	out_be64(&spu->priv1->int_mask_class2_RW,
-		in_be64(&spu->priv1->int_mask_class2_RW) & ~0x10);
+	spu_int_mask_and(spu, 2, ~0x10);
 	spin_unlock(&spu->register_lock);
 	return 0;
 }
@@ -206,8 +204,8 @@ spu_irq_class_0_bottom(struct spu *spu)
 
 	spu->class_0_pending = 0;
 
-	mask = in_be64(&spu->priv1->int_mask_class0_RW);
-	stat = in_be64(&spu->priv1->int_stat_class0_RW);
+	mask = spu_int_mask_get(spu, 0);
+	stat = spu_int_stat_get(spu, 0);
 
 	stat &= mask;
 
@@ -220,7 +218,7 @@ spu_irq_class_0_bottom(struct spu *spu)
 	if (stat & 4) /* error on SPU */
 		__spu_trap_error(spu);
 
-	out_be64(&spu->priv1->int_stat_class0_RW, stat);
+	spu_int_stat_clear(spu, 0, stat);
 
 	return (stat & 0x7) ? -EIO : 0;
 }
@@ -236,13 +234,13 @@ spu_irq_class_1(int irq, void *data, str
 
 	/* atomically read & clear class1 status. */
 	spin_lock(&spu->register_lock);
-	mask  = in_be64(&spu->priv1->int_mask_class1_RW);
-	stat  = in_be64(&spu->priv1->int_stat_class1_RW) & mask;
-	dar   = in_be64(&spu->priv1->mfc_dar_RW);
-	dsisr = in_be64(&spu->priv1->mfc_dsisr_RW);
+	mask  = spu_int_mask_get(spu, 1);
+	stat  = spu_int_stat_get(spu, 1) & mask;
+	dar   = spu_mfc_dar_get(spu);
+	dsisr = spu_mfc_dsisr_get(spu);
 	if (stat & 2) /* mapping fault */
-		out_be64(&spu->priv1->mfc_dsisr_RW, 0UL);
-	out_be64(&spu->priv1->int_stat_class1_RW, stat);
+		spu_mfc_dsisr_set(spu, 0ul);
+	spu_int_stat_clear(spu, 1, stat);
 	spin_unlock(&spu->register_lock);
 
 	if (stat & 1) /* segment fault */
@@ -270,8 +268,8 @@ spu_irq_class_2(int irq, void *data, str
 	unsigned long mask;
 
 	spu = data;
-	stat = in_be64(&spu->priv1->int_stat_class2_RW);
-	mask = in_be64(&spu->priv1->int_mask_class2_RW);
+	stat = spu_int_stat_get(spu, 2);
+	mask = spu_int_mask_get(spu, 2);
 
 	pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
 
@@ -292,7 +290,7 @@ spu_irq_class_2(int irq, void *data, str
 	if (stat & 0x10) /* SPU mailbox threshold */
 		__spu_trap_spubox(spu);
 
-	out_be64(&spu->priv1->int_stat_class2_RW, stat);
+	spu_int_stat_clear(spu, 2, stat);
 	return stat ? IRQ_HANDLED : IRQ_NONE;
 }
 
@@ -309,21 +307,18 @@ spu_request_irqs(struct spu *spu)
 		 spu_irq_class_0, 0, spu->irq_c0, spu);
 	if (ret)
 		goto out;
-	out_be64(&spu->priv1->int_mask_class0_RW, 0x7);
 
 	snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
 	ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
 		 spu_irq_class_1, 0, spu->irq_c1, spu);
 	if (ret)
 		goto out1;
-	out_be64(&spu->priv1->int_mask_class1_RW, 0x3);
 
 	snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number);
 	ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc,
 		 spu_irq_class_2, 0, spu->irq_c2, spu);
 	if (ret)
 		goto out2;
-	out_be64(&spu->priv1->int_mask_class2_RW, 0xe);
 	goto out;
 
 out2:
@@ -383,13 +378,6 @@ static void spu_init_channels(struct spu
 	}
 }
 
-static void spu_init_regs(struct spu *spu)
-{
-	out_be64(&spu->priv1->int_mask_class0_RW, 0x7);
-	out_be64(&spu->priv1->int_mask_class1_RW, 0x3);
-	out_be64(&spu->priv1->int_mask_class2_RW, 0xe);
-}
-
 struct spu *spu_alloc(void)
 {
 	struct spu *spu;
@@ -405,10 +393,8 @@ struct spu *spu_alloc(void)
 	}
 	up(&spu_mutex);
 
-	if (spu) {
+	if (spu)
 		spu_init_channels(spu);
-		spu_init_regs(spu);
-	}
 
 	return spu;
 }
@@ -579,8 +565,7 @@ static int __init spu_map_device(struct 
 		goto out_unmap;
 
 	spu->priv1= map_spe_prop(spe, "priv1");
-	if (!spu->priv1)
-		goto out_unmap;
+	/* priv1 is not available on a hypervisor */
 
 	spu->priv2= map_spe_prop(spe, "priv2");
 	if (!spu->priv2)
@@ -633,8 +618,8 @@ static int __init create_spu(struct devi
 	spu->dsisr = 0UL;
 	spin_lock_init(&spu->register_lock);
 
-	out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
-	out_be64(&spu->priv1->mfc_sr1_RW, 0x33);
+	spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
+	spu_mfc_sr1_set(spu, 0x33);
 
 	spu->ibox_callback = NULL;
 	spu->wbox_callback = NULL;
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_priv1.c
===================================================================
--- /dev/null
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_priv1.c
@@ -0,0 +1,133 @@
+/*
+ * access to SPU privileged registers
+ */
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+
+void spu_int_mask_and(struct spu *spu, int class, u64 mask)
+{
+	u64 old_mask;
+
+	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+	out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_and);
+
+void spu_int_mask_or(struct spu *spu, int class, u64 mask)
+{
+	u64 old_mask;
+
+	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+	out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_or);
+
+void spu_int_mask_set(struct spu *spu, int class, u64 mask)
+{
+	out_be64(&spu->priv1->int_mask_RW[class], mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_set);
+
+u64 spu_int_mask_get(struct spu *spu, int class)
+{
+	return in_be64(&spu->priv1->int_mask_RW[class]);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_get);
+
+void spu_int_stat_clear(struct spu *spu, int class, u64 stat)
+{
+	out_be64(&spu->priv1->int_stat_RW[class], stat);
+}
+EXPORT_SYMBOL_GPL(spu_int_stat_clear);
+
+u64 spu_int_stat_get(struct spu *spu, int class)
+{
+	return in_be64(&spu->priv1->int_stat_RW[class]);
+}
+EXPORT_SYMBOL_GPL(spu_int_stat_get);
+
+void spu_int_route_set(struct spu *spu, u64 route)
+{
+	out_be64(&spu->priv1->int_route_RW, route);
+}
+EXPORT_SYMBOL_GPL(spu_int_route_set);
+
+u64 spu_mfc_dar_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->mfc_dar_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dar_get);
+
+u64 spu_mfc_dsisr_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->mfc_dsisr_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dsisr_get);
+
+void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr)
+{
+	out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dsisr_set);
+
+void spu_mfc_sdr_set(struct spu *spu, u64 sdr)
+{
+	out_be64(&spu->priv1->mfc_sdr_RW, sdr);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sdr_set);
+
+void spu_mfc_sr1_set(struct spu *spu, u64 sr1)
+{
+	out_be64(&spu->priv1->mfc_sr1_RW, sr1);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sr1_set);
+
+u64 spu_mfc_sr1_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->mfc_sr1_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sr1_get);
+
+void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
+{
+	out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_set);
+
+u64 spu_mfc_tclass_id_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->mfc_tclass_id_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_get);
+
+void spu_tlb_invalidate(struct spu *spu)
+{
+	out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
+}
+EXPORT_SYMBOL_GPL(spu_tlb_invalidate);
+
+void spu_resource_allocation_groupID_set(struct spu *spu, u64 id)
+{
+	out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_set);
+
+u64 spu_resource_allocation_groupID_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->resource_allocation_groupID_RW);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_get);
+
+void spu_resource_allocation_enable_set(struct spu *spu, u64 enable)
+{
+	out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_set);
+
+u64 spu_resource_allocation_enable_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->resource_allocation_enable_RW);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_get);
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/hw_ops.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -62,7 +62,6 @@ static unsigned int spu_hw_mbox_stat_pol
 					  unsigned int events)
 {
 	struct spu *spu = ctx->spu;
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	int ret = 0;
 	u32 stat;
 
@@ -78,18 +77,16 @@ static unsigned int spu_hw_mbox_stat_pol
 		if (stat & 0xff0000)
 			ret |= POLLIN | POLLRDNORM;
 		else {
-			out_be64(&priv1->int_stat_class2_RW, 0x1);
-			out_be64(&priv1->int_mask_class2_RW,
-				 in_be64(&priv1->int_mask_class2_RW) | 0x1);
+			spu_int_stat_clear(spu, 2, 0x1);
+			spu_int_mask_or(spu, 2, 0x1);
 		}
 	}
 	if (events & (POLLOUT | POLLWRNORM)) {
 		if (stat & 0x00ff00)
 			ret = POLLOUT | POLLWRNORM;
 		else {
-			out_be64(&priv1->int_stat_class2_RW, 0x10);
-			out_be64(&priv1->int_mask_class2_RW,
-				 in_be64(&priv1->int_mask_class2_RW) | 0x10);
+			spu_int_stat_clear(spu, 2, 0x10);
+			spu_int_mask_or(spu, 2, 0x10);
 		}
 	}
 	spin_unlock_irq(&spu->register_lock);
@@ -100,7 +97,6 @@ static int spu_hw_ibox_read(struct spu_c
 {
 	struct spu *spu = ctx->spu;
 	struct spu_problem __iomem *prob = spu->problem;
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
 	int ret;
 
@@ -111,8 +107,7 @@ static int spu_hw_ibox_read(struct spu_c
 		ret = 4;
 	} else {
 		/* make sure we get woken up by the interrupt */
-		out_be64(&priv1->int_mask_class2_RW,
-			 in_be64(&priv1->int_mask_class2_RW) | 0x1);
+		spu_int_mask_or(spu, 2, 0x1);
 		ret = 0;
 	}
 	spin_unlock_irq(&spu->register_lock);
@@ -123,7 +118,6 @@ static int spu_hw_wbox_write(struct spu_
 {
 	struct spu *spu = ctx->spu;
 	struct spu_problem __iomem *prob = spu->problem;
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	int ret;
 
 	spin_lock_irq(&spu->register_lock);
@@ -134,8 +128,7 @@ static int spu_hw_wbox_write(struct spu_
 	} else {
 		/* make sure we get woken up by the interrupt when space
 		   becomes available */
-		out_be64(&priv1->int_mask_class2_RW,
-			 in_be64(&priv1->int_mask_class2_RW) | 0x10);
+		spu_int_mask_or(spu, 2, 0x10);
 		ret = 0;
 	}
 	spin_unlock_irq(&spu->register_lock);
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/switch.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/switch.c
@@ -108,8 +108,6 @@ static inline int check_spu_isolate(stru
 
 static inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Save, Step 3:
 	 * Restore, Step 2:
 	 *     Save INT_Mask_class0 in CSA.
@@ -121,16 +119,13 @@ static inline void disable_interrupts(st
 	 */
 	spin_lock_irq(&spu->register_lock);
 	if (csa) {
-		csa->priv1.int_mask_class0_RW =
-		    in_be64(&priv1->int_mask_class0_RW);
-		csa->priv1.int_mask_class1_RW =
-		    in_be64(&priv1->int_mask_class1_RW);
-		csa->priv1.int_mask_class2_RW =
-		    in_be64(&priv1->int_mask_class2_RW);
-	}
-	out_be64(&priv1->int_mask_class0_RW, 0UL);
-	out_be64(&priv1->int_mask_class1_RW, 0UL);
-	out_be64(&priv1->int_mask_class2_RW, 0UL);
+		csa->priv1.int_mask_class0_RW = spu_int_mask_get(spu, 0);
+		csa->priv1.int_mask_class1_RW = spu_int_mask_get(spu, 1);
+		csa->priv1.int_mask_class2_RW = spu_int_mask_get(spu, 2);
+	}
+	spu_int_mask_set(spu, 0, 0ul);
+	spu_int_mask_set(spu, 1, 0ul);
+	spu_int_mask_set(spu, 2, 0ul);
 	eieio();
 	spin_unlock_irq(&spu->register_lock);
 }
@@ -195,12 +190,10 @@ static inline void save_spu_runcntl(stru
 
 static inline void save_mfc_sr1(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Save, Step 10:
 	 *     Save MFC_SR1 in the CSA.
 	 */
-	csa->priv1.mfc_sr1_RW = in_be64(&priv1->mfc_sr1_RW);
+	csa->priv1.mfc_sr1_RW = spu_mfc_sr1_get(spu);
 }
 
 static inline void save_spu_status(struct spu_state *csa, struct spu *spu)
@@ -292,15 +285,13 @@ static inline void do_mfc_mssync(struct 
 
 static inline void issue_mfc_tlbie(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Save, Step 17:
 	 * Restore, Step 12.
 	 * Restore, Step 48.
 	 *     Write TLB_Invalidate_Entry[IS,VPN,L,Lp]=0 register.
 	 *     Then issue a PPE sync instruction.
 	 */
-	out_be64(&priv1->tlb_invalidate_entry_W, 0UL);
+	spu_tlb_invalidate(spu);
 	mb();
 }
 
@@ -410,25 +401,21 @@ static inline void save_mfc_csr_ato(stru
 
 static inline void save_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Save, Step 25:
 	 *     Save the MFC_TCLASS_ID register in
 	 *     the CSA.
 	 */
-	csa->priv1.mfc_tclass_id_RW = in_be64(&priv1->mfc_tclass_id_RW);
+	csa->priv1.mfc_tclass_id_RW = spu_mfc_tclass_id_get(spu);
 }
 
 static inline void set_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Save, Step 26:
 	 * Restore, Step 23.
 	 *     Write the MFC_TCLASS_ID register with
 	 *     the value 0x10000000.
 	 */
-	out_be64(&priv1->mfc_tclass_id_RW, 0x10000000);
+	spu_mfc_tclass_id_set(spu, 0x10000000);
 	eieio();
 }
 
@@ -458,14 +445,13 @@ static inline void wait_purge_complete(s
 
 static inline void save_mfc_slbs(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
 	int i;
 
 	/* Save, Step 29:
 	 *     If MFC_SR1[R]='1', save SLBs in CSA.
 	 */
-	if (in_be64(&priv1->mfc_sr1_RW) & MFC_STATE1_RELOCATE_MASK) {
+	if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) {
 		csa->priv2.slb_index_W = in_be64(&priv2->slb_index_W);
 		for (i = 0; i < 8; i++) {
 			out_be64(&priv2->slb_index_W, i);
@@ -479,8 +465,6 @@ static inline void save_mfc_slbs(struct 
 
 static inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Save, Step 30:
 	 * Restore, Step 18:
 	 *     Write MFC_SR1 with MFC_SR1[D=0,S=1] and
@@ -492,9 +476,9 @@ static inline void setup_mfc_sr1(struct 
 	 *     MFC_SR1[Pr] bit is not set.
 	 *
 	 */
-	out_be64(&priv1->mfc_sr1_RW, (MFC_STATE1_MASTER_RUN_CONTROL_MASK |
-				      MFC_STATE1_RELOCATE_MASK |
-				      MFC_STATE1_BUS_TLBIE_MASK));
+	spu_mfc_sr1_set(spu, (MFC_STATE1_MASTER_RUN_CONTROL_MASK |
+			      MFC_STATE1_RELOCATE_MASK |
+			      MFC_STATE1_BUS_TLBIE_MASK));
 }
 
 static inline void save_spu_npc(struct spu_state *csa, struct spu *spu)
@@ -571,16 +555,14 @@ static inline void save_pm_trace(struct 
 
 static inline void save_mfc_rag(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Save, Step 38:
 	 *     Save RA_GROUP_ID register and the
 	 *     RA_ENABLE reigster in the CSA.
 	 */
 	csa->priv1.resource_allocation_groupID_RW =
-	    in_be64(&priv1->resource_allocation_groupID_RW);
+		spu_resource_allocation_groupID_get(spu);
 	csa->priv1.resource_allocation_enable_RW =
-	    in_be64(&priv1->resource_allocation_enable_RW);
+		spu_resource_allocation_enable_get(spu);
 }
 
 static inline void save_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
@@ -698,14 +680,13 @@ static inline void resume_mfc_queue(stru
 
 static inline void invalidate_slbs(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
 
 	/* Save, Step 45:
 	 * Restore, Step 19:
 	 *     If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All.
 	 */
-	if (in_be64(&priv1->mfc_sr1_RW) & MFC_STATE1_RELOCATE_MASK) {
+	if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) {
 		out_be64(&priv2->slb_invalidate_all_W, 0UL);
 		eieio();
 	}
@@ -774,7 +755,6 @@ static inline void set_switch_active(str
 
 static inline void enable_interrupts(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	unsigned long class1_mask = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
 	    CLASS1_ENABLE_STORAGE_FAULT_INTR;
 
@@ -787,12 +767,12 @@ static inline void enable_interrupts(str
 	 *     (translation) interrupts.
 	 */
 	spin_lock_irq(&spu->register_lock);
-	out_be64(&priv1->int_stat_class0_RW, ~(0UL));
-	out_be64(&priv1->int_stat_class1_RW, ~(0UL));
-	out_be64(&priv1->int_stat_class2_RW, ~(0UL));
-	out_be64(&priv1->int_mask_class0_RW, 0UL);
-	out_be64(&priv1->int_mask_class1_RW, class1_mask);
-	out_be64(&priv1->int_mask_class2_RW, 0UL);
+	spu_int_stat_clear(spu, 0, ~0ul);
+	spu_int_stat_clear(spu, 1, ~0ul);
+	spu_int_stat_clear(spu, 2, ~0ul);
+	spu_int_mask_set(spu, 0, 0ul);
+	spu_int_mask_set(spu, 1, class1_mask);
+	spu_int_mask_set(spu, 2, 0ul);
 	spin_unlock_irq(&spu->register_lock);
 }
 
@@ -930,7 +910,6 @@ static inline void set_ppu_querymask(str
 
 static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	struct spu_problem __iomem *prob = spu->problem;
 	u32 mask = MFC_TAGID_TO_TAGMASK(0);
 	unsigned long flags;
@@ -947,14 +926,13 @@ static inline void wait_tag_complete(str
 	POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask);
 
 	local_irq_save(flags);
-	out_be64(&priv1->int_stat_class0_RW, ~(0UL));
-	out_be64(&priv1->int_stat_class2_RW, ~(0UL));
+	spu_int_stat_clear(spu, 0, ~(0ul));
+	spu_int_stat_clear(spu, 2, ~(0ul));
 	local_irq_restore(flags);
 }
 
 static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	struct spu_problem __iomem *prob = spu->problem;
 	unsigned long flags;
 
@@ -967,8 +945,8 @@ static inline void wait_spu_stopped(stru
 	POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
 
 	local_irq_save(flags);
-	out_be64(&priv1->int_stat_class0_RW, ~(0UL));
-	out_be64(&priv1->int_stat_class2_RW, ~(0UL));
+	spu_int_stat_clear(spu, 0, ~(0ul));
+	spu_int_stat_clear(spu, 2, ~(0ul));
 	local_irq_restore(flags);
 }
 
@@ -1067,7 +1045,6 @@ static inline int suspend_spe(struct spu
 static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
 {
 	struct spu_problem __iomem *prob = spu->problem;
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 
 	/* Restore, Step 10:
 	 *    If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1,
@@ -1076,8 +1053,8 @@ 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) {
-			out_be64(&priv1->mfc_sr1_RW,
-				 MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+			spu_mfc_sr1_set(spu,
+					MFC_STATE1_MASTER_RUN_CONTROL_MASK);
 			eieio();
 			out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
 			eieio();
@@ -1088,8 +1065,8 @@ static inline void clear_spu_status(stru
 		     SPU_STATUS_ISOLATED_LOAD_STAUTUS)
 		    || (in_be32(&prob->spu_status_R) &
 			SPU_STATUS_ISOLATED_STATE)) {
-			out_be64(&priv1->mfc_sr1_RW,
-				 MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+			spu_mfc_sr1_set(spu,
+					MFC_STATE1_MASTER_RUN_CONTROL_MASK);
 			eieio();
 			out_be32(&prob->spu_runcntl_RW, 0x2);
 			eieio();
@@ -1257,16 +1234,14 @@ static inline void setup_spu_status_part
 
 static inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Restore, Step 29:
 	 *     Restore RA_GROUP_ID register and the
 	 *     RA_ENABLE reigster from the CSA.
 	 */
-	out_be64(&priv1->resource_allocation_groupID_RW,
-		 csa->priv1.resource_allocation_groupID_RW);
-	out_be64(&priv1->resource_allocation_enable_RW,
-		 csa->priv1.resource_allocation_enable_RW);
+	spu_resource_allocation_groupID_set(spu,
+			csa->priv1.resource_allocation_groupID_RW);
+	spu_resource_allocation_enable_set(spu,
+			csa->priv1.resource_allocation_enable_RW);
 }
 
 static inline void send_restore_code(struct spu_state *csa, struct spu *spu)
@@ -1409,8 +1384,6 @@ static inline void restore_ls_16kb(struc
 
 static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Restore, Step 49:
 	 *     Write INT_MASK_class0 with value of 0.
 	 *     Write INT_MASK_class1 with value of 0.
@@ -1420,12 +1393,12 @@ static inline void clear_interrupts(stru
 	 *     Write INT_STAT_class2 with value of -1.
 	 */
 	spin_lock_irq(&spu->register_lock);
-	out_be64(&priv1->int_mask_class0_RW, 0UL);
-	out_be64(&priv1->int_mask_class1_RW, 0UL);
-	out_be64(&priv1->int_mask_class2_RW, 0UL);
-	out_be64(&priv1->int_stat_class0_RW, ~(0UL));
-	out_be64(&priv1->int_stat_class1_RW, ~(0UL));
-	out_be64(&priv1->int_stat_class2_RW, ~(0UL));
+	spu_int_mask_set(spu, 0, 0ul);
+	spu_int_mask_set(spu, 1, 0ul);
+	spu_int_mask_set(spu, 2, 0ul);
+	spu_int_stat_clear(spu, 0, ~0ul);
+	spu_int_stat_clear(spu, 1, ~0ul);
+	spu_int_stat_clear(spu, 2, ~0ul);
 	spin_unlock_irq(&spu->register_lock);
 }
 
@@ -1522,12 +1495,10 @@ static inline void restore_mfc_csr_ato(s
 
 static inline void restore_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Restore, Step 56:
 	 *     Restore the MFC_TCLASS_ID register from CSA.
 	 */
-	out_be64(&priv1->mfc_tclass_id_RW, csa->priv1.mfc_tclass_id_RW);
+	spu_mfc_tclass_id_set(spu, csa->priv1.mfc_tclass_id_RW);
 	eieio();
 }
 
@@ -1689,7 +1660,6 @@ static inline void check_ppu_mb_stat(str
 
 static inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
 	u64 dummy = 0UL;
 
@@ -1700,8 +1670,7 @@ static inline void check_ppuint_mb_stat(
 	if ((csa->prob.mb_stat_R & 0xFF0000) == 0) {
 		dummy = in_be64(&priv2->puint_mb_R);
 		eieio();
-		out_be64(&priv1->int_stat_class2_RW,
-			 CLASS2_ENABLE_MAILBOX_INTR);
+		spu_int_stat_clear(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
 		eieio();
 	}
 }
@@ -1729,12 +1698,10 @@ static inline void restore_mfc_slbs(stru
 
 static inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Restore, Step 69:
 	 *     Restore the MFC_SR1 register from CSA.
 	 */
-	out_be64(&priv1->mfc_sr1_RW, csa->priv1.mfc_sr1_RW);
+	spu_mfc_sr1_set(spu, csa->priv1.mfc_sr1_RW);
 	eieio();
 }
 
@@ -1792,15 +1759,13 @@ static inline void reset_switch_active(s
 
 static inline void reenable_interrupts(struct spu_state *csa, struct spu *spu)
 {
-	struct spu_priv1 __iomem *priv1 = spu->priv1;
-
 	/* Restore, Step 75:
 	 *     Re-enable SPU interrupts.
 	 */
 	spin_lock_irq(&spu->register_lock);
-	out_be64(&priv1->int_mask_class0_RW, csa->priv1.int_mask_class0_RW);
-	out_be64(&priv1->int_mask_class1_RW, csa->priv1.int_mask_class1_RW);
-	out_be64(&priv1->int_mask_class2_RW, csa->priv1.int_mask_class2_RW);
+	spu_int_mask_set(spu, 0, csa->priv1.int_mask_class0_RW);
+	spu_int_mask_set(spu, 1, csa->priv1.int_mask_class1_RW);
+	spu_int_mask_set(spu, 2, csa->priv1.int_mask_class2_RW);
 	spin_unlock_irq(&spu->register_lock);
 }
 
Index: linux-2.6.15-rc/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.15-rc.orig/include/asm-powerpc/spu.h
+++ linux-2.6.15-rc/include/asm-powerpc/spu.h
@@ -172,6 +172,29 @@ static inline void unregister_spu_syscal
 #endif /* MODULE */
 
 
+/* access to priv1 registers */
+void spu_int_mask_and(struct spu *spu, int class, u64 mask);
+void spu_int_mask_or(struct spu *spu, int class, u64 mask);
+void spu_int_mask_set(struct spu *spu, int class, u64 mask);
+u64 spu_int_mask_get(struct spu *spu, int class);
+void spu_int_stat_clear(struct spu *spu, int class, u64 stat);
+u64 spu_int_stat_get(struct spu *spu, int class);
+void spu_int_route_set(struct spu *spu, u64 route);
+u64 spu_mfc_dar_get(struct spu *spu);
+u64 spu_mfc_dsisr_get(struct spu *spu);
+void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr);
+void spu_mfc_sdr_set(struct spu *spu, u64 sdr);
+void spu_mfc_sr1_set(struct spu *spu, u64 sr1);
+u64 spu_mfc_sr1_get(struct spu *spu);
+void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id);
+u64 spu_mfc_tclass_id_get(struct spu *spu);
+void spu_tlb_invalidate(struct spu *spu);
+void spu_resource_allocation_groupID_set(struct spu *spu, u64 id);
+u64 spu_resource_allocation_groupID_get(struct spu *spu);
+void spu_resource_allocation_enable_set(struct spu *spu, u64 enable);
+u64 spu_resource_allocation_enable_get(struct spu *spu);
+
+
 /*
  * This defines the Local Store, Problem Area and Privlege Area of an SPU.
  */
@@ -379,25 +402,21 @@ struct spu_priv1 {
 
 
 	/* Interrupt Area */
-	u64 int_mask_class0_RW;					/* 0x100 */
+	u64 int_mask_RW[3];					/* 0x100 */
 #define CLASS0_ENABLE_DMA_ALIGNMENT_INTR		0x1L
 #define CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR		0x2L
 #define CLASS0_ENABLE_SPU_ERROR_INTR			0x4L
 #define CLASS0_ENABLE_MFC_FIR_INTR			0x8L
-	u64 int_mask_class1_RW;					/* 0x108 */
 #define CLASS1_ENABLE_SEGMENT_FAULT_INTR		0x1L
 #define CLASS1_ENABLE_STORAGE_FAULT_INTR		0x2L
 #define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_GET_INTR	0x4L
 #define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_PUT_INTR	0x8L
-	u64 int_mask_class2_RW;					/* 0x110 */
 #define CLASS2_ENABLE_MAILBOX_INTR			0x1L
 #define CLASS2_ENABLE_SPU_STOP_INTR			0x2L
 #define CLASS2_ENABLE_SPU_HALT_INTR			0x4L
 #define CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR	0x8L
 	u8  pad_0x118_0x140[0x28];				/* 0x118 */
-	u64 int_stat_class0_RW;					/* 0x140 */
-	u64 int_stat_class1_RW;					/* 0x148 */
-	u64 int_stat_class2_RW;					/* 0x150 */
+	u64 int_stat_RW[3];					/* 0x140 */
 	u8  pad_0x158_0x180[0x28];				/* 0x158 */
 	u64 int_route_RW;					/* 0x180 */
 
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/Makefile
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/Makefile
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/Makefile
@@ -2,6 +2,9 @@ obj-y			+= interrupt.o iommu.o setup.o s
 obj-y			+= pervasive.o
 
 obj-$(CONFIG_SMP)	+= smp.o
-obj-$(CONFIG_SPU_FS)	+= spufs/ spu_base.o
+obj-$(CONFIG_SPU_FS)	+= spufs/ spu-base.o
+
+spu-base-y		+= spu_base.o spu_priv1.o
+
 builtin-spufs-$(CONFIG_SPU_FS)	+= spu_syscalls.o
 obj-y			+= $(builtin-spufs-m)

--


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

* [PATCH 11/13] spufs: fix sparse warnings
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (9 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 10/13] spufs: abstract priv1 register access Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 12/13] spufs: fix allocation on 64k pages Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 13/13] spufs: set irq affinity for running threads Arnd Bergmann
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-sparse-fixes.diff --]
[-- Type: text/plain, Size: 2509 bytes --]

One local variable is missing an __iomem modifier,
in another place, we pass a completely unused argument
with a missing __user modifier.

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

Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
@@ -357,7 +357,7 @@ static void spu_init_channels(struct spu
 		{ 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, },
 		{ 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, },
 	};
-	struct spu_priv2 *priv2;
+	struct spu_priv2 __iomem *priv2;
 	int i;
 
 	priv2 = spu->priv2;
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -101,7 +101,7 @@ extern struct tree_descr spufs_dir_conte
 /* system call implementation */
 long spufs_run_spu(struct file *file,
 		   struct spu_context *ctx, u32 *npc, u32 *status);
-long spufs_create_thread(struct nameidata *nd, const char *name,
+long spufs_create_thread(struct nameidata *nd,
 			 unsigned int flags, mode_t mode);
 extern struct file_operations spufs_context_fops;
 
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/inode.c
@@ -293,9 +293,8 @@ out:
 
 static struct file_system_type spufs_type;
 
-long
-spufs_create_thread(struct nameidata *nd, const char *name,
-			unsigned int flags, mode_t mode)
+long spufs_create_thread(struct nameidata *nd,
+			 unsigned int flags, mode_t mode)
 {
 	struct dentry *dentry;
 	int ret;
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/syscalls.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -85,7 +85,7 @@ asmlinkage long sys_spu_create(const cha
 		ret = path_lookup(tmp, LOOKUP_PARENT|
 				LOOKUP_OPEN|LOOKUP_CREATE, &nd);
 		if (!ret) {
-			ret = spufs_create_thread(&nd, pathname, flags, mode);
+			ret = spufs_create_thread(&nd, flags, mode);
 			path_release(&nd);
 		}
 		putname(tmp);

--


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

* [PATCH 12/13] spufs: fix allocation on 64k pages
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (10 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 11/13] spufs: fix sparse warnings Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-04 19:31 ` [PATCH 13/13] spufs: set irq affinity for running threads Arnd Bergmann
  12 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spufs-64k-page.diff --]
[-- Type: text/plain, Size: 746 bytes --]

The size of the local store is architecture defined
and independent from the page size, so it should
not be defined in terms of pages in the first place.

This mistake broke a few places when building for
64kb pages.

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

Index: linux-2.6.15-rc/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.15-rc.orig/include/asm-powerpc/spu.h
+++ linux-2.6.15-rc/include/asm-powerpc/spu.h
@@ -28,9 +28,7 @@
 #include <linux/kref.h>
 #include <linux/workqueue.h>
 
-#define LS_ORDER (6)		/* 256 kb */
-
-#define LS_SIZE (PAGE_SIZE << LS_ORDER)
+#define LS_SIZE (256 * 1024)
 #define LS_ADDR_MASK (LS_SIZE - 1)
 
 #define MFC_PUT_CMD             0x20

--


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

* [PATCH 13/13] spufs: set irq affinity for running threads
  2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
                   ` (11 preceding siblings ...)
  2006-01-04 19:31 ` [PATCH 12/13] spufs: fix allocation on 64k pages Arnd Bergmann
@ 2006-01-04 19:31 ` Arnd Bergmann
  2006-01-05  4:42   ` Nathan Lynch
  12 siblings, 1 reply; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-04 19:31 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: linuxppc64-dev, linux-kernel, Al Viro, Mark Nutter, Arnd Bergmann

[-- Attachment #1: spu-irq-affinity.diff --]
[-- Type: text/plain, Size: 5214 bytes --]

For far, all SPU triggered interrupts always end up on
the first SMT thread, which is a bad solution.

This patch implements setting the affinity to the
CPU that was running last when entering execution on
an SPU. This should result in a significant reduction
in IPI calls and better cache locality for SPE thread
specific data.

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

Index: linux-2.6.15-rc/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.15-rc.orig/include/asm-powerpc/spu.h
+++ linux-2.6.15-rc/include/asm-powerpc/spu.h
@@ -147,6 +147,7 @@ struct spu *spu_alloc(void);
 void spu_free(struct spu *spu);
 int spu_irq_class_0_bottom(struct spu *spu);
 int spu_irq_class_1_bottom(struct spu *spu);
+void spu_irq_setaffinity(struct spu *spu, int cpu);
 
 extern struct spufs_calls {
 	asmlinkage long (*create_thread)(const char __user *name,
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/interrupt.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/interrupt.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/interrupt.c
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/types.h>
 
@@ -55,6 +56,7 @@ struct iic_regs {
 
 struct iic {
 	struct iic_regs __iomem *regs;
+	u8 target_id;
 };
 
 static DEFINE_PER_CPU(struct iic, iic);
@@ -172,12 +174,11 @@ int iic_get_irq(struct pt_regs *regs)
 	return irq;
 }
 
-static struct iic_regs __iomem *find_iic(int cpu)
+static int setup_iic(int cpu, struct iic *iic)
 {
 	struct device_node *np;
 	int nodeid = cpu / 2;
 	unsigned long regs;
-	struct iic_regs __iomem *iic_regs;
 
 	for (np = of_find_node_by_type(NULL, "cpu");
 	     np;
@@ -188,20 +189,23 @@ static struct iic_regs __iomem *find_iic
 
 	if (!np) {
 		printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
-		iic_regs = NULL;
-	} else {
-		regs = *(long *)get_property(np, "iic", NULL);
-
-		/* hack until we have decided on the devtree info */
-		regs += 0x400;
-		if (cpu & 1)
-			regs += 0x20;
-
-		printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
-		iic_regs = __ioremap(regs, sizeof(struct iic_regs),
-						 _PAGE_NO_CACHE);
+		iic->regs = NULL;
+		iic->target_id = 0xff;
+		return -ENODEV;
 	}
-	return iic_regs;
+
+	regs = *(long *)get_property(np, "iic", NULL);
+
+	/* hack until we have decided on the devtree info */
+	regs += 0x400;
+	if (cpu & 1)
+		regs += 0x20;
+
+	printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
+	iic->regs = __ioremap(regs, sizeof(struct iic_regs),
+					 _PAGE_NO_CACHE);
+	iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
+	return 0;
 }
 
 #ifdef CONFIG_SMP
@@ -227,6 +231,12 @@ void iic_cause_IPI(int cpu, int mesg)
 	out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
 }
 
+u8 iic_get_target_id(int cpu)
+{
+	return per_cpu(iic, cpu).target_id;
+}
+EXPORT_SYMBOL_GPL(iic_get_target_id);
+
 static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
 {
 	smp_message_recv(iic_irq_to_ipi(irq), regs);
@@ -276,7 +286,7 @@ void iic_init_IRQ(void)
 	irq_offset = 0;
 	for_each_cpu(cpu) {
 		iic = &per_cpu(iic, cpu);
-		iic->regs = find_iic(cpu);
+		setup_iic(cpu, iic);
 		if (iic->regs)
 			out_be64(&iic->regs->prio, 0xff);
 	}
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/interrupt.h
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/interrupt.h
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/interrupt.h
@@ -54,6 +54,7 @@ extern void iic_setup_cpu(void);
 extern void iic_local_enable(void);
 extern void iic_local_disable(void);
 
+extern u8 iic_get_target_id(int cpu);
 
 extern void spider_init_IRQ(void);
 extern int spider_get_irq(unsigned long int_pending);
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
@@ -507,6 +507,14 @@ int spu_irq_class_1_bottom(struct spu *s
 	return ret;
 }
 
+void spu_irq_setaffinity(struct spu *spu, int cpu)
+{
+	u64 target = iic_get_target_id(cpu);
+	u64 route = target << 48 | target << 32 | target << 16;
+	spu_int_route_set(spu, route);
+}
+EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
+
 static void __iomem * __init map_spe_prop(struct device_node *n,
 						 const char *name)
 {
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/sched.c
@@ -357,6 +357,11 @@ int spu_activate(struct spu_context *ctx
 	if (!spu)
 		return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
 	bind_context(spu, ctx);
+	/*
+	 * We're likely to wait for interrupts on the same
+	 * CPU that we are now on, so send them here.
+	 */
+	spu_irq_setaffinity(spu, smp_processor_id());
 	put_active_spu(spu);
 	return 0;
 }

--


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

* Re: [PATCH 13/13] spufs: set irq affinity for running threads
  2006-01-04 19:31 ` [PATCH 13/13] spufs: set irq affinity for running threads Arnd Bergmann
@ 2006-01-05  4:42   ` Nathan Lynch
  2006-01-05 14:05     ` Arnd Bergmann
  0 siblings, 1 reply; 16+ messages in thread
From: Nathan Lynch @ 2006-01-05  4:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Mackerras, linuxppc64-dev, Arnd Bergmann, linux-kernel,
	Mark Nutter, Al Viro

Arnd Bergmann wrote:
> For far, all SPU triggered interrupts always end up on
> the first SMT thread, which is a bad solution.
> 
> This patch implements setting the affinity to the
> CPU that was running last when entering execution on
> an SPU. This should result in a significant reduction
> in IPI calls and better cache locality for SPE thread
> specific data.

...

> --- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/sched.c
> +++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/sched.c
> @@ -357,6 +357,11 @@ int spu_activate(struct spu_context *ctx
>  	if (!spu)
>  		return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
>  	bind_context(spu, ctx);
> +	/*
> +	 * We're likely to wait for interrupts on the same
> +	 * CPU that we are now on, so send them here.
> +	 */
> +	spu_irq_setaffinity(spu, smp_processor_id());

With CONFIG_DEBUG_PREEMPT this will give a warning about using
smp_processor_id in pre-emptible context if I'm reading the code
correctly.

Maybe use raw_smp_processor_id, since setting the affinity to this cpu
isn't a hard requirement?


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

* Re: [PATCH 13/13] spufs: set irq affinity for running threads
  2006-01-05  4:42   ` Nathan Lynch
@ 2006-01-05 14:05     ` Arnd Bergmann
  0 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2006-01-05 14:05 UTC (permalink / raw)
  To: Nathan Lynch
  Cc: Paul Mackerras, linuxppc64-dev, linux-kernel, Mark Nutter,
	Al Viro

For far, all SPU triggered interrupts always end up on
the first SMT thread, which is a bad solution.

This patch implements setting the affinity to the
CPU that was running last when entering execution on
an SPU. This should result in a significant reduction
in IPI calls and better cache locality for SPE thread
specific data.

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

---

On Thursday 05 January 2006 04:42, Nathan Lynch wrote:
> > +	spu_irq_setaffinity(spu, smp_processor_id());
> 
> With CONFIG_DEBUG_PREEMPT this will give a warning about using
> smp_processor_id in pre-emptible context if I'm reading the code
> correctly.
> 
> Maybe use raw_smp_processor_id, since setting the affinity to this cpu
> isn't a hard requirement?

Good point. Please use this version instead.

	Arnd <><

Index: linux-2.6.15-rc/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.15-rc.orig/include/asm-powerpc/spu.h
+++ linux-2.6.15-rc/include/asm-powerpc/spu.h
@@ -147,6 +147,7 @@ struct spu *spu_alloc(void);
 void spu_free(struct spu *spu);
 int spu_irq_class_0_bottom(struct spu *spu);
 int spu_irq_class_1_bottom(struct spu *spu);
+void spu_irq_setaffinity(struct spu *spu, int cpu);
 
 extern struct spufs_calls {
 	asmlinkage long (*create_thread)(const char __user *name,
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/interrupt.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/interrupt.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/interrupt.c
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/types.h>
 
@@ -55,6 +56,7 @@ struct iic_regs {
 
 struct iic {
 	struct iic_regs __iomem *regs;
+	u8 target_id;
 };
 
 static DEFINE_PER_CPU(struct iic, iic);
@@ -172,12 +174,11 @@ int iic_get_irq(struct pt_regs *regs)
 	return irq;
 }
 
-static struct iic_regs __iomem *find_iic(int cpu)
+static int setup_iic(int cpu, struct iic *iic)
 {
 	struct device_node *np;
 	int nodeid = cpu / 2;
 	unsigned long regs;
-	struct iic_regs __iomem *iic_regs;
 
 	for (np = of_find_node_by_type(NULL, "cpu");
 	     np;
@@ -188,20 +189,23 @@ static struct iic_regs __iomem *find_iic
 
 	if (!np) {
 		printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
-		iic_regs = NULL;
-	} else {
-		regs = *(long *)get_property(np, "iic", NULL);
-
-		/* hack until we have decided on the devtree info */
-		regs += 0x400;
-		if (cpu & 1)
-			regs += 0x20;
-
-		printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
-		iic_regs = __ioremap(regs, sizeof(struct iic_regs),
-						 _PAGE_NO_CACHE);
+		iic->regs = NULL;
+		iic->target_id = 0xff;
+		return -ENODEV;
 	}
-	return iic_regs;
+
+	regs = *(long *)get_property(np, "iic", NULL);
+
+	/* hack until we have decided on the devtree info */
+	regs += 0x400;
+	if (cpu & 1)
+		regs += 0x20;
+
+	printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
+	iic->regs = __ioremap(regs, sizeof(struct iic_regs),
+					 _PAGE_NO_CACHE);
+	iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
+	return 0;
 }
 
 #ifdef CONFIG_SMP
@@ -227,6 +231,12 @@ void iic_cause_IPI(int cpu, int mesg)
 	out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
 }
 
+u8 iic_get_target_id(int cpu)
+{
+	return per_cpu(iic, cpu).target_id;
+}
+EXPORT_SYMBOL_GPL(iic_get_target_id);
+
 static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
 {
 	smp_message_recv(iic_irq_to_ipi(irq), regs);
@@ -276,7 +286,7 @@ void iic_init_IRQ(void)
 	irq_offset = 0;
 	for_each_cpu(cpu) {
 		iic = &per_cpu(iic, cpu);
-		iic->regs = find_iic(cpu);
+		setup_iic(cpu, iic);
 		if (iic->regs)
 			out_be64(&iic->regs->prio, 0xff);
 	}
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/interrupt.h
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/interrupt.h
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/interrupt.h
@@ -54,6 +54,7 @@ extern void iic_setup_cpu(void);
 extern void iic_local_enable(void);
 extern void iic_local_disable(void);
 
+extern u8 iic_get_target_id(int cpu);
 
 extern void spider_init_IRQ(void);
 extern int spider_get_irq(unsigned long int_pending);
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
@@ -507,6 +507,14 @@ int spu_irq_class_1_bottom(struct spu *s
 	return ret;
 }
 
+void spu_irq_setaffinity(struct spu *spu, int cpu)
+{
+	u64 target = iic_get_target_id(cpu);
+	u64 route = target << 48 | target << 32 | target << 16;
+	spu_int_route_set(spu, route);
+}
+EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
+
 static void __iomem * __init map_spe_prop(struct device_node *n,
 						 const char *name)
 {
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.15-rc.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/sched.c
@@ -357,6 +357,11 @@ int spu_activate(struct spu_context *ctx
 	if (!spu)
 		return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
 	bind_context(spu, ctx);
+	/*
+	 * We're likely to wait for interrupts on the same
+	 * CPU that we are now on, so send them here.
+	 */
+	spu_irq_setaffinity(spu, raw_smp_processor_id());
 	put_active_spu(spu);
 	return 0;
 }

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

end of thread, other threads:[~2006-01-05 14:05 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-04 19:31 [PATCH 00/13] spufs fixes and cleanups Arnd Bergmann
2006-01-04 19:31 ` [PATCH 01/13] spufs: fix locking in spu_acquire_runnable Arnd Bergmann
2006-01-04 19:31 ` [PATCH 02/13] spufs: dont hold root->isem in spu_forget Arnd Bergmann
2006-01-04 19:31 ` [PATCH 03/13] spufs: check for proper file pointer in sys_spu_run Arnd Bergmann
2006-01-04 19:31 ` [PATCH 04/13] spufs: serialize sys_spu_run per spu Arnd Bergmann
2006-01-04 19:31 ` [PATCH 05/13] spufs fix spu_acquire_runnable error path Arnd Bergmann
2006-01-04 19:31 ` [PATCH 06/13] spufs: dont leak directories in failed spu_create Arnd Bergmann
2006-01-04 19:31 ` [PATCH 07/13] spufs: fix spufs_fill_dir error path Arnd Bergmann
2006-01-04 19:31 ` [PATCH 08/13] spufs: clean up use of bitops Arnd Bergmann
2006-01-04 19:31 ` [PATCH 09/13] spufs: move spu_run call to its own file Arnd Bergmann
2006-01-04 19:31 ` [PATCH 10/13] spufs: abstract priv1 register access Arnd Bergmann
2006-01-04 19:31 ` [PATCH 11/13] spufs: fix sparse warnings Arnd Bergmann
2006-01-04 19:31 ` [PATCH 12/13] spufs: fix allocation on 64k pages Arnd Bergmann
2006-01-04 19:31 ` [PATCH 13/13] spufs: set irq affinity for running threads Arnd Bergmann
2006-01-05  4:42   ` Nathan Lynch
2006-01-05 14:05     ` Arnd Bergmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox