diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2007-09-19 00:38:12 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-09-19 01:12:16 -0400 |
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 | |||
13 | endif | 13 | endif |
14 | 14 | ||
15 | # needed only when building loadable spufs.ko | 15 | # needed only when building loadable spufs.ko |
16 | spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o | ||
17 | spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o | 16 | spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o |
18 | 17 | ||
19 | spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o | 18 | spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o |
20 | spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o | 19 | spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o |
21 | 20 | ||
22 | obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ | 21 | obj-$(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 | ||
28 | struct spufs_calls spufs_calls = { | 29 | /* protected by rcu */ |
29 | .owner = NULL, | 30 | static 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 */ | 34 | static 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 | |||
47 | static 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 | |||
57 | static inline struct spufs_calls *spufs_calls_get(void) | ||
58 | { | ||
59 | return spufs_calls; | ||
60 | } | ||
61 | |||
62 | static inline void spufs_calls_put(struct spufs_calls *calls) { } | ||
63 | |||
64 | #endif /* CONFIG_SPU_FS_MODULE */ | ||
35 | 65 | ||
36 | asmlinkage long sys_spu_create(const char __user *name, | 66 | asmlinkage 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 | ||
84 | int register_spu_syscalls(struct spufs_calls *calls) | 114 | int 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 | } |
95 | EXPORT_SYMBOL_GPL(register_spu_syscalls); | 122 | EXPORT_SYMBOL_GPL(register_spu_syscalls); |
96 | 123 | ||
97 | void unregister_spu_syscalls(struct spufs_calls *calls) | 124 | void 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 | } |
102 | EXPORT_SYMBOL_GPL(unregister_spu_syscalls); | 130 | 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[]; | |||
200 | extern struct tree_descr spufs_dir_nosched_contents[]; | 200 | extern struct tree_descr spufs_dir_nosched_contents[]; |
201 | 201 | ||
202 | /* system call implementation */ | 202 | /* system call implementation */ |
203 | extern struct spufs_calls spufs_calls; | ||
203 | long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); | 204 | long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); |
204 | long spufs_create(struct nameidata *nd, unsigned int flags, | 205 | long 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 | ||
62 | asmlinkage 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 | |||
79 | static long do_spu_create(const char __user *pathname, unsigned int flags, | 61 | static 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 | ||
103 | asmlinkage 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 | |||
126 | struct spufs_calls spufs_calls = { | 84 | struct 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 */ |
240 | struct file; | 240 | struct file; |
241 | extern struct spufs_calls { | 241 | struct 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 */ |
251 | struct spu_coredump_calls { | 251 | struct 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 | ||
278 | int register_spu_syscalls(struct spufs_calls *calls); | 277 | int register_spu_syscalls(struct spufs_calls *calls); |
279 | void unregister_spu_syscalls(struct spufs_calls *calls); | 278 | void unregister_spu_syscalls(struct spufs_calls *calls); |
280 | #else | ||
281 | static inline int register_spu_syscalls(struct spufs_calls *calls) | ||
282 | { | ||
283 | return 0; | ||
284 | } | ||
285 | static inline void unregister_spu_syscalls(struct spufs_calls *calls) | ||
286 | { | ||
287 | } | ||
288 | #endif /* MODULE */ | ||
289 | 279 | ||
290 | int register_arch_coredump_calls(struct spu_coredump_calls *calls); | 280 | int register_arch_coredump_calls(struct spu_coredump_calls *calls); |
291 | void unregister_arch_coredump_calls(struct spu_coredump_calls *calls); | 281 | void unregister_arch_coredump_calls(struct spu_coredump_calls *calls); |