162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SPU file system -- system call stubs 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 662306a36Sopenharmony_ci * (C) Copyright 2006-2007, IBM Corporation 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author: Arnd Bergmann <arndb@de.ibm.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/file.h> 1162306a36Sopenharmony_ci#include <linux/fs.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/syscalls.h> 1462306a36Sopenharmony_ci#include <linux/rcupdate.h> 1562306a36Sopenharmony_ci#include <linux/binfmts.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/spu.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* protected by rcu */ 2062306a36Sopenharmony_cistatic struct spufs_calls *spufs_calls; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#ifdef CONFIG_SPU_FS_MODULE 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic inline struct spufs_calls *spufs_calls_get(void) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct spufs_calls *calls = NULL; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci rcu_read_lock(); 2962306a36Sopenharmony_ci calls = rcu_dereference(spufs_calls); 3062306a36Sopenharmony_ci if (calls && !try_module_get(calls->owner)) 3162306a36Sopenharmony_ci calls = NULL; 3262306a36Sopenharmony_ci rcu_read_unlock(); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci return calls; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic inline void spufs_calls_put(struct spufs_calls *calls) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci BUG_ON(calls != spufs_calls); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* we don't need to rcu this, as we hold a reference to the module */ 4262306a36Sopenharmony_ci module_put(spufs_calls->owner); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#else /* !defined CONFIG_SPU_FS_MODULE */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic inline struct spufs_calls *spufs_calls_get(void) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return spufs_calls; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic inline void spufs_calls_put(struct spufs_calls *calls) { } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#endif /* CONFIG_SPU_FS_MODULE */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciSYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, 5762306a36Sopenharmony_ci umode_t, mode, int, neighbor_fd) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci long ret; 6062306a36Sopenharmony_ci struct spufs_calls *calls; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci calls = spufs_calls_get(); 6362306a36Sopenharmony_ci if (!calls) 6462306a36Sopenharmony_ci return -ENOSYS; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (flags & SPU_CREATE_AFFINITY_SPU) { 6762306a36Sopenharmony_ci struct fd neighbor = fdget(neighbor_fd); 6862306a36Sopenharmony_ci ret = -EBADF; 6962306a36Sopenharmony_ci if (neighbor.file) { 7062306a36Sopenharmony_ci ret = calls->create_thread(name, flags, mode, neighbor.file); 7162306a36Sopenharmony_ci fdput(neighbor); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci } else 7462306a36Sopenharmony_ci ret = calls->create_thread(name, flags, mode, NULL); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci spufs_calls_put(calls); 7762306a36Sopenharmony_ci return ret; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciSYSCALL_DEFINE3(spu_run,int, fd, __u32 __user *, unpc, __u32 __user *, ustatus) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci long ret; 8362306a36Sopenharmony_ci struct fd arg; 8462306a36Sopenharmony_ci struct spufs_calls *calls; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci calls = spufs_calls_get(); 8762306a36Sopenharmony_ci if (!calls) 8862306a36Sopenharmony_ci return -ENOSYS; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ret = -EBADF; 9162306a36Sopenharmony_ci arg = fdget(fd); 9262306a36Sopenharmony_ci if (arg.file) { 9362306a36Sopenharmony_ci ret = calls->spu_run(arg.file, unpc, ustatus); 9462306a36Sopenharmony_ci fdput(arg); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci spufs_calls_put(calls); 9862306a36Sopenharmony_ci return ret; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#ifdef CONFIG_COREDUMP 10262306a36Sopenharmony_ciint elf_coredump_extra_notes_size(void) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct spufs_calls *calls; 10562306a36Sopenharmony_ci int ret; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci calls = spufs_calls_get(); 10862306a36Sopenharmony_ci if (!calls) 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ret = calls->coredump_extra_notes_size(); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci spufs_calls_put(calls); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return ret; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciint elf_coredump_extra_notes_write(struct coredump_params *cprm) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct spufs_calls *calls; 12162306a36Sopenharmony_ci int ret; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci calls = spufs_calls_get(); 12462306a36Sopenharmony_ci if (!calls) 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci ret = calls->coredump_extra_notes_write(cprm); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci spufs_calls_put(calls); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return ret; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci#endif 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_civoid notify_spus_active(void) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct spufs_calls *calls; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci calls = spufs_calls_get(); 14062306a36Sopenharmony_ci if (!calls) 14162306a36Sopenharmony_ci return; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci calls->notify_spus_active(); 14462306a36Sopenharmony_ci spufs_calls_put(calls); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ciint register_spu_syscalls(struct spufs_calls *calls) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci if (spufs_calls) 15262306a36Sopenharmony_ci return -EBUSY; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci rcu_assign_pointer(spufs_calls, calls); 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(register_spu_syscalls); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_civoid unregister_spu_syscalls(struct spufs_calls *calls) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci BUG_ON(spufs_calls->owner != calls->owner); 16262306a36Sopenharmony_ci RCU_INIT_POINTER(spufs_calls, NULL); 16362306a36Sopenharmony_ci synchronize_rcu(); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_spu_syscalls); 166