linux/arch/powerpc/platforms/cell/spu_syscalls.c
<<
>>
Prefs
   1/*
   2 * SPU file system -- system call stubs
   3 *
   4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
   5 * (C) Copyright 2006-2007, IBM Corporation
   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>
  24#include <linux/fs.h>
  25#include <linux/module.h>
  26#include <linux/syscalls.h>
  27#include <linux/rcupdate.h>
  28#include <linux/binfmts.h>
  29
  30#include <asm/spu.h>
  31
  32/* protected by rcu */
  33static struct spufs_calls *spufs_calls;
  34
  35#ifdef CONFIG_SPU_FS_MODULE
  36
  37static inline struct spufs_calls *spufs_calls_get(void)
  38{
  39        struct spufs_calls *calls = NULL;
  40
  41        rcu_read_lock();
  42        calls = rcu_dereference(spufs_calls);
  43        if (calls && !try_module_get(calls->owner))
  44                calls = NULL;
  45        rcu_read_unlock();
  46
  47        return calls;
  48}
  49
  50static inline void spufs_calls_put(struct spufs_calls *calls)
  51{
  52        BUG_ON(calls != spufs_calls);
  53
  54        /* we don't need to rcu this, as we hold a reference to the module */
  55        module_put(spufs_calls->owner);
  56}
  57
  58#else /* !defined CONFIG_SPU_FS_MODULE */
  59
  60static inline struct spufs_calls *spufs_calls_get(void)
  61{
  62        return spufs_calls;
  63}
  64
  65static inline void spufs_calls_put(struct spufs_calls *calls) { }
  66
  67#endif /* CONFIG_SPU_FS_MODULE */
  68
  69SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags,
  70        umode_t, mode, int, neighbor_fd)
  71{
  72        long ret;
  73        struct spufs_calls *calls;
  74
  75        calls = spufs_calls_get();
  76        if (!calls)
  77                return -ENOSYS;
  78
  79        if (flags & SPU_CREATE_AFFINITY_SPU) {
  80                struct fd neighbor = fdget(neighbor_fd);
  81                ret = -EBADF;
  82                if (neighbor.file) {
  83                        ret = calls->create_thread(name, flags, mode, neighbor.file);
  84                        fdput(neighbor);
  85                }
  86        } else
  87                ret = calls->create_thread(name, flags, mode, NULL);
  88
  89        spufs_calls_put(calls);
  90        return ret;
  91}
  92
  93asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
  94{
  95        long ret;
  96        struct fd arg;
  97        struct spufs_calls *calls;
  98
  99        calls = spufs_calls_get();
 100        if (!calls)
 101                return -ENOSYS;
 102
 103        ret = -EBADF;
 104        arg = fdget(fd);
 105        if (arg.file) {
 106                ret = calls->spu_run(arg.file, unpc, ustatus);
 107                fdput(arg);
 108        }
 109
 110        spufs_calls_put(calls);
 111        return ret;
 112}
 113
 114#ifdef CONFIG_COREDUMP
 115int elf_coredump_extra_notes_size(void)
 116{
 117        struct spufs_calls *calls;
 118        int ret;
 119
 120        calls = spufs_calls_get();
 121        if (!calls)
 122                return 0;
 123
 124        ret = calls->coredump_extra_notes_size();
 125
 126        spufs_calls_put(calls);
 127
 128        return ret;
 129}
 130
 131int elf_coredump_extra_notes_write(struct coredump_params *cprm)
 132{
 133        struct spufs_calls *calls;
 134        int ret;
 135
 136        calls = spufs_calls_get();
 137        if (!calls)
 138                return 0;
 139
 140        ret = calls->coredump_extra_notes_write(cprm);
 141
 142        spufs_calls_put(calls);
 143
 144        return ret;
 145}
 146#endif
 147
 148void 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
 162int register_spu_syscalls(struct spufs_calls *calls)
 163{
 164        if (spufs_calls)
 165                return -EBUSY;
 166
 167        rcu_assign_pointer(spufs_calls, calls);
 168        return 0;
 169}
 170EXPORT_SYMBOL_GPL(register_spu_syscalls);
 171
 172void unregister_spu_syscalls(struct spufs_calls *calls)
 173{
 174        BUG_ON(spufs_calls->owner != calls->owner);
 175        RCU_INIT_POINTER(spufs_calls, NULL);
 176        synchronize_rcu();
 177}
 178EXPORT_SYMBOL_GPL(unregister_spu_syscalls);
 179