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 
23a33a7d73SArnd Bergmann #undef DEBUG
24a33a7d73SArnd Bergmann 
2567207b96SArnd Bergmann #include <linux/fs.h>
2667207b96SArnd Bergmann #include <linux/ioctl.h>
2767207b96SArnd Bergmann #include <linux/module.h>
28d88cfffaSArnd Bergmann #include <linux/pagemap.h>
2967207b96SArnd Bergmann #include <linux/poll.h>
305110459fSArnd Bergmann #include <linux/ptrace.h>
3167207b96SArnd Bergmann 
3267207b96SArnd Bergmann #include <asm/io.h>
3367207b96SArnd Bergmann #include <asm/semaphore.h>
3467207b96SArnd Bergmann #include <asm/spu.h>
35b9e3bd77SDwayne Grant McConnell #include <asm/spu_info.h>
3667207b96SArnd Bergmann #include <asm/uaccess.h>
3767207b96SArnd Bergmann 
3867207b96SArnd Bergmann #include "spufs.h"
3967207b96SArnd Bergmann 
4027d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
4127d5bf2aSBenjamin Herrenschmidt 
4267207b96SArnd Bergmann static int
4367207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file)
4467207b96SArnd Bergmann {
4567207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
466df10a82SMark Nutter 	struct spu_context *ctx = i->i_ctx;
4743c2bbd9SChristoph Hellwig 
4843c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
496df10a82SMark Nutter 	file->private_data = ctx;
5043c2bbd9SChristoph Hellwig 	if (!i->i_openers++)
516df10a82SMark Nutter 		ctx->local_store = inode->i_mapping;
5243c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
5343c2bbd9SChristoph Hellwig 	smp_wmb();
5443c2bbd9SChristoph Hellwig 	return 0;
5543c2bbd9SChristoph Hellwig }
5643c2bbd9SChristoph Hellwig 
5743c2bbd9SChristoph Hellwig static int
5843c2bbd9SChristoph Hellwig spufs_mem_release(struct inode *inode, struct file *file)
5943c2bbd9SChristoph Hellwig {
6043c2bbd9SChristoph Hellwig 	struct spufs_inode_info *i = SPUFS_I(inode);
6143c2bbd9SChristoph Hellwig 	struct spu_context *ctx = i->i_ctx;
6243c2bbd9SChristoph Hellwig 
6343c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
6443c2bbd9SChristoph Hellwig 	if (!--i->i_openers)
6543c2bbd9SChristoph Hellwig 		ctx->local_store = NULL;
6643c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
6717e0e270SBenjamin Herrenschmidt 	smp_wmb();
6867207b96SArnd Bergmann 	return 0;
6967207b96SArnd Bergmann }
7067207b96SArnd Bergmann 
7167207b96SArnd Bergmann static ssize_t
72bf1ab978SDwayne Grant McConnell __spufs_mem_read(struct spu_context *ctx, char __user *buffer,
73bf1ab978SDwayne Grant McConnell 			size_t size, loff_t *pos)
74bf1ab978SDwayne Grant McConnell {
75bf1ab978SDwayne Grant McConnell 	char *local_store = ctx->ops->get_ls(ctx);
76bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buffer, size, pos, local_store,
77bf1ab978SDwayne Grant McConnell 					LS_SIZE);
78bf1ab978SDwayne Grant McConnell }
79bf1ab978SDwayne Grant McConnell 
80bf1ab978SDwayne Grant McConnell static ssize_t
8167207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer,
8267207b96SArnd Bergmann 				size_t size, loff_t *pos)
8367207b96SArnd Bergmann {
84bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
85aa0ed2bdSArnd Bergmann 	ssize_t ret;
8667207b96SArnd Bergmann 
878b3d6663SArnd Bergmann 	spu_acquire(ctx);
88bf1ab978SDwayne Grant McConnell 	ret = __spufs_mem_read(ctx, buffer, size, pos);
898b3d6663SArnd Bergmann 	spu_release(ctx);
9067207b96SArnd Bergmann 	return ret;
9167207b96SArnd Bergmann }
9267207b96SArnd Bergmann 
9367207b96SArnd Bergmann static ssize_t
9467207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer,
95aa0ed2bdSArnd Bergmann 					size_t size, loff_t *ppos)
9667207b96SArnd Bergmann {
9767207b96SArnd Bergmann 	struct spu_context *ctx = file->private_data;
988b3d6663SArnd Bergmann 	char *local_store;
99aa0ed2bdSArnd Bergmann 	loff_t pos = *ppos;
1008b3d6663SArnd Bergmann 	int ret;
10167207b96SArnd Bergmann 
102aa0ed2bdSArnd Bergmann 	if (pos < 0)
103aa0ed2bdSArnd Bergmann 		return -EINVAL;
104aa0ed2bdSArnd Bergmann 	if (pos > LS_SIZE)
10567207b96SArnd Bergmann 		return -EFBIG;
106aa0ed2bdSArnd Bergmann 	if (size > LS_SIZE - pos)
107aa0ed2bdSArnd Bergmann 		size = LS_SIZE - pos;
1088b3d6663SArnd Bergmann 
1098b3d6663SArnd Bergmann 	spu_acquire(ctx);
1108b3d6663SArnd Bergmann 	local_store = ctx->ops->get_ls(ctx);
111aa0ed2bdSArnd Bergmann 	ret = copy_from_user(local_store + pos, buffer, size);
1128b3d6663SArnd Bergmann 	spu_release(ctx);
113aa0ed2bdSArnd Bergmann 
114aa0ed2bdSArnd Bergmann 	if (ret)
115aa0ed2bdSArnd Bergmann 		return -EFAULT;
116aa0ed2bdSArnd Bergmann 	*ppos = pos + size;
117aa0ed2bdSArnd Bergmann 	return size;
11867207b96SArnd Bergmann }
11967207b96SArnd Bergmann 
12078bde53eSBenjamin Herrenschmidt static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,
12178bde53eSBenjamin Herrenschmidt 					  unsigned long address)
1228b3d6663SArnd Bergmann {
1238b3d6663SArnd Bergmann 	struct spu_context *ctx = vma->vm_file->private_data;
12478bde53eSBenjamin Herrenschmidt 	unsigned long pfn, offset = address - vma->vm_start;
12578bde53eSBenjamin Herrenschmidt 
1268b3d6663SArnd Bergmann 	offset += vma->vm_pgoff << PAGE_SHIFT;
1278b3d6663SArnd Bergmann 
128128b8546SMasato Noguchi 	if (offset >= LS_SIZE)
129128b8546SMasato Noguchi 		return NOPFN_SIGBUS;
130128b8546SMasato Noguchi 
1318b3d6663SArnd Bergmann 	spu_acquire(ctx);
1328b3d6663SArnd Bergmann 
133ac91cb8dSArnd Bergmann 	if (ctx->state == SPU_STATE_SAVED) {
134ac91cb8dSArnd Bergmann 		vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
135932f535dSArnd Bergmann 							& ~_PAGE_NO_CACHE);
13678bde53eSBenjamin Herrenschmidt 		pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset);
137ac91cb8dSArnd Bergmann 	} else {
138ac91cb8dSArnd Bergmann 		vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
139932f535dSArnd Bergmann 					     | _PAGE_NO_CACHE);
14078bde53eSBenjamin Herrenschmidt 		pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT;
141ac91cb8dSArnd Bergmann 	}
14278bde53eSBenjamin Herrenschmidt 	vm_insert_pfn(vma, address, pfn);
14378bde53eSBenjamin Herrenschmidt 
1448b3d6663SArnd Bergmann 	spu_release(ctx);
1458b3d6663SArnd Bergmann 
14678bde53eSBenjamin Herrenschmidt 	return NOPFN_REFAULT;
1478b3d6663SArnd Bergmann }
1488b3d6663SArnd Bergmann 
14978bde53eSBenjamin Herrenschmidt 
1508b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = {
15178bde53eSBenjamin Herrenschmidt 	.nopfn = spufs_mem_mmap_nopfn,
1528b3d6663SArnd Bergmann };
1538b3d6663SArnd Bergmann 
15467207b96SArnd Bergmann static int
15567207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
15667207b96SArnd Bergmann {
1578b3d6663SArnd Bergmann 	if (!(vma->vm_flags & VM_SHARED))
1588b3d6663SArnd Bergmann 		return -EINVAL;
15967207b96SArnd Bergmann 
16078bde53eSBenjamin Herrenschmidt 	vma->vm_flags |= VM_IO | VM_PFNMAP;
16167207b96SArnd Bergmann 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
16267207b96SArnd Bergmann 				     | _PAGE_NO_CACHE);
1638b3d6663SArnd Bergmann 
1648b3d6663SArnd Bergmann 	vma->vm_ops = &spufs_mem_mmap_vmops;
16567207b96SArnd Bergmann 	return 0;
16667207b96SArnd Bergmann }
16767207b96SArnd Bergmann 
1685dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = {
16967207b96SArnd Bergmann 	.open	 = spufs_mem_open,
17043c2bbd9SChristoph Hellwig 	.release = spufs_mem_release,
17167207b96SArnd Bergmann 	.read    = spufs_mem_read,
17267207b96SArnd Bergmann 	.write   = spufs_mem_write,
1738b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
17467207b96SArnd Bergmann 	.mmap    = spufs_mem_mmap,
1758b3d6663SArnd Bergmann };
1768b3d6663SArnd Bergmann 
17778bde53eSBenjamin Herrenschmidt static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
1786df10a82SMark Nutter 				    unsigned long address,
17978bde53eSBenjamin Herrenschmidt 				    unsigned long ps_offs,
18027d5bf2aSBenjamin Herrenschmidt 				    unsigned long ps_size)
1816df10a82SMark Nutter {
1826df10a82SMark Nutter 	struct spu_context *ctx = vma->vm_file->private_data;
18378bde53eSBenjamin Herrenschmidt 	unsigned long area, offset = address - vma->vm_start;
1846df10a82SMark Nutter 	int ret;
1856df10a82SMark Nutter 
1866df10a82SMark Nutter 	offset += vma->vm_pgoff << PAGE_SHIFT;
18727d5bf2aSBenjamin Herrenschmidt 	if (offset >= ps_size)
18878bde53eSBenjamin Herrenschmidt 		return NOPFN_SIGBUS;
1896df10a82SMark Nutter 
19078bde53eSBenjamin Herrenschmidt 	/* error here usually means a signal.. we might want to test
19178bde53eSBenjamin Herrenschmidt 	 * the error code more precisely though
19278bde53eSBenjamin Herrenschmidt 	 */
19326bec673SChristoph Hellwig 	ret = spu_acquire_runnable(ctx, 0);
1946df10a82SMark Nutter 	if (ret)
19578bde53eSBenjamin Herrenschmidt 		return NOPFN_REFAULT;
1966df10a82SMark Nutter 
1976df10a82SMark Nutter 	area = ctx->spu->problem_phys + ps_offs;
19878bde53eSBenjamin Herrenschmidt 	vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT);
1996df10a82SMark Nutter 	spu_release(ctx);
2006df10a82SMark Nutter 
20178bde53eSBenjamin Herrenschmidt 	return NOPFN_REFAULT;
2026df10a82SMark Nutter }
2036df10a82SMark Nutter 
20427d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K
20578bde53eSBenjamin Herrenschmidt static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma,
20678bde53eSBenjamin Herrenschmidt 					   unsigned long address)
2076df10a82SMark Nutter {
20878bde53eSBenjamin Herrenschmidt 	return spufs_ps_nopfn(vma, address, 0x4000, 0x1000);
2096df10a82SMark Nutter }
2106df10a82SMark Nutter 
2116df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = {
21278bde53eSBenjamin Herrenschmidt 	.nopfn = spufs_cntl_mmap_nopfn,
2136df10a82SMark Nutter };
2146df10a82SMark Nutter 
2156df10a82SMark Nutter /*
2166df10a82SMark Nutter  * mmap support for problem state control area [0x4000 - 0x4fff].
2176df10a82SMark Nutter  */
2186df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
2196df10a82SMark Nutter {
2206df10a82SMark Nutter 	if (!(vma->vm_flags & VM_SHARED))
2216df10a82SMark Nutter 		return -EINVAL;
2226df10a82SMark Nutter 
22378bde53eSBenjamin Herrenschmidt 	vma->vm_flags |= VM_IO | VM_PFNMAP;
2246df10a82SMark Nutter 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
22523cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
2266df10a82SMark Nutter 
2276df10a82SMark Nutter 	vma->vm_ops = &spufs_cntl_mmap_vmops;
2286df10a82SMark Nutter 	return 0;
2296df10a82SMark Nutter }
23027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */
23127d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL
23227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */
2336df10a82SMark Nutter 
234e1dbff2bSArnd Bergmann static u64 spufs_cntl_get(void *data)
235e1dbff2bSArnd Bergmann {
236e1dbff2bSArnd Bergmann 	struct spu_context *ctx = data;
237e1dbff2bSArnd Bergmann 	u64 val;
238e1dbff2bSArnd Bergmann 
239e1dbff2bSArnd Bergmann 	spu_acquire(ctx);
240e1dbff2bSArnd Bergmann 	val = ctx->ops->status_read(ctx);
241e1dbff2bSArnd Bergmann 	spu_release(ctx);
242e1dbff2bSArnd Bergmann 
243e1dbff2bSArnd Bergmann 	return val;
244e1dbff2bSArnd Bergmann }
245e1dbff2bSArnd Bergmann 
246e1dbff2bSArnd Bergmann static void spufs_cntl_set(void *data, u64 val)
247e1dbff2bSArnd Bergmann {
248e1dbff2bSArnd Bergmann 	struct spu_context *ctx = data;
249e1dbff2bSArnd Bergmann 
250e1dbff2bSArnd Bergmann 	spu_acquire(ctx);
251e1dbff2bSArnd Bergmann 	ctx->ops->runcntl_write(ctx, val);
252e1dbff2bSArnd Bergmann 	spu_release(ctx);
253e1dbff2bSArnd Bergmann }
254e1dbff2bSArnd Bergmann 
2556df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file)
2566df10a82SMark Nutter {
2576df10a82SMark Nutter 	struct spufs_inode_info *i = SPUFS_I(inode);
2586df10a82SMark Nutter 	struct spu_context *ctx = i->i_ctx;
2596df10a82SMark Nutter 
26043c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
2616df10a82SMark Nutter 	file->private_data = ctx;
26243c2bbd9SChristoph Hellwig 	if (!i->i_openers++)
2636df10a82SMark Nutter 		ctx->cntl = inode->i_mapping;
26443c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
26517e0e270SBenjamin Herrenschmidt 	smp_wmb();
266e1dbff2bSArnd Bergmann 	return simple_attr_open(inode, file, spufs_cntl_get,
267e1dbff2bSArnd Bergmann 					spufs_cntl_set, "0x%08lx");
2686df10a82SMark Nutter }
2696df10a82SMark Nutter 
27043c2bbd9SChristoph Hellwig static int
27143c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file)
27243c2bbd9SChristoph Hellwig {
27343c2bbd9SChristoph Hellwig 	struct spufs_inode_info *i = SPUFS_I(inode);
27443c2bbd9SChristoph Hellwig 	struct spu_context *ctx = i->i_ctx;
27543c2bbd9SChristoph Hellwig 
27643c2bbd9SChristoph Hellwig 	simple_attr_close(inode, file);
27743c2bbd9SChristoph Hellwig 
27843c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
27943c2bbd9SChristoph Hellwig 	if (!--i->i_openers)
28043c2bbd9SChristoph Hellwig 		ctx->cntl = NULL;
28143c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
28243c2bbd9SChristoph Hellwig 	smp_wmb();
28343c2bbd9SChristoph Hellwig 	return 0;
28443c2bbd9SChristoph Hellwig }
28543c2bbd9SChristoph Hellwig 
2865dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = {
2876df10a82SMark Nutter 	.open = spufs_cntl_open,
28843c2bbd9SChristoph Hellwig 	.release = spufs_cntl_release,
289e1dbff2bSArnd Bergmann 	.read = simple_attr_read,
290e1dbff2bSArnd Bergmann 	.write = simple_attr_write,
2916df10a82SMark Nutter 	.mmap = spufs_cntl_mmap,
2926df10a82SMark Nutter };
2936df10a82SMark Nutter 
2948b3d6663SArnd Bergmann static int
2958b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file)
2968b3d6663SArnd Bergmann {
2978b3d6663SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
2988b3d6663SArnd Bergmann 	file->private_data = i->i_ctx;
2998b3d6663SArnd Bergmann 	return 0;
3008b3d6663SArnd Bergmann }
3018b3d6663SArnd Bergmann 
3028b3d6663SArnd Bergmann static ssize_t
303bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer,
304bf1ab978SDwayne Grant McConnell 			size_t size, loff_t *pos)
305bf1ab978SDwayne Grant McConnell {
306bf1ab978SDwayne Grant McConnell 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
307bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buffer, size, pos,
308bf1ab978SDwayne Grant McConnell 				      lscsa->gprs, sizeof lscsa->gprs);
309bf1ab978SDwayne Grant McConnell }
310bf1ab978SDwayne Grant McConnell 
311bf1ab978SDwayne Grant McConnell static ssize_t
3128b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer,
3138b3d6663SArnd Bergmann 		size_t size, loff_t *pos)
3148b3d6663SArnd Bergmann {
3158b3d6663SArnd Bergmann 	int ret;
316bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
3178b3d6663SArnd Bergmann 
3188b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
319bf1ab978SDwayne Grant McConnell 	ret = __spufs_regs_read(ctx, buffer, size, pos);
3208b3d6663SArnd Bergmann 	spu_release(ctx);
3218b3d6663SArnd Bergmann 	return ret;
3228b3d6663SArnd Bergmann }
3238b3d6663SArnd Bergmann 
3248b3d6663SArnd Bergmann static ssize_t
3258b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer,
3268b3d6663SArnd Bergmann 		 size_t size, loff_t *pos)
3278b3d6663SArnd Bergmann {
3288b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
3298b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
3308b3d6663SArnd Bergmann 	int ret;
3318b3d6663SArnd Bergmann 
3328b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
3338b3d6663SArnd Bergmann 	if (size <= 0)
3348b3d6663SArnd Bergmann 		return -EFBIG;
3358b3d6663SArnd Bergmann 	*pos += size;
3368b3d6663SArnd Bergmann 
3378b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
3388b3d6663SArnd Bergmann 
3398b3d6663SArnd Bergmann 	ret = copy_from_user(lscsa->gprs + *pos - size,
3408b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
3418b3d6663SArnd Bergmann 
3428b3d6663SArnd Bergmann 	spu_release(ctx);
3438b3d6663SArnd Bergmann 	return ret;
3448b3d6663SArnd Bergmann }
3458b3d6663SArnd Bergmann 
3465dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = {
3478b3d6663SArnd Bergmann 	.open	 = spufs_regs_open,
3488b3d6663SArnd Bergmann 	.read    = spufs_regs_read,
3498b3d6663SArnd Bergmann 	.write   = spufs_regs_write,
3508b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
3518b3d6663SArnd Bergmann };
3528b3d6663SArnd Bergmann 
3538b3d6663SArnd Bergmann static ssize_t
354bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer,
355bf1ab978SDwayne Grant McConnell 			size_t size, loff_t * pos)
356bf1ab978SDwayne Grant McConnell {
357bf1ab978SDwayne Grant McConnell 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
358bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buffer, size, pos,
359bf1ab978SDwayne Grant McConnell 				      &lscsa->fpcr, sizeof(lscsa->fpcr));
360bf1ab978SDwayne Grant McConnell }
361bf1ab978SDwayne Grant McConnell 
362bf1ab978SDwayne Grant McConnell static ssize_t
3638b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer,
3648b3d6663SArnd Bergmann 		size_t size, loff_t * pos)
3658b3d6663SArnd Bergmann {
3668b3d6663SArnd Bergmann 	int ret;
367bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
3688b3d6663SArnd Bergmann 
3698b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
370bf1ab978SDwayne Grant McConnell 	ret = __spufs_fpcr_read(ctx, buffer, size, pos);
3718b3d6663SArnd Bergmann 	spu_release(ctx);
3728b3d6663SArnd Bergmann 	return ret;
3738b3d6663SArnd Bergmann }
3748b3d6663SArnd Bergmann 
3758b3d6663SArnd Bergmann static ssize_t
3768b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer,
3778b3d6663SArnd Bergmann 		 size_t size, loff_t * pos)
3788b3d6663SArnd Bergmann {
3798b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
3808b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
3818b3d6663SArnd Bergmann 	int ret;
3828b3d6663SArnd Bergmann 
3838b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
3848b3d6663SArnd Bergmann 	if (size <= 0)
3858b3d6663SArnd Bergmann 		return -EFBIG;
3868b3d6663SArnd Bergmann 	*pos += size;
3878b3d6663SArnd Bergmann 
3888b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
3898b3d6663SArnd Bergmann 
3908b3d6663SArnd Bergmann 	ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
3918b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
3928b3d6663SArnd Bergmann 
3938b3d6663SArnd Bergmann 	spu_release(ctx);
3948b3d6663SArnd Bergmann 	return ret;
3958b3d6663SArnd Bergmann }
3968b3d6663SArnd Bergmann 
3975dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = {
3988b3d6663SArnd Bergmann 	.open = spufs_regs_open,
3998b3d6663SArnd Bergmann 	.read = spufs_fpcr_read,
4008b3d6663SArnd Bergmann 	.write = spufs_fpcr_write,
40167207b96SArnd Bergmann 	.llseek = generic_file_llseek,
40267207b96SArnd Bergmann };
40367207b96SArnd Bergmann 
40467207b96SArnd Bergmann /* generic open function for all pipe-like files */
40567207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file)
40667207b96SArnd Bergmann {
40767207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
40867207b96SArnd Bergmann 	file->private_data = i->i_ctx;
40967207b96SArnd Bergmann 
41067207b96SArnd Bergmann 	return nonseekable_open(inode, file);
41167207b96SArnd Bergmann }
41267207b96SArnd Bergmann 
413cdcc89bbSArnd Bergmann /*
414cdcc89bbSArnd Bergmann  * Read as many bytes from the mailbox as possible, until
415cdcc89bbSArnd Bergmann  * one of the conditions becomes true:
416cdcc89bbSArnd Bergmann  *
417cdcc89bbSArnd Bergmann  * - no more data available in the mailbox
418cdcc89bbSArnd Bergmann  * - end of the user provided buffer
419cdcc89bbSArnd Bergmann  * - end of the mapped area
420cdcc89bbSArnd Bergmann  */
42167207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
42267207b96SArnd Bergmann 			size_t len, loff_t *pos)
42367207b96SArnd Bergmann {
4248b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
425cdcc89bbSArnd Bergmann 	u32 mbox_data, __user *udata;
426cdcc89bbSArnd Bergmann 	ssize_t count;
42767207b96SArnd Bergmann 
42867207b96SArnd Bergmann 	if (len < 4)
42967207b96SArnd Bergmann 		return -EINVAL;
43067207b96SArnd Bergmann 
431cdcc89bbSArnd Bergmann 	if (!access_ok(VERIFY_WRITE, buf, len))
43267207b96SArnd Bergmann 		return -EFAULT;
43367207b96SArnd Bergmann 
434cdcc89bbSArnd Bergmann 	udata = (void __user *)buf;
435cdcc89bbSArnd Bergmann 
436cdcc89bbSArnd Bergmann 	spu_acquire(ctx);
437274cef5eSArnd Bergmann 	for (count = 0; (count + 4) <= len; count += 4, udata++) {
438cdcc89bbSArnd Bergmann 		int ret;
439cdcc89bbSArnd Bergmann 		ret = ctx->ops->mbox_read(ctx, &mbox_data);
440cdcc89bbSArnd Bergmann 		if (ret == 0)
441cdcc89bbSArnd Bergmann 			break;
442cdcc89bbSArnd Bergmann 
443cdcc89bbSArnd Bergmann 		/*
444cdcc89bbSArnd Bergmann 		 * at the end of the mapped area, we can fault
445cdcc89bbSArnd Bergmann 		 * but still need to return the data we have
446cdcc89bbSArnd Bergmann 		 * read successfully so far.
447cdcc89bbSArnd Bergmann 		 */
448cdcc89bbSArnd Bergmann 		ret = __put_user(mbox_data, udata);
449cdcc89bbSArnd Bergmann 		if (ret) {
450cdcc89bbSArnd Bergmann 			if (!count)
451cdcc89bbSArnd Bergmann 				count = -EFAULT;
452cdcc89bbSArnd Bergmann 			break;
453cdcc89bbSArnd Bergmann 		}
454cdcc89bbSArnd Bergmann 	}
455cdcc89bbSArnd Bergmann 	spu_release(ctx);
456cdcc89bbSArnd Bergmann 
457cdcc89bbSArnd Bergmann 	if (!count)
458cdcc89bbSArnd Bergmann 		count = -EAGAIN;
459cdcc89bbSArnd Bergmann 
460cdcc89bbSArnd Bergmann 	return count;
46167207b96SArnd Bergmann }
46267207b96SArnd Bergmann 
4635dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = {
46467207b96SArnd Bergmann 	.open	= spufs_pipe_open,
46567207b96SArnd Bergmann 	.read	= spufs_mbox_read,
46667207b96SArnd Bergmann };
46767207b96SArnd Bergmann 
46867207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
46967207b96SArnd Bergmann 			size_t len, loff_t *pos)
47067207b96SArnd Bergmann {
4718b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
47267207b96SArnd Bergmann 	u32 mbox_stat;
47367207b96SArnd Bergmann 
47467207b96SArnd Bergmann 	if (len < 4)
47567207b96SArnd Bergmann 		return -EINVAL;
47667207b96SArnd Bergmann 
4778b3d6663SArnd Bergmann 	spu_acquire(ctx);
4788b3d6663SArnd Bergmann 
4798b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
4808b3d6663SArnd Bergmann 
4818b3d6663SArnd Bergmann 	spu_release(ctx);
48267207b96SArnd Bergmann 
48367207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
48467207b96SArnd Bergmann 		return -EFAULT;
48567207b96SArnd Bergmann 
48667207b96SArnd Bergmann 	return 4;
48767207b96SArnd Bergmann }
48867207b96SArnd Bergmann 
4895dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = {
49067207b96SArnd Bergmann 	.open	= spufs_pipe_open,
49167207b96SArnd Bergmann 	.read	= spufs_mbox_stat_read,
49267207b96SArnd Bergmann };
49367207b96SArnd Bergmann 
49467207b96SArnd Bergmann /* low-level ibox access function */
4958b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
49667207b96SArnd Bergmann {
4978b3d6663SArnd Bergmann 	return ctx->ops->ibox_read(ctx, data);
49867207b96SArnd Bergmann }
49967207b96SArnd Bergmann 
50067207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on)
50167207b96SArnd Bergmann {
5028b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
5038b3d6663SArnd Bergmann 
5048b3d6663SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->ibox_fasync);
5058b3d6663SArnd Bergmann }
5068b3d6663SArnd Bergmann 
5078b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */
5088b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu)
5098b3d6663SArnd Bergmann {
5108b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
5118b3d6663SArnd Bergmann 
5128b3d6663SArnd Bergmann 	wake_up_all(&ctx->ibox_wq);
5138b3d6663SArnd Bergmann 	kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
51467207b96SArnd Bergmann }
51567207b96SArnd Bergmann 
516cdcc89bbSArnd Bergmann /*
517cdcc89bbSArnd Bergmann  * Read as many bytes from the interrupt mailbox as possible, until
518cdcc89bbSArnd Bergmann  * one of the conditions becomes true:
519cdcc89bbSArnd Bergmann  *
520cdcc89bbSArnd Bergmann  * - no more data available in the mailbox
521cdcc89bbSArnd Bergmann  * - end of the user provided buffer
522cdcc89bbSArnd Bergmann  * - end of the mapped area
523cdcc89bbSArnd Bergmann  *
524cdcc89bbSArnd Bergmann  * If the file is opened without O_NONBLOCK, we wait here until
525cdcc89bbSArnd Bergmann  * any data is available, but return when we have been able to
526cdcc89bbSArnd Bergmann  * read something.
527cdcc89bbSArnd Bergmann  */
52867207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
52967207b96SArnd Bergmann 			size_t len, loff_t *pos)
53067207b96SArnd Bergmann {
5318b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
532cdcc89bbSArnd Bergmann 	u32 ibox_data, __user *udata;
533cdcc89bbSArnd Bergmann 	ssize_t count;
53467207b96SArnd Bergmann 
53567207b96SArnd Bergmann 	if (len < 4)
53667207b96SArnd Bergmann 		return -EINVAL;
53767207b96SArnd Bergmann 
538cdcc89bbSArnd Bergmann 	if (!access_ok(VERIFY_WRITE, buf, len))
539cdcc89bbSArnd Bergmann 		return -EFAULT;
540cdcc89bbSArnd Bergmann 
541cdcc89bbSArnd Bergmann 	udata = (void __user *)buf;
542cdcc89bbSArnd Bergmann 
5438b3d6663SArnd Bergmann 	spu_acquire(ctx);
54467207b96SArnd Bergmann 
545cdcc89bbSArnd Bergmann 	/* wait only for the first element */
546cdcc89bbSArnd Bergmann 	count = 0;
54767207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
5488b3d6663SArnd Bergmann 		if (!spu_ibox_read(ctx, &ibox_data))
549cdcc89bbSArnd Bergmann 			count = -EAGAIN;
55067207b96SArnd Bergmann 	} else {
551cdcc89bbSArnd Bergmann 		count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
552cdcc89bbSArnd Bergmann 	}
553cdcc89bbSArnd Bergmann 	if (count)
554cdcc89bbSArnd Bergmann 		goto out;
555cdcc89bbSArnd Bergmann 
556cdcc89bbSArnd Bergmann 	/* if we can't write at all, return -EFAULT */
557cdcc89bbSArnd Bergmann 	count = __put_user(ibox_data, udata);
558cdcc89bbSArnd Bergmann 	if (count)
559cdcc89bbSArnd Bergmann 		goto out;
560cdcc89bbSArnd Bergmann 
561cdcc89bbSArnd Bergmann 	for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
562cdcc89bbSArnd Bergmann 		int ret;
563cdcc89bbSArnd Bergmann 		ret = ctx->ops->ibox_read(ctx, &ibox_data);
564cdcc89bbSArnd Bergmann 		if (ret == 0)
565cdcc89bbSArnd Bergmann 			break;
566cdcc89bbSArnd Bergmann 		/*
567cdcc89bbSArnd Bergmann 		 * at the end of the mapped area, we can fault
568cdcc89bbSArnd Bergmann 		 * but still need to return the data we have
569cdcc89bbSArnd Bergmann 		 * read successfully so far.
570cdcc89bbSArnd Bergmann 		 */
571cdcc89bbSArnd Bergmann 		ret = __put_user(ibox_data, udata);
572cdcc89bbSArnd Bergmann 		if (ret)
573cdcc89bbSArnd Bergmann 			break;
57467207b96SArnd Bergmann 	}
57567207b96SArnd Bergmann 
576cdcc89bbSArnd Bergmann out:
5778b3d6663SArnd Bergmann 	spu_release(ctx);
5788b3d6663SArnd Bergmann 
579cdcc89bbSArnd Bergmann 	return count;
58067207b96SArnd Bergmann }
58167207b96SArnd Bergmann 
58267207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
58367207b96SArnd Bergmann {
5848b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
58567207b96SArnd Bergmann 	unsigned int mask;
58667207b96SArnd Bergmann 
5878b3d6663SArnd Bergmann 	poll_wait(file, &ctx->ibox_wq, wait);
58867207b96SArnd Bergmann 
5893a843d7cSArnd Bergmann 	spu_acquire(ctx);
5903a843d7cSArnd Bergmann 	mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM);
5913a843d7cSArnd Bergmann 	spu_release(ctx);
59267207b96SArnd Bergmann 
59367207b96SArnd Bergmann 	return mask;
59467207b96SArnd Bergmann }
59567207b96SArnd Bergmann 
5965dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = {
59767207b96SArnd Bergmann 	.open	= spufs_pipe_open,
59867207b96SArnd Bergmann 	.read	= spufs_ibox_read,
59967207b96SArnd Bergmann 	.poll	= spufs_ibox_poll,
60067207b96SArnd Bergmann 	.fasync	= spufs_ibox_fasync,
60167207b96SArnd Bergmann };
60267207b96SArnd Bergmann 
60367207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
60467207b96SArnd Bergmann 			size_t len, loff_t *pos)
60567207b96SArnd Bergmann {
6068b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
60767207b96SArnd Bergmann 	u32 ibox_stat;
60867207b96SArnd Bergmann 
60967207b96SArnd Bergmann 	if (len < 4)
61067207b96SArnd Bergmann 		return -EINVAL;
61167207b96SArnd Bergmann 
6128b3d6663SArnd Bergmann 	spu_acquire(ctx);
6138b3d6663SArnd Bergmann 	ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
6148b3d6663SArnd Bergmann 	spu_release(ctx);
61567207b96SArnd Bergmann 
61667207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
61767207b96SArnd Bergmann 		return -EFAULT;
61867207b96SArnd Bergmann 
61967207b96SArnd Bergmann 	return 4;
62067207b96SArnd Bergmann }
62167207b96SArnd Bergmann 
6225dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = {
62367207b96SArnd Bergmann 	.open	= spufs_pipe_open,
62467207b96SArnd Bergmann 	.read	= spufs_ibox_stat_read,
62567207b96SArnd Bergmann };
62667207b96SArnd Bergmann 
62767207b96SArnd Bergmann /* low-level mailbox write */
6288b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data)
62967207b96SArnd Bergmann {
6308b3d6663SArnd Bergmann 	return ctx->ops->wbox_write(ctx, data);
63167207b96SArnd Bergmann }
63267207b96SArnd Bergmann 
63367207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on)
63467207b96SArnd Bergmann {
6358b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
6368b3d6663SArnd Bergmann 	int ret;
6378b3d6663SArnd Bergmann 
6388b3d6663SArnd Bergmann 	ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
6398b3d6663SArnd Bergmann 
6408b3d6663SArnd Bergmann 	return ret;
6418b3d6663SArnd Bergmann }
6428b3d6663SArnd Bergmann 
6438b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */
6448b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu)
6458b3d6663SArnd Bergmann {
6468b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
6478b3d6663SArnd Bergmann 
6488b3d6663SArnd Bergmann 	wake_up_all(&ctx->wbox_wq);
6498b3d6663SArnd Bergmann 	kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
65067207b96SArnd Bergmann }
65167207b96SArnd Bergmann 
652cdcc89bbSArnd Bergmann /*
653cdcc89bbSArnd Bergmann  * Write as many bytes to the interrupt mailbox as possible, until
654cdcc89bbSArnd Bergmann  * one of the conditions becomes true:
655cdcc89bbSArnd Bergmann  *
656cdcc89bbSArnd Bergmann  * - the mailbox is full
657cdcc89bbSArnd Bergmann  * - end of the user provided buffer
658cdcc89bbSArnd Bergmann  * - end of the mapped area
659cdcc89bbSArnd Bergmann  *
660cdcc89bbSArnd Bergmann  * If the file is opened without O_NONBLOCK, we wait here until
661cdcc89bbSArnd Bergmann  * space is availabyl, but return when we have been able to
662cdcc89bbSArnd Bergmann  * write something.
663cdcc89bbSArnd Bergmann  */
66467207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
66567207b96SArnd Bergmann 			size_t len, loff_t *pos)
66667207b96SArnd Bergmann {
6678b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
668cdcc89bbSArnd Bergmann 	u32 wbox_data, __user *udata;
669cdcc89bbSArnd Bergmann 	ssize_t count;
67067207b96SArnd Bergmann 
67167207b96SArnd Bergmann 	if (len < 4)
67267207b96SArnd Bergmann 		return -EINVAL;
67367207b96SArnd Bergmann 
674cdcc89bbSArnd Bergmann 	udata = (void __user *)buf;
675cdcc89bbSArnd Bergmann 	if (!access_ok(VERIFY_READ, buf, len))
676cdcc89bbSArnd Bergmann 		return -EFAULT;
677cdcc89bbSArnd Bergmann 
678cdcc89bbSArnd Bergmann 	if (__get_user(wbox_data, udata))
67967207b96SArnd Bergmann 		return -EFAULT;
68067207b96SArnd Bergmann 
6818b3d6663SArnd Bergmann 	spu_acquire(ctx);
6828b3d6663SArnd Bergmann 
683cdcc89bbSArnd Bergmann 	/*
684cdcc89bbSArnd Bergmann 	 * make sure we can at least write one element, by waiting
685cdcc89bbSArnd Bergmann 	 * in case of !O_NONBLOCK
686cdcc89bbSArnd Bergmann 	 */
687cdcc89bbSArnd Bergmann 	count = 0;
68867207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
6898b3d6663SArnd Bergmann 		if (!spu_wbox_write(ctx, wbox_data))
690cdcc89bbSArnd Bergmann 			count = -EAGAIN;
69167207b96SArnd Bergmann 	} else {
692cdcc89bbSArnd Bergmann 		count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
69367207b96SArnd Bergmann 	}
69467207b96SArnd Bergmann 
695cdcc89bbSArnd Bergmann 	if (count)
696cdcc89bbSArnd Bergmann 		goto out;
6978b3d6663SArnd Bergmann 
698cdcc89bbSArnd Bergmann 	/* write aѕ much as possible */
699cdcc89bbSArnd Bergmann 	for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
700cdcc89bbSArnd Bergmann 		int ret;
701cdcc89bbSArnd Bergmann 		ret = __get_user(wbox_data, udata);
702cdcc89bbSArnd Bergmann 		if (ret)
703cdcc89bbSArnd Bergmann 			break;
704cdcc89bbSArnd Bergmann 
705cdcc89bbSArnd Bergmann 		ret = spu_wbox_write(ctx, wbox_data);
706cdcc89bbSArnd Bergmann 		if (ret == 0)
707cdcc89bbSArnd Bergmann 			break;
708cdcc89bbSArnd Bergmann 	}
709cdcc89bbSArnd Bergmann 
710cdcc89bbSArnd Bergmann out:
711cdcc89bbSArnd Bergmann 	spu_release(ctx);
712cdcc89bbSArnd Bergmann 	return count;
71367207b96SArnd Bergmann }
71467207b96SArnd Bergmann 
71567207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
71667207b96SArnd Bergmann {
7178b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
71867207b96SArnd Bergmann 	unsigned int mask;
71967207b96SArnd Bergmann 
7208b3d6663SArnd Bergmann 	poll_wait(file, &ctx->wbox_wq, wait);
72167207b96SArnd Bergmann 
7223a843d7cSArnd Bergmann 	spu_acquire(ctx);
7233a843d7cSArnd Bergmann 	mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM);
7243a843d7cSArnd Bergmann 	spu_release(ctx);
72567207b96SArnd Bergmann 
72667207b96SArnd Bergmann 	return mask;
72767207b96SArnd Bergmann }
72867207b96SArnd Bergmann 
7295dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = {
73067207b96SArnd Bergmann 	.open	= spufs_pipe_open,
73167207b96SArnd Bergmann 	.write	= spufs_wbox_write,
73267207b96SArnd Bergmann 	.poll	= spufs_wbox_poll,
73367207b96SArnd Bergmann 	.fasync	= spufs_wbox_fasync,
73467207b96SArnd Bergmann };
73567207b96SArnd Bergmann 
73667207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
73767207b96SArnd Bergmann 			size_t len, loff_t *pos)
73867207b96SArnd Bergmann {
7398b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
74067207b96SArnd Bergmann 	u32 wbox_stat;
74167207b96SArnd Bergmann 
74267207b96SArnd Bergmann 	if (len < 4)
74367207b96SArnd Bergmann 		return -EINVAL;
74467207b96SArnd Bergmann 
7458b3d6663SArnd Bergmann 	spu_acquire(ctx);
7468b3d6663SArnd Bergmann 	wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
7478b3d6663SArnd Bergmann 	spu_release(ctx);
74867207b96SArnd Bergmann 
74967207b96SArnd Bergmann 	if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
75067207b96SArnd Bergmann 		return -EFAULT;
75167207b96SArnd Bergmann 
75267207b96SArnd Bergmann 	return 4;
75367207b96SArnd Bergmann }
75467207b96SArnd Bergmann 
7555dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = {
75667207b96SArnd Bergmann 	.open	= spufs_pipe_open,
75767207b96SArnd Bergmann 	.read	= spufs_wbox_stat_read,
75867207b96SArnd Bergmann };
75967207b96SArnd Bergmann 
7606df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file)
7616df10a82SMark Nutter {
7626df10a82SMark Nutter 	struct spufs_inode_info *i = SPUFS_I(inode);
7636df10a82SMark Nutter 	struct spu_context *ctx = i->i_ctx;
76443c2bbd9SChristoph Hellwig 
76543c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
7666df10a82SMark Nutter 	file->private_data = ctx;
76743c2bbd9SChristoph Hellwig 	if (!i->i_openers++)
7686df10a82SMark Nutter 		ctx->signal1 = inode->i_mapping;
76943c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
77017e0e270SBenjamin Herrenschmidt 	smp_wmb();
7716df10a82SMark Nutter 	return nonseekable_open(inode, file);
7726df10a82SMark Nutter }
7736df10a82SMark Nutter 
77443c2bbd9SChristoph Hellwig static int
77543c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file)
77643c2bbd9SChristoph Hellwig {
77743c2bbd9SChristoph Hellwig 	struct spufs_inode_info *i = SPUFS_I(inode);
77843c2bbd9SChristoph Hellwig 	struct spu_context *ctx = i->i_ctx;
77943c2bbd9SChristoph Hellwig 
78043c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
78143c2bbd9SChristoph Hellwig 	if (!--i->i_openers)
78243c2bbd9SChristoph Hellwig 		ctx->signal1 = NULL;
78343c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
78443c2bbd9SChristoph Hellwig 	smp_wmb();
78543c2bbd9SChristoph Hellwig 	return 0;
78643c2bbd9SChristoph Hellwig }
78743c2bbd9SChristoph Hellwig 
788bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
78967207b96SArnd Bergmann 			size_t len, loff_t *pos)
79067207b96SArnd Bergmann {
79117f88cebSDwayne Grant McConnell 	int ret = 0;
79267207b96SArnd Bergmann 	u32 data;
79367207b96SArnd Bergmann 
79467207b96SArnd Bergmann 	if (len < 4)
79567207b96SArnd Bergmann 		return -EINVAL;
79667207b96SArnd Bergmann 
79717f88cebSDwayne Grant McConnell 	if (ctx->csa.spu_chnlcnt_RW[3]) {
79817f88cebSDwayne Grant McConnell 		data = ctx->csa.spu_chnldata_RW[3];
79917f88cebSDwayne Grant McConnell 		ret = 4;
80017f88cebSDwayne Grant McConnell 	}
8018b3d6663SArnd Bergmann 
80217f88cebSDwayne Grant McConnell 	if (!ret)
80317f88cebSDwayne Grant McConnell 		goto out;
80417f88cebSDwayne Grant McConnell 
80567207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
80667207b96SArnd Bergmann 		return -EFAULT;
80767207b96SArnd Bergmann 
80817f88cebSDwayne Grant McConnell out:
80917f88cebSDwayne Grant McConnell 	return ret;
81067207b96SArnd Bergmann }
81167207b96SArnd Bergmann 
812bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
813bf1ab978SDwayne Grant McConnell 			size_t len, loff_t *pos)
814bf1ab978SDwayne Grant McConnell {
815bf1ab978SDwayne Grant McConnell 	int ret;
816bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
817bf1ab978SDwayne Grant McConnell 
818bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
819bf1ab978SDwayne Grant McConnell 	ret = __spufs_signal1_read(ctx, buf, len, pos);
820bf1ab978SDwayne Grant McConnell 	spu_release(ctx);
821bf1ab978SDwayne Grant McConnell 
822bf1ab978SDwayne Grant McConnell 	return ret;
823bf1ab978SDwayne Grant McConnell }
824bf1ab978SDwayne Grant McConnell 
82567207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
82667207b96SArnd Bergmann 			size_t len, loff_t *pos)
82767207b96SArnd Bergmann {
82867207b96SArnd Bergmann 	struct spu_context *ctx;
82967207b96SArnd Bergmann 	u32 data;
83067207b96SArnd Bergmann 
83167207b96SArnd Bergmann 	ctx = file->private_data;
83267207b96SArnd Bergmann 
83367207b96SArnd Bergmann 	if (len < 4)
83467207b96SArnd Bergmann 		return -EINVAL;
83567207b96SArnd Bergmann 
83667207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
83767207b96SArnd Bergmann 		return -EFAULT;
83867207b96SArnd Bergmann 
8398b3d6663SArnd Bergmann 	spu_acquire(ctx);
8408b3d6663SArnd Bergmann 	ctx->ops->signal1_write(ctx, data);
8418b3d6663SArnd Bergmann 	spu_release(ctx);
84267207b96SArnd Bergmann 
84367207b96SArnd Bergmann 	return 4;
84467207b96SArnd Bergmann }
84567207b96SArnd Bergmann 
84678bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma,
84778bde53eSBenjamin Herrenschmidt 					      unsigned long address)
8486df10a82SMark Nutter {
84927d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000
85078bde53eSBenjamin Herrenschmidt 	return spufs_ps_nopfn(vma, address, 0x14000, 0x1000);
85127d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000
85227d5bf2aSBenjamin Herrenschmidt 	/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
85327d5bf2aSBenjamin Herrenschmidt 	 * signal 1 and 2 area
85427d5bf2aSBenjamin Herrenschmidt 	 */
85578bde53eSBenjamin Herrenschmidt 	return spufs_ps_nopfn(vma, address, 0x10000, 0x10000);
85627d5bf2aSBenjamin Herrenschmidt #else
85727d5bf2aSBenjamin Herrenschmidt #error unsupported page size
85827d5bf2aSBenjamin Herrenschmidt #endif
8596df10a82SMark Nutter }
8606df10a82SMark Nutter 
8616df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = {
86278bde53eSBenjamin Herrenschmidt 	.nopfn = spufs_signal1_mmap_nopfn,
8636df10a82SMark Nutter };
8646df10a82SMark Nutter 
8656df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
8666df10a82SMark Nutter {
8676df10a82SMark Nutter 	if (!(vma->vm_flags & VM_SHARED))
8686df10a82SMark Nutter 		return -EINVAL;
8696df10a82SMark Nutter 
87078bde53eSBenjamin Herrenschmidt 	vma->vm_flags |= VM_IO | VM_PFNMAP;
8716df10a82SMark Nutter 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
87223cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
8736df10a82SMark Nutter 
8746df10a82SMark Nutter 	vma->vm_ops = &spufs_signal1_mmap_vmops;
8756df10a82SMark Nutter 	return 0;
8766df10a82SMark Nutter }
8776df10a82SMark Nutter 
8785dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = {
8796df10a82SMark Nutter 	.open = spufs_signal1_open,
88043c2bbd9SChristoph Hellwig 	.release = spufs_signal1_release,
88167207b96SArnd Bergmann 	.read = spufs_signal1_read,
88267207b96SArnd Bergmann 	.write = spufs_signal1_write,
8836df10a82SMark Nutter 	.mmap = spufs_signal1_mmap,
88467207b96SArnd Bergmann };
88567207b96SArnd Bergmann 
8866df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file)
8876df10a82SMark Nutter {
8886df10a82SMark Nutter 	struct spufs_inode_info *i = SPUFS_I(inode);
8896df10a82SMark Nutter 	struct spu_context *ctx = i->i_ctx;
89043c2bbd9SChristoph Hellwig 
89143c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
8926df10a82SMark Nutter 	file->private_data = ctx;
89343c2bbd9SChristoph Hellwig 	if (!i->i_openers++)
8946df10a82SMark Nutter 		ctx->signal2 = inode->i_mapping;
89543c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
89617e0e270SBenjamin Herrenschmidt 	smp_wmb();
8976df10a82SMark Nutter 	return nonseekable_open(inode, file);
8986df10a82SMark Nutter }
8996df10a82SMark Nutter 
90043c2bbd9SChristoph Hellwig static int
90143c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file)
90243c2bbd9SChristoph Hellwig {
90343c2bbd9SChristoph Hellwig 	struct spufs_inode_info *i = SPUFS_I(inode);
90443c2bbd9SChristoph Hellwig 	struct spu_context *ctx = i->i_ctx;
90543c2bbd9SChristoph Hellwig 
90643c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
90743c2bbd9SChristoph Hellwig 	if (!--i->i_openers)
90843c2bbd9SChristoph Hellwig 		ctx->signal2 = NULL;
90943c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
91043c2bbd9SChristoph Hellwig 	smp_wmb();
91143c2bbd9SChristoph Hellwig 	return 0;
91243c2bbd9SChristoph Hellwig }
91343c2bbd9SChristoph Hellwig 
914bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
91567207b96SArnd Bergmann 			size_t len, loff_t *pos)
91667207b96SArnd Bergmann {
91717f88cebSDwayne Grant McConnell 	int ret = 0;
91867207b96SArnd Bergmann 	u32 data;
91967207b96SArnd Bergmann 
92067207b96SArnd Bergmann 	if (len < 4)
92167207b96SArnd Bergmann 		return -EINVAL;
92267207b96SArnd Bergmann 
92317f88cebSDwayne Grant McConnell 	if (ctx->csa.spu_chnlcnt_RW[4]) {
92417f88cebSDwayne Grant McConnell 		data =  ctx->csa.spu_chnldata_RW[4];
92517f88cebSDwayne Grant McConnell 		ret = 4;
92617f88cebSDwayne Grant McConnell 	}
9278b3d6663SArnd Bergmann 
92817f88cebSDwayne Grant McConnell 	if (!ret)
92917f88cebSDwayne Grant McConnell 		goto out;
93017f88cebSDwayne Grant McConnell 
93167207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
93267207b96SArnd Bergmann 		return -EFAULT;
93367207b96SArnd Bergmann 
93417f88cebSDwayne Grant McConnell out:
935bf1ab978SDwayne Grant McConnell 	return ret;
936bf1ab978SDwayne Grant McConnell }
937bf1ab978SDwayne Grant McConnell 
938bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
939bf1ab978SDwayne Grant McConnell 			size_t len, loff_t *pos)
940bf1ab978SDwayne Grant McConnell {
941bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
942bf1ab978SDwayne Grant McConnell 	int ret;
943bf1ab978SDwayne Grant McConnell 
944bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
945bf1ab978SDwayne Grant McConnell 	ret = __spufs_signal2_read(ctx, buf, len, pos);
946bf1ab978SDwayne Grant McConnell 	spu_release(ctx);
947bf1ab978SDwayne Grant McConnell 
948bf1ab978SDwayne Grant McConnell 	return ret;
94967207b96SArnd Bergmann }
95067207b96SArnd Bergmann 
95167207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
95267207b96SArnd Bergmann 			size_t len, loff_t *pos)
95367207b96SArnd Bergmann {
95467207b96SArnd Bergmann 	struct spu_context *ctx;
95567207b96SArnd Bergmann 	u32 data;
95667207b96SArnd Bergmann 
95767207b96SArnd Bergmann 	ctx = file->private_data;
95867207b96SArnd Bergmann 
95967207b96SArnd Bergmann 	if (len < 4)
96067207b96SArnd Bergmann 		return -EINVAL;
96167207b96SArnd Bergmann 
96267207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
96367207b96SArnd Bergmann 		return -EFAULT;
96467207b96SArnd Bergmann 
9658b3d6663SArnd Bergmann 	spu_acquire(ctx);
9668b3d6663SArnd Bergmann 	ctx->ops->signal2_write(ctx, data);
9678b3d6663SArnd Bergmann 	spu_release(ctx);
96867207b96SArnd Bergmann 
96967207b96SArnd Bergmann 	return 4;
97067207b96SArnd Bergmann }
97167207b96SArnd Bergmann 
97227d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K
97378bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma,
97478bde53eSBenjamin Herrenschmidt 					      unsigned long address)
9756df10a82SMark Nutter {
97627d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000
97778bde53eSBenjamin Herrenschmidt 	return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000);
97827d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000
97927d5bf2aSBenjamin Herrenschmidt 	/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
98027d5bf2aSBenjamin Herrenschmidt 	 * signal 1 and 2 area
98127d5bf2aSBenjamin Herrenschmidt 	 */
98278bde53eSBenjamin Herrenschmidt 	return spufs_ps_nopfn(vma, address, 0x10000, 0x10000);
98327d5bf2aSBenjamin Herrenschmidt #else
98427d5bf2aSBenjamin Herrenschmidt #error unsupported page size
98527d5bf2aSBenjamin Herrenschmidt #endif
9866df10a82SMark Nutter }
9876df10a82SMark Nutter 
9886df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = {
98978bde53eSBenjamin Herrenschmidt 	.nopfn = spufs_signal2_mmap_nopfn,
9906df10a82SMark Nutter };
9916df10a82SMark Nutter 
9926df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
9936df10a82SMark Nutter {
9946df10a82SMark Nutter 	if (!(vma->vm_flags & VM_SHARED))
9956df10a82SMark Nutter 		return -EINVAL;
9966df10a82SMark Nutter 
99778bde53eSBenjamin Herrenschmidt 	vma->vm_flags |= VM_IO | VM_PFNMAP;
9986df10a82SMark Nutter 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
99923cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
10006df10a82SMark Nutter 
10016df10a82SMark Nutter 	vma->vm_ops = &spufs_signal2_mmap_vmops;
10026df10a82SMark Nutter 	return 0;
10036df10a82SMark Nutter }
100427d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */
100527d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL
100627d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */
10076df10a82SMark Nutter 
10085dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = {
10096df10a82SMark Nutter 	.open = spufs_signal2_open,
101043c2bbd9SChristoph Hellwig 	.release = spufs_signal2_release,
101167207b96SArnd Bergmann 	.read = spufs_signal2_read,
101267207b96SArnd Bergmann 	.write = spufs_signal2_write,
10136df10a82SMark Nutter 	.mmap = spufs_signal2_mmap,
101467207b96SArnd Bergmann };
101567207b96SArnd Bergmann 
101667207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val)
101767207b96SArnd Bergmann {
101867207b96SArnd Bergmann 	struct spu_context *ctx = data;
101967207b96SArnd Bergmann 
10208b3d6663SArnd Bergmann 	spu_acquire(ctx);
10218b3d6663SArnd Bergmann 	ctx->ops->signal1_type_set(ctx, val);
10228b3d6663SArnd Bergmann 	spu_release(ctx);
102367207b96SArnd Bergmann }
102467207b96SArnd Bergmann 
1025bf1ab978SDwayne Grant McConnell static u64 __spufs_signal1_type_get(void *data)
1026bf1ab978SDwayne Grant McConnell {
1027bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
1028bf1ab978SDwayne Grant McConnell 	return ctx->ops->signal1_type_get(ctx);
1029bf1ab978SDwayne Grant McConnell }
1030bf1ab978SDwayne Grant McConnell 
103167207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data)
103267207b96SArnd Bergmann {
103367207b96SArnd Bergmann 	struct spu_context *ctx = data;
10348b3d6663SArnd Bergmann 	u64 ret;
10358b3d6663SArnd Bergmann 
10368b3d6663SArnd Bergmann 	spu_acquire(ctx);
1037bf1ab978SDwayne Grant McConnell 	ret = __spufs_signal1_type_get(data);
10388b3d6663SArnd Bergmann 	spu_release(ctx);
10398b3d6663SArnd Bergmann 
10408b3d6663SArnd Bergmann 	return ret;
104167207b96SArnd Bergmann }
104267207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
104367207b96SArnd Bergmann 					spufs_signal1_type_set, "%llu");
104467207b96SArnd Bergmann 
104567207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val)
104667207b96SArnd Bergmann {
104767207b96SArnd Bergmann 	struct spu_context *ctx = data;
104867207b96SArnd Bergmann 
10498b3d6663SArnd Bergmann 	spu_acquire(ctx);
10508b3d6663SArnd Bergmann 	ctx->ops->signal2_type_set(ctx, val);
10518b3d6663SArnd Bergmann 	spu_release(ctx);
105267207b96SArnd Bergmann }
105367207b96SArnd Bergmann 
1054bf1ab978SDwayne Grant McConnell static u64 __spufs_signal2_type_get(void *data)
1055bf1ab978SDwayne Grant McConnell {
1056bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
1057bf1ab978SDwayne Grant McConnell 	return ctx->ops->signal2_type_get(ctx);
1058bf1ab978SDwayne Grant McConnell }
1059bf1ab978SDwayne Grant McConnell 
106067207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data)
106167207b96SArnd Bergmann {
106267207b96SArnd Bergmann 	struct spu_context *ctx = data;
10638b3d6663SArnd Bergmann 	u64 ret;
10648b3d6663SArnd Bergmann 
10658b3d6663SArnd Bergmann 	spu_acquire(ctx);
1066bf1ab978SDwayne Grant McConnell 	ret = __spufs_signal2_type_get(data);
10678b3d6663SArnd Bergmann 	spu_release(ctx);
10688b3d6663SArnd Bergmann 
10698b3d6663SArnd Bergmann 	return ret;
107067207b96SArnd Bergmann }
107167207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
107267207b96SArnd Bergmann 					spufs_signal2_type_set, "%llu");
107367207b96SArnd Bergmann 
107427d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K
107578bde53eSBenjamin Herrenschmidt static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma,
107678bde53eSBenjamin Herrenschmidt 					  unsigned long address)
1077d9379c4bSarnd@arndb.de {
107878bde53eSBenjamin Herrenschmidt 	return spufs_ps_nopfn(vma, address, 0x0000, 0x1000);
1079d9379c4bSarnd@arndb.de }
1080d9379c4bSarnd@arndb.de 
1081d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = {
108278bde53eSBenjamin Herrenschmidt 	.nopfn = spufs_mss_mmap_nopfn,
1083d9379c4bSarnd@arndb.de };
1084d9379c4bSarnd@arndb.de 
1085d9379c4bSarnd@arndb.de /*
1086d9379c4bSarnd@arndb.de  * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
1087d9379c4bSarnd@arndb.de  */
1088d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
1089d9379c4bSarnd@arndb.de {
1090d9379c4bSarnd@arndb.de 	if (!(vma->vm_flags & VM_SHARED))
1091d9379c4bSarnd@arndb.de 		return -EINVAL;
1092d9379c4bSarnd@arndb.de 
109378bde53eSBenjamin Herrenschmidt 	vma->vm_flags |= VM_IO | VM_PFNMAP;
1094d9379c4bSarnd@arndb.de 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
109523cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
1096d9379c4bSarnd@arndb.de 
1097d9379c4bSarnd@arndb.de 	vma->vm_ops = &spufs_mss_mmap_vmops;
1098d9379c4bSarnd@arndb.de 	return 0;
1099d9379c4bSarnd@arndb.de }
110027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */
110127d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL
110227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */
1103d9379c4bSarnd@arndb.de 
1104d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file)
1105d9379c4bSarnd@arndb.de {
1106d9379c4bSarnd@arndb.de 	struct spufs_inode_info *i = SPUFS_I(inode);
110717e0e270SBenjamin Herrenschmidt 	struct spu_context *ctx = i->i_ctx;
1108d9379c4bSarnd@arndb.de 
1109d9379c4bSarnd@arndb.de 	file->private_data = i->i_ctx;
111043c2bbd9SChristoph Hellwig 
111143c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
111243c2bbd9SChristoph Hellwig 	if (!i->i_openers++)
111317e0e270SBenjamin Herrenschmidt 		ctx->mss = inode->i_mapping;
111443c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
111517e0e270SBenjamin Herrenschmidt 	smp_wmb();
1116d9379c4bSarnd@arndb.de 	return nonseekable_open(inode, file);
1117d9379c4bSarnd@arndb.de }
1118d9379c4bSarnd@arndb.de 
111943c2bbd9SChristoph Hellwig static int
112043c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file)
112143c2bbd9SChristoph Hellwig {
112243c2bbd9SChristoph Hellwig 	struct spufs_inode_info *i = SPUFS_I(inode);
112343c2bbd9SChristoph Hellwig 	struct spu_context *ctx = i->i_ctx;
112443c2bbd9SChristoph Hellwig 
112543c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
112643c2bbd9SChristoph Hellwig 	if (!--i->i_openers)
112743c2bbd9SChristoph Hellwig 		ctx->mss = NULL;
112843c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
112943c2bbd9SChristoph Hellwig 	smp_wmb();
113043c2bbd9SChristoph Hellwig 	return 0;
113143c2bbd9SChristoph Hellwig }
113243c2bbd9SChristoph Hellwig 
11335dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = {
1134d9379c4bSarnd@arndb.de 	.open	 = spufs_mss_open,
113543c2bbd9SChristoph Hellwig 	.release = spufs_mss_release,
1136d9379c4bSarnd@arndb.de 	.mmap	 = spufs_mss_mmap,
113727d5bf2aSBenjamin Herrenschmidt };
113827d5bf2aSBenjamin Herrenschmidt 
113978bde53eSBenjamin Herrenschmidt static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma,
114078bde53eSBenjamin Herrenschmidt 					    unsigned long address)
114127d5bf2aSBenjamin Herrenschmidt {
114278bde53eSBenjamin Herrenschmidt 	return spufs_ps_nopfn(vma, address, 0x0000, 0x20000);
114327d5bf2aSBenjamin Herrenschmidt }
114427d5bf2aSBenjamin Herrenschmidt 
114527d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = {
114678bde53eSBenjamin Herrenschmidt 	.nopfn = spufs_psmap_mmap_nopfn,
114727d5bf2aSBenjamin Herrenschmidt };
114827d5bf2aSBenjamin Herrenschmidt 
114927d5bf2aSBenjamin Herrenschmidt /*
115027d5bf2aSBenjamin Herrenschmidt  * mmap support for full problem state area [0x00000 - 0x1ffff].
115127d5bf2aSBenjamin Herrenschmidt  */
115227d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma)
115327d5bf2aSBenjamin Herrenschmidt {
115427d5bf2aSBenjamin Herrenschmidt 	if (!(vma->vm_flags & VM_SHARED))
115527d5bf2aSBenjamin Herrenschmidt 		return -EINVAL;
115627d5bf2aSBenjamin Herrenschmidt 
115778bde53eSBenjamin Herrenschmidt 	vma->vm_flags |= VM_IO | VM_PFNMAP;
115827d5bf2aSBenjamin Herrenschmidt 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
115927d5bf2aSBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
116027d5bf2aSBenjamin Herrenschmidt 
116127d5bf2aSBenjamin Herrenschmidt 	vma->vm_ops = &spufs_psmap_mmap_vmops;
116227d5bf2aSBenjamin Herrenschmidt 	return 0;
116327d5bf2aSBenjamin Herrenschmidt }
116427d5bf2aSBenjamin Herrenschmidt 
116527d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file)
116627d5bf2aSBenjamin Herrenschmidt {
116727d5bf2aSBenjamin Herrenschmidt 	struct spufs_inode_info *i = SPUFS_I(inode);
116817e0e270SBenjamin Herrenschmidt 	struct spu_context *ctx = i->i_ctx;
116927d5bf2aSBenjamin Herrenschmidt 
117043c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
117127d5bf2aSBenjamin Herrenschmidt 	file->private_data = i->i_ctx;
117243c2bbd9SChristoph Hellwig 	if (!i->i_openers++)
117317e0e270SBenjamin Herrenschmidt 		ctx->psmap = inode->i_mapping;
117443c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
117517e0e270SBenjamin Herrenschmidt 	smp_wmb();
117627d5bf2aSBenjamin Herrenschmidt 	return nonseekable_open(inode, file);
117727d5bf2aSBenjamin Herrenschmidt }
117827d5bf2aSBenjamin Herrenschmidt 
117943c2bbd9SChristoph Hellwig static int
118043c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file)
118143c2bbd9SChristoph Hellwig {
118243c2bbd9SChristoph Hellwig 	struct spufs_inode_info *i = SPUFS_I(inode);
118343c2bbd9SChristoph Hellwig 	struct spu_context *ctx = i->i_ctx;
118443c2bbd9SChristoph Hellwig 
118543c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
118643c2bbd9SChristoph Hellwig 	if (!--i->i_openers)
118743c2bbd9SChristoph Hellwig 		ctx->psmap = NULL;
118843c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
118943c2bbd9SChristoph Hellwig 	smp_wmb();
119043c2bbd9SChristoph Hellwig 	return 0;
119143c2bbd9SChristoph Hellwig }
119243c2bbd9SChristoph Hellwig 
11935dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = {
119427d5bf2aSBenjamin Herrenschmidt 	.open	 = spufs_psmap_open,
119543c2bbd9SChristoph Hellwig 	.release = spufs_psmap_release,
119627d5bf2aSBenjamin Herrenschmidt 	.mmap	 = spufs_psmap_mmap,
1197d9379c4bSarnd@arndb.de };
1198d9379c4bSarnd@arndb.de 
1199d9379c4bSarnd@arndb.de 
120027d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K
120178bde53eSBenjamin Herrenschmidt static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma,
120278bde53eSBenjamin Herrenschmidt 					  unsigned long address)
12036df10a82SMark Nutter {
120478bde53eSBenjamin Herrenschmidt 	return spufs_ps_nopfn(vma, address, 0x3000, 0x1000);
12056df10a82SMark Nutter }
12066df10a82SMark Nutter 
12076df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = {
120878bde53eSBenjamin Herrenschmidt 	.nopfn = spufs_mfc_mmap_nopfn,
12096df10a82SMark Nutter };
12106df10a82SMark Nutter 
12116df10a82SMark Nutter /*
12126df10a82SMark Nutter  * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
12136df10a82SMark Nutter  */
12146df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
12156df10a82SMark Nutter {
12166df10a82SMark Nutter 	if (!(vma->vm_flags & VM_SHARED))
12176df10a82SMark Nutter 		return -EINVAL;
12186df10a82SMark Nutter 
121978bde53eSBenjamin Herrenschmidt 	vma->vm_flags |= VM_IO | VM_PFNMAP;
12206df10a82SMark Nutter 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
122123cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
12226df10a82SMark Nutter 
12236df10a82SMark Nutter 	vma->vm_ops = &spufs_mfc_mmap_vmops;
12246df10a82SMark Nutter 	return 0;
12256df10a82SMark Nutter }
122627d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */
122727d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL
122827d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */
1229a33a7d73SArnd Bergmann 
1230a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file)
1231a33a7d73SArnd Bergmann {
1232a33a7d73SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
1233a33a7d73SArnd Bergmann 	struct spu_context *ctx = i->i_ctx;
1234a33a7d73SArnd Bergmann 
1235a33a7d73SArnd Bergmann 	/* we don't want to deal with DMA into other processes */
1236a33a7d73SArnd Bergmann 	if (ctx->owner != current->mm)
1237a33a7d73SArnd Bergmann 		return -EINVAL;
1238a33a7d73SArnd Bergmann 
1239a33a7d73SArnd Bergmann 	if (atomic_read(&inode->i_count) != 1)
1240a33a7d73SArnd Bergmann 		return -EBUSY;
1241a33a7d73SArnd Bergmann 
124243c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
1243a33a7d73SArnd Bergmann 	file->private_data = ctx;
124443c2bbd9SChristoph Hellwig 	if (!i->i_openers++)
124517e0e270SBenjamin Herrenschmidt 		ctx->mfc = inode->i_mapping;
124643c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
124717e0e270SBenjamin Herrenschmidt 	smp_wmb();
1248a33a7d73SArnd Bergmann 	return nonseekable_open(inode, file);
1249a33a7d73SArnd Bergmann }
1250a33a7d73SArnd Bergmann 
125143c2bbd9SChristoph Hellwig static int
125243c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file)
125343c2bbd9SChristoph Hellwig {
125443c2bbd9SChristoph Hellwig 	struct spufs_inode_info *i = SPUFS_I(inode);
125543c2bbd9SChristoph Hellwig 	struct spu_context *ctx = i->i_ctx;
125643c2bbd9SChristoph Hellwig 
125743c2bbd9SChristoph Hellwig 	spin_lock(&ctx->mapping_lock);
125843c2bbd9SChristoph Hellwig 	if (!--i->i_openers)
125943c2bbd9SChristoph Hellwig 		ctx->mfc = NULL;
126043c2bbd9SChristoph Hellwig 	spin_unlock(&ctx->mapping_lock);
126143c2bbd9SChristoph Hellwig 	smp_wmb();
126243c2bbd9SChristoph Hellwig 	return 0;
126343c2bbd9SChristoph Hellwig }
126443c2bbd9SChristoph Hellwig 
1265a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */
1266a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu)
1267a33a7d73SArnd Bergmann {
1268a33a7d73SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
1269a33a7d73SArnd Bergmann 
1270a33a7d73SArnd Bergmann 	wake_up_all(&ctx->mfc_wq);
1271a33a7d73SArnd Bergmann 
1272a33a7d73SArnd Bergmann 	pr_debug("%s %s\n", __FUNCTION__, spu->name);
1273a33a7d73SArnd Bergmann 	if (ctx->mfc_fasync) {
1274a33a7d73SArnd Bergmann 		u32 free_elements, tagstatus;
1275a33a7d73SArnd Bergmann 		unsigned int mask;
1276a33a7d73SArnd Bergmann 
1277a33a7d73SArnd Bergmann 		/* no need for spu_acquire in interrupt context */
1278a33a7d73SArnd Bergmann 		free_elements = ctx->ops->get_mfc_free_elements(ctx);
1279a33a7d73SArnd Bergmann 		tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
1280a33a7d73SArnd Bergmann 
1281a33a7d73SArnd Bergmann 		mask = 0;
1282a33a7d73SArnd Bergmann 		if (free_elements & 0xffff)
1283a33a7d73SArnd Bergmann 			mask |= POLLOUT;
1284a33a7d73SArnd Bergmann 		if (tagstatus & ctx->tagwait)
1285a33a7d73SArnd Bergmann 			mask |= POLLIN;
1286a33a7d73SArnd Bergmann 
1287a33a7d73SArnd Bergmann 		kill_fasync(&ctx->mfc_fasync, SIGIO, mask);
1288a33a7d73SArnd Bergmann 	}
1289a33a7d73SArnd Bergmann }
1290a33a7d73SArnd Bergmann 
1291a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status)
1292a33a7d73SArnd Bergmann {
1293a33a7d73SArnd Bergmann 	/* See if there is one tag group is complete */
1294a33a7d73SArnd Bergmann 	/* FIXME we need locking around tagwait */
1295a33a7d73SArnd Bergmann 	*status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait;
1296a33a7d73SArnd Bergmann 	ctx->tagwait &= ~*status;
1297a33a7d73SArnd Bergmann 	if (*status)
1298a33a7d73SArnd Bergmann 		return 1;
1299a33a7d73SArnd Bergmann 
1300a33a7d73SArnd Bergmann 	/* enable interrupt waiting for any tag group,
1301a33a7d73SArnd Bergmann 	   may silently fail if interrupts are already enabled */
1302a33a7d73SArnd Bergmann 	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
1303a33a7d73SArnd Bergmann 	return 0;
1304a33a7d73SArnd Bergmann }
1305a33a7d73SArnd Bergmann 
1306a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer,
1307a33a7d73SArnd Bergmann 			size_t size, loff_t *pos)
1308a33a7d73SArnd Bergmann {
1309a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1310a33a7d73SArnd Bergmann 	int ret = -EINVAL;
1311a33a7d73SArnd Bergmann 	u32 status;
1312a33a7d73SArnd Bergmann 
1313a33a7d73SArnd Bergmann 	if (size != 4)
1314a33a7d73SArnd Bergmann 		goto out;
1315a33a7d73SArnd Bergmann 
1316a33a7d73SArnd Bergmann 	spu_acquire(ctx);
1317a33a7d73SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
1318a33a7d73SArnd Bergmann 		status = ctx->ops->read_mfc_tagstatus(ctx);
1319a33a7d73SArnd Bergmann 		if (!(status & ctx->tagwait))
1320a33a7d73SArnd Bergmann 			ret = -EAGAIN;
1321a33a7d73SArnd Bergmann 		else
1322a33a7d73SArnd Bergmann 			ctx->tagwait &= ~status;
1323a33a7d73SArnd Bergmann 	} else {
1324a33a7d73SArnd Bergmann 		ret = spufs_wait(ctx->mfc_wq,
1325a33a7d73SArnd Bergmann 			   spufs_read_mfc_tagstatus(ctx, &status));
1326a33a7d73SArnd Bergmann 	}
1327a33a7d73SArnd Bergmann 	spu_release(ctx);
1328a33a7d73SArnd Bergmann 
1329a33a7d73SArnd Bergmann 	if (ret)
1330a33a7d73SArnd Bergmann 		goto out;
1331a33a7d73SArnd Bergmann 
1332a33a7d73SArnd Bergmann 	ret = 4;
1333a33a7d73SArnd Bergmann 	if (copy_to_user(buffer, &status, 4))
1334a33a7d73SArnd Bergmann 		ret = -EFAULT;
1335a33a7d73SArnd Bergmann 
1336a33a7d73SArnd Bergmann out:
1337a33a7d73SArnd Bergmann 	return ret;
1338a33a7d73SArnd Bergmann }
1339a33a7d73SArnd Bergmann 
1340a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd)
1341a33a7d73SArnd Bergmann {
1342a33a7d73SArnd Bergmann 	pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa,
1343a33a7d73SArnd Bergmann 		 cmd->ea, cmd->size, cmd->tag, cmd->cmd);
1344a33a7d73SArnd Bergmann 
1345a33a7d73SArnd Bergmann 	switch (cmd->cmd) {
1346a33a7d73SArnd Bergmann 	case MFC_PUT_CMD:
1347a33a7d73SArnd Bergmann 	case MFC_PUTF_CMD:
1348a33a7d73SArnd Bergmann 	case MFC_PUTB_CMD:
1349a33a7d73SArnd Bergmann 	case MFC_GET_CMD:
1350a33a7d73SArnd Bergmann 	case MFC_GETF_CMD:
1351a33a7d73SArnd Bergmann 	case MFC_GETB_CMD:
1352a33a7d73SArnd Bergmann 		break;
1353a33a7d73SArnd Bergmann 	default:
1354a33a7d73SArnd Bergmann 		pr_debug("invalid DMA opcode %x\n", cmd->cmd);
1355a33a7d73SArnd Bergmann 		return -EIO;
1356a33a7d73SArnd Bergmann 	}
1357a33a7d73SArnd Bergmann 
1358a33a7d73SArnd Bergmann 	if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) {
1359a33a7d73SArnd Bergmann 		pr_debug("invalid DMA alignment, ea %lx lsa %x\n",
1360a33a7d73SArnd Bergmann 				cmd->ea, cmd->lsa);
1361a33a7d73SArnd Bergmann 		return -EIO;
1362a33a7d73SArnd Bergmann 	}
1363a33a7d73SArnd Bergmann 
1364a33a7d73SArnd Bergmann 	switch (cmd->size & 0xf) {
1365a33a7d73SArnd Bergmann 	case 1:
1366a33a7d73SArnd Bergmann 		break;
1367a33a7d73SArnd Bergmann 	case 2:
1368a33a7d73SArnd Bergmann 		if (cmd->lsa & 1)
1369a33a7d73SArnd Bergmann 			goto error;
1370a33a7d73SArnd Bergmann 		break;
1371a33a7d73SArnd Bergmann 	case 4:
1372a33a7d73SArnd Bergmann 		if (cmd->lsa & 3)
1373a33a7d73SArnd Bergmann 			goto error;
1374a33a7d73SArnd Bergmann 		break;
1375a33a7d73SArnd Bergmann 	case 8:
1376a33a7d73SArnd Bergmann 		if (cmd->lsa & 7)
1377a33a7d73SArnd Bergmann 			goto error;
1378a33a7d73SArnd Bergmann 		break;
1379a33a7d73SArnd Bergmann 	case 0:
1380a33a7d73SArnd Bergmann 		if (cmd->lsa & 15)
1381a33a7d73SArnd Bergmann 			goto error;
1382a33a7d73SArnd Bergmann 		break;
1383a33a7d73SArnd Bergmann 	error:
1384a33a7d73SArnd Bergmann 	default:
1385a33a7d73SArnd Bergmann 		pr_debug("invalid DMA alignment %x for size %x\n",
1386a33a7d73SArnd Bergmann 			cmd->lsa & 0xf, cmd->size);
1387a33a7d73SArnd Bergmann 		return -EIO;
1388a33a7d73SArnd Bergmann 	}
1389a33a7d73SArnd Bergmann 
1390a33a7d73SArnd Bergmann 	if (cmd->size > 16 * 1024) {
1391a33a7d73SArnd Bergmann 		pr_debug("invalid DMA size %x\n", cmd->size);
1392a33a7d73SArnd Bergmann 		return -EIO;
1393a33a7d73SArnd Bergmann 	}
1394a33a7d73SArnd Bergmann 
1395a33a7d73SArnd Bergmann 	if (cmd->tag & 0xfff0) {
1396a33a7d73SArnd Bergmann 		/* we reserve the higher tag numbers for kernel use */
1397a33a7d73SArnd Bergmann 		pr_debug("invalid DMA tag\n");
1398a33a7d73SArnd Bergmann 		return -EIO;
1399a33a7d73SArnd Bergmann 	}
1400a33a7d73SArnd Bergmann 
1401a33a7d73SArnd Bergmann 	if (cmd->class) {
1402a33a7d73SArnd Bergmann 		/* not supported in this version */
1403a33a7d73SArnd Bergmann 		pr_debug("invalid DMA class\n");
1404a33a7d73SArnd Bergmann 		return -EIO;
1405a33a7d73SArnd Bergmann 	}
1406a33a7d73SArnd Bergmann 
1407a33a7d73SArnd Bergmann 	return 0;
1408a33a7d73SArnd Bergmann }
1409a33a7d73SArnd Bergmann 
1410a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx,
1411a33a7d73SArnd Bergmann 				struct mfc_dma_command cmd,
1412a33a7d73SArnd Bergmann 				int *error)
1413a33a7d73SArnd Bergmann {
1414a33a7d73SArnd Bergmann 	*error = ctx->ops->send_mfc_command(ctx, &cmd);
1415a33a7d73SArnd Bergmann 	if (*error == -EAGAIN) {
1416a33a7d73SArnd Bergmann 		/* wait for any tag group to complete
1417a33a7d73SArnd Bergmann 		   so we have space for the new command */
1418a33a7d73SArnd Bergmann 		ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
1419a33a7d73SArnd Bergmann 		/* try again, because the queue might be
1420a33a7d73SArnd Bergmann 		   empty again */
1421a33a7d73SArnd Bergmann 		*error = ctx->ops->send_mfc_command(ctx, &cmd);
1422a33a7d73SArnd Bergmann 		if (*error == -EAGAIN)
1423a33a7d73SArnd Bergmann 			return 0;
1424a33a7d73SArnd Bergmann 	}
1425a33a7d73SArnd Bergmann 	return 1;
1426a33a7d73SArnd Bergmann }
1427a33a7d73SArnd Bergmann 
1428a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
1429a33a7d73SArnd Bergmann 			size_t size, loff_t *pos)
1430a33a7d73SArnd Bergmann {
1431a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1432a33a7d73SArnd Bergmann 	struct mfc_dma_command cmd;
1433a33a7d73SArnd Bergmann 	int ret = -EINVAL;
1434a33a7d73SArnd Bergmann 
1435a33a7d73SArnd Bergmann 	if (size != sizeof cmd)
1436a33a7d73SArnd Bergmann 		goto out;
1437a33a7d73SArnd Bergmann 
1438a33a7d73SArnd Bergmann 	ret = -EFAULT;
1439a33a7d73SArnd Bergmann 	if (copy_from_user(&cmd, buffer, sizeof cmd))
1440a33a7d73SArnd Bergmann 		goto out;
1441a33a7d73SArnd Bergmann 
1442a33a7d73SArnd Bergmann 	ret = spufs_check_valid_dma(&cmd);
1443a33a7d73SArnd Bergmann 	if (ret)
1444a33a7d73SArnd Bergmann 		goto out;
1445a33a7d73SArnd Bergmann 
144626bec673SChristoph Hellwig 	spu_acquire_runnable(ctx, 0);
1447a33a7d73SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
1448a33a7d73SArnd Bergmann 		ret = ctx->ops->send_mfc_command(ctx, &cmd);
1449a33a7d73SArnd Bergmann 	} else {
1450a33a7d73SArnd Bergmann 		int status;
1451a33a7d73SArnd Bergmann 		ret = spufs_wait(ctx->mfc_wq,
1452a33a7d73SArnd Bergmann 				 spu_send_mfc_command(ctx, cmd, &status));
1453a33a7d73SArnd Bergmann 		if (status)
1454a33a7d73SArnd Bergmann 			ret = status;
1455a33a7d73SArnd Bergmann 	}
1456a33a7d73SArnd Bergmann 	spu_release(ctx);
1457a33a7d73SArnd Bergmann 
1458a33a7d73SArnd Bergmann 	if (ret)
1459a33a7d73SArnd Bergmann 		goto out;
1460a33a7d73SArnd Bergmann 
1461a33a7d73SArnd Bergmann 	ctx->tagwait |= 1 << cmd.tag;
14623692dc66SMasato Noguchi 	ret = size;
1463a33a7d73SArnd Bergmann 
1464a33a7d73SArnd Bergmann out:
1465a33a7d73SArnd Bergmann 	return ret;
1466a33a7d73SArnd Bergmann }
1467a33a7d73SArnd Bergmann 
1468a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait)
1469a33a7d73SArnd Bergmann {
1470a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1471a33a7d73SArnd Bergmann 	u32 free_elements, tagstatus;
1472a33a7d73SArnd Bergmann 	unsigned int mask;
1473a33a7d73SArnd Bergmann 
1474a33a7d73SArnd Bergmann 	spu_acquire(ctx);
1475a33a7d73SArnd Bergmann 	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
1476a33a7d73SArnd Bergmann 	free_elements = ctx->ops->get_mfc_free_elements(ctx);
1477a33a7d73SArnd Bergmann 	tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
1478a33a7d73SArnd Bergmann 	spu_release(ctx);
1479a33a7d73SArnd Bergmann 
1480a33a7d73SArnd Bergmann 	poll_wait(file, &ctx->mfc_wq, wait);
1481a33a7d73SArnd Bergmann 
1482a33a7d73SArnd Bergmann 	mask = 0;
1483a33a7d73SArnd Bergmann 	if (free_elements & 0xffff)
1484a33a7d73SArnd Bergmann 		mask |= POLLOUT | POLLWRNORM;
1485a33a7d73SArnd Bergmann 	if (tagstatus & ctx->tagwait)
1486a33a7d73SArnd Bergmann 		mask |= POLLIN | POLLRDNORM;
1487a33a7d73SArnd Bergmann 
1488a33a7d73SArnd Bergmann 	pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__,
1489a33a7d73SArnd Bergmann 		free_elements, tagstatus, ctx->tagwait);
1490a33a7d73SArnd Bergmann 
1491a33a7d73SArnd Bergmann 	return mask;
1492a33a7d73SArnd Bergmann }
1493a33a7d73SArnd Bergmann 
149473b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id)
1495a33a7d73SArnd Bergmann {
1496a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1497a33a7d73SArnd Bergmann 	int ret;
1498a33a7d73SArnd Bergmann 
1499a33a7d73SArnd Bergmann 	spu_acquire(ctx);
1500a33a7d73SArnd Bergmann #if 0
1501a33a7d73SArnd Bergmann /* this currently hangs */
1502a33a7d73SArnd Bergmann 	ret = spufs_wait(ctx->mfc_wq,
1503a33a7d73SArnd Bergmann 			 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2));
1504a33a7d73SArnd Bergmann 	if (ret)
1505a33a7d73SArnd Bergmann 		goto out;
1506a33a7d73SArnd Bergmann 	ret = spufs_wait(ctx->mfc_wq,
1507a33a7d73SArnd Bergmann 			 ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait);
1508a33a7d73SArnd Bergmann out:
1509a33a7d73SArnd Bergmann #else
1510a33a7d73SArnd Bergmann 	ret = 0;
1511a33a7d73SArnd Bergmann #endif
1512a33a7d73SArnd Bergmann 	spu_release(ctx);
1513a33a7d73SArnd Bergmann 
1514a33a7d73SArnd Bergmann 	return ret;
1515a33a7d73SArnd Bergmann }
1516a33a7d73SArnd Bergmann 
1517a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
1518a33a7d73SArnd Bergmann 			   int datasync)
1519a33a7d73SArnd Bergmann {
152073b6af8aSAl Viro 	return spufs_mfc_flush(file, NULL);
1521a33a7d73SArnd Bergmann }
1522a33a7d73SArnd Bergmann 
1523a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on)
1524a33a7d73SArnd Bergmann {
1525a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1526a33a7d73SArnd Bergmann 
1527a33a7d73SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->mfc_fasync);
1528a33a7d73SArnd Bergmann }
1529a33a7d73SArnd Bergmann 
15305dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = {
1531a33a7d73SArnd Bergmann 	.open	 = spufs_mfc_open,
153243c2bbd9SChristoph Hellwig 	.release = spufs_mfc_release,
1533a33a7d73SArnd Bergmann 	.read	 = spufs_mfc_read,
1534a33a7d73SArnd Bergmann 	.write	 = spufs_mfc_write,
1535a33a7d73SArnd Bergmann 	.poll	 = spufs_mfc_poll,
1536a33a7d73SArnd Bergmann 	.flush	 = spufs_mfc_flush,
1537a33a7d73SArnd Bergmann 	.fsync	 = spufs_mfc_fsync,
1538a33a7d73SArnd Bergmann 	.fasync	 = spufs_mfc_fasync,
15396df10a82SMark Nutter 	.mmap	 = spufs_mfc_mmap,
1540a33a7d73SArnd Bergmann };
1541a33a7d73SArnd Bergmann 
154267207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val)
154367207b96SArnd Bergmann {
154467207b96SArnd Bergmann 	struct spu_context *ctx = data;
15458b3d6663SArnd Bergmann 	spu_acquire(ctx);
15468b3d6663SArnd Bergmann 	ctx->ops->npc_write(ctx, val);
15478b3d6663SArnd Bergmann 	spu_release(ctx);
154867207b96SArnd Bergmann }
154967207b96SArnd Bergmann 
155067207b96SArnd Bergmann static u64 spufs_npc_get(void *data)
155167207b96SArnd Bergmann {
155267207b96SArnd Bergmann 	struct spu_context *ctx = data;
155367207b96SArnd Bergmann 	u64 ret;
15548b3d6663SArnd Bergmann 	spu_acquire(ctx);
15558b3d6663SArnd Bergmann 	ret = ctx->ops->npc_read(ctx);
15568b3d6663SArnd Bergmann 	spu_release(ctx);
155767207b96SArnd Bergmann 	return ret;
155867207b96SArnd Bergmann }
15599b5047e2SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set,
15609b5047e2SDwayne Grant McConnell 			"0x%llx\n")
156167207b96SArnd Bergmann 
15628b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val)
15638b3d6663SArnd Bergmann {
15648b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
15658b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
15668b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
15678b3d6663SArnd Bergmann 	lscsa->decr.slot[0] = (u32) val;
15688b3d6663SArnd Bergmann 	spu_release(ctx);
15698b3d6663SArnd Bergmann }
15708b3d6663SArnd Bergmann 
1571bf1ab978SDwayne Grant McConnell static u64 __spufs_decr_get(void *data)
15728b3d6663SArnd Bergmann {
15738b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
15748b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1575bf1ab978SDwayne Grant McConnell 	return lscsa->decr.slot[0];
1576bf1ab978SDwayne Grant McConnell }
1577bf1ab978SDwayne Grant McConnell 
1578bf1ab978SDwayne Grant McConnell static u64 spufs_decr_get(void *data)
1579bf1ab978SDwayne Grant McConnell {
1580bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
15818b3d6663SArnd Bergmann 	u64 ret;
15828b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1583bf1ab978SDwayne Grant McConnell 	ret = __spufs_decr_get(data);
15848b3d6663SArnd Bergmann 	spu_release(ctx);
15858b3d6663SArnd Bergmann 	return ret;
15868b3d6663SArnd Bergmann }
15878b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
15889b5047e2SDwayne Grant McConnell 			"0x%llx\n")
15898b3d6663SArnd Bergmann 
15908b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val)
15918b3d6663SArnd Bergmann {
15928b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
15938b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
15948b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
15958b3d6663SArnd Bergmann 	lscsa->decr_status.slot[0] = (u32) val;
15968b3d6663SArnd Bergmann 	spu_release(ctx);
15978b3d6663SArnd Bergmann }
15988b3d6663SArnd Bergmann 
1599bf1ab978SDwayne Grant McConnell static u64 __spufs_decr_status_get(void *data)
16008b3d6663SArnd Bergmann {
16018b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
16028b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1603bf1ab978SDwayne Grant McConnell 	return lscsa->decr_status.slot[0];
1604bf1ab978SDwayne Grant McConnell }
1605bf1ab978SDwayne Grant McConnell 
1606bf1ab978SDwayne Grant McConnell static u64 spufs_decr_status_get(void *data)
1607bf1ab978SDwayne Grant McConnell {
1608bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
16098b3d6663SArnd Bergmann 	u64 ret;
16108b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1611bf1ab978SDwayne Grant McConnell 	ret = __spufs_decr_status_get(data);
16128b3d6663SArnd Bergmann 	spu_release(ctx);
16138b3d6663SArnd Bergmann 	return ret;
16148b3d6663SArnd Bergmann }
16158b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
16169b5047e2SDwayne Grant McConnell 			spufs_decr_status_set, "0x%llx\n")
16178b3d6663SArnd Bergmann 
16188b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val)
16198b3d6663SArnd Bergmann {
16208b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
16218b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
16228b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
16238b3d6663SArnd Bergmann 	lscsa->event_mask.slot[0] = (u32) val;
16248b3d6663SArnd Bergmann 	spu_release(ctx);
16258b3d6663SArnd Bergmann }
16268b3d6663SArnd Bergmann 
1627bf1ab978SDwayne Grant McConnell static u64 __spufs_event_mask_get(void *data)
16288b3d6663SArnd Bergmann {
16298b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
16308b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1631bf1ab978SDwayne Grant McConnell 	return lscsa->event_mask.slot[0];
1632bf1ab978SDwayne Grant McConnell }
1633bf1ab978SDwayne Grant McConnell 
1634bf1ab978SDwayne Grant McConnell static u64 spufs_event_mask_get(void *data)
1635bf1ab978SDwayne Grant McConnell {
1636bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
16378b3d6663SArnd Bergmann 	u64 ret;
16388b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1639bf1ab978SDwayne Grant McConnell 	ret = __spufs_event_mask_get(data);
16408b3d6663SArnd Bergmann 	spu_release(ctx);
16418b3d6663SArnd Bergmann 	return ret;
16428b3d6663SArnd Bergmann }
16438b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
16449b5047e2SDwayne Grant McConnell 			spufs_event_mask_set, "0x%llx\n")
16458b3d6663SArnd Bergmann 
1646bf1ab978SDwayne Grant McConnell static u64 __spufs_event_status_get(void *data)
1647b9e3bd77SDwayne Grant McConnell {
1648b9e3bd77SDwayne Grant McConnell 	struct spu_context *ctx = data;
1649b9e3bd77SDwayne Grant McConnell 	struct spu_state *state = &ctx->csa;
1650b9e3bd77SDwayne Grant McConnell 	u64 stat;
1651b9e3bd77SDwayne Grant McConnell 	stat = state->spu_chnlcnt_RW[0];
1652b9e3bd77SDwayne Grant McConnell 	if (stat)
1653bf1ab978SDwayne Grant McConnell 		return state->spu_chnldata_RW[0];
1654bf1ab978SDwayne Grant McConnell 	return 0;
1655bf1ab978SDwayne Grant McConnell }
1656bf1ab978SDwayne Grant McConnell 
1657bf1ab978SDwayne Grant McConnell static u64 spufs_event_status_get(void *data)
1658bf1ab978SDwayne Grant McConnell {
1659bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
1660bf1ab978SDwayne Grant McConnell 	u64 ret = 0;
1661bf1ab978SDwayne Grant McConnell 
1662bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
1663bf1ab978SDwayne Grant McConnell 	ret = __spufs_event_status_get(data);
1664b9e3bd77SDwayne Grant McConnell 	spu_release(ctx);
1665b9e3bd77SDwayne Grant McConnell 	return ret;
1666b9e3bd77SDwayne Grant McConnell }
1667b9e3bd77SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
1668b9e3bd77SDwayne Grant McConnell 			NULL, "0x%llx\n")
1669b9e3bd77SDwayne Grant McConnell 
16708b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val)
16718b3d6663SArnd Bergmann {
16728b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
16738b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
16748b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
16758b3d6663SArnd Bergmann 	lscsa->srr0.slot[0] = (u32) val;
16768b3d6663SArnd Bergmann 	spu_release(ctx);
16778b3d6663SArnd Bergmann }
16788b3d6663SArnd Bergmann 
16798b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data)
16808b3d6663SArnd Bergmann {
16818b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
16828b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
16838b3d6663SArnd Bergmann 	u64 ret;
16848b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
16858b3d6663SArnd Bergmann 	ret = lscsa->srr0.slot[0];
16868b3d6663SArnd Bergmann 	spu_release(ctx);
16878b3d6663SArnd Bergmann 	return ret;
16888b3d6663SArnd Bergmann }
16898b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
16909b5047e2SDwayne Grant McConnell 			"0x%llx\n")
16918b3d6663SArnd Bergmann 
16927b1a7014Sarnd@arndb.de static u64 spufs_id_get(void *data)
16937b1a7014Sarnd@arndb.de {
16947b1a7014Sarnd@arndb.de 	struct spu_context *ctx = data;
16957b1a7014Sarnd@arndb.de 	u64 num;
16967b1a7014Sarnd@arndb.de 
16977b1a7014Sarnd@arndb.de 	spu_acquire(ctx);
16987b1a7014Sarnd@arndb.de 	if (ctx->state == SPU_STATE_RUNNABLE)
16997b1a7014Sarnd@arndb.de 		num = ctx->spu->number;
17007b1a7014Sarnd@arndb.de 	else
17017b1a7014Sarnd@arndb.de 		num = (unsigned int)-1;
17027b1a7014Sarnd@arndb.de 	spu_release(ctx);
17037b1a7014Sarnd@arndb.de 
17047b1a7014Sarnd@arndb.de 	return num;
17057b1a7014Sarnd@arndb.de }
1706e45d6634SAl Viro DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n")
17077b1a7014Sarnd@arndb.de 
1708bf1ab978SDwayne Grant McConnell static u64 __spufs_object_id_get(void *data)
170986767277SArnd Bergmann {
171086767277SArnd Bergmann 	struct spu_context *ctx = data;
171186767277SArnd Bergmann 	return ctx->object_id;
171286767277SArnd Bergmann }
171386767277SArnd Bergmann 
1714bf1ab978SDwayne Grant McConnell static u64 spufs_object_id_get(void *data)
1715bf1ab978SDwayne Grant McConnell {
1716bf1ab978SDwayne Grant McConnell 	/* FIXME: Should there really be no locking here? */
1717bf1ab978SDwayne Grant McConnell 	return __spufs_object_id_get(data);
1718bf1ab978SDwayne Grant McConnell }
1719bf1ab978SDwayne Grant McConnell 
172086767277SArnd Bergmann static void spufs_object_id_set(void *data, u64 id)
172186767277SArnd Bergmann {
172286767277SArnd Bergmann 	struct spu_context *ctx = data;
172386767277SArnd Bergmann 	ctx->object_id = id;
172486767277SArnd Bergmann }
172586767277SArnd Bergmann 
172686767277SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get,
172786767277SArnd Bergmann 		spufs_object_id_set, "0x%llx\n");
172886767277SArnd Bergmann 
1729bf1ab978SDwayne Grant McConnell static u64 __spufs_lslr_get(void *data)
1730bf1ab978SDwayne Grant McConnell {
1731bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
1732bf1ab978SDwayne Grant McConnell 	return ctx->csa.priv2.spu_lslr_RW;
1733bf1ab978SDwayne Grant McConnell }
1734bf1ab978SDwayne Grant McConnell 
1735b9e3bd77SDwayne Grant McConnell static u64 spufs_lslr_get(void *data)
1736b9e3bd77SDwayne Grant McConnell {
1737b9e3bd77SDwayne Grant McConnell 	struct spu_context *ctx = data;
1738b9e3bd77SDwayne Grant McConnell 	u64 ret;
1739b9e3bd77SDwayne Grant McConnell 
1740b9e3bd77SDwayne Grant McConnell 	spu_acquire_saved(ctx);
1741bf1ab978SDwayne Grant McConnell 	ret = __spufs_lslr_get(data);
1742b9e3bd77SDwayne Grant McConnell 	spu_release(ctx);
1743b9e3bd77SDwayne Grant McConnell 
1744b9e3bd77SDwayne Grant McConnell 	return ret;
1745b9e3bd77SDwayne Grant McConnell }
1746b9e3bd77SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n")
1747b9e3bd77SDwayne Grant McConnell 
1748b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file)
1749b9e3bd77SDwayne Grant McConnell {
1750b9e3bd77SDwayne Grant McConnell 	struct spufs_inode_info *i = SPUFS_I(inode);
1751b9e3bd77SDwayne Grant McConnell 	struct spu_context *ctx = i->i_ctx;
1752b9e3bd77SDwayne Grant McConnell 	file->private_data = ctx;
1753b9e3bd77SDwayne Grant McConnell 	return 0;
1754b9e3bd77SDwayne Grant McConnell }
1755b9e3bd77SDwayne Grant McConnell 
1756bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
1757bf1ab978SDwayne Grant McConnell 			char __user *buf, size_t len, loff_t *pos)
1758bf1ab978SDwayne Grant McConnell {
1759bf1ab978SDwayne Grant McConnell 	u32 mbox_stat;
1760bf1ab978SDwayne Grant McConnell 	u32 data;
1761bf1ab978SDwayne Grant McConnell 
1762bf1ab978SDwayne Grant McConnell 	mbox_stat = ctx->csa.prob.mb_stat_R;
1763bf1ab978SDwayne Grant McConnell 	if (mbox_stat & 0x0000ff) {
1764bf1ab978SDwayne Grant McConnell 		data = ctx->csa.prob.pu_mb_R;
1765bf1ab978SDwayne Grant McConnell 	}
1766bf1ab978SDwayne Grant McConnell 
1767bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
1768bf1ab978SDwayne Grant McConnell }
1769bf1ab978SDwayne Grant McConnell 
177069a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
177169a2f00cSDwayne Grant McConnell 				   size_t len, loff_t *pos)
177269a2f00cSDwayne Grant McConnell {
1773bf1ab978SDwayne Grant McConnell 	int ret;
177469a2f00cSDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
177569a2f00cSDwayne Grant McConnell 
177669a2f00cSDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
177769a2f00cSDwayne Grant McConnell 		return -EFAULT;
177869a2f00cSDwayne Grant McConnell 
177969a2f00cSDwayne Grant McConnell 	spu_acquire_saved(ctx);
178069a2f00cSDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1781bf1ab978SDwayne Grant McConnell 	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
178269a2f00cSDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
178369a2f00cSDwayne Grant McConnell 	spu_release(ctx);
178469a2f00cSDwayne Grant McConnell 
1785bf1ab978SDwayne Grant McConnell 	return ret;
178669a2f00cSDwayne Grant McConnell }
178769a2f00cSDwayne Grant McConnell 
17885dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = {
178969a2f00cSDwayne Grant McConnell 	.open = spufs_info_open,
179069a2f00cSDwayne Grant McConnell 	.read = spufs_mbox_info_read,
179169a2f00cSDwayne Grant McConnell 	.llseek  = generic_file_llseek,
179269a2f00cSDwayne Grant McConnell };
179369a2f00cSDwayne Grant McConnell 
1794bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx,
1795bf1ab978SDwayne Grant McConnell 				char __user *buf, size_t len, loff_t *pos)
1796bf1ab978SDwayne Grant McConnell {
1797bf1ab978SDwayne Grant McConnell 	u32 ibox_stat;
1798bf1ab978SDwayne Grant McConnell 	u32 data;
1799bf1ab978SDwayne Grant McConnell 
1800bf1ab978SDwayne Grant McConnell 	ibox_stat = ctx->csa.prob.mb_stat_R;
1801bf1ab978SDwayne Grant McConnell 	if (ibox_stat & 0xff0000) {
1802bf1ab978SDwayne Grant McConnell 		data = ctx->csa.priv2.puint_mb_R;
1803bf1ab978SDwayne Grant McConnell 	}
1804bf1ab978SDwayne Grant McConnell 
1805bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
1806bf1ab978SDwayne Grant McConnell }
1807bf1ab978SDwayne Grant McConnell 
180869a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
180969a2f00cSDwayne Grant McConnell 				   size_t len, loff_t *pos)
181069a2f00cSDwayne Grant McConnell {
181169a2f00cSDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
1812bf1ab978SDwayne Grant McConnell 	int ret;
181369a2f00cSDwayne Grant McConnell 
181469a2f00cSDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
181569a2f00cSDwayne Grant McConnell 		return -EFAULT;
181669a2f00cSDwayne Grant McConnell 
181769a2f00cSDwayne Grant McConnell 	spu_acquire_saved(ctx);
181869a2f00cSDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1819bf1ab978SDwayne Grant McConnell 	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
182069a2f00cSDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
182169a2f00cSDwayne Grant McConnell 	spu_release(ctx);
182269a2f00cSDwayne Grant McConnell 
1823bf1ab978SDwayne Grant McConnell 	return ret;
182469a2f00cSDwayne Grant McConnell }
182569a2f00cSDwayne Grant McConnell 
18265dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = {
182769a2f00cSDwayne Grant McConnell 	.open = spufs_info_open,
182869a2f00cSDwayne Grant McConnell 	.read = spufs_ibox_info_read,
182969a2f00cSDwayne Grant McConnell 	.llseek  = generic_file_llseek,
183069a2f00cSDwayne Grant McConnell };
183169a2f00cSDwayne Grant McConnell 
1832bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
1833bf1ab978SDwayne Grant McConnell 			char __user *buf, size_t len, loff_t *pos)
1834bf1ab978SDwayne Grant McConnell {
1835bf1ab978SDwayne Grant McConnell 	int i, cnt;
1836bf1ab978SDwayne Grant McConnell 	u32 data[4];
1837bf1ab978SDwayne Grant McConnell 	u32 wbox_stat;
1838bf1ab978SDwayne Grant McConnell 
1839bf1ab978SDwayne Grant McConnell 	wbox_stat = ctx->csa.prob.mb_stat_R;
1840bf1ab978SDwayne Grant McConnell 	cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
1841bf1ab978SDwayne Grant McConnell 	for (i = 0; i < cnt; i++) {
1842bf1ab978SDwayne Grant McConnell 		data[i] = ctx->csa.spu_mailbox_data[i];
1843bf1ab978SDwayne Grant McConnell 	}
1844bf1ab978SDwayne Grant McConnell 
1845bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &data,
1846bf1ab978SDwayne Grant McConnell 				cnt * sizeof(u32));
1847bf1ab978SDwayne Grant McConnell }
1848bf1ab978SDwayne Grant McConnell 
184969a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
185069a2f00cSDwayne Grant McConnell 				   size_t len, loff_t *pos)
185169a2f00cSDwayne Grant McConnell {
185269a2f00cSDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
1853bf1ab978SDwayne Grant McConnell 	int ret;
185469a2f00cSDwayne Grant McConnell 
185569a2f00cSDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
185669a2f00cSDwayne Grant McConnell 		return -EFAULT;
185769a2f00cSDwayne Grant McConnell 
185869a2f00cSDwayne Grant McConnell 	spu_acquire_saved(ctx);
185969a2f00cSDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1860bf1ab978SDwayne Grant McConnell 	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
186169a2f00cSDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
186269a2f00cSDwayne Grant McConnell 	spu_release(ctx);
186369a2f00cSDwayne Grant McConnell 
1864bf1ab978SDwayne Grant McConnell 	return ret;
186569a2f00cSDwayne Grant McConnell }
186669a2f00cSDwayne Grant McConnell 
18675dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = {
186869a2f00cSDwayne Grant McConnell 	.open = spufs_info_open,
186969a2f00cSDwayne Grant McConnell 	.read = spufs_wbox_info_read,
187069a2f00cSDwayne Grant McConnell 	.llseek  = generic_file_llseek,
187169a2f00cSDwayne Grant McConnell };
187269a2f00cSDwayne Grant McConnell 
1873bf1ab978SDwayne Grant McConnell static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
1874bf1ab978SDwayne Grant McConnell 			char __user *buf, size_t len, loff_t *pos)
1875b9e3bd77SDwayne Grant McConnell {
1876b9e3bd77SDwayne Grant McConnell 	struct spu_dma_info info;
1877b9e3bd77SDwayne Grant McConnell 	struct mfc_cq_sr *qp, *spuqp;
1878b9e3bd77SDwayne Grant McConnell 	int i;
1879b9e3bd77SDwayne Grant McConnell 
1880b9e3bd77SDwayne Grant McConnell 	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
1881b9e3bd77SDwayne Grant McConnell 	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
1882b9e3bd77SDwayne Grant McConnell 	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
1883b9e3bd77SDwayne Grant McConnell 	info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
1884b9e3bd77SDwayne Grant McConnell 	info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
1885b9e3bd77SDwayne Grant McConnell 	for (i = 0; i < 16; i++) {
1886b9e3bd77SDwayne Grant McConnell 		qp = &info.dma_info_command_data[i];
1887b9e3bd77SDwayne Grant McConnell 		spuqp = &ctx->csa.priv2.spuq[i];
1888b9e3bd77SDwayne Grant McConnell 
1889b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
1890b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
1891b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
1892b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
1893b9e3bd77SDwayne Grant McConnell 	}
1894b9e3bd77SDwayne Grant McConnell 
1895b9e3bd77SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &info,
1896b9e3bd77SDwayne Grant McConnell 				sizeof info);
1897b9e3bd77SDwayne Grant McConnell }
1898b9e3bd77SDwayne Grant McConnell 
1899bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
1900bf1ab978SDwayne Grant McConnell 			      size_t len, loff_t *pos)
1901bf1ab978SDwayne Grant McConnell {
1902bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
1903bf1ab978SDwayne Grant McConnell 	int ret;
1904bf1ab978SDwayne Grant McConnell 
1905bf1ab978SDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
1906bf1ab978SDwayne Grant McConnell 		return -EFAULT;
1907bf1ab978SDwayne Grant McConnell 
1908bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
1909bf1ab978SDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1910bf1ab978SDwayne Grant McConnell 	ret = __spufs_dma_info_read(ctx, buf, len, pos);
1911bf1ab978SDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
1912bf1ab978SDwayne Grant McConnell 	spu_release(ctx);
1913bf1ab978SDwayne Grant McConnell 
1914bf1ab978SDwayne Grant McConnell 	return ret;
1915bf1ab978SDwayne Grant McConnell }
1916bf1ab978SDwayne Grant McConnell 
19175dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = {
1918b9e3bd77SDwayne Grant McConnell 	.open = spufs_info_open,
1919b9e3bd77SDwayne Grant McConnell 	.read = spufs_dma_info_read,
1920b9e3bd77SDwayne Grant McConnell };
1921b9e3bd77SDwayne Grant McConnell 
1922bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
1923bf1ab978SDwayne Grant McConnell 			char __user *buf, size_t len, loff_t *pos)
1924b9e3bd77SDwayne Grant McConnell {
1925b9e3bd77SDwayne Grant McConnell 	struct spu_proxydma_info info;
1926b9e3bd77SDwayne Grant McConnell 	struct mfc_cq_sr *qp, *puqp;
1927bf1ab978SDwayne Grant McConnell 	int ret = sizeof info;
1928b9e3bd77SDwayne Grant McConnell 	int i;
1929b9e3bd77SDwayne Grant McConnell 
1930b9e3bd77SDwayne Grant McConnell 	if (len < ret)
1931b9e3bd77SDwayne Grant McConnell 		return -EINVAL;
1932b9e3bd77SDwayne Grant McConnell 
1933b9e3bd77SDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
1934b9e3bd77SDwayne Grant McConnell 		return -EFAULT;
1935b9e3bd77SDwayne Grant McConnell 
1936b9e3bd77SDwayne Grant McConnell 	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
1937b9e3bd77SDwayne Grant McConnell 	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
1938b9e3bd77SDwayne Grant McConnell 	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
1939b9e3bd77SDwayne Grant McConnell 	for (i = 0; i < 8; i++) {
1940b9e3bd77SDwayne Grant McConnell 		qp = &info.proxydma_info_command_data[i];
1941b9e3bd77SDwayne Grant McConnell 		puqp = &ctx->csa.priv2.puq[i];
1942b9e3bd77SDwayne Grant McConnell 
1943b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
1944b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
1945b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
1946b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
1947b9e3bd77SDwayne Grant McConnell 	}
1948bf1ab978SDwayne Grant McConnell 
1949bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &info,
1950bf1ab978SDwayne Grant McConnell 				sizeof info);
1951bf1ab978SDwayne Grant McConnell }
1952bf1ab978SDwayne Grant McConnell 
1953bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
1954bf1ab978SDwayne Grant McConnell 				   size_t len, loff_t *pos)
1955bf1ab978SDwayne Grant McConnell {
1956bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
1957bf1ab978SDwayne Grant McConnell 	int ret;
1958bf1ab978SDwayne Grant McConnell 
1959bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
1960bf1ab978SDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1961bf1ab978SDwayne Grant McConnell 	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
1962b9e3bd77SDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
1963b9e3bd77SDwayne Grant McConnell 	spu_release(ctx);
1964b9e3bd77SDwayne Grant McConnell 
1965b9e3bd77SDwayne Grant McConnell 	return ret;
1966b9e3bd77SDwayne Grant McConnell }
1967b9e3bd77SDwayne Grant McConnell 
19685dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = {
1969b9e3bd77SDwayne Grant McConnell 	.open = spufs_info_open,
1970b9e3bd77SDwayne Grant McConnell 	.read = spufs_proxydma_info_read,
1971b9e3bd77SDwayne Grant McConnell };
1972b9e3bd77SDwayne Grant McConnell 
197367207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = {
197467207b96SArnd Bergmann 	{ "mem",  &spufs_mem_fops,  0666, },
19758b3d6663SArnd Bergmann 	{ "regs", &spufs_regs_fops,  0666, },
197667207b96SArnd Bergmann 	{ "mbox", &spufs_mbox_fops, 0444, },
197767207b96SArnd Bergmann 	{ "ibox", &spufs_ibox_fops, 0444, },
197867207b96SArnd Bergmann 	{ "wbox", &spufs_wbox_fops, 0222, },
197967207b96SArnd Bergmann 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
198067207b96SArnd Bergmann 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
198167207b96SArnd Bergmann 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
198267207b96SArnd Bergmann 	{ "signal1", &spufs_signal1_fops, 0666, },
198367207b96SArnd Bergmann 	{ "signal2", &spufs_signal2_fops, 0666, },
198467207b96SArnd Bergmann 	{ "signal1_type", &spufs_signal1_type, 0666, },
198567207b96SArnd Bergmann 	{ "signal2_type", &spufs_signal2_type, 0666, },
19866df10a82SMark Nutter 	{ "cntl", &spufs_cntl_fops,  0666, },
19878b3d6663SArnd Bergmann 	{ "fpcr", &spufs_fpcr_fops, 0666, },
1988b9e3bd77SDwayne Grant McConnell 	{ "lslr", &spufs_lslr_ops, 0444, },
1989b9e3bd77SDwayne Grant McConnell 	{ "mfc", &spufs_mfc_fops, 0666, },
1990b9e3bd77SDwayne Grant McConnell 	{ "mss", &spufs_mss_fops, 0666, },
1991b9e3bd77SDwayne Grant McConnell 	{ "npc", &spufs_npc_ops, 0666, },
1992b9e3bd77SDwayne Grant McConnell 	{ "srr0", &spufs_srr0_ops, 0666, },
19938b3d6663SArnd Bergmann 	{ "decr", &spufs_decr_ops, 0666, },
19948b3d6663SArnd Bergmann 	{ "decr_status", &spufs_decr_status_ops, 0666, },
19958b3d6663SArnd Bergmann 	{ "event_mask", &spufs_event_mask_ops, 0666, },
1996b9e3bd77SDwayne Grant McConnell 	{ "event_status", &spufs_event_status_ops, 0444, },
199727d5bf2aSBenjamin Herrenschmidt 	{ "psmap", &spufs_psmap_fops, 0666, },
199886767277SArnd Bergmann 	{ "phys-id", &spufs_id_ops, 0666, },
199986767277SArnd Bergmann 	{ "object-id", &spufs_object_id_ops, 0666, },
200069a2f00cSDwayne Grant McConnell 	{ "mbox_info", &spufs_mbox_info_fops, 0444, },
200169a2f00cSDwayne Grant McConnell 	{ "ibox_info", &spufs_ibox_info_fops, 0444, },
200269a2f00cSDwayne Grant McConnell 	{ "wbox_info", &spufs_wbox_info_fops, 0444, },
2003b9e3bd77SDwayne Grant McConnell 	{ "dma_info", &spufs_dma_info_fops, 0444, },
2004b9e3bd77SDwayne Grant McConnell 	{ "proxydma_info", &spufs_proxydma_info_fops, 0444, },
200567207b96SArnd Bergmann 	{},
200667207b96SArnd Bergmann };
20075737edd1SMark Nutter 
20085737edd1SMark Nutter struct tree_descr spufs_dir_nosched_contents[] = {
20095737edd1SMark Nutter 	{ "mem",  &spufs_mem_fops,  0666, },
20105737edd1SMark Nutter 	{ "mbox", &spufs_mbox_fops, 0444, },
20115737edd1SMark Nutter 	{ "ibox", &spufs_ibox_fops, 0444, },
20125737edd1SMark Nutter 	{ "wbox", &spufs_wbox_fops, 0222, },
20135737edd1SMark Nutter 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
20145737edd1SMark Nutter 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
20155737edd1SMark Nutter 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
20165737edd1SMark Nutter 	{ "signal1", &spufs_signal1_fops, 0666, },
20175737edd1SMark Nutter 	{ "signal2", &spufs_signal2_fops, 0666, },
20185737edd1SMark Nutter 	{ "signal1_type", &spufs_signal1_type, 0666, },
20195737edd1SMark Nutter 	{ "signal2_type", &spufs_signal2_type, 0666, },
20205737edd1SMark Nutter 	{ "mss", &spufs_mss_fops, 0666, },
20215737edd1SMark Nutter 	{ "mfc", &spufs_mfc_fops, 0666, },
20225737edd1SMark Nutter 	{ "cntl", &spufs_cntl_fops,  0666, },
20235737edd1SMark Nutter 	{ "npc", &spufs_npc_ops, 0666, },
20245737edd1SMark Nutter 	{ "psmap", &spufs_psmap_fops, 0666, },
20255737edd1SMark Nutter 	{ "phys-id", &spufs_id_ops, 0666, },
20265737edd1SMark Nutter 	{ "object-id", &spufs_object_id_ops, 0666, },
20275737edd1SMark Nutter 	{},
20285737edd1SMark Nutter };
2029bf1ab978SDwayne Grant McConnell 
2030bf1ab978SDwayne Grant McConnell struct spufs_coredump_reader spufs_coredump_read[] = {
2031bf1ab978SDwayne Grant McConnell 	{ "regs", __spufs_regs_read, NULL, 128 * 16 },
2032bf1ab978SDwayne Grant McConnell 	{ "fpcr", __spufs_fpcr_read, NULL, 16 },
2033bf1ab978SDwayne Grant McConnell 	{ "lslr", NULL, __spufs_lslr_get, 11 },
2034bf1ab978SDwayne Grant McConnell 	{ "decr", NULL, __spufs_decr_get, 11 },
2035bf1ab978SDwayne Grant McConnell 	{ "decr_status", NULL, __spufs_decr_status_get, 11 },
2036bf1ab978SDwayne Grant McConnell 	{ "mem", __spufs_mem_read, NULL, 256 * 1024, },
2037bf1ab978SDwayne Grant McConnell 	{ "signal1", __spufs_signal1_read, NULL, 4 },
2038bf1ab978SDwayne Grant McConnell 	{ "signal1_type", NULL, __spufs_signal1_type_get, 2 },
2039bf1ab978SDwayne Grant McConnell 	{ "signal2", __spufs_signal2_read, NULL, 4 },
2040bf1ab978SDwayne Grant McConnell 	{ "signal2_type", NULL, __spufs_signal2_type_get, 2 },
2041bf1ab978SDwayne Grant McConnell 	{ "event_mask", NULL, __spufs_event_mask_get, 8 },
2042bf1ab978SDwayne Grant McConnell 	{ "event_status", NULL, __spufs_event_status_get, 8 },
2043bf1ab978SDwayne Grant McConnell 	{ "mbox_info", __spufs_mbox_info_read, NULL, 4 },
2044bf1ab978SDwayne Grant McConnell 	{ "ibox_info", __spufs_ibox_info_read, NULL, 4 },
2045bf1ab978SDwayne Grant McConnell 	{ "wbox_info", __spufs_wbox_info_read, NULL, 16 },
2046bf1ab978SDwayne Grant McConnell 	{ "dma_info", __spufs_dma_info_read, NULL, 69 * 8 },
2047bf1ab978SDwayne Grant McConnell 	{ "proxydma_info", __spufs_proxydma_info_read, NULL, 35 * 8 },
2048bf1ab978SDwayne Grant McConnell 	{ "object-id", NULL, __spufs_object_id_get, 19 },
2049bf1ab978SDwayne Grant McConnell 	{ },
2050bf1ab978SDwayne Grant McConnell };
2051bf1ab978SDwayne Grant McConnell int spufs_coredump_num_notes = ARRAY_SIZE(spufs_coredump_read) - 1;
2052bf1ab978SDwayne Grant McConnell 
2053