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>
285110459fSArnd Bergmann #include <linux/ptrace.h>
2967207b96SArnd Bergmann 
3067207b96SArnd Bergmann #include <asm/io.h>
3167207b96SArnd Bergmann #include <asm/semaphore.h>
3267207b96SArnd Bergmann #include <asm/spu.h>
3367207b96SArnd Bergmann #include <asm/uaccess.h>
3467207b96SArnd Bergmann 
3567207b96SArnd Bergmann #include "spufs.h"
3667207b96SArnd Bergmann 
378b3d6663SArnd Bergmann 
3867207b96SArnd Bergmann static int
3967207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file)
4067207b96SArnd Bergmann {
4167207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
4267207b96SArnd Bergmann 	file->private_data = i->i_ctx;
438b3d6663SArnd Bergmann 	file->f_mapping = i->i_ctx->local_store;
4467207b96SArnd Bergmann 	return 0;
4567207b96SArnd Bergmann }
4667207b96SArnd Bergmann 
4767207b96SArnd Bergmann static ssize_t
4867207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer,
4967207b96SArnd Bergmann 				size_t size, loff_t *pos)
5067207b96SArnd Bergmann {
518b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
528b3d6663SArnd Bergmann 	char *local_store;
5367207b96SArnd Bergmann 	int ret;
5467207b96SArnd Bergmann 
558b3d6663SArnd Bergmann 	spu_acquire(ctx);
5667207b96SArnd Bergmann 
578b3d6663SArnd Bergmann 	local_store = ctx->ops->get_ls(ctx);
588b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
5967207b96SArnd Bergmann 
608b3d6663SArnd Bergmann 	spu_release(ctx);
6167207b96SArnd Bergmann 	return ret;
6267207b96SArnd Bergmann }
6367207b96SArnd Bergmann 
6467207b96SArnd Bergmann static ssize_t
6567207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer,
6667207b96SArnd Bergmann 					size_t size, loff_t *pos)
6767207b96SArnd Bergmann {
6867207b96SArnd Bergmann 	struct spu_context *ctx = file->private_data;
698b3d6663SArnd Bergmann 	char *local_store;
708b3d6663SArnd Bergmann 	int ret;
7167207b96SArnd Bergmann 
7267207b96SArnd Bergmann 	size = min_t(ssize_t, LS_SIZE - *pos, size);
7367207b96SArnd Bergmann 	if (size <= 0)
7467207b96SArnd Bergmann 		return -EFBIG;
7567207b96SArnd Bergmann 	*pos += size;
768b3d6663SArnd Bergmann 
778b3d6663SArnd Bergmann 	spu_acquire(ctx);
788b3d6663SArnd Bergmann 
798b3d6663SArnd Bergmann 	local_store = ctx->ops->get_ls(ctx);
808b3d6663SArnd Bergmann 	ret = copy_from_user(local_store + *pos - size,
8167207b96SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
828b3d6663SArnd Bergmann 
838b3d6663SArnd Bergmann 	spu_release(ctx);
848b3d6663SArnd Bergmann 	return ret;
8567207b96SArnd Bergmann }
8667207b96SArnd Bergmann 
878b3d6663SArnd Bergmann #ifdef CONFIG_SPARSEMEM
888b3d6663SArnd Bergmann static struct page *
898b3d6663SArnd Bergmann spufs_mem_mmap_nopage(struct vm_area_struct *vma,
908b3d6663SArnd Bergmann 		      unsigned long address, int *type)
918b3d6663SArnd Bergmann {
928b3d6663SArnd Bergmann 	struct page *page = NOPAGE_SIGBUS;
938b3d6663SArnd Bergmann 
948b3d6663SArnd Bergmann 	struct spu_context *ctx = vma->vm_file->private_data;
958b3d6663SArnd Bergmann 	unsigned long offset = address - vma->vm_start;
968b3d6663SArnd Bergmann 	offset += vma->vm_pgoff << PAGE_SHIFT;
978b3d6663SArnd Bergmann 
988b3d6663SArnd Bergmann 	spu_acquire(ctx);
998b3d6663SArnd Bergmann 
1008b3d6663SArnd Bergmann 	if (ctx->state == SPU_STATE_SAVED)
1018b3d6663SArnd Bergmann 		page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
1028b3d6663SArnd Bergmann 	else
1038b3d6663SArnd Bergmann 		page = pfn_to_page((ctx->spu->local_store_phys + offset)
1048b3d6663SArnd Bergmann 				   >> PAGE_SHIFT);
1058b3d6663SArnd Bergmann 
1068b3d6663SArnd Bergmann 	spu_release(ctx);
1078b3d6663SArnd Bergmann 
1088b3d6663SArnd Bergmann 	if (type)
1098b3d6663SArnd Bergmann 		*type = VM_FAULT_MINOR;
1108b3d6663SArnd Bergmann 
111d88cfffaSArnd Bergmann 	page_cache_get(page);
1128b3d6663SArnd Bergmann 	return page;
1138b3d6663SArnd Bergmann }
1148b3d6663SArnd Bergmann 
1158b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = {
1168b3d6663SArnd Bergmann 	.nopage = spufs_mem_mmap_nopage,
1178b3d6663SArnd Bergmann };
1188b3d6663SArnd Bergmann 
11967207b96SArnd Bergmann static int
12067207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
12167207b96SArnd Bergmann {
1228b3d6663SArnd Bergmann 	if (!(vma->vm_flags & VM_SHARED))
1238b3d6663SArnd Bergmann 		return -EINVAL;
12467207b96SArnd Bergmann 
1258b3d6663SArnd Bergmann 	/* FIXME: */
12667207b96SArnd Bergmann 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
12767207b96SArnd Bergmann 				     | _PAGE_NO_CACHE);
1288b3d6663SArnd Bergmann 
1298b3d6663SArnd Bergmann 	vma->vm_ops = &spufs_mem_mmap_vmops;
13067207b96SArnd Bergmann 	return 0;
13167207b96SArnd Bergmann }
1328b3d6663SArnd Bergmann #endif
13367207b96SArnd Bergmann 
13467207b96SArnd Bergmann static struct file_operations spufs_mem_fops = {
13567207b96SArnd Bergmann 	.open	 = spufs_mem_open,
13667207b96SArnd Bergmann 	.read    = spufs_mem_read,
13767207b96SArnd Bergmann 	.write   = spufs_mem_write,
1388b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
1398b3d6663SArnd Bergmann #ifdef CONFIG_SPARSEMEM
14067207b96SArnd Bergmann 	.mmap    = spufs_mem_mmap,
1418b3d6663SArnd Bergmann #endif
1428b3d6663SArnd Bergmann };
1438b3d6663SArnd Bergmann 
1448b3d6663SArnd Bergmann static int
1458b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file)
1468b3d6663SArnd Bergmann {
1478b3d6663SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
1488b3d6663SArnd Bergmann 	file->private_data = i->i_ctx;
1498b3d6663SArnd Bergmann 	return 0;
1508b3d6663SArnd Bergmann }
1518b3d6663SArnd Bergmann 
1528b3d6663SArnd Bergmann static ssize_t
1538b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer,
1548b3d6663SArnd Bergmann 		size_t size, loff_t *pos)
1558b3d6663SArnd Bergmann {
1568b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1578b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1588b3d6663SArnd Bergmann 	int ret;
1598b3d6663SArnd Bergmann 
1608b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1618b3d6663SArnd Bergmann 
1628b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos,
1638b3d6663SArnd Bergmann 				      lscsa->gprs, sizeof lscsa->gprs);
1648b3d6663SArnd Bergmann 
1658b3d6663SArnd Bergmann 	spu_release(ctx);
1668b3d6663SArnd Bergmann 	return ret;
1678b3d6663SArnd Bergmann }
1688b3d6663SArnd Bergmann 
1698b3d6663SArnd Bergmann static ssize_t
1708b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer,
1718b3d6663SArnd Bergmann 		 size_t size, loff_t *pos)
1728b3d6663SArnd Bergmann {
1738b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1748b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1758b3d6663SArnd Bergmann 	int ret;
1768b3d6663SArnd Bergmann 
1778b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
1788b3d6663SArnd Bergmann 	if (size <= 0)
1798b3d6663SArnd Bergmann 		return -EFBIG;
1808b3d6663SArnd Bergmann 	*pos += size;
1818b3d6663SArnd Bergmann 
1828b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1838b3d6663SArnd Bergmann 
1848b3d6663SArnd Bergmann 	ret = copy_from_user(lscsa->gprs + *pos - size,
1858b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
1868b3d6663SArnd Bergmann 
1878b3d6663SArnd Bergmann 	spu_release(ctx);
1888b3d6663SArnd Bergmann 	return ret;
1898b3d6663SArnd Bergmann }
1908b3d6663SArnd Bergmann 
1918b3d6663SArnd Bergmann static struct file_operations spufs_regs_fops = {
1928b3d6663SArnd Bergmann 	.open	 = spufs_regs_open,
1938b3d6663SArnd Bergmann 	.read    = spufs_regs_read,
1948b3d6663SArnd Bergmann 	.write   = spufs_regs_write,
1958b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
1968b3d6663SArnd Bergmann };
1978b3d6663SArnd Bergmann 
1988b3d6663SArnd Bergmann static ssize_t
1998b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer,
2008b3d6663SArnd Bergmann 		size_t size, loff_t * pos)
2018b3d6663SArnd Bergmann {
2028b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
2038b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
2048b3d6663SArnd Bergmann 	int ret;
2058b3d6663SArnd Bergmann 
2068b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
2078b3d6663SArnd Bergmann 
2088b3d6663SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos,
2098b3d6663SArnd Bergmann 				      &lscsa->fpcr, sizeof(lscsa->fpcr));
2108b3d6663SArnd Bergmann 
2118b3d6663SArnd Bergmann 	spu_release(ctx);
2128b3d6663SArnd Bergmann 	return ret;
2138b3d6663SArnd Bergmann }
2148b3d6663SArnd Bergmann 
2158b3d6663SArnd Bergmann static ssize_t
2168b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer,
2178b3d6663SArnd Bergmann 		 size_t size, loff_t * pos)
2188b3d6663SArnd Bergmann {
2198b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
2208b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
2218b3d6663SArnd Bergmann 	int ret;
2228b3d6663SArnd Bergmann 
2238b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
2248b3d6663SArnd Bergmann 	if (size <= 0)
2258b3d6663SArnd Bergmann 		return -EFBIG;
2268b3d6663SArnd Bergmann 	*pos += size;
2278b3d6663SArnd Bergmann 
2288b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
2298b3d6663SArnd Bergmann 
2308b3d6663SArnd Bergmann 	ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
2318b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
2328b3d6663SArnd Bergmann 
2338b3d6663SArnd Bergmann 	spu_release(ctx);
2348b3d6663SArnd Bergmann 	return ret;
2358b3d6663SArnd Bergmann }
2368b3d6663SArnd Bergmann 
2378b3d6663SArnd Bergmann static struct file_operations spufs_fpcr_fops = {
2388b3d6663SArnd Bergmann 	.open = spufs_regs_open,
2398b3d6663SArnd Bergmann 	.read = spufs_fpcr_read,
2408b3d6663SArnd Bergmann 	.write = spufs_fpcr_write,
24167207b96SArnd Bergmann 	.llseek = generic_file_llseek,
24267207b96SArnd Bergmann };
24367207b96SArnd Bergmann 
24467207b96SArnd Bergmann /* generic open function for all pipe-like files */
24567207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file)
24667207b96SArnd Bergmann {
24767207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
24867207b96SArnd Bergmann 	file->private_data = i->i_ctx;
24967207b96SArnd Bergmann 
25067207b96SArnd Bergmann 	return nonseekable_open(inode, file);
25167207b96SArnd Bergmann }
25267207b96SArnd Bergmann 
25367207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
25467207b96SArnd Bergmann 			size_t len, loff_t *pos)
25567207b96SArnd Bergmann {
2568b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
25767207b96SArnd Bergmann 	u32 mbox_data;
2588b3d6663SArnd Bergmann 	int ret;
25967207b96SArnd Bergmann 
26067207b96SArnd Bergmann 	if (len < 4)
26167207b96SArnd Bergmann 		return -EINVAL;
26267207b96SArnd Bergmann 
2638b3d6663SArnd Bergmann 	spu_acquire(ctx);
2648b3d6663SArnd Bergmann 	ret = ctx->ops->mbox_read(ctx, &mbox_data);
2658b3d6663SArnd Bergmann 	spu_release(ctx);
26667207b96SArnd Bergmann 
2678b3d6663SArnd Bergmann 	if (!ret)
2688b3d6663SArnd Bergmann 		return -EAGAIN;
26967207b96SArnd Bergmann 
27067207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
27167207b96SArnd Bergmann 		return -EFAULT;
27267207b96SArnd Bergmann 
27367207b96SArnd Bergmann 	return 4;
27467207b96SArnd Bergmann }
27567207b96SArnd Bergmann 
27667207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = {
27767207b96SArnd Bergmann 	.open	= spufs_pipe_open,
27867207b96SArnd Bergmann 	.read	= spufs_mbox_read,
27967207b96SArnd Bergmann };
28067207b96SArnd Bergmann 
28167207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
28267207b96SArnd Bergmann 			size_t len, loff_t *pos)
28367207b96SArnd Bergmann {
2848b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
28567207b96SArnd Bergmann 	u32 mbox_stat;
28667207b96SArnd Bergmann 
28767207b96SArnd Bergmann 	if (len < 4)
28867207b96SArnd Bergmann 		return -EINVAL;
28967207b96SArnd Bergmann 
2908b3d6663SArnd Bergmann 	spu_acquire(ctx);
2918b3d6663SArnd Bergmann 
2928b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
2938b3d6663SArnd Bergmann 
2948b3d6663SArnd Bergmann 	spu_release(ctx);
29567207b96SArnd Bergmann 
29667207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
29767207b96SArnd Bergmann 		return -EFAULT;
29867207b96SArnd Bergmann 
29967207b96SArnd Bergmann 	return 4;
30067207b96SArnd Bergmann }
30167207b96SArnd Bergmann 
30267207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = {
30367207b96SArnd Bergmann 	.open	= spufs_pipe_open,
30467207b96SArnd Bergmann 	.read	= spufs_mbox_stat_read,
30567207b96SArnd Bergmann };
30667207b96SArnd Bergmann 
3078b3d6663SArnd Bergmann /*
3088b3d6663SArnd Bergmann  * spufs_wait
3098b3d6663SArnd Bergmann  * 	Same as wait_event_interruptible(), except that here
3108b3d6663SArnd Bergmann  *	we need to call spu_release(ctx) before sleeping, and
3118b3d6663SArnd Bergmann  *	then spu_acquire(ctx) when awoken.
3128b3d6663SArnd Bergmann  */
3138b3d6663SArnd Bergmann 
3148b3d6663SArnd Bergmann #define spufs_wait(wq, condition)					\
3158b3d6663SArnd Bergmann ({									\
3168b3d6663SArnd Bergmann 	int __ret = 0;							\
3178b3d6663SArnd Bergmann 	DEFINE_WAIT(__wait);						\
3188b3d6663SArnd Bergmann 	for (;;) {							\
3198b3d6663SArnd Bergmann 		prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);	\
3208b3d6663SArnd Bergmann 		if (condition)						\
3218b3d6663SArnd Bergmann 			break;						\
3228b3d6663SArnd Bergmann 		if (!signal_pending(current)) {				\
3238b3d6663SArnd Bergmann 			spu_release(ctx);				\
3248b3d6663SArnd Bergmann 			schedule();					\
3258b3d6663SArnd Bergmann 			spu_acquire(ctx);				\
3268b3d6663SArnd Bergmann 			continue;					\
3278b3d6663SArnd Bergmann 		}							\
3288b3d6663SArnd Bergmann 		__ret = -ERESTARTSYS;					\
3298b3d6663SArnd Bergmann 		break;							\
3308b3d6663SArnd Bergmann 	}								\
3318b3d6663SArnd Bergmann 	finish_wait(&(wq), &__wait);					\
3328b3d6663SArnd Bergmann 	__ret;								\
3338b3d6663SArnd Bergmann })
3348b3d6663SArnd Bergmann 
33567207b96SArnd Bergmann /* low-level ibox access function */
3368b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
33767207b96SArnd Bergmann {
3388b3d6663SArnd Bergmann 	return ctx->ops->ibox_read(ctx, data);
33967207b96SArnd Bergmann }
34067207b96SArnd Bergmann 
34167207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on)
34267207b96SArnd Bergmann {
3438b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
3448b3d6663SArnd Bergmann 
3458b3d6663SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->ibox_fasync);
3468b3d6663SArnd Bergmann }
3478b3d6663SArnd Bergmann 
3488b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */
3498b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu)
3508b3d6663SArnd Bergmann {
3518b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
3528b3d6663SArnd Bergmann 
3538b3d6663SArnd Bergmann 	wake_up_all(&ctx->ibox_wq);
3548b3d6663SArnd Bergmann 	kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
35567207b96SArnd Bergmann }
35667207b96SArnd Bergmann 
35767207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
35867207b96SArnd Bergmann 			size_t len, loff_t *pos)
35967207b96SArnd Bergmann {
3608b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
36167207b96SArnd Bergmann 	u32 ibox_data;
36267207b96SArnd Bergmann 	ssize_t ret;
36367207b96SArnd Bergmann 
36467207b96SArnd Bergmann 	if (len < 4)
36567207b96SArnd Bergmann 		return -EINVAL;
36667207b96SArnd Bergmann 
3678b3d6663SArnd Bergmann 	spu_acquire(ctx);
36867207b96SArnd Bergmann 
36967207b96SArnd Bergmann 	ret = 0;
37067207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
3718b3d6663SArnd Bergmann 		if (!spu_ibox_read(ctx, &ibox_data))
37267207b96SArnd Bergmann 			ret = -EAGAIN;
37367207b96SArnd Bergmann 	} else {
3748b3d6663SArnd Bergmann 		ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
37567207b96SArnd Bergmann 	}
37667207b96SArnd Bergmann 
3778b3d6663SArnd Bergmann 	spu_release(ctx);
3788b3d6663SArnd Bergmann 
37967207b96SArnd Bergmann 	if (ret)
38067207b96SArnd Bergmann 		return ret;
38167207b96SArnd Bergmann 
38267207b96SArnd Bergmann 	ret = 4;
38367207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
38467207b96SArnd Bergmann 		ret = -EFAULT;
38567207b96SArnd Bergmann 
38667207b96SArnd Bergmann 	return ret;
38767207b96SArnd Bergmann }
38867207b96SArnd Bergmann 
38967207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
39067207b96SArnd Bergmann {
3918b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
39267207b96SArnd Bergmann 	u32 mbox_stat;
39367207b96SArnd Bergmann 	unsigned int mask;
39467207b96SArnd Bergmann 
3958b3d6663SArnd Bergmann 	spu_acquire(ctx);
39667207b96SArnd Bergmann 
3978b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx);
3988b3d6663SArnd Bergmann 
3998b3d6663SArnd Bergmann 	spu_release(ctx);
4008b3d6663SArnd Bergmann 
4018b3d6663SArnd Bergmann 	poll_wait(file, &ctx->ibox_wq, wait);
40267207b96SArnd Bergmann 
40367207b96SArnd Bergmann 	mask = 0;
40467207b96SArnd Bergmann 	if (mbox_stat & 0xff0000)
40567207b96SArnd Bergmann 		mask |= POLLIN | POLLRDNORM;
40667207b96SArnd Bergmann 
40767207b96SArnd Bergmann 	return mask;
40867207b96SArnd Bergmann }
40967207b96SArnd Bergmann 
41067207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = {
41167207b96SArnd Bergmann 	.open	= spufs_pipe_open,
41267207b96SArnd Bergmann 	.read	= spufs_ibox_read,
41367207b96SArnd Bergmann 	.poll	= spufs_ibox_poll,
41467207b96SArnd Bergmann 	.fasync	= spufs_ibox_fasync,
41567207b96SArnd Bergmann };
41667207b96SArnd Bergmann 
41767207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
41867207b96SArnd Bergmann 			size_t len, loff_t *pos)
41967207b96SArnd Bergmann {
4208b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
42167207b96SArnd Bergmann 	u32 ibox_stat;
42267207b96SArnd Bergmann 
42367207b96SArnd Bergmann 	if (len < 4)
42467207b96SArnd Bergmann 		return -EINVAL;
42567207b96SArnd Bergmann 
4268b3d6663SArnd Bergmann 	spu_acquire(ctx);
4278b3d6663SArnd Bergmann 	ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
4288b3d6663SArnd Bergmann 	spu_release(ctx);
42967207b96SArnd Bergmann 
43067207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
43167207b96SArnd Bergmann 		return -EFAULT;
43267207b96SArnd Bergmann 
43367207b96SArnd Bergmann 	return 4;
43467207b96SArnd Bergmann }
43567207b96SArnd Bergmann 
43667207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = {
43767207b96SArnd Bergmann 	.open	= spufs_pipe_open,
43867207b96SArnd Bergmann 	.read	= spufs_ibox_stat_read,
43967207b96SArnd Bergmann };
44067207b96SArnd Bergmann 
44167207b96SArnd Bergmann /* low-level mailbox write */
4428b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data)
44367207b96SArnd Bergmann {
4448b3d6663SArnd Bergmann 	return ctx->ops->wbox_write(ctx, data);
44567207b96SArnd Bergmann }
44667207b96SArnd Bergmann 
44767207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on)
44867207b96SArnd Bergmann {
4498b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
4508b3d6663SArnd Bergmann 	int ret;
4518b3d6663SArnd Bergmann 
4528b3d6663SArnd Bergmann 	ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
4538b3d6663SArnd Bergmann 
4548b3d6663SArnd Bergmann 	return ret;
4558b3d6663SArnd Bergmann }
4568b3d6663SArnd Bergmann 
4578b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */
4588b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu)
4598b3d6663SArnd Bergmann {
4608b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
4618b3d6663SArnd Bergmann 
4628b3d6663SArnd Bergmann 	wake_up_all(&ctx->wbox_wq);
4638b3d6663SArnd Bergmann 	kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
46467207b96SArnd Bergmann }
46567207b96SArnd Bergmann 
46667207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
46767207b96SArnd Bergmann 			size_t len, loff_t *pos)
46867207b96SArnd Bergmann {
4698b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
47067207b96SArnd Bergmann 	u32 wbox_data;
47167207b96SArnd Bergmann 	int ret;
47267207b96SArnd Bergmann 
47367207b96SArnd Bergmann 	if (len < 4)
47467207b96SArnd Bergmann 		return -EINVAL;
47567207b96SArnd Bergmann 
47667207b96SArnd Bergmann 	if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
47767207b96SArnd Bergmann 		return -EFAULT;
47867207b96SArnd Bergmann 
4798b3d6663SArnd Bergmann 	spu_acquire(ctx);
4808b3d6663SArnd Bergmann 
48167207b96SArnd Bergmann 	ret = 0;
48267207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
4838b3d6663SArnd Bergmann 		if (!spu_wbox_write(ctx, wbox_data))
48467207b96SArnd Bergmann 			ret = -EAGAIN;
48567207b96SArnd Bergmann 	} else {
4868b3d6663SArnd Bergmann 		ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
48767207b96SArnd Bergmann 	}
48867207b96SArnd Bergmann 
4898b3d6663SArnd Bergmann 	spu_release(ctx);
4908b3d6663SArnd Bergmann 
49167207b96SArnd Bergmann 	return ret ? ret : sizeof wbox_data;
49267207b96SArnd Bergmann }
49367207b96SArnd Bergmann 
49467207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
49567207b96SArnd Bergmann {
4968b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
49767207b96SArnd Bergmann 	u32 mbox_stat;
49867207b96SArnd Bergmann 	unsigned int mask;
49967207b96SArnd Bergmann 
5008b3d6663SArnd Bergmann 	spu_acquire(ctx);
5018b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx);
5028b3d6663SArnd Bergmann 	spu_release(ctx);
50367207b96SArnd Bergmann 
5048b3d6663SArnd Bergmann 	poll_wait(file, &ctx->wbox_wq, wait);
50567207b96SArnd Bergmann 
50667207b96SArnd Bergmann 	mask = 0;
50767207b96SArnd Bergmann 	if (mbox_stat & 0x00ff00)
50867207b96SArnd Bergmann 		mask = POLLOUT | POLLWRNORM;
50967207b96SArnd Bergmann 
51067207b96SArnd Bergmann 	return mask;
51167207b96SArnd Bergmann }
51267207b96SArnd Bergmann 
51367207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = {
51467207b96SArnd Bergmann 	.open	= spufs_pipe_open,
51567207b96SArnd Bergmann 	.write	= spufs_wbox_write,
51667207b96SArnd Bergmann 	.poll	= spufs_wbox_poll,
51767207b96SArnd Bergmann 	.fasync	= spufs_wbox_fasync,
51867207b96SArnd Bergmann };
51967207b96SArnd Bergmann 
52067207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
52167207b96SArnd Bergmann 			size_t len, loff_t *pos)
52267207b96SArnd Bergmann {
5238b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
52467207b96SArnd Bergmann 	u32 wbox_stat;
52567207b96SArnd Bergmann 
52667207b96SArnd Bergmann 	if (len < 4)
52767207b96SArnd Bergmann 		return -EINVAL;
52867207b96SArnd Bergmann 
5298b3d6663SArnd Bergmann 	spu_acquire(ctx);
5308b3d6663SArnd Bergmann 	wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
5318b3d6663SArnd Bergmann 	spu_release(ctx);
53267207b96SArnd Bergmann 
53367207b96SArnd Bergmann 	if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
53467207b96SArnd Bergmann 		return -EFAULT;
53567207b96SArnd Bergmann 
53667207b96SArnd Bergmann 	return 4;
53767207b96SArnd Bergmann }
53867207b96SArnd Bergmann 
53967207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = {
54067207b96SArnd Bergmann 	.open	= spufs_pipe_open,
54167207b96SArnd Bergmann 	.read	= spufs_wbox_stat_read,
54267207b96SArnd Bergmann };
54367207b96SArnd Bergmann 
5445110459fSArnd Bergmann /* interrupt-level stop callback function. */
5455110459fSArnd Bergmann void spufs_stop_callback(struct spu *spu)
5465110459fSArnd Bergmann {
5475110459fSArnd Bergmann 	struct spu_context *ctx = spu->ctx;
5485110459fSArnd Bergmann 
5495110459fSArnd Bergmann 	wake_up_all(&ctx->stop_wq);
5505110459fSArnd Bergmann }
5515110459fSArnd Bergmann 
5525110459fSArnd Bergmann static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
5535110459fSArnd Bergmann {
5545110459fSArnd Bergmann 	struct spu *spu;
5555110459fSArnd Bergmann 	u64 pte_fault;
5565110459fSArnd Bergmann 
5575110459fSArnd Bergmann 	*stat = ctx->ops->status_read(ctx);
5585110459fSArnd Bergmann 	if (ctx->state != SPU_STATE_RUNNABLE)
5595110459fSArnd Bergmann 		return 1;
5605110459fSArnd Bergmann 	spu = ctx->spu;
5615110459fSArnd Bergmann 	pte_fault = spu->dsisr &
5625110459fSArnd Bergmann 	    (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
5635110459fSArnd Bergmann 	return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
5645110459fSArnd Bergmann }
5655110459fSArnd Bergmann 
5665110459fSArnd Bergmann static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
5675110459fSArnd Bergmann 			       u32 * status)
5685110459fSArnd Bergmann {
5695110459fSArnd Bergmann 	int ret;
5705110459fSArnd Bergmann 
5715110459fSArnd Bergmann 	if ((ret = spu_acquire_runnable(ctx)) != 0)
5725110459fSArnd Bergmann 		return ret;
5735110459fSArnd Bergmann 	ctx->ops->npc_write(ctx, *npc);
5745110459fSArnd Bergmann 	ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
5755110459fSArnd Bergmann 	return 0;
5765110459fSArnd Bergmann }
5775110459fSArnd Bergmann 
5785110459fSArnd Bergmann static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
5795110459fSArnd Bergmann 			       u32 * status)
5805110459fSArnd Bergmann {
5815110459fSArnd Bergmann 	int ret = 0;
5825110459fSArnd Bergmann 
5835110459fSArnd Bergmann 	*status = ctx->ops->status_read(ctx);
5845110459fSArnd Bergmann 	*npc = ctx->ops->npc_read(ctx);
5855110459fSArnd Bergmann 	spu_release(ctx);
5865110459fSArnd Bergmann 
5875110459fSArnd Bergmann 	if (signal_pending(current))
5885110459fSArnd Bergmann 		ret = -ERESTARTSYS;
5895110459fSArnd Bergmann 	if (unlikely(current->ptrace & PT_PTRACED)) {
5905110459fSArnd Bergmann 		if ((*status & SPU_STATUS_STOPPED_BY_STOP)
5915110459fSArnd Bergmann 		    && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
5925110459fSArnd Bergmann 			force_sig(SIGTRAP, current);
5935110459fSArnd Bergmann 			ret = -ERESTARTSYS;
5945110459fSArnd Bergmann 		}
5955110459fSArnd Bergmann 	}
5965110459fSArnd Bergmann 	return ret;
5975110459fSArnd Bergmann }
5985110459fSArnd Bergmann 
5995110459fSArnd Bergmann static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
6005110459fSArnd Bergmann 				         u32 *status)
6015110459fSArnd Bergmann {
6025110459fSArnd Bergmann 	int ret;
6035110459fSArnd Bergmann 
6045110459fSArnd Bergmann 	if ((ret = spu_run_fini(ctx, npc, status)) != 0)
6055110459fSArnd Bergmann 		return ret;
6065110459fSArnd Bergmann 	if (*status & (SPU_STATUS_STOPPED_BY_STOP |
6075110459fSArnd Bergmann 		       SPU_STATUS_STOPPED_BY_HALT)) {
6085110459fSArnd Bergmann 		return *status;
6095110459fSArnd Bergmann 	}
6105110459fSArnd Bergmann 	if ((ret = spu_run_init(ctx, npc, status)) != 0)
6115110459fSArnd Bergmann 		return ret;
6125110459fSArnd Bergmann 	return 0;
6135110459fSArnd Bergmann }
6145110459fSArnd Bergmann 
6155110459fSArnd Bergmann static inline int spu_process_events(struct spu_context *ctx)
6165110459fSArnd Bergmann {
6175110459fSArnd Bergmann 	struct spu *spu = ctx->spu;
6185110459fSArnd Bergmann 	u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
6195110459fSArnd Bergmann 	int ret = 0;
6205110459fSArnd Bergmann 
6215110459fSArnd Bergmann 	if (spu->dsisr & pte_fault)
6225110459fSArnd Bergmann 		ret = spu_irq_class_1_bottom(spu);
6235110459fSArnd Bergmann 	if (spu->class_0_pending)
6245110459fSArnd Bergmann 		ret = spu_irq_class_0_bottom(spu);
6255110459fSArnd Bergmann 	if (!ret && signal_pending(current))
6265110459fSArnd Bergmann 		ret = -ERESTARTSYS;
6275110459fSArnd Bergmann 	return ret;
6285110459fSArnd Bergmann }
6295110459fSArnd Bergmann 
63067207b96SArnd Bergmann long spufs_run_spu(struct file *file, struct spu_context *ctx,
63167207b96SArnd Bergmann 		   u32 * npc, u32 * status)
63267207b96SArnd Bergmann {
63367207b96SArnd Bergmann 	int ret;
63467207b96SArnd Bergmann 
6355110459fSArnd Bergmann 	if ((ret = spu_run_init(ctx, npc, status)) != 0)
6368b3d6663SArnd Bergmann 		return ret;
63767207b96SArnd Bergmann 
6385110459fSArnd Bergmann 	do {
6395110459fSArnd Bergmann 		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
6405110459fSArnd Bergmann 		if (unlikely(ret))
6415110459fSArnd Bergmann 			break;
6425110459fSArnd Bergmann 		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
6435110459fSArnd Bergmann 			ret = spu_reacquire_runnable(ctx, npc, status);
6445110459fSArnd Bergmann 			if (ret) {
6455110459fSArnd Bergmann 				return ret;
6465110459fSArnd Bergmann 			}
6475110459fSArnd Bergmann 			continue;
6485110459fSArnd Bergmann 		}
6495110459fSArnd Bergmann 		ret = spu_process_events(ctx);
65067207b96SArnd Bergmann 
6515110459fSArnd Bergmann 	} while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
6525110459fSArnd Bergmann 				      SPU_STATUS_STOPPED_BY_HALT)));
65367207b96SArnd Bergmann 
6545110459fSArnd Bergmann 	ctx->ops->runcntl_stop(ctx);
6555110459fSArnd Bergmann 	ret = spu_run_fini(ctx, npc, status);
6568b3d6663SArnd Bergmann 	if (!ret)
6575110459fSArnd Bergmann 		ret = *status;
6588b3d6663SArnd Bergmann 	spu_yield(ctx);
6595110459fSArnd Bergmann 
66067207b96SArnd Bergmann 	return ret;
66167207b96SArnd Bergmann }
66267207b96SArnd Bergmann 
66367207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
66467207b96SArnd Bergmann 			size_t len, loff_t *pos)
66567207b96SArnd Bergmann {
6668b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
66767207b96SArnd Bergmann 	u32 data;
66867207b96SArnd Bergmann 
66967207b96SArnd Bergmann 	if (len < 4)
67067207b96SArnd Bergmann 		return -EINVAL;
67167207b96SArnd Bergmann 
6728b3d6663SArnd Bergmann 	spu_acquire(ctx);
6738b3d6663SArnd Bergmann 	data = ctx->ops->signal1_read(ctx);
6748b3d6663SArnd Bergmann 	spu_release(ctx);
6758b3d6663SArnd Bergmann 
67667207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
67767207b96SArnd Bergmann 		return -EFAULT;
67867207b96SArnd Bergmann 
67967207b96SArnd Bergmann 	return 4;
68067207b96SArnd Bergmann }
68167207b96SArnd Bergmann 
68267207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
68367207b96SArnd Bergmann 			size_t len, loff_t *pos)
68467207b96SArnd Bergmann {
68567207b96SArnd Bergmann 	struct spu_context *ctx;
68667207b96SArnd Bergmann 	u32 data;
68767207b96SArnd Bergmann 
68867207b96SArnd Bergmann 	ctx = file->private_data;
68967207b96SArnd Bergmann 
69067207b96SArnd Bergmann 	if (len < 4)
69167207b96SArnd Bergmann 		return -EINVAL;
69267207b96SArnd Bergmann 
69367207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
69467207b96SArnd Bergmann 		return -EFAULT;
69567207b96SArnd Bergmann 
6968b3d6663SArnd Bergmann 	spu_acquire(ctx);
6978b3d6663SArnd Bergmann 	ctx->ops->signal1_write(ctx, data);
6988b3d6663SArnd Bergmann 	spu_release(ctx);
69967207b96SArnd Bergmann 
70067207b96SArnd Bergmann 	return 4;
70167207b96SArnd Bergmann }
70267207b96SArnd Bergmann 
70367207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = {
70467207b96SArnd Bergmann 	.open = spufs_pipe_open,
70567207b96SArnd Bergmann 	.read = spufs_signal1_read,
70667207b96SArnd Bergmann 	.write = spufs_signal1_write,
70767207b96SArnd Bergmann };
70867207b96SArnd Bergmann 
70967207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
71067207b96SArnd Bergmann 			size_t len, loff_t *pos)
71167207b96SArnd Bergmann {
71267207b96SArnd Bergmann 	struct spu_context *ctx;
71367207b96SArnd Bergmann 	u32 data;
71467207b96SArnd Bergmann 
71567207b96SArnd Bergmann 	ctx = file->private_data;
71667207b96SArnd Bergmann 
71767207b96SArnd Bergmann 	if (len < 4)
71867207b96SArnd Bergmann 		return -EINVAL;
71967207b96SArnd Bergmann 
7208b3d6663SArnd Bergmann 	spu_acquire(ctx);
7218b3d6663SArnd Bergmann 	data = ctx->ops->signal2_read(ctx);
7228b3d6663SArnd Bergmann 	spu_release(ctx);
7238b3d6663SArnd Bergmann 
72467207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
72567207b96SArnd Bergmann 		return -EFAULT;
72667207b96SArnd Bergmann 
72767207b96SArnd Bergmann 	return 4;
72867207b96SArnd Bergmann }
72967207b96SArnd Bergmann 
73067207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
73167207b96SArnd Bergmann 			size_t len, loff_t *pos)
73267207b96SArnd Bergmann {
73367207b96SArnd Bergmann 	struct spu_context *ctx;
73467207b96SArnd Bergmann 	u32 data;
73567207b96SArnd Bergmann 
73667207b96SArnd Bergmann 	ctx = file->private_data;
73767207b96SArnd Bergmann 
73867207b96SArnd Bergmann 	if (len < 4)
73967207b96SArnd Bergmann 		return -EINVAL;
74067207b96SArnd Bergmann 
74167207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
74267207b96SArnd Bergmann 		return -EFAULT;
74367207b96SArnd Bergmann 
7448b3d6663SArnd Bergmann 	spu_acquire(ctx);
7458b3d6663SArnd Bergmann 	ctx->ops->signal2_write(ctx, data);
7468b3d6663SArnd Bergmann 	spu_release(ctx);
74767207b96SArnd Bergmann 
74867207b96SArnd Bergmann 	return 4;
74967207b96SArnd Bergmann }
75067207b96SArnd Bergmann 
75167207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = {
75267207b96SArnd Bergmann 	.open = spufs_pipe_open,
75367207b96SArnd Bergmann 	.read = spufs_signal2_read,
75467207b96SArnd Bergmann 	.write = spufs_signal2_write,
75567207b96SArnd Bergmann };
75667207b96SArnd Bergmann 
75767207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val)
75867207b96SArnd Bergmann {
75967207b96SArnd Bergmann 	struct spu_context *ctx = data;
76067207b96SArnd Bergmann 
7618b3d6663SArnd Bergmann 	spu_acquire(ctx);
7628b3d6663SArnd Bergmann 	ctx->ops->signal1_type_set(ctx, val);
7638b3d6663SArnd Bergmann 	spu_release(ctx);
76467207b96SArnd Bergmann }
76567207b96SArnd Bergmann 
76667207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data)
76767207b96SArnd Bergmann {
76867207b96SArnd Bergmann 	struct spu_context *ctx = data;
7698b3d6663SArnd Bergmann 	u64 ret;
7708b3d6663SArnd Bergmann 
7718b3d6663SArnd Bergmann 	spu_acquire(ctx);
7728b3d6663SArnd Bergmann 	ret = ctx->ops->signal1_type_get(ctx);
7738b3d6663SArnd Bergmann 	spu_release(ctx);
7748b3d6663SArnd Bergmann 
7758b3d6663SArnd Bergmann 	return ret;
77667207b96SArnd Bergmann }
77767207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
77867207b96SArnd Bergmann 					spufs_signal1_type_set, "%llu");
77967207b96SArnd Bergmann 
78067207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val)
78167207b96SArnd Bergmann {
78267207b96SArnd Bergmann 	struct spu_context *ctx = data;
78367207b96SArnd Bergmann 
7848b3d6663SArnd Bergmann 	spu_acquire(ctx);
7858b3d6663SArnd Bergmann 	ctx->ops->signal2_type_set(ctx, val);
7868b3d6663SArnd Bergmann 	spu_release(ctx);
78767207b96SArnd Bergmann }
78867207b96SArnd Bergmann 
78967207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data)
79067207b96SArnd Bergmann {
79167207b96SArnd Bergmann 	struct spu_context *ctx = data;
7928b3d6663SArnd Bergmann 	u64 ret;
7938b3d6663SArnd Bergmann 
7948b3d6663SArnd Bergmann 	spu_acquire(ctx);
7958b3d6663SArnd Bergmann 	ret = ctx->ops->signal2_type_get(ctx);
7968b3d6663SArnd Bergmann 	spu_release(ctx);
7978b3d6663SArnd Bergmann 
7988b3d6663SArnd Bergmann 	return ret;
79967207b96SArnd Bergmann }
80067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
80167207b96SArnd Bergmann 					spufs_signal2_type_set, "%llu");
80267207b96SArnd Bergmann 
80367207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val)
80467207b96SArnd Bergmann {
80567207b96SArnd Bergmann 	struct spu_context *ctx = data;
8068b3d6663SArnd Bergmann 	spu_acquire(ctx);
8078b3d6663SArnd Bergmann 	ctx->ops->npc_write(ctx, val);
8088b3d6663SArnd Bergmann 	spu_release(ctx);
80967207b96SArnd Bergmann }
81067207b96SArnd Bergmann 
81167207b96SArnd Bergmann static u64 spufs_npc_get(void *data)
81267207b96SArnd Bergmann {
81367207b96SArnd Bergmann 	struct spu_context *ctx = data;
81467207b96SArnd Bergmann 	u64 ret;
8158b3d6663SArnd Bergmann 	spu_acquire(ctx);
8168b3d6663SArnd Bergmann 	ret = ctx->ops->npc_read(ctx);
8178b3d6663SArnd Bergmann 	spu_release(ctx);
81867207b96SArnd Bergmann 	return ret;
81967207b96SArnd Bergmann }
82067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
82167207b96SArnd Bergmann 
8228b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val)
8238b3d6663SArnd Bergmann {
8248b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8258b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8268b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8278b3d6663SArnd Bergmann 	lscsa->decr.slot[0] = (u32) val;
8288b3d6663SArnd Bergmann 	spu_release(ctx);
8298b3d6663SArnd Bergmann }
8308b3d6663SArnd Bergmann 
8318b3d6663SArnd Bergmann static u64 spufs_decr_get(void *data)
8328b3d6663SArnd Bergmann {
8338b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8348b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8358b3d6663SArnd Bergmann 	u64 ret;
8368b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8378b3d6663SArnd Bergmann 	ret = lscsa->decr.slot[0];
8388b3d6663SArnd Bergmann 	spu_release(ctx);
8398b3d6663SArnd Bergmann 	return ret;
8408b3d6663SArnd Bergmann }
8418b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
8428b3d6663SArnd Bergmann 			"%llx\n")
8438b3d6663SArnd Bergmann 
8448b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val)
8458b3d6663SArnd Bergmann {
8468b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8478b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8488b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8498b3d6663SArnd Bergmann 	lscsa->decr_status.slot[0] = (u32) val;
8508b3d6663SArnd Bergmann 	spu_release(ctx);
8518b3d6663SArnd Bergmann }
8528b3d6663SArnd Bergmann 
8538b3d6663SArnd Bergmann static u64 spufs_decr_status_get(void *data)
8548b3d6663SArnd Bergmann {
8558b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8568b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8578b3d6663SArnd Bergmann 	u64 ret;
8588b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8598b3d6663SArnd Bergmann 	ret = lscsa->decr_status.slot[0];
8608b3d6663SArnd Bergmann 	spu_release(ctx);
8618b3d6663SArnd Bergmann 	return ret;
8628b3d6663SArnd Bergmann }
8638b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
8648b3d6663SArnd Bergmann 			spufs_decr_status_set, "%llx\n")
8658b3d6663SArnd Bergmann 
8668b3d6663SArnd Bergmann static void spufs_spu_tag_mask_set(void *data, u64 val)
8678b3d6663SArnd Bergmann {
8688b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8698b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8708b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8718b3d6663SArnd Bergmann 	lscsa->tag_mask.slot[0] = (u32) val;
8728b3d6663SArnd Bergmann 	spu_release(ctx);
8738b3d6663SArnd Bergmann }
8748b3d6663SArnd Bergmann 
8758b3d6663SArnd Bergmann static u64 spufs_spu_tag_mask_get(void *data)
8768b3d6663SArnd Bergmann {
8778b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8788b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8798b3d6663SArnd Bergmann 	u64 ret;
8808b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8818b3d6663SArnd Bergmann 	ret = lscsa->tag_mask.slot[0];
8828b3d6663SArnd Bergmann 	spu_release(ctx);
8838b3d6663SArnd Bergmann 	return ret;
8848b3d6663SArnd Bergmann }
8858b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
8868b3d6663SArnd Bergmann 			spufs_spu_tag_mask_set, "%llx\n")
8878b3d6663SArnd Bergmann 
8888b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val)
8898b3d6663SArnd Bergmann {
8908b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
8918b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
8928b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
8938b3d6663SArnd Bergmann 	lscsa->event_mask.slot[0] = (u32) val;
8948b3d6663SArnd Bergmann 	spu_release(ctx);
8958b3d6663SArnd Bergmann }
8968b3d6663SArnd Bergmann 
8978b3d6663SArnd Bergmann static u64 spufs_event_mask_get(void *data)
8988b3d6663SArnd Bergmann {
8998b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
9008b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
9018b3d6663SArnd Bergmann 	u64 ret;
9028b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
9038b3d6663SArnd Bergmann 	ret = lscsa->event_mask.slot[0];
9048b3d6663SArnd Bergmann 	spu_release(ctx);
9058b3d6663SArnd Bergmann 	return ret;
9068b3d6663SArnd Bergmann }
9078b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
9088b3d6663SArnd Bergmann 			spufs_event_mask_set, "%llx\n")
9098b3d6663SArnd Bergmann 
9108b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val)
9118b3d6663SArnd Bergmann {
9128b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
9138b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
9148b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
9158b3d6663SArnd Bergmann 	lscsa->srr0.slot[0] = (u32) val;
9168b3d6663SArnd Bergmann 	spu_release(ctx);
9178b3d6663SArnd Bergmann }
9188b3d6663SArnd Bergmann 
9198b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data)
9208b3d6663SArnd Bergmann {
9218b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
9228b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
9238b3d6663SArnd Bergmann 	u64 ret;
9248b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
9258b3d6663SArnd Bergmann 	ret = lscsa->srr0.slot[0];
9268b3d6663SArnd Bergmann 	spu_release(ctx);
9278b3d6663SArnd Bergmann 	return ret;
9288b3d6663SArnd Bergmann }
9298b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
9308b3d6663SArnd Bergmann 			"%llx\n")
9318b3d6663SArnd Bergmann 
93267207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = {
93367207b96SArnd Bergmann 	{ "mem",  &spufs_mem_fops,  0666, },
9348b3d6663SArnd Bergmann 	{ "regs", &spufs_regs_fops,  0666, },
93567207b96SArnd Bergmann 	{ "mbox", &spufs_mbox_fops, 0444, },
93667207b96SArnd Bergmann 	{ "ibox", &spufs_ibox_fops, 0444, },
93767207b96SArnd Bergmann 	{ "wbox", &spufs_wbox_fops, 0222, },
93867207b96SArnd Bergmann 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
93967207b96SArnd Bergmann 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
94067207b96SArnd Bergmann 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
94167207b96SArnd Bergmann 	{ "signal1", &spufs_signal1_fops, 0666, },
94267207b96SArnd Bergmann 	{ "signal2", &spufs_signal2_fops, 0666, },
94367207b96SArnd Bergmann 	{ "signal1_type", &spufs_signal1_type, 0666, },
94467207b96SArnd Bergmann 	{ "signal2_type", &spufs_signal2_type, 0666, },
94567207b96SArnd Bergmann 	{ "npc", &spufs_npc_ops, 0666, },
9468b3d6663SArnd Bergmann 	{ "fpcr", &spufs_fpcr_fops, 0666, },
9478b3d6663SArnd Bergmann 	{ "decr", &spufs_decr_ops, 0666, },
9488b3d6663SArnd Bergmann 	{ "decr_status", &spufs_decr_status_ops, 0666, },
9498b3d6663SArnd Bergmann 	{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
9508b3d6663SArnd Bergmann 	{ "event_mask", &spufs_event_mask_ops, 0666, },
9518b3d6663SArnd Bergmann 	{ "srr0", &spufs_srr0_ops, 0666, },
95267207b96SArnd Bergmann 	{},
95367207b96SArnd Bergmann };
954