[Cbe-oss-dev] [PATCH 4/6] spufs: extension of spu_create to support affinity definition
Andre Detsch
adetsch at br.ibm.com
Mon Feb 12 12:14:41 EST 2007
Subject: spufs: extension of spu_create to support affinity definition
From: Andre Detsch <adetsch at br.ibm.com>
This patch adds support for additional flags at spu_create, which relate
to the establishment of affinity between contexts and contexts to memory.
A fourth, optional, parameter is supported. This parameter represent
a affinity neighbor of the context being created, and is used when defining
SPU-SPU affinity.
Affinity is represented as a doubly linked list of spu_contexts.
Signed-off-by: Andre Detsch <adetsch at br.ibm.com>
Index: linux-2.6.20/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6.20/arch/powerpc/platforms/cell/spufs/inode.c
@@ -307,11 +307,102 @@ out:
return ret;
}
-static int spufs_create_context(struct inode *inode,
- struct dentry *dentry,
- struct vfsmount *mnt, int flags, int mode)
+static struct spu_context *
+spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
+ struct file *filp)
+{
+ struct spu_context *tmp, *neighbor = NULL;
+ int count, node;
+ int aff_supp;
+
+ aff_supp = !list_empty(&(list_entry(be_spu_info[0].available_spus.next,
+ struct spu, available_list))->aff_list);
+
+ if (!aff_supp)
+ return ERR_PTR(-ENOTSUPP);
+
+ if (flags & SPU_CREATE_GANG)
+ return ERR_PTR(-EINVAL);
+
+ if (flags & SPU_CREATE_AFFINITY_MEM &&
+ gang->aff_ref_point &&
+ gang->aff_ref_point->aff_flags & AFF_HAS_MEM_AFFINITY)
+ return ERR_PTR(-EEXIST);
+
+ if (flags & SPU_CREATE_AFFINITY_SPU) {
+ if (!filp || filp->f_op != &spufs_context_fops)
+ return ERR_PTR(-EINVAL);
+
+ neighbor = SPUFS_I(filp->f_dentry->d_inode)->i_ctx;
+
+ if (!list_empty(&neighbor->aff_list) &&
+ !(neighbor->aff_flags & AFF_SUBLIST_HEAD) &&
+ !list_entry(neighbor->aff_list.next, struct spu_context,
+ aff_list)->aff_flags & AFF_SUBLIST_HEAD)
+ return ERR_PTR(-EEXIST);
+
+ if (gang != neighbor->gang)
+ return ERR_PTR(-EINVAL);
+
+ count = 1;
+ list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+ count++;
+ if (list_empty(&neighbor->aff_list))
+ count++;
+
+ for (node = 0; node < MAX_NUMNODES; node++) {
+ if ((be_spu_info[node].n_spus - atomic_read(
+ &be_spu_info[node].isolated_spus)) > count)
+ break;
+ }
+
+ if (node == MAX_NUMNODES)
+ return ERR_PTR(-EEXIST);
+ }
+
+ return neighbor;
+}
+
+static void
+spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
+ struct spu_context *neighbor)
+{
+ if (flags & SPU_CREATE_AFFINITY_MEM) {
+ ctx->gang->aff_ref_point = ctx;
+ ctx->aff_flags |= AFF_HAS_MEM_AFFINITY;
+ }
+ if (flags & SPU_CREATE_AFFINITY_SPU) {
+ if (list_empty(&neighbor->aff_list)) {
+ list_add_tail(&neighbor->aff_list,
+ &ctx->gang->aff_list_head);
+ neighbor->aff_flags |= AFF_SUBLIST_HEAD;
+ }
+
+ if (list_is_last(&neighbor->aff_list,&ctx->gang->aff_list_head)
+ || list_entry(neighbor->aff_list.next, struct
+ spu_context, aff_list)->aff_flags & AFF_SUBLIST_HEAD) {
+ list_add(&ctx->aff_list, &neighbor->aff_list);
+ } else {
+ list_add_tail(&ctx->aff_list, &neighbor->aff_list);
+ if (neighbor->aff_flags & AFF_SUBLIST_HEAD) {
+ neighbor->aff_flags &= ~AFF_SUBLIST_HEAD;
+ ctx->aff_flags |= AFF_SUBLIST_HEAD;
+ }
+ }
+
+ if (!ctx->gang->aff_ref_point)
+ ctx->gang->aff_ref_point = ctx;
+ }
+}
+
+static int
+spufs_create_context(struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt, int flags, int mode,
+ struct file *aff_filp)
{
int ret;
+ struct spu_gang *gang = NULL;
+ struct spu_context *neighbor = NULL;
ret = -EPERM;
if ((flags & SPU_CREATE_NOSCHED) &&
@@ -326,10 +417,29 @@ static int spufs_create_context(struct i
ret = -ENODEV;
if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
goto out_unlock;
+ if (flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU)) {
+ gang = SPUFS_I(inode)->i_gang;
+ mutex_lock(&gang->aff_mutex);
+ neighbor = spufs_assert_affinity(flags, gang, aff_filp);
+ if (IS_ERR(neighbor)) {
+ ret = PTR_ERR(neighbor);
+ mutex_unlock(&gang->aff_mutex);
+ goto out_unlock;
+ }
+ }
ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
- if (ret)
+ if (ret) {
+ if (flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU))
+ mutex_unlock(&gang->aff_mutex);
goto out_unlock;
+ }
+
+ if (flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU)) {
+ spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
+ neighbor);
+ mutex_unlock(&gang->aff_mutex);
+ }
/*
* get references for dget and mntget, will be released
@@ -471,7 +581,8 @@ out:
static struct file_system_type spufs_type;
-long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
+long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode,
+ struct file *filp)
{
struct dentry *dentry;
int ret;
@@ -508,7 +619,7 @@ long spufs_create(struct nameidata *nd,
dentry, nd->mnt, mode);
else
return spufs_create_context(nd->dentry->d_inode,
- dentry, nd->mnt, flags, mode);
+ dentry, nd->mnt, flags, mode, filp);
out_dput:
dput(dentry);
Index: linux-2.6.20/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6.20/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -82,15 +82,32 @@ struct spu_context {
struct list_head rq;
unsigned long sched_flags;
int prio;
+
+ struct list_head aff_list;
+ int aff_flags;
};
+/* Flag bits for spu_context aff_flags */
+#define AFF_HAS_MEM_AFFINITY 1
+#define AFF_HAS_SPU_AFFINITY 2
+#define AFF_SUBLIST_HEAD 4
+
struct spu_gang {
struct list_head list;
struct mutex mutex;
struct kref kref;
int contexts;
+
+ struct spu_context *aff_ref_point;
+ struct list_head aff_list_head;
+ struct mutex aff_mutex;
+ int aff_flags;
};
+/* Flag bits for spu_gang aff_flags */
+#define AFF_REL_DISPL_SET 1
+#define AFF_MERGED 2
+
struct mfc_dma_command {
int32_t pad; /* reserved */
uint32_t lsa; /* local storage address */
@@ -155,7 +172,7 @@ extern struct tree_descr spufs_dir_nosch
long spufs_run_spu(struct file *file,
struct spu_context *ctx, u32 *npc, u32 *status);
long spufs_create(struct nameidata *nd,
- unsigned int flags, mode_t mode);
+ unsigned int flags, mode_t mode, struct file *filp);
extern struct file_operations spufs_context_fops;
/* gang management */
Index: linux-2.6.20/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.20.orig/include/asm-powerpc/spu.h
+++ linux-2.6.20/include/asm-powerpc/spu.h
@@ -161,6 +161,7 @@ extern struct be_spu_info be_spu_info[];
struct spu *spu_alloc(void);
struct spu *spu_alloc_node(int node);
+struct spu *spu_alloc_spu(struct spu *spu);
void spu_free(struct spu *spu);
int spu_irq_class_0_bottom(struct spu *spu);
int spu_irq_class_1_bottom(struct spu *spu);
@@ -177,7 +178,8 @@ extern long spu_sys_callback(struct spu_
struct file;
extern struct spufs_calls {
asmlinkage long (*create_thread)(const char __user *name,
- unsigned int flags, mode_t mode);
+ unsigned int flags, mode_t mode,
+ struct file *filp);
asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
__u32 __user *ustatus);
struct module *owner;
@@ -204,8 +206,10 @@ struct spu_coredump_calls {
#define SPU_CREATE_GANG 0x0002
#define SPU_CREATE_NOSCHED 0x0004
#define SPU_CREATE_ISOLATE 0x0008
+#define SPU_CREATE_AFFINITY_SPU 0x0010
+#define SPU_CREATE_AFFINITY_MEM 0x0020
-#define SPU_CREATE_FLAG_ALL 0x000f /* mask of all valid flags */
+#define SPU_CREATE_FLAG_ALL 0x003f /* mask of all valid flags */
#ifdef CONFIG_SPU_FS_MODULE
Index: linux-2.6.20/arch/powerpc/platforms/cell/spufs/gang.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spufs/gang.c
+++ linux-2.6.20/arch/powerpc/platforms/cell/spufs/gang.c
@@ -35,7 +35,9 @@ struct spu_gang *alloc_spu_gang(void)
kref_init(&gang->kref);
mutex_init(&gang->mutex);
+ mutex_init(&gang->aff_mutex);
INIT_LIST_HEAD(&gang->list);
+ INIT_LIST_HEAD(&gang->aff_list_head);
out:
return gang;
@@ -75,6 +77,8 @@ void spu_gang_remove_ctx(struct spu_gang
WARN_ON(ctx->gang != gang);
list_del_init(&ctx->gang_list);
gang->contexts--;
+ if (ctx->aff_flags & (AFF_HAS_SPU_AFFINITY | AFF_HAS_MEM_AFFINITY))
+ list_del(&ctx->aff_list);
mutex_unlock(&gang->mutex);
put_spu_gang(gang);
Index: linux-2.6.20/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spufs/context.c
+++ linux-2.6.20/arch/powerpc/platforms/cell/spufs/context.c
@@ -51,6 +51,7 @@ struct spu_context *alloc_spu_context(st
ctx->state = SPU_STATE_SAVED;
ctx->ops = &spu_backing_ops;
ctx->owner = get_task_mm(current);
+ INIT_LIST_HEAD(&ctx->aff_list);
if (gang)
spu_gang_add_ctx(gang, ctx);
ctx->prio = current->prio;
Index: linux-2.6.20/include/linux/syscalls.h
===================================================================
--- linux-2.6.20.orig/include/linux/syscalls.h
+++ linux-2.6.20/include/linux/syscalls.h
@@ -549,7 +549,7 @@ asmlinkage long sys_inotify_rm_watch(int
asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
__u32 __user *ustatus);
asmlinkage long sys_spu_create(const char __user *name,
- unsigned int flags, mode_t mode);
+ unsigned int flags, mode_t mode, int fd);
asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode,
unsigned dev);
Index: linux-2.6.20/arch/powerpc/platforms/cell/spu_syscalls.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spu_syscalls.c
+++ linux-2.6.20/arch/powerpc/platforms/cell/spu_syscalls.c
@@ -34,14 +34,27 @@ struct spufs_calls spufs_calls = {
* this file is not used and the syscalls directly enter the fs code */
asmlinkage long sys_spu_create(const char __user *name,
- unsigned int flags, mode_t mode)
+ unsigned int flags, mode_t mode, int fd)
{
long ret;
struct module *owner = spufs_calls.owner;
+ struct file *filp;
+ int fput_needed;
ret = -ENOSYS;
if (owner && try_module_get(owner)) {
- ret = spufs_calls.create_thread(name, flags, mode);
+ if (flags & SPU_CREATE_AFFINITY_SPU) {
+ filp = fget_light(fd, &fput_needed);
+ if (filp) {
+ ret = spufs_calls.create_thread(name, flags,
+ mode, filp);
+ fput_light(filp, fput_needed);
+ }
+ }
+ else {
+ ret = spufs_calls.create_thread(name, flags,
+ mode, NULL);
+ }
module_put(owner);
}
return ret;
Index: linux-2.6.20/arch/powerpc/platforms/cell/spufs/syscalls.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ linux-2.6.20/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -76,8 +76,8 @@ asmlinkage long sys_spu_run(int fd, __u3
}
#endif
-asmlinkage long sys_spu_create(const char __user *pathname,
- unsigned int flags, mode_t mode)
+asmlinkage long do_spu_create(const char __user *pathname, unsigned int
flags,
+ mode_t mode, struct file *filp)
{
char *tmp;
int ret;
@@ -90,7 +90,10 @@ asmlinkage long sys_spu_create(const cha
ret = path_lookup(tmp, LOOKUP_PARENT|
LOOKUP_OPEN|LOOKUP_CREATE, &nd);
if (!ret) {
- ret = spufs_create(&nd, flags, mode);
+ if (flags & SPU_CREATE_AFFINITY_SPU)
+ ret = spufs_create(&nd, flags, mode, filp);
+ else
+ ret = spufs_create(&nd, flags, mode, NULL);
path_release(&nd);
}
putname(tmp);
@@ -99,8 +102,32 @@ asmlinkage long sys_spu_create(const cha
return ret;
}
+#ifndef MODULE
+asmlinkage long sys_spu_create(const char __user *pathname, unsigned int
flags,
+ mode_t mode, int fd)
+{
+ int fput_needed;
+ struct file *filp;
+ long ret;
+
+ if (flags & SPU_CREATE_AFFINITY_SPU) {
+ ret = -EBADF;
+ filp = fget_light(fd, &fput_needed);
+ if (filp) {
+ ret = do_spu_create(pathname, flags, mode, filp);
+ fput_light(filp, fput_needed);
+ }
+ }
+ else {
+ ret = do_spu_create(pathname, flags, mode, NULL);
+ }
+
+ return ret;
+}
+#endif
+
struct spufs_calls spufs_calls = {
- .create_thread = sys_spu_create,
+ .create_thread = do_spu_create,
.spu_run = do_spu_run,
.owner = THIS_MODULE,
};
--
Andre Detsch
More information about the cbe-oss-dev
mailing list