linux/arch/powerpc/platforms/cell/spu_syscalls.c
<<
>>
Prefs
   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 */
  20static struct spufs_calls *spufs_calls;
  21
  22#ifdef CONFIG_SPU_FS_MODULE
  23
  24static 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
  37static inline void spufs_calls_put(struct spufs_calls *calls)
  38{
  39        BUG_ON(calls != spufs_calls);
  40
  41        /* we don't need to rcu this, as we hold a reference to the module */
  42        module_put(spufs_calls->owner);
  43}
  44
  45#else /* !defined CONFIG_SPU_FS_MODULE */
  46
  47static inline struct spufs_calls *spufs_calls_get(void)
  48{
  49        return spufs_calls;
  50}
  51
  52static inline void spufs_calls_put(struct spufs_calls *calls) { }
  53
  54#endif /* CONFIG_SPU_FS_MODULE */
  55
  56SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags,
  57        umode_t, mode, int, neighbor_fd)
  58{
  59        long ret;
  60        struct spufs_calls *calls;
  61
  62        calls = spufs_calls_get();
  63        if (!calls)
  64                return -ENOSYS;
  65
  66        if (flags & SPU_CREATE_AFFINITY_SPU) {
  67                struct fd neighbor = fdget(neighbor_fd);
  68                ret = -EBADF;
  69                if (neighbor.file) {
  70                        ret = calls->create_thread(name, flags, mode, neighbor.file);
  71                        fdput(neighbor);
  72                }
  73        } else
  74                ret = calls->create_thread(name, flags, mode, NULL);
  75
  76        spufs_calls_put(calls);
  77        return ret;
  78}
  79
  80SYSCALL_DEFINE3(spu_run,int, fd, __u32 __user *, unpc, __u32 __user *, ustatus)
  81{
  82        long ret;
  83        struct fd arg;
  84        struct spufs_calls *calls;
  85
  86        calls = spufs_calls_get();
  87        if (!calls)
  88                return -ENOSYS;
  89
  90        ret = -EBADF;
  91        arg = fdget(fd);
  92        if (arg.file) {
  93                ret = calls->spu_run(arg.file, unpc, ustatus);
  94                fdput(arg);
  95        }
  96
  97        spufs_calls_put(calls);
  98        return ret;
  99}
 100
 101#ifdef CONFIG_COREDUMP
 102int elf_coredump_extra_notes_size(void)
 103{
 104        struct spufs_calls *calls;
 105        int ret;
 106
 107        calls = spufs_calls_get();
 108        if (!calls)
 109                return 0;
 110
 111        ret = calls->coredump_extra_notes_size();
 112
 113        spufs_calls_put(calls);
 114
 115        return ret;
 116}
 117
 118int elf_coredump_extra_notes_write(struct coredump_params *cprm)
 119{
 120        struct spufs_calls *calls;
 121        int ret;
 122
 123        calls = spufs_calls_get();
 124        if (!calls)
 125                return 0;
 126
 127        ret = calls->coredump_extra_notes_write(cprm);
 128
 129        spufs_calls_put(calls);
 130
 131        return ret;
 132}
 133#endif
 134
 135void notify_spus_active(void)
 136{
 137        struct spufs_calls *calls;
 138
 139        calls = spufs_calls_get();
 140        if (!calls)
 141                return;
 142
 143        calls->notify_spus_active();
 144        spufs_calls_put(calls);
 145
 146        return;
 147}
 148
 149int register_spu_syscalls(struct spufs_calls *calls)
 150{
 151        if (spufs_calls)
 152                return -EBUSY;
 153
 154        rcu_assign_pointer(spufs_calls, calls);
 155        return 0;
 156}
 157EXPORT_SYMBOL_GPL(register_spu_syscalls);
 158
 159void unregister_spu_syscalls(struct spufs_calls *calls)
 160{
 161        BUG_ON(spufs_calls->owner != calls->owner);
 162        RCU_INIT_POINTER(spufs_calls, NULL);
 163        synchronize_rcu();
 164}
 165EXPORT_SYMBOL_GPL(unregister_spu_syscalls);
 166