1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * SPU file system -- system call stubs 4 * 5 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 6 * (C) Copyright 2006-2007, IBM Corporation 7 * 8 * Author: Arnd Bergmann <arndb@de.ibm.com> 9 */ 10 #include <linux/file.h> 11 #include <linux/fs.h> 12 #include <linux/module.h> 13 #include <linux/syscalls.h> 14 #include <linux/rcupdate.h> 15 #include <linux/binfmts.h> 16 17 #include <asm/spu.h> 18 19 /* protected by rcu */ 20 static struct spufs_calls *spufs_calls; 21 22 #ifdef CONFIG_SPU_FS_MODULE 23 24 static inline struct spufs_calls *spufs_calls_get(void) 25 { 26 struct spufs_calls *calls = NULL; 27 28 rcu_read_lock(); 29 calls = rcu_dereference(spufs_calls); 30 if (calls && !try_module_get(calls->owner)) 31 calls = NULL; 32 rcu_read_unlock(); 33 34 return calls; 35 } 36 37 static inline void spufs_calls_put(struct spufs_calls *calls) 38 { 39 if (!calls) 40 return; 41 42 BUG_ON(calls != spufs_calls); 43 44 /* we don't need to rcu this, as we hold a reference to the module */ 45 module_put(spufs_calls->owner); 46 } 47 48 #else /* !defined CONFIG_SPU_FS_MODULE */ 49 50 static inline struct spufs_calls *spufs_calls_get(void) 51 { 52 return spufs_calls; 53 } 54 55 static inline void spufs_calls_put(struct spufs_calls *calls) { } 56 57 #endif /* CONFIG_SPU_FS_MODULE */ 58 59 DEFINE_CLASS(spufs_calls, struct spufs_calls *, spufs_calls_put(_T), spufs_calls_get(), void) 60 61 SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, 62 umode_t, mode, int, neighbor_fd) 63 { 64 CLASS(spufs_calls, calls)(); 65 if (!calls) 66 return -ENOSYS; 67 68 if (flags & SPU_CREATE_AFFINITY_SPU) { 69 CLASS(fd, neighbor)(neighbor_fd); 70 if (fd_empty(neighbor)) 71 return -EBADF; 72 return calls->create_thread(name, flags, mode, fd_file(neighbor)); 73 } else { 74 return calls->create_thread(name, flags, mode, NULL); 75 } 76 } 77 78 SYSCALL_DEFINE3(spu_run,int, fd, __u32 __user *, unpc, __u32 __user *, ustatus) 79 { 80 CLASS(spufs_calls, calls)(); 81 if (!calls) 82 return -ENOSYS; 83 84 CLASS(fd, arg)(fd); 85 if (fd_empty(arg)) 86 return -EBADF; 87 88 return calls->spu_run(fd_file(arg), unpc, ustatus); 89 } 90 91 #ifdef CONFIG_COREDUMP 92 int elf_coredump_extra_notes_size(void) 93 { 94 CLASS(spufs_calls, calls)(); 95 if (!calls) 96 return 0; 97 98 return calls->coredump_extra_notes_size(); 99 } 100 101 int elf_coredump_extra_notes_write(struct coredump_params *cprm) 102 { 103 CLASS(spufs_calls, calls)(); 104 if (!calls) 105 return 0; 106 107 return calls->coredump_extra_notes_write(cprm); 108 } 109 #endif 110 111 void notify_spus_active(void) 112 { 113 struct spufs_calls *calls; 114 115 calls = spufs_calls_get(); 116 if (!calls) 117 return; 118 119 calls->notify_spus_active(); 120 spufs_calls_put(calls); 121 122 return; 123 } 124 125 int register_spu_syscalls(struct spufs_calls *calls) 126 { 127 if (spufs_calls) 128 return -EBUSY; 129 130 rcu_assign_pointer(spufs_calls, calls); 131 return 0; 132 } 133 EXPORT_SYMBOL_GPL(register_spu_syscalls); 134 135 void unregister_spu_syscalls(struct spufs_calls *calls) 136 { 137 BUG_ON(spufs_calls->owner != calls->owner); 138 RCU_INIT_POINTER(spufs_calls, NULL); 139 synchronize_rcu(); 140 } 141 EXPORT_SYMBOL_GPL(unregister_spu_syscalls); 142