0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/file.h>
0011 #include <linux/fs.h>
0012 #include <linux/module.h>
0013 #include <linux/syscalls.h>
0014 #include <linux/rcupdate.h>
0015 #include <linux/binfmts.h>
0016
0017 #include <asm/spu.h>
0018
0019
0020 static struct spufs_calls *spufs_calls;
0021
0022 #ifdef CONFIG_SPU_FS_MODULE
0023
0024 static inline struct spufs_calls *spufs_calls_get(void)
0025 {
0026 struct spufs_calls *calls = NULL;
0027
0028 rcu_read_lock();
0029 calls = rcu_dereference(spufs_calls);
0030 if (calls && !try_module_get(calls->owner))
0031 calls = NULL;
0032 rcu_read_unlock();
0033
0034 return calls;
0035 }
0036
0037 static inline void spufs_calls_put(struct spufs_calls *calls)
0038 {
0039 BUG_ON(calls != spufs_calls);
0040
0041
0042 module_put(spufs_calls->owner);
0043 }
0044
0045 #else
0046
0047 static inline struct spufs_calls *spufs_calls_get(void)
0048 {
0049 return spufs_calls;
0050 }
0051
0052 static inline void spufs_calls_put(struct spufs_calls *calls) { }
0053
0054 #endif
0055
0056 SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags,
0057 umode_t, mode, int, neighbor_fd)
0058 {
0059 long ret;
0060 struct spufs_calls *calls;
0061
0062 calls = spufs_calls_get();
0063 if (!calls)
0064 return -ENOSYS;
0065
0066 if (flags & SPU_CREATE_AFFINITY_SPU) {
0067 struct fd neighbor = fdget(neighbor_fd);
0068 ret = -EBADF;
0069 if (neighbor.file) {
0070 ret = calls->create_thread(name, flags, mode, neighbor.file);
0071 fdput(neighbor);
0072 }
0073 } else
0074 ret = calls->create_thread(name, flags, mode, NULL);
0075
0076 spufs_calls_put(calls);
0077 return ret;
0078 }
0079
0080 SYSCALL_DEFINE3(spu_run,int, fd, __u32 __user *, unpc, __u32 __user *, ustatus)
0081 {
0082 long ret;
0083 struct fd arg;
0084 struct spufs_calls *calls;
0085
0086 calls = spufs_calls_get();
0087 if (!calls)
0088 return -ENOSYS;
0089
0090 ret = -EBADF;
0091 arg = fdget(fd);
0092 if (arg.file) {
0093 ret = calls->spu_run(arg.file, unpc, ustatus);
0094 fdput(arg);
0095 }
0096
0097 spufs_calls_put(calls);
0098 return ret;
0099 }
0100
0101 #ifdef CONFIG_COREDUMP
0102 int elf_coredump_extra_notes_size(void)
0103 {
0104 struct spufs_calls *calls;
0105 int ret;
0106
0107 calls = spufs_calls_get();
0108 if (!calls)
0109 return 0;
0110
0111 ret = calls->coredump_extra_notes_size();
0112
0113 spufs_calls_put(calls);
0114
0115 return ret;
0116 }
0117
0118 int elf_coredump_extra_notes_write(struct coredump_params *cprm)
0119 {
0120 struct spufs_calls *calls;
0121 int ret;
0122
0123 calls = spufs_calls_get();
0124 if (!calls)
0125 return 0;
0126
0127 ret = calls->coredump_extra_notes_write(cprm);
0128
0129 spufs_calls_put(calls);
0130
0131 return ret;
0132 }
0133 #endif
0134
0135 void notify_spus_active(void)
0136 {
0137 struct spufs_calls *calls;
0138
0139 calls = spufs_calls_get();
0140 if (!calls)
0141 return;
0142
0143 calls->notify_spus_active();
0144 spufs_calls_put(calls);
0145
0146 return;
0147 }
0148
0149 int register_spu_syscalls(struct spufs_calls *calls)
0150 {
0151 if (spufs_calls)
0152 return -EBUSY;
0153
0154 rcu_assign_pointer(spufs_calls, calls);
0155 return 0;
0156 }
0157 EXPORT_SYMBOL_GPL(register_spu_syscalls);
0158
0159 void unregister_spu_syscalls(struct spufs_calls *calls)
0160 {
0161 BUG_ON(spufs_calls->owner != calls->owner);
0162 RCU_INIT_POINTER(spufs_calls, NULL);
0163 synchronize_rcu();
0164 }
0165 EXPORT_SYMBOL_GPL(unregister_spu_syscalls);