Commit 67207b96 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Paul Mackerras

[PATCH] spufs: The SPU file system, base

This is the current version of the spu file system, used
for driving SPEs on the Cell Broadband Engine.

This release is almost identical to the version for the
2.6.14 kernel posted earlier, which is available as part
of the Cell BE Linux distribution from
http://www.bsc.es/projects/deepcomputing/linuxoncell/.

The first patch provides all the interfaces for running
spu application, but does not have any support for
debugging SPU tasks or for scheduling. Both these
functionalities are added in the subsequent patches.

See Documentation/filesystems/spufs.txt on how to use
spufs.
Signed-off-by: default avatarArnd Bergmann <arndb@de.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent d7a30103
This diff is collapsed.
...@@ -482,6 +482,7 @@ source arch/powerpc/platforms/embedded6xx/Kconfig ...@@ -482,6 +482,7 @@ source arch/powerpc/platforms/embedded6xx/Kconfig
source arch/powerpc/platforms/4xx/Kconfig source arch/powerpc/platforms/4xx/Kconfig
source arch/powerpc/platforms/85xx/Kconfig source arch/powerpc/platforms/85xx/Kconfig
source arch/powerpc/platforms/8xx/Kconfig source arch/powerpc/platforms/8xx/Kconfig
source arch/powerpc/platforms/cell/Kconfig
menu "Kernel options" menu "Kernel options"
......
...@@ -319,3 +319,5 @@ COMPAT_SYS(ioprio_get) ...@@ -319,3 +319,5 @@ COMPAT_SYS(ioprio_get)
SYSCALL(inotify_init) SYSCALL(inotify_init)
SYSCALL(inotify_add_watch) SYSCALL(inotify_add_watch)
SYSCALL(inotify_rm_watch) SYSCALL(inotify_rm_watch)
SYSCALL(spu_run)
SYSCALL(spu_create)
...@@ -644,6 +644,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) ...@@ -644,6 +644,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
DBG_LOW(" -> rc=%d\n", rc); DBG_LOW(" -> rc=%d\n", rc);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(hash_page);
void hash_preload(struct mm_struct *mm, unsigned long ea, void hash_preload(struct mm_struct *mm, unsigned long ea,
unsigned long access, unsigned long trap) unsigned long access, unsigned long trap)
......
menu "Cell Broadband Engine options"
depends on PPC_CELL
config SPU_FS
tristate "SPU file system"
default m
depends on PPC_CELL
help
The SPU file system is used to access Synergistic Processing
Units on machines implementing the Broadband Processor
Architecture.
endmenu
obj-y += interrupt.o iommu.o setup.o spider-pic.o obj-y += interrupt.o iommu.o setup.o spider-pic.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SPU_FS) += spufs/ spu_base.o
builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o
obj-y += $(builtin-spufs-m)
This diff is collapsed.
/*
* SPU file system -- system call stubs
*
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author: Arnd Bergmann <arndb@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/file.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <asm/spu.h>
struct spufs_calls spufs_calls = {
.owner = NULL,
};
/* These stub syscalls are needed to have the actual implementation
* within a loadable module. When spufs is built into the kernel,
* this file is not used and the syscalls directly enter the fs code */
asmlinkage long sys_spu_create(const char __user *name,
unsigned int flags, mode_t mode)
{
long ret;
ret = -ENOSYS;
if (try_module_get(spufs_calls.owner)) {
ret = spufs_calls.create_thread(name, flags, mode);
module_put(spufs_calls.owner);
}
return ret;
}
asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
{
long ret;
struct file *filp;
int fput_needed;
ret = -ENOSYS;
if (try_module_get(spufs_calls.owner)) {
ret = -EBADF;
filp = fget_light(fd, &fput_needed);
if (filp) {
ret = spufs_calls.spu_run(filp, unpc, ustatus);
fput_light(filp, fput_needed);
}
module_put(spufs_calls.owner);
}
return ret;
}
int register_spu_syscalls(struct spufs_calls *calls)
{
if (spufs_calls.owner)
return -EBUSY;
spufs_calls.create_thread = calls->create_thread;
spufs_calls.spu_run = calls->spu_run;
smp_mb();
spufs_calls.owner = calls->owner;
return 0;
}
EXPORT_SYMBOL_GPL(register_spu_syscalls);
void unregister_spu_syscalls(struct spufs_calls *calls)
{
BUG_ON(spufs_calls.owner != calls->owner);
spufs_calls.owner = NULL;
}
EXPORT_SYMBOL_GPL(unregister_spu_syscalls);
obj-$(CONFIG_SPU_FS) += spufs.o
spufs-y += inode.o file.o context.o syscalls.o
/*
* SPU file system -- SPU context management
*
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author: Arnd Bergmann <arndb@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/slab.h>
#include <asm/spu.h>
#include "spufs.h"
struct spu_context *alloc_spu_context(void)
{
struct spu_context *ctx;
ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
if (!ctx)
goto out;
ctx->spu = spu_alloc();
if (!ctx->spu)
goto out_free;
init_rwsem(&ctx->backing_sema);
spin_lock_init(&ctx->mmio_lock);
kref_init(&ctx->kref);
goto out;
out_free:
kfree(ctx);
ctx = NULL;
out:
return ctx;
}
void destroy_spu_context(struct kref *kref)
{
struct spu_context *ctx;
ctx = container_of(kref, struct spu_context, kref);
if (ctx->spu)
spu_free(ctx->spu);
kfree(ctx);
}
struct spu_context * get_spu_context(struct spu_context *ctx)
{
kref_get(&ctx->kref);
return ctx;
}
int put_spu_context(struct spu_context *ctx)
{
return kref_put(&ctx->kref, &destroy_spu_context);
}
This diff is collapsed.
This diff is collapsed.
/*
* SPU file system
*
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author: Arnd Bergmann <arndb@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef SPUFS_H
#define SPUFS_H
#include <linux/kref.h>
#include <linux/rwsem.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <asm/spu.h>
/* The magic number for our file system */
enum {
SPUFS_MAGIC = 0x23c9b64e,
};
struct spu_context {
struct spu *spu; /* pointer to a physical SPU */
struct rw_semaphore backing_sema; /* protects the above */
spinlock_t mmio_lock; /* protects mmio access */
struct kref kref;
};
struct spufs_inode_info {
struct spu_context *i_ctx;
struct inode vfs_inode;
};
#define SPUFS_I(inode) \
container_of(inode, struct spufs_inode_info, vfs_inode)
extern struct tree_descr spufs_dir_contents[];
/* system call implementation */
long spufs_run_spu(struct file *file,
struct spu_context *ctx, u32 *npc, u32 *status);
long spufs_create_thread(struct nameidata *nd, const char *name,
unsigned int flags, mode_t mode);
/* context management */
struct spu_context * alloc_spu_context(void);
void destroy_spu_context(struct kref *kref);
struct spu_context * get_spu_context(struct spu_context *ctx);
int put_spu_context(struct spu_context *ctx);
void spu_acquire(struct spu_context *ctx);
void spu_release(struct spu_context *ctx);
void spu_acquire_runnable(struct spu_context *ctx);
void spu_acquire_saved(struct spu_context *ctx);
#endif
#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))
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 (ret ==-EAGAIN || ret == -EIO)
ret = status;
if (put_user(npc, unpc))
ret = -EFAULT;
if (ustatus && 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,
};
...@@ -307,7 +307,6 @@ EXPORT_SYMBOL(__res); ...@@ -307,7 +307,6 @@ EXPORT_SYMBOL(__res);
EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(next_mmu_context);
EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(set_context);
EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */
EXPORT_SYMBOL(disarm_decr); EXPORT_SYMBOL(disarm_decr);
#ifdef CONFIG_PPC_STD_MMU #ifdef CONFIG_PPC_STD_MMU
extern long mol_trampoline; extern long mol_trampoline;
......
This diff is collapsed.
...@@ -296,6 +296,8 @@ ...@@ -296,6 +296,8 @@
#define __NR_inotify_init 275 #define __NR_inotify_init 275
#define __NR_inotify_add_watch 276 #define __NR_inotify_add_watch 276
#define __NR_inotify_rm_watch 277 #define __NR_inotify_rm_watch 277
#define __NR_spu_run 278
#define __NR_spu_create 279
#define __NR_syscalls 278 #define __NR_syscalls 278
......
...@@ -512,4 +512,9 @@ asmlinkage long sys_ioprio_get(int which, int who); ...@@ -512,4 +512,9 @@ asmlinkage long sys_ioprio_get(int which, int who);
asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask,
unsigned long maxnode); unsigned long maxnode);
asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
__u32 __user *ustatus);
asmlinkage long sys_spu_create(const char __user *name,
unsigned int flags, mode_t mode);
#endif #endif
...@@ -90,3 +90,5 @@ cond_syscall(sys_pciconfig_iobase); ...@@ -90,3 +90,5 @@ cond_syscall(sys_pciconfig_iobase);
cond_syscall(sys32_ipc); cond_syscall(sys32_ipc);
cond_syscall(sys32_sysctl); cond_syscall(sys32_sysctl);
cond_syscall(ppc_rtas); cond_syscall(ppc_rtas);
cond_syscall(sys_spu_run);
cond_syscall(sys_spu_create);
...@@ -2267,6 +2267,8 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -2267,6 +2267,8 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
return handle_pte_fault(mm, vma, address, pte, pmd, write_access); return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
} }
EXPORT_SYMBOL_GPL(__handle_mm_fault);
#ifndef __PAGETABLE_PUD_FOLDED #ifndef __PAGETABLE_PUD_FOLDED
/* /*
* Allocate page upper directory. * Allocate page upper directory.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment