aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2007-09-19 00:38:12 -0400
committerPaul Mackerras <paulus@samba.org>2007-09-19 01:12:16 -0400
commit98f06978ffebbec16abdea58489f217229580859 (patch)
tree4c0cad43f6bc59083e00a20c423864ac579cdf32
parent36ddbb1380f282b4280c57efdb646dd8647a789f (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/Makefile4
-rw-r--r--arch/powerpc/platforms/cell/spu_syscalls.c108
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h1
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c42
-rw-r--r--include/asm-powerpc/spu.h14
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
13endif 13endif
14 14
15# needed only when building loadable spufs.ko 15# needed only when building loadable spufs.ko
16spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
17spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o 16spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o
18 17
19spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o 18spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o
20spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o 19spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o
21 20
22obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ 21obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
23 spu_coredump.o \ 22 spu_coredump.o spu_syscalls.o \
24 $(spufs-modular-m) \
25 $(spu-priv1-y) \ 23 $(spu-priv1-y) \
26 $(spu-manage-y) \ 24 $(spu-manage-y) \
27 spufs/ 25 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 @@
22#include <linux/file.h> 22#include <linux/file.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/syscalls.h> 24#include <linux/syscalls.h>
25#include <linux/rcupdate.h>
25 26
26#include <asm/spu.h> 27#include <asm/spu.h>
27 28
28struct spufs_calls spufs_calls = { 29/* protected by rcu */
29 .owner = NULL, 30static struct spufs_calls *spufs_calls;
30};
31 31
32/* These stub syscalls are needed to have the actual implementation 32#ifdef CONFIG_SPU_FS_MODULE
33 * within a loadable module. When spufs is built into the kernel, 33
34 * this file is not used and the syscalls directly enter the fs code */ 34static inline struct spufs_calls *spufs_calls_get(void)
35{
36 struct spufs_calls *calls = NULL;
37
38 rcu_read_lock();
39 calls = rcu_dereference(spufs_calls);
40 if (calls && !try_module_get(calls->owner))
41 calls = NULL;
42 rcu_read_unlock();
43
44 return calls;
45}
46
47static inline void spufs_calls_put(struct spufs_calls *calls)
48{
49 BUG_ON(calls != spufs_calls);
50
51 /* we don't need to rcu this, as we hold a reference to the module */
52 module_put(spufs_calls->owner);
53}
54
55#else /* !defined CONFIG_SPU_FS_MODULE */
56
57static inline struct spufs_calls *spufs_calls_get(void)
58{
59 return spufs_calls;
60}
61
62static inline void spufs_calls_put(struct spufs_calls *calls) { }
63
64#endif /* CONFIG_SPU_FS_MODULE */
35 65
36asmlinkage long sys_spu_create(const char __user *name, 66asmlinkage long sys_spu_create(const char __user *name,
37 unsigned int flags, mode_t mode, int neighbor_fd) 67 unsigned int flags, mode_t mode, int neighbor_fd)
38{ 68{
39 long ret; 69 long ret;
40 struct module *owner = spufs_calls.owner;
41 struct file *neighbor; 70 struct file *neighbor;
42 int fput_needed; 71 int fput_needed;
72 struct spufs_calls *calls;
43 73
44 ret = -ENOSYS; 74 calls = spufs_calls_get();
45 if (owner && try_module_get(owner)) { 75 if (!calls)
46 if (flags & SPU_CREATE_AFFINITY_SPU) { 76 return -ENOSYS;
47 neighbor = fget_light(neighbor_fd, &fput_needed); 77
48 ret = -EBADF; 78 if (flags & SPU_CREATE_AFFINITY_SPU) {
49 if (neighbor) { 79 ret = -EBADF;
50 ret = spufs_calls.create_thread(name, flags, 80 neighbor = fget_light(neighbor_fd, &fput_needed);
51 mode, neighbor); 81 if (neighbor) {
52 fput_light(neighbor, fput_needed); 82 ret = calls->create_thread(name, flags, mode, neighbor);
53 } 83 fput_light(neighbor, fput_needed);
54 }
55 else {
56 ret = spufs_calls.create_thread(name, flags,
57 mode, NULL);
58 } 84 }
59 module_put(owner); 85 } else
60 } 86 ret = calls->create_thread(name, flags, mode, NULL);
87
88 spufs_calls_put(calls);
61 return ret; 89 return ret;
62} 90}
63 91
@@ -66,37 +94,37 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
66 long ret; 94 long ret;
67 struct file *filp; 95 struct file *filp;
68 int fput_needed; 96 int fput_needed;
69 struct module *owner = spufs_calls.owner; 97 struct spufs_calls *calls;
70 98
71 ret = -ENOSYS; 99 calls = spufs_calls_get();
72 if (owner && try_module_get(owner)) { 100 if (!calls)
73 ret = -EBADF; 101 return -ENOSYS;
74 filp = fget_light(fd, &fput_needed); 102
75 if (filp) { 103 ret = -EBADF;
76 ret = spufs_calls.spu_run(filp, unpc, ustatus); 104 filp = fget_light(fd, &fput_needed);
77 fput_light(filp, fput_needed); 105 if (filp) {
78 } 106 ret = calls->spu_run(filp, unpc, ustatus);
79 module_put(owner); 107 fput_light(filp, fput_needed);
80 } 108 }
109
110 spufs_calls_put(calls);
81 return ret; 111 return ret;
82} 112}
83 113
84int register_spu_syscalls(struct spufs_calls *calls) 114int register_spu_syscalls(struct spufs_calls *calls)
85{ 115{
86 if (spufs_calls.owner) 116 if (spufs_calls)
87 return -EBUSY; 117 return -EBUSY;
88 118
89 spufs_calls.create_thread = calls->create_thread; 119 rcu_assign_pointer(spufs_calls, calls);
90 spufs_calls.spu_run = calls->spu_run;
91 smp_mb();
92 spufs_calls.owner = calls->owner;
93 return 0; 120 return 0;
94} 121}
95EXPORT_SYMBOL_GPL(register_spu_syscalls); 122EXPORT_SYMBOL_GPL(register_spu_syscalls);
96 123
97void unregister_spu_syscalls(struct spufs_calls *calls) 124void unregister_spu_syscalls(struct spufs_calls *calls)
98{ 125{
99 BUG_ON(spufs_calls.owner != calls->owner); 126 BUG_ON(spufs_calls->owner != calls->owner);
100 spufs_calls.owner = NULL; 127 rcu_assign_pointer(spufs_calls, NULL);
128 synchronize_rcu();
101} 129}
102EXPORT_SYMBOL_GPL(unregister_spu_syscalls); 130EXPORT_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[];
200extern struct tree_descr spufs_dir_nosched_contents[]; 200extern struct tree_descr spufs_dir_nosched_contents[];
201 201
202/* system call implementation */ 202/* system call implementation */
203extern struct spufs_calls spufs_calls;
203long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); 204long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status);
204long spufs_create(struct nameidata *nd, unsigned int flags, 205long spufs_create(struct nameidata *nd, unsigned int flags,
205 mode_t mode, struct file *filp); 206 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:
58 return ret; 58 return ret;
59} 59}
60 60
61#ifndef MODULE
62asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
63{
64 int fput_needed;
65 struct file *filp;
66 long ret;
67
68 ret = -EBADF;
69 filp = fget_light(fd, &fput_needed);
70 if (filp) {
71 ret = do_spu_run(filp, unpc, ustatus);
72 fput_light(filp, fput_needed);
73 }
74
75 return ret;
76}
77#endif
78
79static long do_spu_create(const char __user *pathname, unsigned int flags, 61static long do_spu_create(const char __user *pathname, unsigned int flags,
80 mode_t mode, struct file *neighbor) 62 mode_t mode, struct file *neighbor)
81{ 63{
@@ -99,30 +81,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
99 return ret; 81 return ret;
100} 82}
101 83
102#ifndef MODULE
103asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags,
104 mode_t mode, int neighbor_fd)
105{
106 int fput_needed;
107 struct file *neighbor;
108 long ret;
109
110 if (flags & SPU_CREATE_AFFINITY_SPU) {
111 ret = -EBADF;
112 neighbor = fget_light(neighbor_fd, &fput_needed);
113 if (neighbor) {
114 ret = do_spu_create(pathname, flags, mode, neighbor);
115 fput_light(neighbor, fput_needed);
116 }
117 }
118 else {
119 ret = do_spu_create(pathname, flags, mode, NULL);
120 }
121
122 return ret;
123}
124#endif
125
126struct spufs_calls spufs_calls = { 84struct spufs_calls spufs_calls = {
127 .create_thread = do_spu_create, 85 .create_thread = do_spu_create,
128 .spu_run = do_spu_run, 86 .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);
238 238
239/* syscalls implemented in spufs */ 239/* syscalls implemented in spufs */
240struct file; 240struct file;
241extern struct spufs_calls { 241struct spufs_calls {
242 asmlinkage long (*create_thread)(const char __user *name, 242 asmlinkage long (*create_thread)(const char __user *name,
243 unsigned int flags, mode_t mode, 243 unsigned int flags, mode_t mode,
244 struct file *neighbor); 244 struct file *neighbor);
245 asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, 245 asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
246 __u32 __user *ustatus); 246 __u32 __user *ustatus);
247 struct module *owner; 247 struct module *owner;
248} spufs_calls; 248};
249 249
250/* coredump calls implemented in spufs */ 250/* coredump calls implemented in spufs */
251struct spu_coredump_calls { 251struct spu_coredump_calls {
@@ -274,18 +274,8 @@ struct spu_coredump_calls {
274#define SPU_CREATE_FLAG_ALL 0x003f /* mask of all valid flags */ 274#define SPU_CREATE_FLAG_ALL 0x003f /* mask of all valid flags */
275 275
276 276
277#ifdef CONFIG_SPU_FS_MODULE
278int register_spu_syscalls(struct spufs_calls *calls); 277int register_spu_syscalls(struct spufs_calls *calls);
279void unregister_spu_syscalls(struct spufs_calls *calls); 278void unregister_spu_syscalls(struct spufs_calls *calls);
280#else
281static inline int register_spu_syscalls(struct spufs_calls *calls)
282{
283 return 0;
284}
285static inline void unregister_spu_syscalls(struct spufs_calls *calls)
286{
287}
288#endif /* MODULE */
289 279
290int register_arch_coredump_calls(struct spu_coredump_calls *calls); 280int register_arch_coredump_calls(struct spu_coredump_calls *calls);
291void unregister_arch_coredump_calls(struct spu_coredump_calls *calls); 281void unregister_arch_coredump_calls(struct spu_coredump_calls *calls);