linux/arch/powerpc/platforms/cell/spufs/syscalls.c
Arnd Bergmann 8b3d6663c6 [PATCH] spufs: cooperative scheduler support
This adds a scheduler for SPUs to make it possible to use
more logical SPUs than physical ones are present in the
system.

Currently, there is no support for preempting a running
SPU thread, they have to leave the SPU by either triggering
an event on the SPU that causes it to return to the
owning thread or by sending a signal to it.

This patch also adds operations that enable accessing an SPU
in either runnable or saved state. We use an RW semaphore
to protect the state of the SPU from changing underneath
us, while we are holding it readable. In order to change
the state, it is acquired writeable and a context save
or restore is executed before downgrading the semaphore
to read-only.

From: Mark Nutter <mnutter@us.ibm.com>,
      Uli Weigand <Ulrich.Weigand@de.ibm.com>
Signed-off-by: Arnd Bergmann <arndb@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2006-01-09 14:49:30 +11:00

100 lines
2.2 KiB
C

#include <linux/file.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <asm/uaccess.h>
#include "spufs.h"
/**
* sys_spu_run - run code loaded into an SPU
*
* @unpc: next program counter for the SPU
* @ustatus: status of the SPU
*
* This system call transfers the control of execution of a
* user space thread to an SPU. It will return when the
* SPU has finished executing or when it hits an error
* condition and it will be interrupted if a signal needs
* to be delivered to a handler in user space.
*
* The next program counter is set to the passed value
* before the SPU starts fetching code and the user space
* pointer gets updated with the new value when returning
* from kernel space.
*
* The status value returned from spu_run reflects the
* value of the spu_status register after the SPU has stopped.
*
*/
long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus)
{
long ret;
struct spufs_inode_info *i;
u32 npc, status;
ret = -EFAULT;
if (get_user(npc, unpc) || get_user(status, ustatus))
goto out;
ret = -EINVAL;
if (filp->f_vfsmnt->mnt_sb->s_magic != SPUFS_MAGIC)
goto out;
i = SPUFS_I(filp->f_dentry->d_inode);
ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
if (put_user(npc, unpc) || put_user(status, ustatus))
ret = -EFAULT;
out:
return ret;
}
#ifndef MODULE
asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
{
int fput_needed;
struct file *filp;
long ret;
ret = -EBADF;
filp = fget_light(fd, &fput_needed);
if (filp) {
ret = do_spu_run(filp, unpc, ustatus);
fput_light(filp, fput_needed);
}
return ret;
}
#endif
asmlinkage long sys_spu_create(const char __user *pathname,
unsigned int flags, mode_t mode)
{
char *tmp;
int ret;
tmp = getname(pathname);
ret = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
struct nameidata nd;
ret = path_lookup(tmp, LOOKUP_PARENT|
LOOKUP_OPEN|LOOKUP_CREATE, &nd);
if (!ret) {
ret = spufs_create_thread(&nd, pathname, flags, mode);
path_release(&nd);
}
putname(tmp);
}
return ret;
}
struct spufs_calls spufs_calls = {
.create_thread = sys_spu_create,
.spu_run = do_spu_run,
.owner = THIS_MODULE,
};