diff options
author | Jeremy Kerr | 2007-09-19 14:38:12 +1000 |
---|---|---|
committer | Paul Mackerras | 2007-09-19 15:12:16 +1000 |
commit | 98f06978ffebbec16abdea58489f217229580859 (patch) | |
tree | 4c0cad43f6bc59083e00a20c423864ac579cdf32 | |
parent | 36ddbb1380f282b4280c57efdb646dd8647a789f (diff) |
[POWERPC] cell: Unify spufs syscall path
At present, a built-in spufs will not use the spufs_calls callbacks, but
directly call sys_spu_create. This saves us an indirect branch, but
means we have duplicated functions - one for CONFIG_SPU_FS=y and one for
=m.
This change unifies the spufs syscall path, and provides access to the
spufs_calls structure through a get/put pair. At present, the only user
of the spufs_calls structure is spu_syscalls.c, but this will facilitate
adding the coredump calls later.
Everyone likes numbers, right? Here's a before/after comparison with
CONFIG_SPU_FS=y, doing spu_create(); close(); 64k times.
Before:
[jk@cell ~]$ time ./spu_create
performing 65536 spu_create calls
real 0m24.075s
user 0m0.146s
sys 0m23.925s
After:
[jk@cell ~]$ time ./spu_create
performing 65536 spu_create calls
real 0m24.777s
user 0m0.141s
sys 0m24.631s
So, we're adding around 11us per syscall, at the benefit of having
only one syscall path.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/cell/Makefile | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spu_syscalls.c | 108 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/syscalls.c | 42 | ||||
-rw-r--r-- | include/asm-powerpc/spu.h | 14 |
5 files changed, 72 insertions, 97 deletions
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index f88a7c76f296..40f78e908953 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -13,15 +13,13 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o endif # needed only when building loadable spufs.ko -spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ - spu_coredump.o \ - $(spufs-modular-m) \ + spu_coredump.o spu_syscalls.o \ $(spu-priv1-y) \ $(spu-manage-y) \ spufs/ diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index 027ac32cc636..c0238dd9ff27 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -22,42 +22,70 @@ #include <linux/file.h> #include <linux/module.h> #include <linux/syscalls.h> +#include <linux/rcupdate.h> #include <asm/spu.h> -struct spufs_calls spufs_calls = { - .owner = NULL, -}; +/* protected by rcu */ +static struct spufs_calls *spufs_calls; -/* These stub syscalls are needed to have the actual implementation - * within a loadable module. When spufs is built into the kernel, - * this file is not used and the syscalls directly enter the fs code */ +#ifdef CONFIG_SPU_FS_MODULE + +static inline struct spufs_calls *spufs_calls_get(void) +{ + struct spufs_calls *calls = NULL; + + rcu_read_lock(); + calls = rcu_dereference(spufs_calls); + if (calls && !try_module_get(calls->owner)) + calls = NULL; + rcu_read_unlock(); + + return calls; +} + +static inline void spufs_calls_put(struct spufs_calls *calls) +{ + BUG_ON(calls != spufs_calls); + + /* we don't need to rcu this, as we hold a reference to the module */ + module_put(spufs_calls->owner); +} + +#else /* !defined CONFIG_SPU_FS_MODULE */ + +static inline struct spufs_calls *spufs_calls_get(void) +{ + return spufs_calls; +} + +static inline void spufs_calls_put(struct spufs_calls *calls) { } + +#endif /* CONFIG_SPU_FS_MODULE */ asmlinkage long sys_spu_create(const char __user *name, unsigned int flags, mode_t mode, int neighbor_fd) { long ret; - struct module *owner = spufs_calls.owner; struct file *neighbor; int fput_needed; + struct spufs_calls *calls; - ret = -ENOSYS; - if (owner && try_module_get(owner)) { - if (flags & SPU_CREATE_AFFINITY_SPU) { - neighbor = fget_light(neighbor_fd, &fput_needed); - ret = -EBADF; - if (neighbor) { - ret = spufs_calls.create_thread(name, flags, - mode, neighbor); - fput_light(neighbor, fput_needed); - } - } - else { - ret = spufs_calls.create_thread(name, flags, - mode, NULL); + calls = spufs_calls_get(); + if (!calls) + return -ENOSYS; + + if (flags & SPU_CREATE_AFFINITY_SPU) { + ret = -EBADF; + neighbor = fget_light(neighbor_fd, &fput_needed); + if (neighbor) { + ret = calls->create_thread(name, flags, mode, neighbor); + fput_light(neighbor, fput_needed); } - module_put(owner); - } + } else + ret = calls->create_thread(name, flags, mode, NULL); + + spufs_calls_put(calls); return ret; } @@ -66,37 +94,37 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) long ret; struct file *filp; int fput_needed; - struct module *owner = spufs_calls.owner; + struct spufs_calls *calls; - ret = -ENOSYS; - if (owner && try_module_get(owner)) { - ret = -EBADF; - filp = fget_light(fd, &fput_needed); - if (filp) { - ret = spufs_calls.spu_run(filp, unpc, ustatus); - fput_light(filp, fput_needed); - } - module_put(owner); + calls = spufs_calls_get(); + if (!calls) + return -ENOSYS; + + ret = -EBADF; + filp = fget_light(fd, &fput_needed); + if (filp) { + ret = calls->spu_run(filp, unpc, ustatus); + fput_light(filp, fput_needed); } + + spufs_calls_put(calls); return ret; } int register_spu_syscalls(struct spufs_calls *calls) { - if (spufs_calls.owner) + if (spufs_calls) return -EBUSY; - spufs_calls.create_thread = calls->create_thread; - spufs_calls.spu_run = calls->spu_run; - smp_mb(); - spufs_calls.owner = calls->owner; + rcu_assign_pointer(spufs_calls, calls); return 0; } EXPORT_SYMBOL_GPL(register_spu_syscalls); void unregister_spu_syscalls(struct spufs_calls *calls) { - BUG_ON(spufs_calls.owner != calls->owner); - spufs_calls.owner = NULL; + BUG_ON(spufs_calls->owner != calls->owner); + rcu_assign_pointer(spufs_calls, NULL); + synchronize_rcu(); } EXPORT_SYMBOL_GPL(unregister_spu_syscalls); diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 2bfdeb8ea8bd..3dbffebb3cef 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -200,6 +200,7 @@ extern struct tree_descr spufs_dir_contents[]; extern struct tree_descr spufs_dir_nosched_contents[]; /* system call implementation */ +extern struct spufs_calls spufs_calls; long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, struct file *filp); diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 936e0a8af3a9..22b138dc335c 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -58,24 +58,6 @@ out: return ret; } -#ifndef MODULE -asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) -{ - int fput_needed; - struct file *filp; - long ret; - - ret = -EBADF; - filp = fget_light(fd, &fput_needed); - if (filp) { - ret = do_spu_run(filp, unpc, ustatus); - fput_light(filp, fput_needed); - } - - return ret; -} -#endif - static long do_spu_create(const char __user *pathname, unsigned int flags, mode_t mode, struct file *neighbor) { @@ -99,30 +81,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags, return ret; } -#ifndef MODULE -asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags, - mode_t mode, int neighbor_fd) -{ - int fput_needed; - struct file *neighbor; - long ret; - - if (flags & SPU_CREATE_AFFINITY_SPU) { - ret = -EBADF; - neighbor = fget_light(neighbor_fd, &fput_needed); - if (neighbor) { - ret = do_spu_create(pathname, flags, mode, neighbor); - fput_light(neighbor, fput_needed); - } - } - else { - ret = do_spu_create(pathname, flags, mode, NULL); - } - - return ret; -} -#endif - struct spufs_calls spufs_calls = { .create_thread = do_spu_create, .spu_run = do_spu_run, diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 5bde3980bf49..383ecfdf7eb0 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -238,14 +238,14 @@ extern long spu_sys_callback(struct spu_syscall_block *s); /* syscalls implemented in spufs */ struct file; -extern struct spufs_calls { +struct spufs_calls { asmlinkage long (*create_thread)(const char __user *name, unsigned int flags, mode_t mode, struct file *neighbor); asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus); struct module *owner; -} spufs_calls; +}; /* coredump calls implemented in spufs */ struct spu_coredump_calls { @@ -274,18 +274,8 @@ struct spu_coredump_calls { #define SPU_CREATE_FLAG_ALL 0x003f /* mask of all valid flags */ -#ifdef CONFIG_SPU_FS_MODULE int register_spu_syscalls(struct spufs_calls *calls); void unregister_spu_syscalls(struct spufs_calls *calls); -#else -static inline int register_spu_syscalls(struct spufs_calls *calls) -{ - return 0; -} -static inline void unregister_spu_syscalls(struct spufs_calls *calls) -{ -} -#endif /* MODULE */ int register_arch_coredump_calls(struct spu_coredump_calls *calls); void unregister_arch_coredump_calls(struct spu_coredump_calls *calls); |