167207b96SArnd Bergmann /*
267207b96SArnd Bergmann  * SPU file system -- file contents
367207b96SArnd Bergmann  *
467207b96SArnd Bergmann  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
567207b96SArnd Bergmann  *
667207b96SArnd Bergmann  * Author: Arnd Bergmann <arndb@de.ibm.com>
767207b96SArnd Bergmann  *
867207b96SArnd Bergmann  * This program is free software; you can redistribute it and/or modify
967207b96SArnd Bergmann  * it under the terms of the GNU General Public License as published by
1067207b96SArnd Bergmann  * the Free Software Foundation; either version 2, or (at your option)
1167207b96SArnd Bergmann  * any later version.
1267207b96SArnd Bergmann  *
1367207b96SArnd Bergmann  * This program is distributed in the hope that it will be useful,
1467207b96SArnd Bergmann  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1567207b96SArnd Bergmann  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1667207b96SArnd Bergmann  * GNU General Public License for more details.
1767207b96SArnd Bergmann  *
1867207b96SArnd Bergmann  * You should have received a copy of the GNU General Public License
1967207b96SArnd Bergmann  * along with this program; if not, write to the Free Software
2067207b96SArnd Bergmann  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2167207b96SArnd Bergmann  */
2267207b96SArnd Bergmann 
2367207b96SArnd Bergmann #include <linux/fs.h>
2467207b96SArnd Bergmann #include <linux/ioctl.h>
2567207b96SArnd Bergmann #include <linux/module.h>
2667207b96SArnd Bergmann #include <linux/poll.h>
2767207b96SArnd Bergmann 
2867207b96SArnd Bergmann #include <asm/io.h>
2967207b96SArnd Bergmann #include <asm/semaphore.h>
3067207b96SArnd Bergmann #include <asm/spu.h>
3167207b96SArnd Bergmann #include <asm/uaccess.h>
3267207b96SArnd Bergmann 
3367207b96SArnd Bergmann #include "spufs.h"
3467207b96SArnd Bergmann 
358b3d6663SArnd Bergmann 
3667207b96SArnd Bergmann static int
3767207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file)
3867207b96SArnd Bergmann {
3967207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
4067207b96SArnd Bergmann 	file->private_data = i->i_ctx;
418b3d6663SArnd Bergmann 	file->f_mapping = i->i_ctx->local_store;
4267207b96SArnd Bergmann 	return 0;
4367207b96SArnd Bergmann }
4467207b96SArnd Bergmann 
4567207b96SArnd Bergmann static ssize_t
4667207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer,
4767207b96SArnd Bergmann 				size_t size, loff_t *pos)
4867207b96SArnd Bergmann {
498b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
508b3d6663SArnd Bergmann 	char *local_store;
5167207b96SArnd Bergmann 	int ret;
5267207b96SArnd Bergmann 
538b3d6663SArnd Bergmann 	spu_acquire(ctx);
5467207b96SArnd Bergmann 
558b3d6663SArnd Bergmann 	local_store = ctx->ops->get_ls(ctx);
568b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
5767207b96SArnd Bergmann 
588b3d6663SArnd Bergmann 	spu_release(ctx);
5967207b96SArnd Bergmann 	return ret;
6067207b96SArnd Bergmann }
6167207b96SArnd Bergmann 
6267207b96SArnd Bergmann static ssize_t
6367207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer,
6467207b96SArnd Bergmann 					size_t size, loff_t *pos)
6567207b96SArnd Bergmann {
6667207b96SArnd Bergmann 	struct spu_context *ctx = file->private_data;
678b3d6663SArnd Bergmann 	char *local_store;
688b3d6663SArnd Bergmann 	int ret;
6967207b96SArnd Bergmann 
7067207b96SArnd Bergmann 	size = min_t(ssize_t, LS_SIZE - *pos, size);
7167207b96SArnd Bergmann 	if (size <= 0)
7267207b96SArnd Bergmann 		return -EFBIG;
7367207b96SArnd Bergmann 	*pos += size;
748b3d6663SArnd Bergmann 
758b3d6663SArnd Bergmann 	spu_acquire(ctx);
768b3d6663SArnd Bergmann 
778b3d6663SArnd Bergmann 	local_store = ctx->ops->get_ls(ctx);
788b3d6663SArnd Bergmann 	ret = copy_from_user(local_store + *pos - size,
7967207b96SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
808b3d6663SArnd Bergmann 
818b3d6663SArnd Bergmann 	spu_release(ctx);
828b3d6663SArnd Bergmann 	return ret;
8367207b96SArnd Bergmann }
8467207b96SArnd Bergmann 
858b3d6663SArnd Bergmann #ifdef CONFIG_SPARSEMEM
868b3d6663SArnd Bergmann static struct page *
878b3d6663SArnd Bergmann spufs_mem_mmap_nopage(struct vm_area_struct *vma,
888b3d6663SArnd Bergmann 		      unsigned long address, int *type)
898b3d6663SArnd Bergmann {
908b3d6663SArnd Bergmann 	struct page *page = NOPAGE_SIGBUS;
918b3d6663SArnd Bergmann 
928b3d6663SArnd Bergmann 	struct spu_context *ctx = vma->vm_file->private_data;
938b3d6663SArnd Bergmann 	unsigned long offset = address - vma->vm_start;
948b3d6663SArnd Bergmann 	offset += vma->vm_pgoff << PAGE_SHIFT;
958b3d6663SArnd Bergmann 
968b3d6663SArnd Bergmann 	spu_acquire(ctx);
978b3d6663SArnd Bergmann 
988b3d6663SArnd Bergmann 	if (ctx->state == SPU_STATE_SAVED)
998b3d6663SArnd Bergmann 		page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
1008b3d6663SArnd Bergmann 	else
1018b3d6663SArnd Bergmann 		page = pfn_to_page((ctx->spu->local_store_phys + offset)
1028b3d6663SArnd Bergmann 				   >> PAGE_SHIFT);
1038b3d6663SArnd Bergmann 
1048b3d6663SArnd Bergmann 	spu_release(ctx);
1058b3d6663SArnd Bergmann 
1068b3d6663SArnd Bergmann 	if (type)
1078b3d6663SArnd Bergmann 		*type = VM_FAULT_MINOR;
1088b3d6663SArnd Bergmann 
1098b3d6663SArnd Bergmann 	return page;
1108b3d6663SArnd Bergmann }
1118b3d6663SArnd Bergmann 
1128b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = {
1138b3d6663SArnd Bergmann 	.nopage = spufs_mem_mmap_nopage,
1148b3d6663SArnd Bergmann };
1158b3d6663SArnd Bergmann 
11667207b96SArnd Bergmann static int
11767207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
11867207b96SArnd Bergmann {
1198b3d6663SArnd Bergmann 	if (!(vma->vm_flags & VM_SHARED))
1208b3d6663SArnd Bergmann 		return -EINVAL;
12167207b96SArnd Bergmann 
1228b3d6663SArnd Bergmann 	/* FIXME: */
12367207b96SArnd Bergmann 	vma->vm_flags |= VM_RESERVED;
12467207b96SArnd Bergmann 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
12567207b96SArnd Bergmann 				     | _PAGE_NO_CACHE);
1268b3d6663SArnd Bergmann 
1278b3d6663SArnd Bergmann 	vma->vm_ops = &spufs_mem_mmap_vmops;
12867207b96SArnd Bergmann 	return 0;
12967207b96SArnd Bergmann }
1308b3d6663SArnd Bergmann #endif
13167207b96SArnd Bergmann 
13267207b96SArnd Bergmann static struct file_operations spufs_mem_fops = {
13367207b96SArnd Bergmann 	.open	 = spufs_mem_open,
13467207b96SArnd Bergmann 	.read    = spufs_mem_read,
13567207b96SArnd Bergmann 	.write   = spufs_mem_write,
1368b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
1378b3d6663SArnd Bergmann #ifdef CONFIG_SPARSEMEM
13867207b96SArnd Bergmann 	.mmap    = spufs_mem_mmap,
1398b3d6663SArnd Bergmann #endif
1408b3d6663SArnd Bergmann };
1418b3d6663SArnd Bergmann 
1428b3d6663SArnd Bergmann static int
1438b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file)
1448b3d6663SArnd Bergmann {
1458b3d6663SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
1468b3d6663SArnd Bergmann 	file->private_data = i->i_ctx;
1478b3d6663SArnd Bergmann 	return 0;
1488b3d6663SArnd Bergmann }
1498b3d6663SArnd Bergmann 
1508b3d6663SArnd Bergmann static ssize_t
1518b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer,
1528b3d6663SArnd Bergmann 		size_t size, loff_t *pos)
1538b3d6663SArnd Bergmann {
1548b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1558b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1568b3d6663SArnd Bergmann 	int ret;
1578b3d6663SArnd Bergmann 
1588b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1598b3d6663SArnd Bergmann 
1608b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos,
1618b3d6663SArnd Bergmann 				      lscsa->gprs, sizeof lscsa->gprs);
1628b3d6663SArnd Bergmann 
1638b3d6663SArnd Bergmann 	spu_release(ctx);
1648b3d6663SArnd Bergmann 	return ret;
1658b3d6663SArnd Bergmann }
1668b3d6663SArnd Bergmann 
1678b3d6663SArnd Bergmann static ssize_t
1688b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer,
1698b3d6663SArnd Bergmann 		 size_t size, loff_t *pos)
1708b3d6663SArnd Bergmann {
1718b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1728b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1738b3d6663SArnd Bergmann 	int ret;
1748b3d6663SArnd Bergmann 
1758b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
1768b3d6663SArnd Bergmann 	if (size <= 0)
1778b3d6663SArnd Bergmann 		return -EFBIG;
1788b3d6663SArnd Bergmann 	*pos += size;
1798b3d6663SArnd Bergmann 
1808b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1818b3d6663SArnd Bergmann 
1828b3d6663SArnd Bergmann 	ret = copy_from_user(lscsa->gprs + *pos - size,
1838b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
1848b3d6663SArnd Bergmann 
1858b3d6663SArnd Bergmann 	spu_release(ctx);
1868b3d6663SArnd Bergmann 	return ret;
1878b3d6663SArnd Bergmann }
1888b3d6663SArnd Bergmann 
1898b3d6663SArnd Bergmann static struct file_operations spufs_regs_fops = {
1908b3d6663SArnd Bergmann 	.open	 = spufs_regs_open,
1918b3d6663SArnd Bergmann 	.read    = spufs_regs_read,
1928b3d6663SArnd Bergmann 	.write   = spufs_regs_write,
1938b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
1948b3d6663SArnd Bergmann };
1958b3d6663SArnd Bergmann 
1968b3d6663SArnd Bergmann static ssize_t
1978b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer,
1988b3d6663SArnd Bergmann 		size_t size, loff_t * pos)
1998b3d6663SArnd Bergmann {
2008b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
2018b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
2028b3d6663SArnd Bergmann 	int ret;
2038b3d6663SArnd Bergmann 
2048b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
2058b3d6663SArnd Bergmann 
2068b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos,
2078b3d6663SArnd Bergmann 				      &lscsa->fpcr, sizeof(lscsa->fpcr));
2088b3d6663SArnd Bergmann 
2098b3d6663SArnd Bergmann 	spu_release(ctx);
2108b3d6663SArnd Bergmann 	return ret;
2118b3d6663SArnd Bergmann }
2128b3d6663SArnd Bergmann 
2138b3d6663SArnd Bergmann static ssize_t
2148b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer,
2158b3d6663SArnd Bergmann 		 size_t size, loff_t * pos)
2168b3d6663SArnd Bergmann {
2178b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
2188b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
2198b3d6663SArnd Bergmann 	int ret;
2208b3d6663SArnd Bergmann 
2218b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
2228b3d6663SArnd Bergmann 	if (size <= 0)
2238b3d6663SArnd Bergmann 		return -EFBIG;
2248b3d6663SArnd Bergmann 	*pos += size;
2258b3d6663SArnd Bergmann 
2268b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
2278b3d6663SArnd Bergmann 
2288b3d6663SArnd Bergmann 	ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
2298b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
2308b3d6663SArnd Bergmann 
2318b3d6663SArnd Bergmann 	spu_release(ctx);
2328b3d6663SArnd Bergmann 	return ret;
2338b3d6663SArnd Bergmann }
2348b3d6663SArnd Bergmann 
2358b3d6663SArnd Bergmann static struct file_operations spufs_fpcr_fops = {
2368b3d6663SArnd Bergmann 	.open = spufs_regs_open,
2378b3d6663SArnd Bergmann 	.read = spufs_fpcr_read,
2388b3d6663SArnd Bergmann 	.write = spufs_fpcr_write,
23967207b96SArnd Bergmann 	.llseek = generic_file_llseek,
24067207b96SArnd Bergmann };
24167207b96SArnd Bergmann 
24267207b96SArnd Bergmann /* generic open function for all pipe-like files */
24367207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file)
24467207b96SArnd Bergmann {
24567207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
24667207b96SArnd Bergmann 	file->private_data = i->i_ctx;
24767207b96SArnd Bergmann 
24867207b96SArnd Bergmann 	return nonseekable_open(inode, file);
24967207b96SArnd Bergmann }
25067207b96SArnd Bergmann 
25167207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
25267207b96SArnd Bergmann 			size_t len, loff_t *pos)
25367207b96SArnd Bergmann {
2548b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
25567207b96SArnd Bergmann 	u32 mbox_data;
2568b3d6663SArnd Bergmann 	int ret;
25767207b96SArnd Bergmann 
25867207b96SArnd Bergmann 	if (len < 4)
25967207b96SArnd Bergmann 		return -EINVAL;
26067207b96SArnd Bergmann 
2618b3d6663SArnd Bergmann 	spu_acquire(ctx);
2628b3d6663SArnd Bergmann 	ret = ctx->ops->mbox_read(ctx, &mbox_data);
2638b3d6663SArnd Bergmann 	spu_release(ctx);
26467207b96SArnd Bergmann 
2658b3d6663SArnd Bergmann 	if (!ret)
2668b3d6663SArnd Bergmann 		return -EAGAIN;
26767207b96SArnd Bergmann 
26867207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
26967207b96SArnd Bergmann 		return -EFAULT;
27067207b96SArnd Bergmann 
27167207b96SArnd Bergmann 	return 4;
27267207b96SArnd Bergmann }
27367207b96SArnd Bergmann 
27467207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = {
27567207b96SArnd Bergmann 	.open	= spufs_pipe_open,
27667207b96SArnd Bergmann 	.read	= spufs_mbox_read,
27767207b96SArnd Bergmann };
27867207b96SArnd Bergmann 
27967207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
28067207b96SArnd Bergmann 			size_t len, loff_t *pos)
28167207b96SArnd Bergmann {
2828b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
28367207b96SArnd Bergmann 	u32 mbox_stat;
28467207b96SArnd Bergmann 
28567207b96SArnd Bergmann 	if (len < 4)
28667207b96SArnd Bergmann 		return -EINVAL;
28767207b96SArnd Bergmann 
2888b3d6663SArnd Bergmann 	spu_acquire(ctx);
2898b3d6663SArnd Bergmann 
2908b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
2918b3d6663SArnd Bergmann 
2928b3d6663SArnd Bergmann 	spu_release(ctx);
29367207b96SArnd Bergmann 
29467207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
29567207b96SArnd Bergmann 		return -EFAULT;
29667207b96SArnd Bergmann 
29767207b96SArnd Bergmann 	return 4;
29867207b96SArnd Bergmann }
29967207b96SArnd Bergmann 
30067207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = {
30167207b96SArnd Bergmann 	.open	= spufs_pipe_open,
30267207b96SArnd Bergmann 	.read	= spufs_mbox_stat_read,
30367207b96SArnd Bergmann };
30467207b96SArnd Bergmann 
3058b3d6663SArnd Bergmann /*
3068b3d6663SArnd Bergmann  * spufs_wait
3078b3d6663SArnd Bergmann  * 	Same as wait_event_interruptible(), except that here
3088b3d6663SArnd Bergmann  *	we need to call spu_release(ctx) before sleeping, and
3098b3d6663SArnd Bergmann  *	then spu_acquire(ctx) when awoken.
3108b3d6663SArnd Bergmann  */
3118b3d6663SArnd Bergmann 
3128b3d6663SArnd Bergmann #define spufs_wait(wq, condition)					\
3138b3d6663SArnd Bergmann ({									\
3148b3d6663SArnd Bergmann 	int __ret = 0;							\
3158b3d6663SArnd Bergmann 	DEFINE_WAIT(__wait);						\
3168b3d6663SArnd Bergmann 	for (;;) {							\
3178b3d6663SArnd Bergmann 		prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);	\
3188b3d6663SArnd Bergmann 		if (condition)						\
3198b3d6663SArnd Bergmann 			break;						\
3208b3d6663SArnd Bergmann 		if (!signal_pending(current)) {				\
3218b3d6663SArnd Bergmann 			spu_release(ctx);				\
3228b3d6663SArnd Bergmann 			schedule();					\
3238b3d6663SArnd Bergmann 			spu_acquire(ctx);				\
3248b3d6663SArnd Bergmann 			continue;					\
3258b3d6663SArnd Bergmann 		}							\
3268b3d6663SArnd Bergmann 		__ret = -ERESTARTSYS;					\
3278b3d6663SArnd Bergmann 		break;							\
3288b3d6663SArnd Bergmann 	}								\
3298b3d6663SArnd Bergmann 	finish_wait(&(wq), &__wait);					\
3308b3d6663SArnd Bergmann 	__ret;								\
3318b3d6663SArnd Bergmann })
3328b3d6663SArnd Bergmann 
33367207b96SArnd Bergmann /* low-level ibox access function */
3348b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
33567207b96SArnd Bergmann {
3368b3d6663SArnd Bergmann 	return ctx->ops->ibox_read(ctx, data);
33767207b96SArnd Bergmann }
33867207b96SArnd Bergmann 
33967207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on)
34067207b96SArnd Bergmann {
3418b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
3428b3d6663SArnd Bergmann 
3438b3d6663SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->ibox_fasync);
3448b3d6663SArnd Bergmann }
3458b3d6663SArnd Bergmann 
3468b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */
3478b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu)
3488b3d6663SArnd Bergmann {
3498b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
3508b3d6663SArnd Bergmann 
3518b3d6663SArnd Bergmann 	wake_up_all(&ctx->ibox_wq);
3528b3d6663SArnd Bergmann 	kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
35367207b96SArnd Bergmann }
35467207b96SArnd Bergmann 
35567207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
35667207b96SArnd Bergmann 			size_t len, loff_t *pos)
35767207b96SArnd Bergmann {
3588b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
35967207b96SArnd Bergmann 	u32 ibox_data;
36067207b96SArnd Bergmann 	ssize_t ret;
36167207b96SArnd Bergmann 
36267207b96SArnd Bergmann 	if (len < 4)
36367207b96SArnd Bergmann 		return -EINVAL;
36467207b96SArnd Bergmann 
3658b3d6663SArnd Bergmann 	spu_acquire(ctx);
36667207b96SArnd Bergmann 
36767207b96SArnd Bergmann 	ret = 0;
36867207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
3698b3d6663SArnd Bergmann 		if (!spu_ibox_read(ctx, &ibox_data))
37067207b96SArnd Bergmann 			ret = -EAGAIN;
37167207b96SArnd Bergmann 	} else {
3728b3d6663SArnd Bergmann 		ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
37367207b96SArnd Bergmann 	}
37467207b96SArnd Bergmann 
3758b3d6663SArnd Bergmann 	spu_release(ctx);
3768b3d6663SArnd Bergmann 
37767207b96SArnd Bergmann 	if (ret)
37867207b96SArnd Bergmann 		return ret;
37967207b96SArnd Bergmann 
38067207b96SArnd Bergmann 	ret = 4;
38167207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
38267207b96SArnd Bergmann 		ret = -EFAULT;
38367207b96SArnd Bergmann 
38467207b96SArnd Bergmann 	return ret;
38567207b96SArnd Bergmann }
38667207b96SArnd Bergmann 
38767207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
38867207b96SArnd Bergmann {
3898b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
39067207b96SArnd Bergmann 	u32 mbox_stat;
39167207b96SArnd Bergmann 	unsigned int mask;
39267207b96SArnd Bergmann 
3938b3d6663SArnd Bergmann 	spu_acquire(ctx);
39467207b96SArnd Bergmann 
3958b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx);
3968b3d6663SArnd Bergmann 
3978b3d6663SArnd Bergmann 	spu_release(ctx);
3988b3d6663SArnd Bergmann 
3998b3d6663SArnd Bergmann 	poll_wait(file, &ctx->ibox_wq, wait);
40067207b96SArnd Bergmann 
40167207b96SArnd Bergmann 	mask = 0;
40267207b96SArnd Bergmann 	if (mbox_stat & 0xff0000)
40367207b96SArnd Bergmann 		mask |= POLLIN | POLLRDNORM;
40467207b96SArnd Bergmann 
40567207b96SArnd Bergmann 	return mask;
40667207b96SArnd Bergmann }
40767207b96SArnd Bergmann 
40867207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = {
40967207b96SArnd Bergmann 	.open	= spufs_pipe_open,
41067207b96SArnd Bergmann 	.read	= spufs_ibox_read,
41167207b96SArnd Bergmann 	.poll	= spufs_ibox_poll,
41267207b96SArnd Bergmann 	.fasync	= spufs_ibox_fasync,
41367207b96SArnd Bergmann };
41467207b96SArnd Bergmann 
41567207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
41667207b96SArnd Bergmann 			size_t len, loff_t *pos)
41767207b96SArnd Bergmann {
4188b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
41967207b96SArnd Bergmann 	u32 ibox_stat;
42067207b96SArnd Bergmann 
42167207b96SArnd Bergmann 	if (len < 4)
42267207b96SArnd Bergmann 		return -EINVAL;
42367207b96SArnd Bergmann 
4248b3d6663SArnd Bergmann 	spu_acquire(ctx);
4258b3d6663SArnd Bergmann 	ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
4268b3d6663SArnd Bergmann 	spu_release(ctx);
42767207b96SArnd Bergmann 
42867207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
42967207b96SArnd Bergmann 		return -EFAULT;
43067207b96SArnd Bergmann 
43167207b96SArnd Bergmann 	return 4;
43267207b96SArnd Bergmann }
43367207b96SArnd Bergmann 
43467207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = {
43567207b96SArnd Bergmann 	.open	= spufs_pipe_open,
43667207b96SArnd Bergmann 	.read	= spufs_ibox_stat_read,
43767207b96SArnd Bergmann };
43867207b96SArnd Bergmann 
43967207b96SArnd Bergmann /* low-level mailbox write */
4408b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data)
44167207b96SArnd Bergmann {
4428b3d6663SArnd Bergmann 	return ctx->ops->wbox_write(ctx, data);
44367207b96SArnd Bergmann }
44467207b96SArnd Bergmann 
44567207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on)
44667207b96SArnd Bergmann {
4478b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
4488b3d6663SArnd Bergmann 	int ret;
4498b3d6663SArnd Bergmann 
4508b3d6663SArnd Bergmann 	ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
4518b3d6663SArnd Bergmann 
4528b3d6663SArnd Bergmann 	return ret;
4538b3d6663SArnd Bergmann }
4548b3d6663SArnd Bergmann 
4558b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */
4568b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu)
4578b3d6663SArnd Bergmann {
4588b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
4598b3d6663SArnd Bergmann 
4608b3d6663SArnd Bergmann 	wake_up_all(&ctx->wbox_wq);
4618b3d6663SArnd Bergmann 	kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
46267207b96SArnd Bergmann }
46367207b96SArnd Bergmann 
46467207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
46567207b96SArnd Bergmann 			size_t len, loff_t *pos)
46667207b96SArnd Bergmann {
4678b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
46867207b96SArnd Bergmann 	u32 wbox_data;
46967207b96SArnd Bergmann 	int ret;
47067207b96SArnd Bergmann 
47167207b96SArnd Bergmann 	if (len < 4)
47267207b96SArnd Bergmann 		return -EINVAL;
47367207b96SArnd Bergmann 
47467207b96SArnd Bergmann 	if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
47567207b96SArnd Bergmann 		return -EFAULT;
47667207b96SArnd Bergmann 
4778b3d6663SArnd Bergmann 	spu_acquire(ctx);
4788b3d6663SArnd Bergmann 
47967207b96SArnd Bergmann 	ret = 0;
48067207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
4818b3d6663SArnd Bergmann 		if (!spu_wbox_write(ctx, wbox_data))
48267207b96SArnd Bergmann 			ret = -EAGAIN;
48367207b96SArnd Bergmann 	} else {
4848b3d6663SArnd Bergmann 		ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
48567207b96SArnd Bergmann 	}
48667207b96SArnd Bergmann 
4878b3d6663SArnd Bergmann 	spu_release(ctx);
4888b3d6663SArnd Bergmann 
48967207b96SArnd Bergmann 	return ret ? ret : sizeof wbox_data;
49067207b96SArnd Bergmann }
49167207b96SArnd Bergmann 
49267207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
49367207b96SArnd Bergmann {
4948b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
49567207b96SArnd Bergmann 	u32 mbox_stat;
49667207b96SArnd Bergmann 	unsigned int mask;
49767207b96SArnd Bergmann 
4988b3d6663SArnd Bergmann 	spu_acquire(ctx);
4998b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx);
5008b3d6663SArnd Bergmann 	spu_release(ctx);
50167207b96SArnd Bergmann 
5028b3d6663SArnd Bergmann 	poll_wait(file, &ctx->wbox_wq, wait);
50367207b96SArnd Bergmann 
50467207b96SArnd Bergmann 	mask = 0;
50567207b96SArnd Bergmann 	if (mbox_stat & 0x00ff00)
50667207b96SArnd Bergmann 		mask = POLLOUT | POLLWRNORM;
50767207b96SArnd Bergmann 
50867207b96SArnd Bergmann 	return mask;
50967207b96SArnd Bergmann }
51067207b96SArnd Bergmann 
51167207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = {
51267207b96SArnd Bergmann 	.open	= spufs_pipe_open,
51367207b96SArnd Bergmann 	.write	= spufs_wbox_write,
51467207b96SArnd Bergmann 	.poll	= spufs_wbox_poll,
51567207b96SArnd Bergmann 	.fasync	= spufs_wbox_fasync,
51667207b96SArnd Bergmann };
51767207b96SArnd Bergmann 
51867207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
51967207b96SArnd Bergmann 			size_t len, loff_t *pos)
52067207b96SArnd Bergmann {
5218b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
52267207b96SArnd Bergmann 	u32 wbox_stat;
52367207b96SArnd Bergmann 
52467207b96SArnd Bergmann 	if (len < 4)
52567207b96SArnd Bergmann 		return -EINVAL;
52667207b96SArnd Bergmann 
5278b3d6663SArnd Bergmann 	spu_acquire(ctx);
5288b3d6663SArnd Bergmann 	wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
5298b3d6663SArnd Bergmann 	spu_release(ctx);
53067207b96SArnd Bergmann 
53167207b96SArnd Bergmann 	if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
53267207b96SArnd Bergmann 		return -EFAULT;
53367207b96SArnd Bergmann 
53467207b96SArnd Bergmann 	return 4;
53567207b96SArnd Bergmann }
53667207b96SArnd Bergmann 
53767207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = {
53867207b96SArnd Bergmann 	.open	= spufs_pipe_open,
53967207b96SArnd Bergmann 	.read	= spufs_wbox_stat_read,
54067207b96SArnd Bergmann };
54167207b96SArnd Bergmann 
54267207b96SArnd Bergmann long spufs_run_spu(struct file *file, struct spu_context *ctx,
54367207b96SArnd Bergmann 				u32 *npc, u32 *status)
54467207b96SArnd Bergmann {
54567207b96SArnd Bergmann 	int ret;
54667207b96SArnd Bergmann 
5478b3d6663SArnd Bergmann 	ret = spu_acquire_runnable(ctx);
5488b3d6663SArnd Bergmann 	if (ret)
5498b3d6663SArnd Bergmann 		return ret;
55067207b96SArnd Bergmann 
5518b3d6663SArnd Bergmann 	ctx->ops->npc_write(ctx, *npc);
55267207b96SArnd Bergmann 
55367207b96SArnd Bergmann 	ret = spu_run(ctx->spu);
55467207b96SArnd Bergmann 
5558b3d6663SArnd Bergmann 	if (!ret)
5568b3d6663SArnd Bergmann 		ret = ctx->ops->status_read(ctx);
55767207b96SArnd Bergmann 
5588b3d6663SArnd Bergmann 	*npc = ctx->ops->npc_read(ctx);
55967207b96SArnd Bergmann 
5608b3d6663SArnd Bergmann 	spu_release(ctx);
5618b3d6663SArnd Bergmann 	spu_yield(ctx);
56267207b96SArnd Bergmann 	return ret;
56367207b96SArnd Bergmann }
56467207b96SArnd Bergmann 
56567207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
56667207b96SArnd Bergmann 			size_t len, loff_t *pos)
56767207b96SArnd Bergmann {
5688b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
56967207b96SArnd Bergmann 	u32 data;
57067207b96SArnd Bergmann 
57167207b96SArnd Bergmann 	if (len < 4)
57267207b96SArnd Bergmann 		return -EINVAL;
57367207b96SArnd Bergmann 
5748b3d6663SArnd Bergmann 	spu_acquire(ctx);
5758b3d6663SArnd Bergmann 	data = ctx->ops->signal1_read(ctx);
5768b3d6663SArnd Bergmann 	spu_release(ctx);
5778b3d6663SArnd Bergmann 
57867207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
57967207b96SArnd Bergmann 		return -EFAULT;
58067207b96SArnd Bergmann 
58167207b96SArnd Bergmann 	return 4;
58267207b96SArnd Bergmann }
58367207b96SArnd Bergmann 
58467207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
58567207b96SArnd Bergmann 			size_t len, loff_t *pos)
58667207b96SArnd Bergmann {
58767207b96SArnd Bergmann 	struct spu_context *ctx;
58867207b96SArnd Bergmann 	u32 data;
58967207b96SArnd Bergmann 
59067207b96SArnd Bergmann 	ctx = file->private_data;
59167207b96SArnd Bergmann 
59267207b96SArnd Bergmann 	if (len < 4)
59367207b96SArnd Bergmann 		return -EINVAL;
59467207b96SArnd Bergmann 
59567207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
59667207b96SArnd Bergmann 		return -EFAULT;
59767207b96SArnd Bergmann 
5988b3d6663SArnd Bergmann 	spu_acquire(ctx);
5998b3d6663SArnd Bergmann 	ctx->ops->signal1_write(ctx, data);
6008b3d6663SArnd Bergmann 	spu_release(ctx);
60167207b96SArnd Bergmann 
60267207b96SArnd Bergmann 	return 4;
60367207b96SArnd Bergmann }
60467207b96SArnd Bergmann 
60567207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = {
60667207b96SArnd Bergmann 	.open = spufs_pipe_open,
60767207b96SArnd Bergmann 	.read = spufs_signal1_read,
60867207b96SArnd Bergmann 	.write = spufs_signal1_write,
60967207b96SArnd Bergmann };
61067207b96SArnd Bergmann 
61167207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
61267207b96SArnd Bergmann 			size_t len, loff_t *pos)
61367207b96SArnd Bergmann {
61467207b96SArnd Bergmann 	struct spu_context *ctx;
61567207b96SArnd Bergmann 	u32 data;
61667207b96SArnd Bergmann 
61767207b96SArnd Bergmann 	ctx = file->private_data;
61867207b96SArnd Bergmann 
61967207b96SArnd Bergmann 	if (len < 4)
62067207b96SArnd Bergmann 		return -EINVAL;
62167207b96SArnd Bergmann 
6228b3d6663SArnd Bergmann 	spu_acquire(ctx);
6238b3d6663SArnd Bergmann 	data = ctx->ops->signal2_read(ctx);
6248b3d6663SArnd Bergmann 	spu_release(ctx);
6258b3d6663SArnd Bergmann 
62667207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
62767207b96SArnd Bergmann 		return -EFAULT;
62867207b96SArnd Bergmann 
62967207b96SArnd Bergmann 	return 4;
63067207b96SArnd Bergmann }
63167207b96SArnd Bergmann 
63267207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
63367207b96SArnd Bergmann 			size_t len, loff_t *pos)
63467207b96SArnd Bergmann {
63567207b96SArnd Bergmann 	struct spu_context *ctx;
63667207b96SArnd Bergmann 	u32 data;
63767207b96SArnd Bergmann 
63867207b96SArnd Bergmann 	ctx = file->private_data;
63967207b96SArnd Bergmann 
64067207b96SArnd Bergmann 	if (len < 4)
64167207b96SArnd Bergmann 		return -EINVAL;
64267207b96SArnd Bergmann 
64367207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
64467207b96SArnd Bergmann 		return -EFAULT;
64567207b96SArnd Bergmann 
6468b3d6663SArnd Bergmann 	spu_acquire(ctx);
6478b3d6663SArnd Bergmann 	ctx->ops->signal2_write(ctx, data);
6488b3d6663SArnd Bergmann 	spu_release(ctx);
64967207b96SArnd Bergmann 
65067207b96SArnd Bergmann 	return 4;
65167207b96SArnd Bergmann }
65267207b96SArnd Bergmann 
65367207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = {
65467207b96SArnd Bergmann 	.open = spufs_pipe_open,
65567207b96SArnd Bergmann 	.read = spufs_signal2_read,
65667207b96SArnd Bergmann 	.write = spufs_signal2_write,
65767207b96SArnd Bergmann };
65867207b96SArnd Bergmann 
65967207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val)
66067207b96SArnd Bergmann {
66167207b96SArnd Bergmann 	struct spu_context *ctx = data;
66267207b96SArnd Bergmann 
6638b3d6663SArnd Bergmann 	spu_acquire(ctx);
6648b3d6663SArnd Bergmann 	ctx->ops->signal1_type_set(ctx, val);
6658b3d6663SArnd Bergmann 	spu_release(ctx);
66667207b96SArnd Bergmann }
66767207b96SArnd Bergmann 
66867207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data)
66967207b96SArnd Bergmann {
67067207b96SArnd Bergmann 	struct spu_context *ctx = data;
6718b3d6663SArnd Bergmann 	u64 ret;
6728b3d6663SArnd Bergmann 
6738b3d6663SArnd Bergmann 	spu_acquire(ctx);
6748b3d6663SArnd Bergmann 	ret = ctx->ops->signal1_type_get(ctx);
6758b3d6663SArnd Bergmann 	spu_release(ctx);
6768b3d6663SArnd Bergmann 
6778b3d6663SArnd Bergmann 	return ret;
67867207b96SArnd Bergmann }
67967207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
68067207b96SArnd Bergmann 					spufs_signal1_type_set, "%llu");
68167207b96SArnd Bergmann 
68267207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val)
68367207b96SArnd Bergmann {
68467207b96SArnd Bergmann 	struct spu_context *ctx = data;
68567207b96SArnd Bergmann 
6868b3d6663SArnd Bergmann 	spu_acquire(ctx);
6878b3d6663SArnd Bergmann 	ctx->ops->signal2_type_set(ctx, val);
6888b3d6663SArnd Bergmann 	spu_release(ctx);
68967207b96SArnd Bergmann }
69067207b96SArnd Bergmann 
69167207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data)
69267207b96SArnd Bergmann {
69367207b96SArnd Bergmann 	struct spu_context *ctx = data;
6948b3d6663SArnd Bergmann 	u64 ret;
6958b3d6663SArnd Bergmann 
6968b3d6663SArnd Bergmann 	spu_acquire(ctx);
6978b3d6663SArnd Bergmann 	ret = ctx->ops->signal2_type_get(ctx);
6988b3d6663SArnd Bergmann 	spu_release(ctx);
6998b3d6663SArnd Bergmann 
7008b3d6663SArnd Bergmann 	return ret;
70167207b96SArnd Bergmann }
70267207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
70367207b96SArnd Bergmann 					spufs_signal2_type_set, "%llu");
70467207b96SArnd Bergmann 
70567207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val)
70667207b96SArnd Bergmann {
70767207b96SArnd Bergmann 	struct spu_context *ctx = data;
7088b3d6663SArnd Bergmann 	spu_acquire(ctx);
7098b3d6663SArnd Bergmann 	ctx->ops->npc_write(ctx, val);
7108b3d6663SArnd Bergmann 	spu_release(ctx);
71167207b96SArnd Bergmann }
71267207b96SArnd Bergmann 
71367207b96SArnd Bergmann static u64 spufs_npc_get(void *data)
71467207b96SArnd Bergmann {
71567207b96SArnd Bergmann 	struct spu_context *ctx = data;
71667207b96SArnd Bergmann 	u64 ret;
7178b3d6663SArnd Bergmann 	spu_acquire(ctx);
7188b3d6663SArnd Bergmann 	ret = ctx->ops->npc_read(ctx);
7198b3d6663SArnd Bergmann 	spu_release(ctx);
72067207b96SArnd Bergmann 	return ret;
72167207b96SArnd Bergmann }
72267207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
72367207b96SArnd Bergmann 
7248b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val)
7258b3d6663SArnd Bergmann {
7268b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7278b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7288b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7298b3d6663SArnd Bergmann 	lscsa->decr.slot[0] = (u32) val;
7308b3d6663SArnd Bergmann 	spu_release(ctx);
7318b3d6663SArnd Bergmann }
7328b3d6663SArnd Bergmann 
7338b3d6663SArnd Bergmann static u64 spufs_decr_get(void *data)
7348b3d6663SArnd Bergmann {
7358b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7368b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7378b3d6663SArnd Bergmann 	u64 ret;
7388b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7398b3d6663SArnd Bergmann 	ret = lscsa->decr.slot[0];
7408b3d6663SArnd Bergmann 	spu_release(ctx);
7418b3d6663SArnd Bergmann 	return ret;
7428b3d6663SArnd Bergmann }
7438b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
7448b3d6663SArnd Bergmann 			"%llx\n")
7458b3d6663SArnd Bergmann 
7468b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val)
7478b3d6663SArnd Bergmann {
7488b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7498b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7508b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7518b3d6663SArnd Bergmann 	lscsa->decr_status.slot[0] = (u32) val;
7528b3d6663SArnd Bergmann 	spu_release(ctx);
7538b3d6663SArnd Bergmann }
7548b3d6663SArnd Bergmann 
7558b3d6663SArnd Bergmann static u64 spufs_decr_status_get(void *data)
7568b3d6663SArnd Bergmann {
7578b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7588b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7598b3d6663SArnd Bergmann 	u64 ret;
7608b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7618b3d6663SArnd Bergmann 	ret = lscsa->decr_status.slot[0];
7628b3d6663SArnd Bergmann 	spu_release(ctx);
7638b3d6663SArnd Bergmann 	return ret;
7648b3d6663SArnd Bergmann }
7658b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
7668b3d6663SArnd Bergmann 			spufs_decr_status_set, "%llx\n")
7678b3d6663SArnd Bergmann 
7688b3d6663SArnd Bergmann static void spufs_spu_tag_mask_set(void *data, u64 val)
7698b3d6663SArnd Bergmann {
7708b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7718b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7728b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7738b3d6663SArnd Bergmann 	lscsa->tag_mask.slot[0] = (u32) val;
7748b3d6663SArnd Bergmann 	spu_release(ctx);
7758b3d6663SArnd Bergmann }
7768b3d6663SArnd Bergmann 
7778b3d6663SArnd Bergmann static u64 spufs_spu_tag_mask_get(void *data)
7788b3d6663SArnd Bergmann {
7798b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7808b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7818b3d6663SArnd Bergmann 	u64 ret;
7828b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7838b3d6663SArnd Bergmann 	ret = lscsa->tag_mask.slot[0];
7848b3d6663SArnd Bergmann 	spu_release(ctx);
7858b3d6663SArnd Bergmann 	return ret;
7868b3d6663SArnd Bergmann }
7878b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
7888b3d6663SArnd Bergmann 			spufs_spu_tag_mask_set, "%llx\n")
7898b3d6663SArnd Bergmann 
7908b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val)
7918b3d6663SArnd Bergmann {
7928b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7938b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7948b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7958b3d6663SArnd Bergmann 	lscsa->event_mask.slot[0] = (u32) val;
7968b3d6663SArnd Bergmann 	spu_release(ctx);
7978b3d6663SArnd Bergmann }
7988b3d6663SArnd Bergmann 
7998b3d6663SArnd Bergmann static u64 spufs_event_mask_get(void *data)
8008b3d6663SArnd Bergmann {
8018b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8028b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8038b3d6663SArnd Bergmann 	u64 ret;
8048b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8058b3d6663SArnd Bergmann 	ret = lscsa->event_mask.slot[0];
8068b3d6663SArnd Bergmann 	spu_release(ctx);
8078b3d6663SArnd Bergmann 	return ret;
8088b3d6663SArnd Bergmann }
8098b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
8108b3d6663SArnd Bergmann 			spufs_event_mask_set, "%llx\n")
8118b3d6663SArnd Bergmann 
8128b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val)
8138b3d6663SArnd Bergmann {
8148b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8158b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8168b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8178b3d6663SArnd Bergmann 	lscsa->srr0.slot[0] = (u32) val;
8188b3d6663SArnd Bergmann 	spu_release(ctx);
8198b3d6663SArnd Bergmann }
8208b3d6663SArnd Bergmann 
8218b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data)
8228b3d6663SArnd Bergmann {
8238b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8248b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8258b3d6663SArnd Bergmann 	u64 ret;
8268b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8278b3d6663SArnd Bergmann 	ret = lscsa->srr0.slot[0];
8288b3d6663SArnd Bergmann 	spu_release(ctx);
8298b3d6663SArnd Bergmann 	return ret;
8308b3d6663SArnd Bergmann }
8318b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
8328b3d6663SArnd Bergmann 			"%llx\n")
8338b3d6663SArnd Bergmann 
83467207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = {
83567207b96SArnd Bergmann 	{ "mem",  &spufs_mem_fops,  0666, },
8368b3d6663SArnd Bergmann 	{ "regs", &spufs_regs_fops,  0666, },
83767207b96SArnd Bergmann 	{ "mbox", &spufs_mbox_fops, 0444, },
83867207b96SArnd Bergmann 	{ "ibox", &spufs_ibox_fops, 0444, },
83967207b96SArnd Bergmann 	{ "wbox", &spufs_wbox_fops, 0222, },
84067207b96SArnd Bergmann 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
84167207b96SArnd Bergmann 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
84267207b96SArnd Bergmann 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
84367207b96SArnd Bergmann 	{ "signal1", &spufs_signal1_fops, 0666, },
84467207b96SArnd Bergmann 	{ "signal2", &spufs_signal2_fops, 0666, },
84567207b96SArnd Bergmann 	{ "signal1_type", &spufs_signal1_type, 0666, },
84667207b96SArnd Bergmann 	{ "signal2_type", &spufs_signal2_type, 0666, },
84767207b96SArnd Bergmann 	{ "npc", &spufs_npc_ops, 0666, },
8488b3d6663SArnd Bergmann 	{ "fpcr", &spufs_fpcr_fops, 0666, },
8498b3d6663SArnd Bergmann 	{ "decr", &spufs_decr_ops, 0666, },
8508b3d6663SArnd Bergmann 	{ "decr_status", &spufs_decr_status_ops, 0666, },
8518b3d6663SArnd Bergmann 	{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
8528b3d6663SArnd Bergmann 	{ "event_mask", &spufs_event_mask_ops, 0666, },
8538b3d6663SArnd Bergmann 	{ "srr0", &spufs_srr0_ops, 0666, },
85467207b96SArnd Bergmann 	{},
85567207b96SArnd Bergmann };
856