Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98f06978 authored by Jeremy Kerr's avatar Jeremy Kerr Committed by Paul Mackerras
Browse files

[POWERPC] cell: Unify spufs syscall path



At present, a built-in spufs will not use the spufs_calls callbacks, but
directly call sys_spu_create.  This saves us an indirect branch, but
means we have duplicated functions - one for CONFIG_SPU_FS=y and one for
=m.

This change unifies the spufs syscall path, and provides access to the
spufs_calls structure through a get/put pair.  At present, the only user
of the spufs_calls structure is spu_syscalls.c, but this will facilitate
adding the coredump calls later.

Everyone likes numbers, right?  Here's a before/after comparison with
CONFIG_SPU_FS=y, doing spu_create(); close(); 64k times.

Before:
	[jk@cell ~]$ time ./spu_create
	performing 65536 spu_create calls

	real    0m24.075s
	user    0m0.146s
	sys     0m23.925s

After:
	[jk@cell ~]$ time ./spu_create
	performing 65536 spu_create calls

	real    0m24.777s
	user    0m0.141s
	sys     0m24.631s

So, we're adding around 11us per syscall, at the benefit of having
only one syscall path.

Signed-off-by: default avatarJeremy Kerr <jk@ozlabs.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 36ddbb13
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -13,15 +13,13 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o
endif

# needed only when building loadable spufs.ko
spufs-modular-$(CONFIG_SPU_FS)		+= spu_syscalls.o
spu-priv1-$(CONFIG_PPC_CELL_NATIVE)	+= spu_priv1_mmio.o

spu-manage-$(CONFIG_PPC_CELLEB)		+= spu_manage.o
spu-manage-$(CONFIG_PPC_CELL_NATIVE)	+= spu_manage.o

obj-$(CONFIG_SPU_BASE)			+= spu_callbacks.o spu_base.o \
					   spu_coredump.o \
					   $(spufs-modular-m) \
					   spu_coredump.o spu_syscalls.o \
					   $(spu-priv1-y) \
					   $(spu-manage-y) \
					   spufs/
+68 −40
Original line number Diff line number Diff line
@@ -22,42 +22,70 @@
#include <linux/file.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/rcupdate.h>

#include <asm/spu.h>

struct spufs_calls spufs_calls = {
	.owner = NULL,
};
/* protected by rcu */
static struct spufs_calls *spufs_calls;

/* 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 */
#ifdef CONFIG_SPU_FS_MODULE

static inline struct spufs_calls *spufs_calls_get(void)
{
	struct spufs_calls *calls = NULL;

	rcu_read_lock();
	calls = rcu_dereference(spufs_calls);
	if (calls && !try_module_get(calls->owner))
		calls = NULL;
	rcu_read_unlock();

	return calls;
}

static inline void spufs_calls_put(struct spufs_calls *calls)
{
	BUG_ON(calls != spufs_calls);

	/* we don't need to rcu this, as we hold a reference to the module */
	module_put(spufs_calls->owner);
}

#else /* !defined CONFIG_SPU_FS_MODULE */

static inline struct spufs_calls *spufs_calls_get(void)
{
	return spufs_calls;
}

static inline void spufs_calls_put(struct spufs_calls *calls) { }

#endif /* CONFIG_SPU_FS_MODULE */

asmlinkage long sys_spu_create(const char __user *name,
		unsigned int flags, mode_t mode, int neighbor_fd)
{
	long ret;
	struct module *owner = spufs_calls.owner;
	struct file *neighbor;
	int fput_needed;
	struct spufs_calls *calls;

	calls = spufs_calls_get();
	if (!calls)
		return -ENOSYS;

	ret = -ENOSYS;
	if (owner && try_module_get(owner)) {
	if (flags & SPU_CREATE_AFFINITY_SPU) {
			neighbor = fget_light(neighbor_fd, &fput_needed);
		ret = -EBADF;
		neighbor = fget_light(neighbor_fd, &fput_needed);
		if (neighbor) {
				ret = spufs_calls.create_thread(name, flags,
								mode, neighbor);
			ret = calls->create_thread(name, flags, mode, neighbor);
			fput_light(neighbor, fput_needed);
		}
		}
		else {
			ret = spufs_calls.create_thread(name, flags,
							mode, NULL);
		}
		module_put(owner);
	}
	} else
		ret = calls->create_thread(name, flags, mode, NULL);

	spufs_calls_put(calls);
	return ret;
}

@@ -66,37 +94,37 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
	long ret;
	struct file *filp;
	int fput_needed;
	struct module *owner = spufs_calls.owner;
	struct spufs_calls *calls;

	calls = spufs_calls_get();
	if (!calls)
		return -ENOSYS;

	ret = -ENOSYS;
	if (owner && try_module_get(owner)) {
	ret = -EBADF;
	filp = fget_light(fd, &fput_needed);
	if (filp) {
			ret = spufs_calls.spu_run(filp, unpc, ustatus);
		ret = calls->spu_run(filp, unpc, ustatus);
		fput_light(filp, fput_needed);
	}
		module_put(owner);
	}

	spufs_calls_put(calls);
	return ret;
}

int register_spu_syscalls(struct spufs_calls *calls)
{
	if (spufs_calls.owner)
	if (spufs_calls)
		return -EBUSY;

	spufs_calls.create_thread = calls->create_thread;
	spufs_calls.spu_run = calls->spu_run;
	smp_mb();
	spufs_calls.owner = calls->owner;
	rcu_assign_pointer(spufs_calls, calls);
	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;
	BUG_ON(spufs_calls->owner != calls->owner);
	rcu_assign_pointer(spufs_calls, NULL);
	synchronize_rcu();
}
EXPORT_SYMBOL_GPL(unregister_spu_syscalls);
+1 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ extern struct tree_descr spufs_dir_contents[];
extern struct tree_descr spufs_dir_nosched_contents[];

/* system call implementation */
extern struct spufs_calls spufs_calls;
long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status);
long spufs_create(struct nameidata *nd, unsigned int flags,
			mode_t mode, struct file *filp);
+0 −42
Original line number Diff line number Diff line
@@ -58,24 +58,6 @@ static long do_spu_run(struct file *filp,
	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

static long do_spu_create(const char __user *pathname, unsigned int flags,
		mode_t mode, struct file *neighbor)
{
@@ -99,30 +81,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
	return ret;
}

#ifndef MODULE
asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags,
				mode_t mode, int neighbor_fd)
{
	int fput_needed;
	struct file *neighbor;
	long ret;

	if (flags & SPU_CREATE_AFFINITY_SPU) {
		ret = -EBADF;
		neighbor = fget_light(neighbor_fd, &fput_needed);
		if (neighbor) {
			ret = do_spu_create(pathname, flags, mode, neighbor);
			fput_light(neighbor, fput_needed);
		}
	}
	else {
		ret = do_spu_create(pathname, flags, mode, NULL);
	}

	return ret;
}
#endif

struct spufs_calls spufs_calls = {
	.create_thread = do_spu_create,
	.spu_run = do_spu_run,
+2 −12
Original line number Diff line number Diff line
@@ -238,14 +238,14 @@ extern long spu_sys_callback(struct spu_syscall_block *s);

/* syscalls implemented in spufs */
struct file;
extern struct spufs_calls {
struct spufs_calls {
	asmlinkage long (*create_thread)(const char __user *name,
					unsigned int flags, mode_t mode,
					struct file *neighbor);
	asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
						__u32 __user *ustatus);
	struct module *owner;
} spufs_calls;
};

/* coredump calls implemented in spufs */
struct spu_coredump_calls {
@@ -274,18 +274,8 @@ struct spu_coredump_calls {
#define SPU_CREATE_FLAG_ALL		0x003f /* mask of all valid flags */


#ifdef CONFIG_SPU_FS_MODULE
int register_spu_syscalls(struct spufs_calls *calls);
void unregister_spu_syscalls(struct spufs_calls *calls);
#else
static inline int register_spu_syscalls(struct spufs_calls *calls)
{
	return 0;
}
static inline void unregister_spu_syscalls(struct spufs_calls *calls)
{
}
#endif /* MODULE */

int register_arch_coredump_calls(struct spu_coredump_calls *calls);
void unregister_arch_coredump_calls(struct spu_coredump_calls *calls);