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 
3567207b96SArnd Bergmann static int
3667207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file)
3767207b96SArnd Bergmann {
3867207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
3967207b96SArnd Bergmann 	file->private_data = i->i_ctx;
4067207b96SArnd Bergmann 	return 0;
4167207b96SArnd Bergmann }
4267207b96SArnd Bergmann 
4367207b96SArnd Bergmann static ssize_t
4467207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer,
4567207b96SArnd Bergmann 				size_t size, loff_t *pos)
4667207b96SArnd Bergmann {
4767207b96SArnd Bergmann 	struct spu *spu;
4867207b96SArnd Bergmann 	struct spu_context *ctx;
4967207b96SArnd Bergmann 	int ret;
5067207b96SArnd Bergmann 
5167207b96SArnd Bergmann 	ctx = file->private_data;
5267207b96SArnd Bergmann 	spu = ctx->spu;
5367207b96SArnd Bergmann 
5467207b96SArnd Bergmann 	down_read(&ctx->backing_sema);
5567207b96SArnd Bergmann 	if (spu->number & 0/*1*/) {
5667207b96SArnd Bergmann 		ret = generic_file_read(file, buffer, size, pos);
5767207b96SArnd Bergmann 		goto out;
5867207b96SArnd Bergmann 	}
5967207b96SArnd Bergmann 
6067207b96SArnd Bergmann 	ret = simple_read_from_buffer(buffer, size, pos,
6167207b96SArnd Bergmann 					spu->local_store, LS_SIZE);
6267207b96SArnd Bergmann out:
6367207b96SArnd Bergmann 	up_read(&ctx->backing_sema);
6467207b96SArnd Bergmann 	return ret;
6567207b96SArnd Bergmann }
6667207b96SArnd Bergmann 
6767207b96SArnd Bergmann static ssize_t
6867207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer,
6967207b96SArnd Bergmann 					size_t size, loff_t *pos)
7067207b96SArnd Bergmann {
7167207b96SArnd Bergmann 	struct spu_context *ctx = file->private_data;
7267207b96SArnd Bergmann 	struct spu *spu = ctx->spu;
7367207b96SArnd Bergmann 
7467207b96SArnd Bergmann 	if (spu->number & 0) //1)
7567207b96SArnd Bergmann 		return generic_file_write(file, buffer, size, pos);
7667207b96SArnd Bergmann 
7767207b96SArnd Bergmann 	size = min_t(ssize_t, LS_SIZE - *pos, size);
7867207b96SArnd Bergmann 	if (size <= 0)
7967207b96SArnd Bergmann 		return -EFBIG;
8067207b96SArnd Bergmann 	*pos += size;
8167207b96SArnd Bergmann 	return copy_from_user(spu->local_store + *pos - size,
8267207b96SArnd Bergmann 				buffer, size) ? -EFAULT : size;
8367207b96SArnd Bergmann }
8467207b96SArnd Bergmann 
8567207b96SArnd Bergmann static int
8667207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
8767207b96SArnd Bergmann {
8867207b96SArnd Bergmann 	struct spu_context *ctx = file->private_data;
8967207b96SArnd Bergmann 	struct spu *spu = ctx->spu;
9067207b96SArnd Bergmann 	unsigned long pfn;
9167207b96SArnd Bergmann 
9267207b96SArnd Bergmann 	if (spu->number & 0) //1)
9367207b96SArnd Bergmann 		return generic_file_mmap(file, vma);
9467207b96SArnd Bergmann 
9567207b96SArnd Bergmann 	vma->vm_flags |= VM_RESERVED;
9667207b96SArnd Bergmann 	vma->vm_page_prot = __pgprot(pgprot_val (vma->vm_page_prot)
9767207b96SArnd Bergmann 							| _PAGE_NO_CACHE);
9867207b96SArnd Bergmann 	pfn = spu->local_store_phys >> PAGE_SHIFT;
9967207b96SArnd Bergmann 	/*
10067207b96SArnd Bergmann 	 * This will work for actual SPUs, but not for vmalloc memory:
10167207b96SArnd Bergmann 	 */
10267207b96SArnd Bergmann 	if (remap_pfn_range(vma, vma->vm_start, pfn,
10367207b96SArnd Bergmann 				vma->vm_end-vma->vm_start, vma->vm_page_prot))
10467207b96SArnd Bergmann 		return -EAGAIN;
10567207b96SArnd Bergmann 	return 0;
10667207b96SArnd Bergmann }
10767207b96SArnd Bergmann 
10867207b96SArnd Bergmann static struct file_operations spufs_mem_fops = {
10967207b96SArnd Bergmann 	.open	 = spufs_mem_open,
11067207b96SArnd Bergmann 	.read    = spufs_mem_read,
11167207b96SArnd Bergmann 	.write   = spufs_mem_write,
11267207b96SArnd Bergmann 	.mmap    = spufs_mem_mmap,
11367207b96SArnd Bergmann 	.llseek  = generic_file_llseek,
11467207b96SArnd Bergmann };
11567207b96SArnd Bergmann 
11667207b96SArnd Bergmann /* generic open function for all pipe-like files */
11767207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file)
11867207b96SArnd Bergmann {
11967207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
12067207b96SArnd Bergmann 	file->private_data = i->i_ctx;
12167207b96SArnd Bergmann 
12267207b96SArnd Bergmann 	return nonseekable_open(inode, file);
12367207b96SArnd Bergmann }
12467207b96SArnd Bergmann 
12567207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
12667207b96SArnd Bergmann 			size_t len, loff_t *pos)
12767207b96SArnd Bergmann {
12867207b96SArnd Bergmann 	struct spu_context *ctx;
12967207b96SArnd Bergmann 	struct spu_problem __iomem *prob;
13067207b96SArnd Bergmann 	u32 mbox_stat;
13167207b96SArnd Bergmann 	u32 mbox_data;
13267207b96SArnd Bergmann 
13367207b96SArnd Bergmann 	if (len < 4)
13467207b96SArnd Bergmann 		return -EINVAL;
13567207b96SArnd Bergmann 
13667207b96SArnd Bergmann 	ctx = file->private_data;
13767207b96SArnd Bergmann 	prob = ctx->spu->problem;
13867207b96SArnd Bergmann 	mbox_stat = in_be32(&prob->mb_stat_R);
13967207b96SArnd Bergmann 	if (!(mbox_stat & 0x0000ff))
14067207b96SArnd Bergmann 		return -EAGAIN;
14167207b96SArnd Bergmann 
14267207b96SArnd Bergmann 	mbox_data = in_be32(&prob->pu_mb_R);
14367207b96SArnd Bergmann 
14467207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
14567207b96SArnd Bergmann 		return -EFAULT;
14667207b96SArnd Bergmann 
14767207b96SArnd Bergmann 	return 4;
14867207b96SArnd Bergmann }
14967207b96SArnd Bergmann 
15067207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = {
15167207b96SArnd Bergmann 	.open	= spufs_pipe_open,
15267207b96SArnd Bergmann 	.read	= spufs_mbox_read,
15367207b96SArnd Bergmann };
15467207b96SArnd Bergmann 
15567207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
15667207b96SArnd Bergmann 			size_t len, loff_t *pos)
15767207b96SArnd Bergmann {
15867207b96SArnd Bergmann 	struct spu_context *ctx;
15967207b96SArnd Bergmann 	u32 mbox_stat;
16067207b96SArnd Bergmann 
16167207b96SArnd Bergmann 	if (len < 4)
16267207b96SArnd Bergmann 		return -EINVAL;
16367207b96SArnd Bergmann 
16467207b96SArnd Bergmann 	ctx = file->private_data;
16567207b96SArnd Bergmann 	mbox_stat = in_be32(&ctx->spu->problem->mb_stat_R) & 0xff;
16667207b96SArnd Bergmann 
16767207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
16867207b96SArnd Bergmann 		return -EFAULT;
16967207b96SArnd Bergmann 
17067207b96SArnd Bergmann 	return 4;
17167207b96SArnd Bergmann }
17267207b96SArnd Bergmann 
17367207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = {
17467207b96SArnd Bergmann 	.open	= spufs_pipe_open,
17567207b96SArnd Bergmann 	.read	= spufs_mbox_stat_read,
17667207b96SArnd Bergmann };
17767207b96SArnd Bergmann 
17867207b96SArnd Bergmann /* low-level ibox access function */
17967207b96SArnd Bergmann size_t spu_ibox_read(struct spu *spu, u32 *data)
18067207b96SArnd Bergmann {
18167207b96SArnd Bergmann 	int ret;
18267207b96SArnd Bergmann 
18367207b96SArnd Bergmann 	spin_lock_irq(&spu->register_lock);
18467207b96SArnd Bergmann 
18567207b96SArnd Bergmann 	if (in_be32(&spu->problem->mb_stat_R) & 0xff0000) {
18667207b96SArnd Bergmann 		/* read the first available word */
18767207b96SArnd Bergmann 		*data = in_be64(&spu->priv2->puint_mb_R);
18867207b96SArnd Bergmann 		ret = 4;
18967207b96SArnd Bergmann 	} else {
19067207b96SArnd Bergmann 		/* make sure we get woken up by the interrupt */
19167207b96SArnd Bergmann 		out_be64(&spu->priv1->int_mask_class2_RW,
19267207b96SArnd Bergmann 			in_be64(&spu->priv1->int_mask_class2_RW) | 0x1);
19367207b96SArnd Bergmann 		ret = 0;
19467207b96SArnd Bergmann 	}
19567207b96SArnd Bergmann 
19667207b96SArnd Bergmann 	spin_unlock_irq(&spu->register_lock);
19767207b96SArnd Bergmann 	return ret;
19867207b96SArnd Bergmann }
19967207b96SArnd Bergmann EXPORT_SYMBOL(spu_ibox_read);
20067207b96SArnd Bergmann 
20167207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on)
20267207b96SArnd Bergmann {
20367207b96SArnd Bergmann 	struct spu_context *ctx;
20467207b96SArnd Bergmann 	ctx = file->private_data;
20567207b96SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->spu->ibox_fasync);
20667207b96SArnd Bergmann }
20767207b96SArnd Bergmann 
20867207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
20967207b96SArnd Bergmann 			size_t len, loff_t *pos)
21067207b96SArnd Bergmann {
21167207b96SArnd Bergmann 	struct spu_context *ctx;
21267207b96SArnd Bergmann 	u32 ibox_data;
21367207b96SArnd Bergmann 	ssize_t ret;
21467207b96SArnd Bergmann 
21567207b96SArnd Bergmann 	if (len < 4)
21667207b96SArnd Bergmann 		return -EINVAL;
21767207b96SArnd Bergmann 
21867207b96SArnd Bergmann 	ctx = file->private_data;
21967207b96SArnd Bergmann 
22067207b96SArnd Bergmann 	ret = 0;
22167207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
22267207b96SArnd Bergmann 		if (!spu_ibox_read(ctx->spu, &ibox_data))
22367207b96SArnd Bergmann 			ret = -EAGAIN;
22467207b96SArnd Bergmann 	} else {
22567207b96SArnd Bergmann 		ret = wait_event_interruptible(ctx->spu->ibox_wq,
22667207b96SArnd Bergmann 				 spu_ibox_read(ctx->spu, &ibox_data));
22767207b96SArnd Bergmann 	}
22867207b96SArnd Bergmann 
22967207b96SArnd Bergmann 	if (ret)
23067207b96SArnd Bergmann 		return ret;
23167207b96SArnd Bergmann 
23267207b96SArnd Bergmann 	ret = 4;
23367207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
23467207b96SArnd Bergmann 		ret = -EFAULT;
23567207b96SArnd Bergmann 
23667207b96SArnd Bergmann 	return ret;
23767207b96SArnd Bergmann }
23867207b96SArnd Bergmann 
23967207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
24067207b96SArnd Bergmann {
24167207b96SArnd Bergmann 	struct spu_context *ctx;
24267207b96SArnd Bergmann 	struct spu_problem __iomem *prob;
24367207b96SArnd Bergmann 	u32 mbox_stat;
24467207b96SArnd Bergmann 	unsigned int mask;
24567207b96SArnd Bergmann 
24667207b96SArnd Bergmann 	ctx = file->private_data;
24767207b96SArnd Bergmann 	prob = ctx->spu->problem;
24867207b96SArnd Bergmann 	mbox_stat = in_be32(&prob->mb_stat_R);
24967207b96SArnd Bergmann 
25067207b96SArnd Bergmann 	poll_wait(file, &ctx->spu->ibox_wq, wait);
25167207b96SArnd Bergmann 
25267207b96SArnd Bergmann 	mask = 0;
25367207b96SArnd Bergmann 	if (mbox_stat & 0xff0000)
25467207b96SArnd Bergmann 		mask |= POLLIN | POLLRDNORM;
25567207b96SArnd Bergmann 
25667207b96SArnd Bergmann 	return mask;
25767207b96SArnd Bergmann }
25867207b96SArnd Bergmann 
25967207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = {
26067207b96SArnd Bergmann 	.open	= spufs_pipe_open,
26167207b96SArnd Bergmann 	.read	= spufs_ibox_read,
26267207b96SArnd Bergmann 	.poll	= spufs_ibox_poll,
26367207b96SArnd Bergmann 	.fasync	= spufs_ibox_fasync,
26467207b96SArnd Bergmann };
26567207b96SArnd Bergmann 
26667207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
26767207b96SArnd Bergmann 			size_t len, loff_t *pos)
26867207b96SArnd Bergmann {
26967207b96SArnd Bergmann 	struct spu_context *ctx;
27067207b96SArnd Bergmann 	u32 ibox_stat;
27167207b96SArnd Bergmann 
27267207b96SArnd Bergmann 	if (len < 4)
27367207b96SArnd Bergmann 		return -EINVAL;
27467207b96SArnd Bergmann 
27567207b96SArnd Bergmann 	ctx = file->private_data;
27667207b96SArnd Bergmann 	ibox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 16) & 0xff;
27767207b96SArnd Bergmann 
27867207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
27967207b96SArnd Bergmann 		return -EFAULT;
28067207b96SArnd Bergmann 
28167207b96SArnd Bergmann 	return 4;
28267207b96SArnd Bergmann }
28367207b96SArnd Bergmann 
28467207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = {
28567207b96SArnd Bergmann 	.open	= spufs_pipe_open,
28667207b96SArnd Bergmann 	.read	= spufs_ibox_stat_read,
28767207b96SArnd Bergmann };
28867207b96SArnd Bergmann 
28967207b96SArnd Bergmann /* low-level mailbox write */
29067207b96SArnd Bergmann size_t spu_wbox_write(struct spu *spu, u32 data)
29167207b96SArnd Bergmann {
29267207b96SArnd Bergmann 	int ret;
29367207b96SArnd Bergmann 
29467207b96SArnd Bergmann 	spin_lock_irq(&spu->register_lock);
29567207b96SArnd Bergmann 
29667207b96SArnd Bergmann 	if (in_be32(&spu->problem->mb_stat_R) & 0x00ff00) {
29767207b96SArnd Bergmann 		/* we have space to write wbox_data to */
29867207b96SArnd Bergmann 		out_be32(&spu->problem->spu_mb_W, data);
29967207b96SArnd Bergmann 		ret = 4;
30067207b96SArnd Bergmann 	} else {
30167207b96SArnd Bergmann 		/* make sure we get woken up by the interrupt when space
30267207b96SArnd Bergmann 		   becomes available */
30367207b96SArnd Bergmann 		out_be64(&spu->priv1->int_mask_class2_RW,
30467207b96SArnd Bergmann 			in_be64(&spu->priv1->int_mask_class2_RW) | 0x10);
30567207b96SArnd Bergmann 		ret = 0;
30667207b96SArnd Bergmann 	}
30767207b96SArnd Bergmann 
30867207b96SArnd Bergmann 	spin_unlock_irq(&spu->register_lock);
30967207b96SArnd Bergmann 	return ret;
31067207b96SArnd Bergmann }
31167207b96SArnd Bergmann EXPORT_SYMBOL(spu_wbox_write);
31267207b96SArnd Bergmann 
31367207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on)
31467207b96SArnd Bergmann {
31567207b96SArnd Bergmann 	struct spu_context *ctx;
31667207b96SArnd Bergmann 	ctx = file->private_data;
31767207b96SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->spu->wbox_fasync);
31867207b96SArnd Bergmann }
31967207b96SArnd Bergmann 
32067207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
32167207b96SArnd Bergmann 			size_t len, loff_t *pos)
32267207b96SArnd Bergmann {
32367207b96SArnd Bergmann 	struct spu_context *ctx;
32467207b96SArnd Bergmann 	u32 wbox_data;
32567207b96SArnd Bergmann 	int ret;
32667207b96SArnd Bergmann 
32767207b96SArnd Bergmann 	if (len < 4)
32867207b96SArnd Bergmann 		return -EINVAL;
32967207b96SArnd Bergmann 
33067207b96SArnd Bergmann 	ctx = file->private_data;
33167207b96SArnd Bergmann 
33267207b96SArnd Bergmann 	if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
33367207b96SArnd Bergmann 		return -EFAULT;
33467207b96SArnd Bergmann 
33567207b96SArnd Bergmann 	ret = 0;
33667207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
33767207b96SArnd Bergmann 		if (!spu_wbox_write(ctx->spu, wbox_data))
33867207b96SArnd Bergmann 			ret = -EAGAIN;
33967207b96SArnd Bergmann 	} else {
34067207b96SArnd Bergmann 		ret = wait_event_interruptible(ctx->spu->wbox_wq,
34167207b96SArnd Bergmann 			spu_wbox_write(ctx->spu, wbox_data));
34267207b96SArnd Bergmann 	}
34367207b96SArnd Bergmann 
34467207b96SArnd Bergmann 	return ret ? ret : sizeof wbox_data;
34567207b96SArnd Bergmann }
34667207b96SArnd Bergmann 
34767207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
34867207b96SArnd Bergmann {
34967207b96SArnd Bergmann 	struct spu_context *ctx;
35067207b96SArnd Bergmann 	struct spu_problem __iomem *prob;
35167207b96SArnd Bergmann 	u32 mbox_stat;
35267207b96SArnd Bergmann 	unsigned int mask;
35367207b96SArnd Bergmann 
35467207b96SArnd Bergmann 	ctx = file->private_data;
35567207b96SArnd Bergmann 	prob = ctx->spu->problem;
35667207b96SArnd Bergmann 	mbox_stat = in_be32(&prob->mb_stat_R);
35767207b96SArnd Bergmann 
35867207b96SArnd Bergmann 	poll_wait(file, &ctx->spu->wbox_wq, wait);
35967207b96SArnd Bergmann 
36067207b96SArnd Bergmann 	mask = 0;
36167207b96SArnd Bergmann 	if (mbox_stat & 0x00ff00)
36267207b96SArnd Bergmann 		mask = POLLOUT | POLLWRNORM;
36367207b96SArnd Bergmann 
36467207b96SArnd Bergmann 	return mask;
36567207b96SArnd Bergmann }
36667207b96SArnd Bergmann 
36767207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = {
36867207b96SArnd Bergmann 	.open	= spufs_pipe_open,
36967207b96SArnd Bergmann 	.write	= spufs_wbox_write,
37067207b96SArnd Bergmann 	.poll	= spufs_wbox_poll,
37167207b96SArnd Bergmann 	.fasync	= spufs_wbox_fasync,
37267207b96SArnd Bergmann };
37367207b96SArnd Bergmann 
37467207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
37567207b96SArnd Bergmann 			size_t len, loff_t *pos)
37667207b96SArnd Bergmann {
37767207b96SArnd Bergmann 	struct spu_context *ctx;
37867207b96SArnd Bergmann 	u32 wbox_stat;
37967207b96SArnd Bergmann 
38067207b96SArnd Bergmann 	if (len < 4)
38167207b96SArnd Bergmann 		return -EINVAL;
38267207b96SArnd Bergmann 
38367207b96SArnd Bergmann 	ctx = file->private_data;
38467207b96SArnd Bergmann 	wbox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 8) & 0xff;
38567207b96SArnd Bergmann 
38667207b96SArnd Bergmann 	if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
38767207b96SArnd Bergmann 		return -EFAULT;
38867207b96SArnd Bergmann 
38967207b96SArnd Bergmann 	return 4;
39067207b96SArnd Bergmann }
39167207b96SArnd Bergmann 
39267207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = {
39367207b96SArnd Bergmann 	.open	= spufs_pipe_open,
39467207b96SArnd Bergmann 	.read	= spufs_wbox_stat_read,
39567207b96SArnd Bergmann };
39667207b96SArnd Bergmann 
39767207b96SArnd Bergmann long spufs_run_spu(struct file *file, struct spu_context *ctx,
39867207b96SArnd Bergmann 		u32 *npc, u32 *status)
39967207b96SArnd Bergmann {
40067207b96SArnd Bergmann 	struct spu_problem __iomem *prob;
40167207b96SArnd Bergmann 	int ret;
40267207b96SArnd Bergmann 
40367207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
40467207b96SArnd Bergmann 		ret = -EAGAIN;
40567207b96SArnd Bergmann 		if (!down_write_trylock(&ctx->backing_sema))
40667207b96SArnd Bergmann 			goto out;
40767207b96SArnd Bergmann 	} else {
40867207b96SArnd Bergmann 		down_write(&ctx->backing_sema);
40967207b96SArnd Bergmann 	}
41067207b96SArnd Bergmann 
41167207b96SArnd Bergmann 	prob = ctx->spu->problem;
41267207b96SArnd Bergmann 	out_be32(&prob->spu_npc_RW, *npc);
41367207b96SArnd Bergmann 
41467207b96SArnd Bergmann 	ret = spu_run(ctx->spu);
41567207b96SArnd Bergmann 
41667207b96SArnd Bergmann 	*status = in_be32(&prob->spu_status_R);
41767207b96SArnd Bergmann 	*npc = in_be32(&prob->spu_npc_RW);
41867207b96SArnd Bergmann 
41967207b96SArnd Bergmann 	up_write(&ctx->backing_sema);
42067207b96SArnd Bergmann 
42167207b96SArnd Bergmann out:
42267207b96SArnd Bergmann 	return ret;
42367207b96SArnd Bergmann }
42467207b96SArnd Bergmann 
42567207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
42667207b96SArnd Bergmann 			size_t len, loff_t *pos)
42767207b96SArnd Bergmann {
42867207b96SArnd Bergmann 	struct spu_context *ctx;
42967207b96SArnd Bergmann 	struct spu_problem *prob;
43067207b96SArnd Bergmann 	u32 data;
43167207b96SArnd Bergmann 
43267207b96SArnd Bergmann 	ctx = file->private_data;
43367207b96SArnd Bergmann 	prob = ctx->spu->problem;
43467207b96SArnd Bergmann 
43567207b96SArnd Bergmann 	if (len < 4)
43667207b96SArnd Bergmann 		return -EINVAL;
43767207b96SArnd Bergmann 
43867207b96SArnd Bergmann 	data = in_be32(&prob->signal_notify1);
43967207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
44067207b96SArnd Bergmann 		return -EFAULT;
44167207b96SArnd Bergmann 
44267207b96SArnd Bergmann 	return 4;
44367207b96SArnd Bergmann }
44467207b96SArnd Bergmann 
44567207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
44667207b96SArnd Bergmann 			size_t len, loff_t *pos)
44767207b96SArnd Bergmann {
44867207b96SArnd Bergmann 	struct spu_context *ctx;
44967207b96SArnd Bergmann 	struct spu_problem *prob;
45067207b96SArnd Bergmann 	u32 data;
45167207b96SArnd Bergmann 
45267207b96SArnd Bergmann 	ctx = file->private_data;
45367207b96SArnd Bergmann 	prob = ctx->spu->problem;
45467207b96SArnd Bergmann 
45567207b96SArnd Bergmann 	if (len < 4)
45667207b96SArnd Bergmann 		return -EINVAL;
45767207b96SArnd Bergmann 
45867207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
45967207b96SArnd Bergmann 		return -EFAULT;
46067207b96SArnd Bergmann 
46167207b96SArnd Bergmann 	out_be32(&prob->signal_notify1, data);
46267207b96SArnd Bergmann 
46367207b96SArnd Bergmann 	return 4;
46467207b96SArnd Bergmann }
46567207b96SArnd Bergmann 
46667207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = {
46767207b96SArnd Bergmann 	.open = spufs_pipe_open,
46867207b96SArnd Bergmann 	.read = spufs_signal1_read,
46967207b96SArnd Bergmann 	.write = spufs_signal1_write,
47067207b96SArnd Bergmann };
47167207b96SArnd Bergmann 
47267207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
47367207b96SArnd Bergmann 			size_t len, loff_t *pos)
47467207b96SArnd Bergmann {
47567207b96SArnd Bergmann 	struct spu_context *ctx;
47667207b96SArnd Bergmann 	struct spu_problem *prob;
47767207b96SArnd Bergmann 	u32 data;
47867207b96SArnd Bergmann 
47967207b96SArnd Bergmann 	ctx = file->private_data;
48067207b96SArnd Bergmann 	prob = ctx->spu->problem;
48167207b96SArnd Bergmann 
48267207b96SArnd Bergmann 	if (len < 4)
48367207b96SArnd Bergmann 		return -EINVAL;
48467207b96SArnd Bergmann 
48567207b96SArnd Bergmann 	data = in_be32(&prob->signal_notify2);
48667207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
48767207b96SArnd Bergmann 		return -EFAULT;
48867207b96SArnd Bergmann 
48967207b96SArnd Bergmann 	return 4;
49067207b96SArnd Bergmann }
49167207b96SArnd Bergmann 
49267207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
49367207b96SArnd Bergmann 			size_t len, loff_t *pos)
49467207b96SArnd Bergmann {
49567207b96SArnd Bergmann 	struct spu_context *ctx;
49667207b96SArnd Bergmann 	struct spu_problem *prob;
49767207b96SArnd Bergmann 	u32 data;
49867207b96SArnd Bergmann 
49967207b96SArnd Bergmann 	ctx = file->private_data;
50067207b96SArnd Bergmann 	prob = ctx->spu->problem;
50167207b96SArnd Bergmann 
50267207b96SArnd Bergmann 	if (len < 4)
50367207b96SArnd Bergmann 		return -EINVAL;
50467207b96SArnd Bergmann 
50567207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
50667207b96SArnd Bergmann 		return -EFAULT;
50767207b96SArnd Bergmann 
50867207b96SArnd Bergmann 	out_be32(&prob->signal_notify2, data);
50967207b96SArnd Bergmann 
51067207b96SArnd Bergmann 	return 4;
51167207b96SArnd Bergmann }
51267207b96SArnd Bergmann 
51367207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = {
51467207b96SArnd Bergmann 	.open = spufs_pipe_open,
51567207b96SArnd Bergmann 	.read = spufs_signal2_read,
51667207b96SArnd Bergmann 	.write = spufs_signal2_write,
51767207b96SArnd Bergmann };
51867207b96SArnd Bergmann 
51967207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val)
52067207b96SArnd Bergmann {
52167207b96SArnd Bergmann 	struct spu_context *ctx = data;
52267207b96SArnd Bergmann 	struct spu_priv2 *priv2 = ctx->spu->priv2;
52367207b96SArnd Bergmann 	u64 tmp;
52467207b96SArnd Bergmann 
52567207b96SArnd Bergmann 	spin_lock_irq(&ctx->spu->register_lock);
52667207b96SArnd Bergmann 	tmp = in_be64(&priv2->spu_cfg_RW);
52767207b96SArnd Bergmann 	if (val)
52867207b96SArnd Bergmann 		tmp |= 1;
52967207b96SArnd Bergmann 	else
53067207b96SArnd Bergmann 		tmp &= ~1;
53167207b96SArnd Bergmann 	out_be64(&priv2->spu_cfg_RW, tmp);
53267207b96SArnd Bergmann 	spin_unlock_irq(&ctx->spu->register_lock);
53367207b96SArnd Bergmann }
53467207b96SArnd Bergmann 
53567207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data)
53667207b96SArnd Bergmann {
53767207b96SArnd Bergmann 	struct spu_context *ctx = data;
53867207b96SArnd Bergmann 	return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0;
53967207b96SArnd Bergmann }
54067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
54167207b96SArnd Bergmann 					spufs_signal1_type_set, "%llu");
54267207b96SArnd Bergmann 
54367207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val)
54467207b96SArnd Bergmann {
54567207b96SArnd Bergmann 	struct spu_context *ctx = data;
54667207b96SArnd Bergmann 	struct spu_priv2 *priv2 = ctx->spu->priv2;
54767207b96SArnd Bergmann 	u64 tmp;
54867207b96SArnd Bergmann 
54967207b96SArnd Bergmann 	spin_lock_irq(&ctx->spu->register_lock);
55067207b96SArnd Bergmann 	tmp = in_be64(&priv2->spu_cfg_RW);
55167207b96SArnd Bergmann 	if (val)
55267207b96SArnd Bergmann 		tmp |= 2;
55367207b96SArnd Bergmann 	else
55467207b96SArnd Bergmann 		tmp &= ~2;
55567207b96SArnd Bergmann 	out_be64(&priv2->spu_cfg_RW, tmp);
55667207b96SArnd Bergmann 	spin_unlock_irq(&ctx->spu->register_lock);
55767207b96SArnd Bergmann }
55867207b96SArnd Bergmann 
55967207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data)
56067207b96SArnd Bergmann {
56167207b96SArnd Bergmann 	struct spu_context *ctx = data;
56267207b96SArnd Bergmann 	return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0;
56367207b96SArnd Bergmann }
56467207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
56567207b96SArnd Bergmann 					spufs_signal2_type_set, "%llu");
56667207b96SArnd Bergmann 
56767207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val)
56867207b96SArnd Bergmann {
56967207b96SArnd Bergmann 	struct spu_context *ctx = data;
57067207b96SArnd Bergmann 	out_be32(&ctx->spu->problem->spu_npc_RW, val);
57167207b96SArnd Bergmann }
57267207b96SArnd Bergmann 
57367207b96SArnd Bergmann static u64 spufs_npc_get(void *data)
57467207b96SArnd Bergmann {
57567207b96SArnd Bergmann 	struct spu_context *ctx = data;
57667207b96SArnd Bergmann 	u64 ret;
57767207b96SArnd Bergmann 	ret = in_be32(&ctx->spu->problem->spu_npc_RW);
57867207b96SArnd Bergmann 	return ret;
57967207b96SArnd Bergmann }
58067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
58167207b96SArnd Bergmann 
58267207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = {
58367207b96SArnd Bergmann 	{ "mem",  &spufs_mem_fops,  0666, },
58467207b96SArnd Bergmann 	{ "mbox", &spufs_mbox_fops, 0444, },
58567207b96SArnd Bergmann 	{ "ibox", &spufs_ibox_fops, 0444, },
58667207b96SArnd Bergmann 	{ "wbox", &spufs_wbox_fops, 0222, },
58767207b96SArnd Bergmann 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
58867207b96SArnd Bergmann 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
58967207b96SArnd Bergmann 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
59067207b96SArnd Bergmann 	{ "signal1", &spufs_signal1_fops, 0666, },
59167207b96SArnd Bergmann 	{ "signal2", &spufs_signal2_fops, 0666, },
59267207b96SArnd Bergmann 	{ "signal1_type", &spufs_signal1_type, 0666, },
59367207b96SArnd Bergmann 	{ "signal2_type", &spufs_signal2_type, 0666, },
59467207b96SArnd Bergmann 	{ "npc", &spufs_npc_ops, 0666, },
59567207b96SArnd Bergmann 	{},
59667207b96SArnd Bergmann };
597