Commit | Line | Data |
---|---|---|
67207b96 AB |
1 | /* |
2 | * SPU file system -- system call stubs | |
3 | * | |
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | |
48cad41f | 5 | * (C) Copyright 2006-2007, IBM Corporation |
67207b96 AB |
6 | * |
7 | * Author: Arnd Bergmann <arndb@de.ibm.com> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2, or (at your option) | |
12 | * any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | */ | |
23 | #include <linux/file.h> | |
e5501492 | 24 | #include <linux/fs.h> |
67207b96 AB |
25 | #include <linux/module.h> |
26 | #include <linux/syscalls.h> | |
98f06978 | 27 | #include <linux/rcupdate.h> |
67207b96 AB |
28 | |
29 | #include <asm/spu.h> | |
30 | ||
98f06978 JK |
31 | /* protected by rcu */ |
32 | static struct spufs_calls *spufs_calls; | |
67207b96 | 33 | |
98f06978 JK |
34 | #ifdef CONFIG_SPU_FS_MODULE |
35 | ||
36 | static inline struct spufs_calls *spufs_calls_get(void) | |
37 | { | |
38 | struct spufs_calls *calls = NULL; | |
39 | ||
40 | rcu_read_lock(); | |
41 | calls = rcu_dereference(spufs_calls); | |
42 | if (calls && !try_module_get(calls->owner)) | |
43 | calls = NULL; | |
44 | rcu_read_unlock(); | |
45 | ||
46 | return calls; | |
47 | } | |
48 | ||
49 | static inline void spufs_calls_put(struct spufs_calls *calls) | |
50 | { | |
51 | BUG_ON(calls != spufs_calls); | |
52 | ||
53 | /* we don't need to rcu this, as we hold a reference to the module */ | |
54 | module_put(spufs_calls->owner); | |
55 | } | |
56 | ||
57 | #else /* !defined CONFIG_SPU_FS_MODULE */ | |
58 | ||
59 | static inline struct spufs_calls *spufs_calls_get(void) | |
60 | { | |
61 | return spufs_calls; | |
62 | } | |
63 | ||
64 | static inline void spufs_calls_put(struct spufs_calls *calls) { } | |
65 | ||
66 | #endif /* CONFIG_SPU_FS_MODULE */ | |
67207b96 | 67 | |
1bc94226 AV |
68 | SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, |
69 | umode_t, mode, int, neighbor_fd) | |
67207b96 AB |
70 | { |
71 | long ret; | |
8e68e2f2 AB |
72 | struct file *neighbor; |
73 | int fput_needed; | |
98f06978 | 74 | struct spufs_calls *calls; |
67207b96 | 75 | |
98f06978 JK |
76 | calls = spufs_calls_get(); |
77 | if (!calls) | |
78 | return -ENOSYS; | |
79 | ||
80 | if (flags & SPU_CREATE_AFFINITY_SPU) { | |
81 | ret = -EBADF; | |
82 | neighbor = fget_light(neighbor_fd, &fput_needed); | |
83 | if (neighbor) { | |
84 | ret = calls->create_thread(name, flags, mode, neighbor); | |
85 | fput_light(neighbor, fput_needed); | |
8e68e2f2 | 86 | } |
98f06978 JK |
87 | } else |
88 | ret = calls->create_thread(name, flags, mode, NULL); | |
89 | ||
90 | spufs_calls_put(calls); | |
67207b96 AB |
91 | return ret; |
92 | } | |
93 | ||
94 | asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) | |
95 | { | |
96 | long ret; | |
97 | struct file *filp; | |
98 | int fput_needed; | |
98f06978 | 99 | struct spufs_calls *calls; |
67207b96 | 100 | |
98f06978 JK |
101 | calls = spufs_calls_get(); |
102 | if (!calls) | |
103 | return -ENOSYS; | |
104 | ||
105 | ret = -EBADF; | |
106 | filp = fget_light(fd, &fput_needed); | |
107 | if (filp) { | |
108 | ret = calls->spu_run(filp, unpc, ustatus); | |
109 | fput_light(filp, fput_needed); | |
67207b96 | 110 | } |
98f06978 JK |
111 | |
112 | spufs_calls_put(calls); | |
67207b96 AB |
113 | return ret; |
114 | } | |
115 | ||
e5501492 | 116 | int elf_coredump_extra_notes_size(void) |
48cad41f ME |
117 | { |
118 | struct spufs_calls *calls; | |
119 | int ret; | |
120 | ||
121 | calls = spufs_calls_get(); | |
122 | if (!calls) | |
123 | return 0; | |
124 | ||
125 | ret = calls->coredump_extra_notes_size(); | |
126 | ||
127 | spufs_calls_put(calls); | |
128 | ||
129 | return ret; | |
130 | } | |
131 | ||
e5501492 | 132 | int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset) |
48cad41f ME |
133 | { |
134 | struct spufs_calls *calls; | |
7af1443a | 135 | int ret; |
48cad41f ME |
136 | |
137 | calls = spufs_calls_get(); | |
138 | if (!calls) | |
e5501492 | 139 | return 0; |
48cad41f | 140 | |
7af1443a | 141 | ret = calls->coredump_extra_notes_write(file, foffset); |
48cad41f ME |
142 | |
143 | spufs_calls_put(calls); | |
e5501492 | 144 | |
7af1443a | 145 | return ret; |
48cad41f ME |
146 | } |
147 | ||
aed3a8c9 BN |
148 | void notify_spus_active(void) |
149 | { | |
150 | struct spufs_calls *calls; | |
151 | ||
152 | calls = spufs_calls_get(); | |
153 | if (!calls) | |
154 | return; | |
155 | ||
156 | calls->notify_spus_active(); | |
157 | spufs_calls_put(calls); | |
158 | ||
159 | return; | |
160 | } | |
161 | ||
67207b96 AB |
162 | int register_spu_syscalls(struct spufs_calls *calls) |
163 | { | |
98f06978 | 164 | if (spufs_calls) |
67207b96 AB |
165 | return -EBUSY; |
166 | ||
98f06978 | 167 | rcu_assign_pointer(spufs_calls, calls); |
67207b96 AB |
168 | return 0; |
169 | } | |
170 | EXPORT_SYMBOL_GPL(register_spu_syscalls); | |
171 | ||
172 | void unregister_spu_syscalls(struct spufs_calls *calls) | |
173 | { | |
98f06978 JK |
174 | BUG_ON(spufs_calls->owner != calls->owner); |
175 | rcu_assign_pointer(spufs_calls, NULL); | |
176 | synchronize_rcu(); | |
67207b96 AB |
177 | } |
178 | EXPORT_SYMBOL_GPL(unregister_spu_syscalls); |