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>
26d88cfffaSArnd Bergmann #include <linux/pagemap.h>
2767207b96SArnd Bergmann #include <linux/poll.h>
2867207b96SArnd Bergmann 
2967207b96SArnd Bergmann #include <asm/io.h>
3067207b96SArnd Bergmann #include <asm/semaphore.h>
3167207b96SArnd Bergmann #include <asm/spu.h>
3267207b96SArnd Bergmann #include <asm/uaccess.h>
3367207b96SArnd Bergmann 
3467207b96SArnd Bergmann #include "spufs.h"
3567207b96SArnd Bergmann 
368b3d6663SArnd Bergmann 
3767207b96SArnd Bergmann static int
3867207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file)
3967207b96SArnd Bergmann {
4067207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
4167207b96SArnd Bergmann 	file->private_data = i->i_ctx;
428b3d6663SArnd Bergmann 	file->f_mapping = i->i_ctx->local_store;
4367207b96SArnd Bergmann 	return 0;
4467207b96SArnd Bergmann }
4567207b96SArnd Bergmann 
4667207b96SArnd Bergmann static ssize_t
4767207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer,
4867207b96SArnd Bergmann 				size_t size, loff_t *pos)
4967207b96SArnd Bergmann {
508b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
518b3d6663SArnd Bergmann 	char *local_store;
5267207b96SArnd Bergmann 	int ret;
5367207b96SArnd Bergmann 
548b3d6663SArnd Bergmann 	spu_acquire(ctx);
5567207b96SArnd Bergmann 
568b3d6663SArnd Bergmann 	local_store = ctx->ops->get_ls(ctx);
578b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
5867207b96SArnd Bergmann 
598b3d6663SArnd Bergmann 	spu_release(ctx);
6067207b96SArnd Bergmann 	return ret;
6167207b96SArnd Bergmann }
6267207b96SArnd Bergmann 
6367207b96SArnd Bergmann static ssize_t
6467207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer,
6567207b96SArnd Bergmann 					size_t size, loff_t *pos)
6667207b96SArnd Bergmann {
6767207b96SArnd Bergmann 	struct spu_context *ctx = file->private_data;
688b3d6663SArnd Bergmann 	char *local_store;
698b3d6663SArnd Bergmann 	int ret;
7067207b96SArnd Bergmann 
7167207b96SArnd Bergmann 	size = min_t(ssize_t, LS_SIZE - *pos, size);
7267207b96SArnd Bergmann 	if (size <= 0)
7367207b96SArnd Bergmann 		return -EFBIG;
7467207b96SArnd Bergmann 	*pos += size;
758b3d6663SArnd Bergmann 
768b3d6663SArnd Bergmann 	spu_acquire(ctx);
778b3d6663SArnd Bergmann 
788b3d6663SArnd Bergmann 	local_store = ctx->ops->get_ls(ctx);
798b3d6663SArnd Bergmann 	ret = copy_from_user(local_store + *pos - size,
8067207b96SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
818b3d6663SArnd Bergmann 
828b3d6663SArnd Bergmann 	spu_release(ctx);
838b3d6663SArnd Bergmann 	return ret;
8467207b96SArnd Bergmann }
8567207b96SArnd Bergmann 
868b3d6663SArnd Bergmann #ifdef CONFIG_SPARSEMEM
878b3d6663SArnd Bergmann static struct page *
888b3d6663SArnd Bergmann spufs_mem_mmap_nopage(struct vm_area_struct *vma,
898b3d6663SArnd Bergmann 		      unsigned long address, int *type)
908b3d6663SArnd Bergmann {
918b3d6663SArnd Bergmann 	struct page *page = NOPAGE_SIGBUS;
928b3d6663SArnd Bergmann 
938b3d6663SArnd Bergmann 	struct spu_context *ctx = vma->vm_file->private_data;
948b3d6663SArnd Bergmann 	unsigned long offset = address - vma->vm_start;
958b3d6663SArnd Bergmann 	offset += vma->vm_pgoff << PAGE_SHIFT;
968b3d6663SArnd Bergmann 
978b3d6663SArnd Bergmann 	spu_acquire(ctx);
988b3d6663SArnd Bergmann 
998b3d6663SArnd Bergmann 	if (ctx->state == SPU_STATE_SAVED)
1008b3d6663SArnd Bergmann 		page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
1018b3d6663SArnd Bergmann 	else
1028b3d6663SArnd Bergmann 		page = pfn_to_page((ctx->spu->local_store_phys + offset)
1038b3d6663SArnd Bergmann 				   >> PAGE_SHIFT);
1048b3d6663SArnd Bergmann 
1058b3d6663SArnd Bergmann 	spu_release(ctx);
1068b3d6663SArnd Bergmann 
1078b3d6663SArnd Bergmann 	if (type)
1088b3d6663SArnd Bergmann 		*type = VM_FAULT_MINOR;
1098b3d6663SArnd Bergmann 
110d88cfffaSArnd Bergmann 	page_cache_get(page);
1118b3d6663SArnd Bergmann 	return page;
1128b3d6663SArnd Bergmann }
1138b3d6663SArnd Bergmann 
1148b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = {
1158b3d6663SArnd Bergmann 	.nopage = spufs_mem_mmap_nopage,
1168b3d6663SArnd Bergmann };
1178b3d6663SArnd Bergmann 
11867207b96SArnd Bergmann static int
11967207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
12067207b96SArnd Bergmann {
1218b3d6663SArnd Bergmann 	if (!(vma->vm_flags & VM_SHARED))
1228b3d6663SArnd Bergmann 		return -EINVAL;
12367207b96SArnd Bergmann 
1248b3d6663SArnd Bergmann 	/* FIXME: */
12567207b96SArnd Bergmann 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
12667207b96SArnd Bergmann 				     | _PAGE_NO_CACHE);
1278b3d6663SArnd Bergmann 
1288b3d6663SArnd Bergmann 	vma->vm_ops = &spufs_mem_mmap_vmops;
12967207b96SArnd Bergmann 	return 0;
13067207b96SArnd Bergmann }
1318b3d6663SArnd Bergmann #endif
13267207b96SArnd Bergmann 
13367207b96SArnd Bergmann static struct file_operations spufs_mem_fops = {
13467207b96SArnd Bergmann 	.open	 = spufs_mem_open,
13567207b96SArnd Bergmann 	.read    = spufs_mem_read,
13667207b96SArnd Bergmann 	.write   = spufs_mem_write,
1378b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
1388b3d6663SArnd Bergmann #ifdef CONFIG_SPARSEMEM
13967207b96SArnd Bergmann 	.mmap    = spufs_mem_mmap,
1408b3d6663SArnd Bergmann #endif
1418b3d6663SArnd Bergmann };
1428b3d6663SArnd Bergmann 
1438b3d6663SArnd Bergmann static int
1448b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file)
1458b3d6663SArnd Bergmann {
1468b3d6663SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
1478b3d6663SArnd Bergmann 	file->private_data = i->i_ctx;
1488b3d6663SArnd Bergmann 	return 0;
1498b3d6663SArnd Bergmann }
1508b3d6663SArnd Bergmann 
1518b3d6663SArnd Bergmann static ssize_t
1528b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer,
1538b3d6663SArnd Bergmann 		size_t size, loff_t *pos)
1548b3d6663SArnd Bergmann {
1558b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1568b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1578b3d6663SArnd Bergmann 	int ret;
1588b3d6663SArnd Bergmann 
1598b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1608b3d6663SArnd Bergmann 
1618b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos,
1628b3d6663SArnd Bergmann 				      lscsa->gprs, sizeof lscsa->gprs);
1638b3d6663SArnd Bergmann 
1648b3d6663SArnd Bergmann 	spu_release(ctx);
1658b3d6663SArnd Bergmann 	return ret;
1668b3d6663SArnd Bergmann }
1678b3d6663SArnd Bergmann 
1688b3d6663SArnd Bergmann static ssize_t
1698b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer,
1708b3d6663SArnd Bergmann 		 size_t size, loff_t *pos)
1718b3d6663SArnd Bergmann {
1728b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1738b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1748b3d6663SArnd Bergmann 	int ret;
1758b3d6663SArnd Bergmann 
1768b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
1778b3d6663SArnd Bergmann 	if (size <= 0)
1788b3d6663SArnd Bergmann 		return -EFBIG;
1798b3d6663SArnd Bergmann 	*pos += size;
1808b3d6663SArnd Bergmann 
1818b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1828b3d6663SArnd Bergmann 
1838b3d6663SArnd Bergmann 	ret = copy_from_user(lscsa->gprs + *pos - size,
1848b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
1858b3d6663SArnd Bergmann 
1868b3d6663SArnd Bergmann 	spu_release(ctx);
1878b3d6663SArnd Bergmann 	return ret;
1888b3d6663SArnd Bergmann }
1898b3d6663SArnd Bergmann 
1908b3d6663SArnd Bergmann static struct file_operations spufs_regs_fops = {
1918b3d6663SArnd Bergmann 	.open	 = spufs_regs_open,
1928b3d6663SArnd Bergmann 	.read    = spufs_regs_read,
1938b3d6663SArnd Bergmann 	.write   = spufs_regs_write,
1948b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
1958b3d6663SArnd Bergmann };
1968b3d6663SArnd Bergmann 
1978b3d6663SArnd Bergmann static ssize_t
1988b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer,
1998b3d6663SArnd Bergmann 		size_t size, loff_t * pos)
2008b3d6663SArnd Bergmann {
2018b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
2028b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
2038b3d6663SArnd Bergmann 	int ret;
2048b3d6663SArnd Bergmann 
2058b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
2068b3d6663SArnd Bergmann 
2078b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos,
2088b3d6663SArnd Bergmann 				      &lscsa->fpcr, sizeof(lscsa->fpcr));
2098b3d6663SArnd Bergmann 
2108b3d6663SArnd Bergmann 	spu_release(ctx);
2118b3d6663SArnd Bergmann 	return ret;
2128b3d6663SArnd Bergmann }
2138b3d6663SArnd Bergmann 
2148b3d6663SArnd Bergmann static ssize_t
2158b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer,
2168b3d6663SArnd Bergmann 		 size_t size, loff_t * pos)
2178b3d6663SArnd Bergmann {
2188b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
2198b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
2208b3d6663SArnd Bergmann 	int ret;
2218b3d6663SArnd Bergmann 
2228b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
2238b3d6663SArnd Bergmann 	if (size <= 0)
2248b3d6663SArnd Bergmann 		return -EFBIG;
2258b3d6663SArnd Bergmann 	*pos += size;
2268b3d6663SArnd Bergmann 
2278b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
2288b3d6663SArnd Bergmann 
2298b3d6663SArnd Bergmann 	ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
2308b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
2318b3d6663SArnd Bergmann 
2328b3d6663SArnd Bergmann 	spu_release(ctx);
2338b3d6663SArnd Bergmann 	return ret;
2348b3d6663SArnd Bergmann }
2358b3d6663SArnd Bergmann 
2368b3d6663SArnd Bergmann static struct file_operations spufs_fpcr_fops = {
2378b3d6663SArnd Bergmann 	.open = spufs_regs_open,
2388b3d6663SArnd Bergmann 	.read = spufs_fpcr_read,
2398b3d6663SArnd Bergmann 	.write = spufs_fpcr_write,
24067207b96SArnd Bergmann 	.llseek = generic_file_llseek,
24167207b96SArnd Bergmann };
24267207b96SArnd Bergmann 
24367207b96SArnd Bergmann /* generic open function for all pipe-like files */
24467207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file)
24567207b96SArnd Bergmann {
24667207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
24767207b96SArnd Bergmann 	file->private_data = i->i_ctx;
24867207b96SArnd Bergmann 
24967207b96SArnd Bergmann 	return nonseekable_open(inode, file);
25067207b96SArnd Bergmann }
25167207b96SArnd Bergmann 
25267207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
25367207b96SArnd Bergmann 			size_t len, loff_t *pos)
25467207b96SArnd Bergmann {
2558b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
25667207b96SArnd Bergmann 	u32 mbox_data;
2578b3d6663SArnd Bergmann 	int ret;
25867207b96SArnd Bergmann 
25967207b96SArnd Bergmann 	if (len < 4)
26067207b96SArnd Bergmann 		return -EINVAL;
26167207b96SArnd Bergmann 
2628b3d6663SArnd Bergmann 	spu_acquire(ctx);
2638b3d6663SArnd Bergmann 	ret = ctx->ops->mbox_read(ctx, &mbox_data);
2648b3d6663SArnd Bergmann 	spu_release(ctx);
26567207b96SArnd Bergmann 
2668b3d6663SArnd Bergmann 	if (!ret)
2678b3d6663SArnd Bergmann 		return -EAGAIN;
26867207b96SArnd Bergmann 
26967207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
27067207b96SArnd Bergmann 		return -EFAULT;
27167207b96SArnd Bergmann 
27267207b96SArnd Bergmann 	return 4;
27367207b96SArnd Bergmann }
27467207b96SArnd Bergmann 
27567207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = {
27667207b96SArnd Bergmann 	.open	= spufs_pipe_open,
27767207b96SArnd Bergmann 	.read	= spufs_mbox_read,
27867207b96SArnd Bergmann };
27967207b96SArnd Bergmann 
28067207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
28167207b96SArnd Bergmann 			size_t len, loff_t *pos)
28267207b96SArnd Bergmann {
2838b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
28467207b96SArnd Bergmann 	u32 mbox_stat;
28567207b96SArnd Bergmann 
28667207b96SArnd Bergmann 	if (len < 4)
28767207b96SArnd Bergmann 		return -EINVAL;
28867207b96SArnd Bergmann 
2898b3d6663SArnd Bergmann 	spu_acquire(ctx);
2908b3d6663SArnd Bergmann 
2918b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
2928b3d6663SArnd Bergmann 
2938b3d6663SArnd Bergmann 	spu_release(ctx);
29467207b96SArnd Bergmann 
29567207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
29667207b96SArnd Bergmann 		return -EFAULT;
29767207b96SArnd Bergmann 
29867207b96SArnd Bergmann 	return 4;
29967207b96SArnd Bergmann }
30067207b96SArnd Bergmann 
30167207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = {
30267207b96SArnd Bergmann 	.open	= spufs_pipe_open,
30367207b96SArnd Bergmann 	.read	= spufs_mbox_stat_read,
30467207b96SArnd Bergmann };
30567207b96SArnd Bergmann 
3068b3d6663SArnd Bergmann /*
3078b3d6663SArnd Bergmann  * spufs_wait
3088b3d6663SArnd Bergmann  * 	Same as wait_event_interruptible(), except that here
3098b3d6663SArnd Bergmann  *	we need to call spu_release(ctx) before sleeping, and
3108b3d6663SArnd Bergmann  *	then spu_acquire(ctx) when awoken.
3118b3d6663SArnd Bergmann  */
3128b3d6663SArnd Bergmann 
3138b3d6663SArnd Bergmann #define spufs_wait(wq, condition)					\
3148b3d6663SArnd Bergmann ({									\
3158b3d6663SArnd Bergmann 	int __ret = 0;							\
3168b3d6663SArnd Bergmann 	DEFINE_WAIT(__wait);						\
3178b3d6663SArnd Bergmann 	for (;;) {							\
3188b3d6663SArnd Bergmann 		prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);	\
3198b3d6663SArnd Bergmann 		if (condition)						\
3208b3d6663SArnd Bergmann 			break;						\
3218b3d6663SArnd Bergmann 		if (!signal_pending(current)) {				\
3228b3d6663SArnd Bergmann 			spu_release(ctx);				\
3238b3d6663SArnd Bergmann 			schedule();					\
3248b3d6663SArnd Bergmann 			spu_acquire(ctx);				\
3258b3d6663SArnd Bergmann 			continue;					\
3268b3d6663SArnd Bergmann 		}							\
3278b3d6663SArnd Bergmann 		__ret = -ERESTARTSYS;					\
3288b3d6663SArnd Bergmann 		break;							\
3298b3d6663SArnd Bergmann 	}								\
3308b3d6663SArnd Bergmann 	finish_wait(&(wq), &__wait);					\
3318b3d6663SArnd Bergmann 	__ret;								\
3328b3d6663SArnd Bergmann })
3338b3d6663SArnd Bergmann 
33467207b96SArnd Bergmann /* low-level ibox access function */
3358b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
33667207b96SArnd Bergmann {
3378b3d6663SArnd Bergmann 	return ctx->ops->ibox_read(ctx, data);
33867207b96SArnd Bergmann }
33967207b96SArnd Bergmann 
34067207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on)
34167207b96SArnd Bergmann {
3428b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
3438b3d6663SArnd Bergmann 
3448b3d6663SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->ibox_fasync);
3458b3d6663SArnd Bergmann }
3468b3d6663SArnd Bergmann 
3478b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */
3488b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu)
3498b3d6663SArnd Bergmann {
3508b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
3518b3d6663SArnd Bergmann 
3528b3d6663SArnd Bergmann 	wake_up_all(&ctx->ibox_wq);
3538b3d6663SArnd Bergmann 	kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
35467207b96SArnd Bergmann }
35567207b96SArnd Bergmann 
35667207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
35767207b96SArnd Bergmann 			size_t len, loff_t *pos)
35867207b96SArnd Bergmann {
3598b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
36067207b96SArnd Bergmann 	u32 ibox_data;
36167207b96SArnd Bergmann 	ssize_t ret;
36267207b96SArnd Bergmann 
36367207b96SArnd Bergmann 	if (len < 4)
36467207b96SArnd Bergmann 		return -EINVAL;
36567207b96SArnd Bergmann 
3668b3d6663SArnd Bergmann 	spu_acquire(ctx);
36767207b96SArnd Bergmann 
36867207b96SArnd Bergmann 	ret = 0;
36967207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
3708b3d6663SArnd Bergmann 		if (!spu_ibox_read(ctx, &ibox_data))
37167207b96SArnd Bergmann 			ret = -EAGAIN;
37267207b96SArnd Bergmann 	} else {
3738b3d6663SArnd Bergmann 		ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
37467207b96SArnd Bergmann 	}
37567207b96SArnd Bergmann 
3768b3d6663SArnd Bergmann 	spu_release(ctx);
3778b3d6663SArnd Bergmann 
37867207b96SArnd Bergmann 	if (ret)
37967207b96SArnd Bergmann 		return ret;
38067207b96SArnd Bergmann 
38167207b96SArnd Bergmann 	ret = 4;
38267207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
38367207b96SArnd Bergmann 		ret = -EFAULT;
38467207b96SArnd Bergmann 
38567207b96SArnd Bergmann 	return ret;
38667207b96SArnd Bergmann }
38767207b96SArnd Bergmann 
38867207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
38967207b96SArnd Bergmann {
3908b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
39167207b96SArnd Bergmann 	u32 mbox_stat;
39267207b96SArnd Bergmann 	unsigned int mask;
39367207b96SArnd Bergmann 
3948b3d6663SArnd Bergmann 	spu_acquire(ctx);
39567207b96SArnd Bergmann 
3968b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx);
3978b3d6663SArnd Bergmann 
3988b3d6663SArnd Bergmann 	spu_release(ctx);
3998b3d6663SArnd Bergmann 
4008b3d6663SArnd Bergmann 	poll_wait(file, &ctx->ibox_wq, wait);
40167207b96SArnd Bergmann 
40267207b96SArnd Bergmann 	mask = 0;
40367207b96SArnd Bergmann 	if (mbox_stat & 0xff0000)
40467207b96SArnd Bergmann 		mask |= POLLIN | POLLRDNORM;
40567207b96SArnd Bergmann 
40667207b96SArnd Bergmann 	return mask;
40767207b96SArnd Bergmann }
40867207b96SArnd Bergmann 
40967207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = {
41067207b96SArnd Bergmann 	.open	= spufs_pipe_open,
41167207b96SArnd Bergmann 	.read	= spufs_ibox_read,
41267207b96SArnd Bergmann 	.poll	= spufs_ibox_poll,
41367207b96SArnd Bergmann 	.fasync	= spufs_ibox_fasync,
41467207b96SArnd Bergmann };
41567207b96SArnd Bergmann 
41667207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
41767207b96SArnd Bergmann 			size_t len, loff_t *pos)
41867207b96SArnd Bergmann {
4198b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
42067207b96SArnd Bergmann 	u32 ibox_stat;
42167207b96SArnd Bergmann 
42267207b96SArnd Bergmann 	if (len < 4)
42367207b96SArnd Bergmann 		return -EINVAL;
42467207b96SArnd Bergmann 
4258b3d6663SArnd Bergmann 	spu_acquire(ctx);
4268b3d6663SArnd Bergmann 	ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
4278b3d6663SArnd Bergmann 	spu_release(ctx);
42867207b96SArnd Bergmann 
42967207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
43067207b96SArnd Bergmann 		return -EFAULT;
43167207b96SArnd Bergmann 
43267207b96SArnd Bergmann 	return 4;
43367207b96SArnd Bergmann }
43467207b96SArnd Bergmann 
43567207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = {
43667207b96SArnd Bergmann 	.open	= spufs_pipe_open,
43767207b96SArnd Bergmann 	.read	= spufs_ibox_stat_read,
43867207b96SArnd Bergmann };
43967207b96SArnd Bergmann 
44067207b96SArnd Bergmann /* low-level mailbox write */
4418b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data)
44267207b96SArnd Bergmann {
4438b3d6663SArnd Bergmann 	return ctx->ops->wbox_write(ctx, data);
44467207b96SArnd Bergmann }
44567207b96SArnd Bergmann 
44667207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on)
44767207b96SArnd Bergmann {
4488b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
4498b3d6663SArnd Bergmann 	int ret;
4508b3d6663SArnd Bergmann 
4518b3d6663SArnd Bergmann 	ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
4528b3d6663SArnd Bergmann 
4538b3d6663SArnd Bergmann 	return ret;
4548b3d6663SArnd Bergmann }
4558b3d6663SArnd Bergmann 
4568b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */
4578b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu)
4588b3d6663SArnd Bergmann {
4598b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
4608b3d6663SArnd Bergmann 
4618b3d6663SArnd Bergmann 	wake_up_all(&ctx->wbox_wq);
4628b3d6663SArnd Bergmann 	kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
46367207b96SArnd Bergmann }
46467207b96SArnd Bergmann 
46567207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
46667207b96SArnd Bergmann 			size_t len, loff_t *pos)
46767207b96SArnd Bergmann {
4688b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
46967207b96SArnd Bergmann 	u32 wbox_data;
47067207b96SArnd Bergmann 	int ret;
47167207b96SArnd Bergmann 
47267207b96SArnd Bergmann 	if (len < 4)
47367207b96SArnd Bergmann 		return -EINVAL;
47467207b96SArnd Bergmann 
47567207b96SArnd Bergmann 	if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
47667207b96SArnd Bergmann 		return -EFAULT;
47767207b96SArnd Bergmann 
4788b3d6663SArnd Bergmann 	spu_acquire(ctx);
4798b3d6663SArnd Bergmann 
48067207b96SArnd Bergmann 	ret = 0;
48167207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
4828b3d6663SArnd Bergmann 		if (!spu_wbox_write(ctx, wbox_data))
48367207b96SArnd Bergmann 			ret = -EAGAIN;
48467207b96SArnd Bergmann 	} else {
4858b3d6663SArnd Bergmann 		ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
48667207b96SArnd Bergmann 	}
48767207b96SArnd Bergmann 
4888b3d6663SArnd Bergmann 	spu_release(ctx);
4898b3d6663SArnd Bergmann 
49067207b96SArnd Bergmann 	return ret ? ret : sizeof wbox_data;
49167207b96SArnd Bergmann }
49267207b96SArnd Bergmann 
49367207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
49467207b96SArnd Bergmann {
4958b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
49667207b96SArnd Bergmann 	u32 mbox_stat;
49767207b96SArnd Bergmann 	unsigned int mask;
49867207b96SArnd Bergmann 
4998b3d6663SArnd Bergmann 	spu_acquire(ctx);
5008b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx);
5018b3d6663SArnd Bergmann 	spu_release(ctx);
50267207b96SArnd Bergmann 
5038b3d6663SArnd Bergmann 	poll_wait(file, &ctx->wbox_wq, wait);
50467207b96SArnd Bergmann 
50567207b96SArnd Bergmann 	mask = 0;
50667207b96SArnd Bergmann 	if (mbox_stat & 0x00ff00)
50767207b96SArnd Bergmann 		mask = POLLOUT | POLLWRNORM;
50867207b96SArnd Bergmann 
50967207b96SArnd Bergmann 	return mask;
51067207b96SArnd Bergmann }
51167207b96SArnd Bergmann 
51267207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = {
51367207b96SArnd Bergmann 	.open	= spufs_pipe_open,
51467207b96SArnd Bergmann 	.write	= spufs_wbox_write,
51567207b96SArnd Bergmann 	.poll	= spufs_wbox_poll,
51667207b96SArnd Bergmann 	.fasync	= spufs_wbox_fasync,
51767207b96SArnd Bergmann };
51867207b96SArnd Bergmann 
51967207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
52067207b96SArnd Bergmann 			size_t len, loff_t *pos)
52167207b96SArnd Bergmann {
5228b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
52367207b96SArnd Bergmann 	u32 wbox_stat;
52467207b96SArnd Bergmann 
52567207b96SArnd Bergmann 	if (len < 4)
52667207b96SArnd Bergmann 		return -EINVAL;
52767207b96SArnd Bergmann 
5288b3d6663SArnd Bergmann 	spu_acquire(ctx);
5298b3d6663SArnd Bergmann 	wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
5308b3d6663SArnd Bergmann 	spu_release(ctx);
53167207b96SArnd Bergmann 
53267207b96SArnd Bergmann 	if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
53367207b96SArnd Bergmann 		return -EFAULT;
53467207b96SArnd Bergmann 
53567207b96SArnd Bergmann 	return 4;
53667207b96SArnd Bergmann }
53767207b96SArnd Bergmann 
53867207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = {
53967207b96SArnd Bergmann 	.open	= spufs_pipe_open,
54067207b96SArnd Bergmann 	.read	= spufs_wbox_stat_read,
54167207b96SArnd Bergmann };
54267207b96SArnd Bergmann 
54367207b96SArnd Bergmann long spufs_run_spu(struct file *file, struct spu_context *ctx,
54467207b96SArnd Bergmann 				u32 *npc, u32 *status)
54567207b96SArnd Bergmann {
54667207b96SArnd Bergmann 	int ret;
54767207b96SArnd Bergmann 
5488b3d6663SArnd Bergmann 	ret = spu_acquire_runnable(ctx);
5498b3d6663SArnd Bergmann 	if (ret)
5508b3d6663SArnd Bergmann 		return ret;
55167207b96SArnd Bergmann 
5528b3d6663SArnd Bergmann 	ctx->ops->npc_write(ctx, *npc);
55367207b96SArnd Bergmann 
55467207b96SArnd Bergmann 	ret = spu_run(ctx->spu);
55567207b96SArnd Bergmann 
5568b3d6663SArnd Bergmann 	if (!ret)
5578b3d6663SArnd Bergmann 		ret = ctx->ops->status_read(ctx);
55867207b96SArnd Bergmann 
5598b3d6663SArnd Bergmann 	*npc = ctx->ops->npc_read(ctx);
56067207b96SArnd Bergmann 
5618b3d6663SArnd Bergmann 	spu_release(ctx);
5628b3d6663SArnd Bergmann 	spu_yield(ctx);
56367207b96SArnd Bergmann 	return ret;
56467207b96SArnd Bergmann }
56567207b96SArnd Bergmann 
56667207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
56767207b96SArnd Bergmann 			size_t len, loff_t *pos)
56867207b96SArnd Bergmann {
5698b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
57067207b96SArnd Bergmann 	u32 data;
57167207b96SArnd Bergmann 
57267207b96SArnd Bergmann 	if (len < 4)
57367207b96SArnd Bergmann 		return -EINVAL;
57467207b96SArnd Bergmann 
5758b3d6663SArnd Bergmann 	spu_acquire(ctx);
5768b3d6663SArnd Bergmann 	data = ctx->ops->signal1_read(ctx);
5778b3d6663SArnd Bergmann 	spu_release(ctx);
5788b3d6663SArnd Bergmann 
57967207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
58067207b96SArnd Bergmann 		return -EFAULT;
58167207b96SArnd Bergmann 
58267207b96SArnd Bergmann 	return 4;
58367207b96SArnd Bergmann }
58467207b96SArnd Bergmann 
58567207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
58667207b96SArnd Bergmann 			size_t len, loff_t *pos)
58767207b96SArnd Bergmann {
58867207b96SArnd Bergmann 	struct spu_context *ctx;
58967207b96SArnd Bergmann 	u32 data;
59067207b96SArnd Bergmann 
59167207b96SArnd Bergmann 	ctx = file->private_data;
59267207b96SArnd Bergmann 
59367207b96SArnd Bergmann 	if (len < 4)
59467207b96SArnd Bergmann 		return -EINVAL;
59567207b96SArnd Bergmann 
59667207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
59767207b96SArnd Bergmann 		return -EFAULT;
59867207b96SArnd Bergmann 
5998b3d6663SArnd Bergmann 	spu_acquire(ctx);
6008b3d6663SArnd Bergmann 	ctx->ops->signal1_write(ctx, data);
6018b3d6663SArnd Bergmann 	spu_release(ctx);
60267207b96SArnd Bergmann 
60367207b96SArnd Bergmann 	return 4;
60467207b96SArnd Bergmann }
60567207b96SArnd Bergmann 
60667207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = {
60767207b96SArnd Bergmann 	.open = spufs_pipe_open,
60867207b96SArnd Bergmann 	.read = spufs_signal1_read,
60967207b96SArnd Bergmann 	.write = spufs_signal1_write,
61067207b96SArnd Bergmann };
61167207b96SArnd Bergmann 
61267207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
61367207b96SArnd Bergmann 			size_t len, loff_t *pos)
61467207b96SArnd Bergmann {
61567207b96SArnd Bergmann 	struct spu_context *ctx;
61667207b96SArnd Bergmann 	u32 data;
61767207b96SArnd Bergmann 
61867207b96SArnd Bergmann 	ctx = file->private_data;
61967207b96SArnd Bergmann 
62067207b96SArnd Bergmann 	if (len < 4)
62167207b96SArnd Bergmann 		return -EINVAL;
62267207b96SArnd Bergmann 
6238b3d6663SArnd Bergmann 	spu_acquire(ctx);
6248b3d6663SArnd Bergmann 	data = ctx->ops->signal2_read(ctx);
6258b3d6663SArnd Bergmann 	spu_release(ctx);
6268b3d6663SArnd Bergmann 
62767207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
62867207b96SArnd Bergmann 		return -EFAULT;
62967207b96SArnd Bergmann 
63067207b96SArnd Bergmann 	return 4;
63167207b96SArnd Bergmann }
63267207b96SArnd Bergmann 
63367207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
63467207b96SArnd Bergmann 			size_t len, loff_t *pos)
63567207b96SArnd Bergmann {
63667207b96SArnd Bergmann 	struct spu_context *ctx;
63767207b96SArnd Bergmann 	u32 data;
63867207b96SArnd Bergmann 
63967207b96SArnd Bergmann 	ctx = file->private_data;
64067207b96SArnd Bergmann 
64167207b96SArnd Bergmann 	if (len < 4)
64267207b96SArnd Bergmann 		return -EINVAL;
64367207b96SArnd Bergmann 
64467207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
64567207b96SArnd Bergmann 		return -EFAULT;
64667207b96SArnd Bergmann 
6478b3d6663SArnd Bergmann 	spu_acquire(ctx);
6488b3d6663SArnd Bergmann 	ctx->ops->signal2_write(ctx, data);
6498b3d6663SArnd Bergmann 	spu_release(ctx);
65067207b96SArnd Bergmann 
65167207b96SArnd Bergmann 	return 4;
65267207b96SArnd Bergmann }
65367207b96SArnd Bergmann 
65467207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = {
65567207b96SArnd Bergmann 	.open = spufs_pipe_open,
65667207b96SArnd Bergmann 	.read = spufs_signal2_read,
65767207b96SArnd Bergmann 	.write = spufs_signal2_write,
65867207b96SArnd Bergmann };
65967207b96SArnd Bergmann 
66067207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val)
66167207b96SArnd Bergmann {
66267207b96SArnd Bergmann 	struct spu_context *ctx = data;
66367207b96SArnd Bergmann 
6648b3d6663SArnd Bergmann 	spu_acquire(ctx);
6658b3d6663SArnd Bergmann 	ctx->ops->signal1_type_set(ctx, val);
6668b3d6663SArnd Bergmann 	spu_release(ctx);
66767207b96SArnd Bergmann }
66867207b96SArnd Bergmann 
66967207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data)
67067207b96SArnd Bergmann {
67167207b96SArnd Bergmann 	struct spu_context *ctx = data;
6728b3d6663SArnd Bergmann 	u64 ret;
6738b3d6663SArnd Bergmann 
6748b3d6663SArnd Bergmann 	spu_acquire(ctx);
6758b3d6663SArnd Bergmann 	ret = ctx->ops->signal1_type_get(ctx);
6768b3d6663SArnd Bergmann 	spu_release(ctx);
6778b3d6663SArnd Bergmann 
6788b3d6663SArnd Bergmann 	return ret;
67967207b96SArnd Bergmann }
68067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
68167207b96SArnd Bergmann 					spufs_signal1_type_set, "%llu");
68267207b96SArnd Bergmann 
68367207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val)
68467207b96SArnd Bergmann {
68567207b96SArnd Bergmann 	struct spu_context *ctx = data;
68667207b96SArnd Bergmann 
6878b3d6663SArnd Bergmann 	spu_acquire(ctx);
6888b3d6663SArnd Bergmann 	ctx->ops->signal2_type_set(ctx, val);
6898b3d6663SArnd Bergmann 	spu_release(ctx);
69067207b96SArnd Bergmann }
69167207b96SArnd Bergmann 
69267207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data)
69367207b96SArnd Bergmann {
69467207b96SArnd Bergmann 	struct spu_context *ctx = data;
6958b3d6663SArnd Bergmann 	u64 ret;
6968b3d6663SArnd Bergmann 
6978b3d6663SArnd Bergmann 	spu_acquire(ctx);
6988b3d6663SArnd Bergmann 	ret = ctx->ops->signal2_type_get(ctx);
6998b3d6663SArnd Bergmann 	spu_release(ctx);
7008b3d6663SArnd Bergmann 
7018b3d6663SArnd Bergmann 	return ret;
70267207b96SArnd Bergmann }
70367207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
70467207b96SArnd Bergmann 					spufs_signal2_type_set, "%llu");
70567207b96SArnd Bergmann 
70667207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val)
70767207b96SArnd Bergmann {
70867207b96SArnd Bergmann 	struct spu_context *ctx = data;
7098b3d6663SArnd Bergmann 	spu_acquire(ctx);
7108b3d6663SArnd Bergmann 	ctx->ops->npc_write(ctx, val);
7118b3d6663SArnd Bergmann 	spu_release(ctx);
71267207b96SArnd Bergmann }
71367207b96SArnd Bergmann 
71467207b96SArnd Bergmann static u64 spufs_npc_get(void *data)
71567207b96SArnd Bergmann {
71667207b96SArnd Bergmann 	struct spu_context *ctx = data;
71767207b96SArnd Bergmann 	u64 ret;
7188b3d6663SArnd Bergmann 	spu_acquire(ctx);
7198b3d6663SArnd Bergmann 	ret = ctx->ops->npc_read(ctx);
7208b3d6663SArnd Bergmann 	spu_release(ctx);
72167207b96SArnd Bergmann 	return ret;
72267207b96SArnd Bergmann }
72367207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
72467207b96SArnd Bergmann 
7258b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val)
7268b3d6663SArnd Bergmann {
7278b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7288b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7298b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7308b3d6663SArnd Bergmann 	lscsa->decr.slot[0] = (u32) val;
7318b3d6663SArnd Bergmann 	spu_release(ctx);
7328b3d6663SArnd Bergmann }
7338b3d6663SArnd Bergmann 
7348b3d6663SArnd Bergmann static u64 spufs_decr_get(void *data)
7358b3d6663SArnd Bergmann {
7368b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7378b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7388b3d6663SArnd Bergmann 	u64 ret;
7398b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7408b3d6663SArnd Bergmann 	ret = lscsa->decr.slot[0];
7418b3d6663SArnd Bergmann 	spu_release(ctx);
7428b3d6663SArnd Bergmann 	return ret;
7438b3d6663SArnd Bergmann }
7448b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
7458b3d6663SArnd Bergmann 			"%llx\n")
7468b3d6663SArnd Bergmann 
7478b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val)
7488b3d6663SArnd Bergmann {
7498b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7508b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7518b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7528b3d6663SArnd Bergmann 	lscsa->decr_status.slot[0] = (u32) val;
7538b3d6663SArnd Bergmann 	spu_release(ctx);
7548b3d6663SArnd Bergmann }
7558b3d6663SArnd Bergmann 
7568b3d6663SArnd Bergmann static u64 spufs_decr_status_get(void *data)
7578b3d6663SArnd Bergmann {
7588b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7598b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7608b3d6663SArnd Bergmann 	u64 ret;
7618b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7628b3d6663SArnd Bergmann 	ret = lscsa->decr_status.slot[0];
7638b3d6663SArnd Bergmann 	spu_release(ctx);
7648b3d6663SArnd Bergmann 	return ret;
7658b3d6663SArnd Bergmann }
7668b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
7678b3d6663SArnd Bergmann 			spufs_decr_status_set, "%llx\n")
7688b3d6663SArnd Bergmann 
7698b3d6663SArnd Bergmann static void spufs_spu_tag_mask_set(void *data, u64 val)
7708b3d6663SArnd Bergmann {
7718b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7728b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7738b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7748b3d6663SArnd Bergmann 	lscsa->tag_mask.slot[0] = (u32) val;
7758b3d6663SArnd Bergmann 	spu_release(ctx);
7768b3d6663SArnd Bergmann }
7778b3d6663SArnd Bergmann 
7788b3d6663SArnd Bergmann static u64 spufs_spu_tag_mask_get(void *data)
7798b3d6663SArnd Bergmann {
7808b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7818b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7828b3d6663SArnd Bergmann 	u64 ret;
7838b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7848b3d6663SArnd Bergmann 	ret = lscsa->tag_mask.slot[0];
7858b3d6663SArnd Bergmann 	spu_release(ctx);
7868b3d6663SArnd Bergmann 	return ret;
7878b3d6663SArnd Bergmann }
7888b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
7898b3d6663SArnd Bergmann 			spufs_spu_tag_mask_set, "%llx\n")
7908b3d6663SArnd Bergmann 
7918b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val)
7928b3d6663SArnd Bergmann {
7938b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
7948b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
7958b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
7968b3d6663SArnd Bergmann 	lscsa->event_mask.slot[0] = (u32) val;
7978b3d6663SArnd Bergmann 	spu_release(ctx);
7988b3d6663SArnd Bergmann }
7998b3d6663SArnd Bergmann 
8008b3d6663SArnd Bergmann static u64 spufs_event_mask_get(void *data)
8018b3d6663SArnd Bergmann {
8028b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8038b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8048b3d6663SArnd Bergmann 	u64 ret;
8058b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8068b3d6663SArnd Bergmann 	ret = lscsa->event_mask.slot[0];
8078b3d6663SArnd Bergmann 	spu_release(ctx);
8088b3d6663SArnd Bergmann 	return ret;
8098b3d6663SArnd Bergmann }
8108b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
8118b3d6663SArnd Bergmann 			spufs_event_mask_set, "%llx\n")
8128b3d6663SArnd Bergmann 
8138b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val)
8148b3d6663SArnd Bergmann {
8158b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8168b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8178b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8188b3d6663SArnd Bergmann 	lscsa->srr0.slot[0] = (u32) val;
8198b3d6663SArnd Bergmann 	spu_release(ctx);
8208b3d6663SArnd Bergmann }
8218b3d6663SArnd Bergmann 
8228b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data)
8238b3d6663SArnd Bergmann {
8248b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8258b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8268b3d6663SArnd Bergmann 	u64 ret;
8278b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8288b3d6663SArnd Bergmann 	ret = lscsa->srr0.slot[0];
8298b3d6663SArnd Bergmann 	spu_release(ctx);
8308b3d6663SArnd Bergmann 	return ret;
8318b3d6663SArnd Bergmann }
8328b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
8338b3d6663SArnd Bergmann 			"%llx\n")
8348b3d6663SArnd Bergmann 
83567207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = {
83667207b96SArnd Bergmann 	{ "mem",  &spufs_mem_fops,  0666, },
8378b3d6663SArnd Bergmann 	{ "regs", &spufs_regs_fops,  0666, },
83867207b96SArnd Bergmann 	{ "mbox", &spufs_mbox_fops, 0444, },
83967207b96SArnd Bergmann 	{ "ibox", &spufs_ibox_fops, 0444, },
84067207b96SArnd Bergmann 	{ "wbox", &spufs_wbox_fops, 0222, },
84167207b96SArnd Bergmann 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
84267207b96SArnd Bergmann 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
84367207b96SArnd Bergmann 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
84467207b96SArnd Bergmann 	{ "signal1", &spufs_signal1_fops, 0666, },
84567207b96SArnd Bergmann 	{ "signal2", &spufs_signal2_fops, 0666, },
84667207b96SArnd Bergmann 	{ "signal1_type", &spufs_signal1_type, 0666, },
84767207b96SArnd Bergmann 	{ "signal2_type", &spufs_signal2_type, 0666, },
84867207b96SArnd Bergmann 	{ "npc", &spufs_npc_ops, 0666, },
8498b3d6663SArnd Bergmann 	{ "fpcr", &spufs_fpcr_fops, 0666, },
8508b3d6663SArnd Bergmann 	{ "decr", &spufs_decr_ops, 0666, },
8518b3d6663SArnd Bergmann 	{ "decr_status", &spufs_decr_status_ops, 0666, },
8528b3d6663SArnd Bergmann 	{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
8538b3d6663SArnd Bergmann 	{ "event_mask", &spufs_event_mask_ops, 0666, },
8548b3d6663SArnd Bergmann 	{ "srr0", &spufs_srr0_ops, 0666, },
85567207b96SArnd Bergmann 	{},
85667207b96SArnd Bergmann };
857