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;
476df10a82SMark Nutter 	file->private_data = ctx;
486df10a82SMark Nutter 	file->f_mapping = inode->i_mapping;
496df10a82SMark Nutter 	ctx->local_store = inode->i_mapping;
5067207b96SArnd Bergmann 	return 0;
5167207b96SArnd Bergmann }
5267207b96SArnd Bergmann 
5367207b96SArnd Bergmann static ssize_t
54bf1ab978SDwayne Grant McConnell __spufs_mem_read(struct spu_context *ctx, char __user *buffer,
55bf1ab978SDwayne Grant McConnell 			size_t size, loff_t *pos)
56bf1ab978SDwayne Grant McConnell {
57bf1ab978SDwayne Grant McConnell 	char *local_store = ctx->ops->get_ls(ctx);
58bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buffer, size, pos, local_store,
59bf1ab978SDwayne Grant McConnell 					LS_SIZE);
60bf1ab978SDwayne Grant McConnell }
61bf1ab978SDwayne Grant McConnell 
62bf1ab978SDwayne Grant McConnell static ssize_t
6367207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer,
6467207b96SArnd Bergmann 				size_t size, loff_t *pos)
6567207b96SArnd Bergmann {
6667207b96SArnd Bergmann 	int ret;
67bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
6867207b96SArnd Bergmann 
698b3d6663SArnd Bergmann 	spu_acquire(ctx);
70bf1ab978SDwayne Grant McConnell 	ret = __spufs_mem_read(ctx, buffer, size, pos);
718b3d6663SArnd Bergmann 	spu_release(ctx);
7267207b96SArnd Bergmann 	return ret;
7367207b96SArnd Bergmann }
7467207b96SArnd Bergmann 
7567207b96SArnd Bergmann static ssize_t
7667207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer,
7767207b96SArnd Bergmann 					size_t size, loff_t *pos)
7867207b96SArnd Bergmann {
7967207b96SArnd Bergmann 	struct spu_context *ctx = file->private_data;
808b3d6663SArnd Bergmann 	char *local_store;
818b3d6663SArnd Bergmann 	int ret;
8267207b96SArnd Bergmann 
8367207b96SArnd Bergmann 	size = min_t(ssize_t, LS_SIZE - *pos, size);
8467207b96SArnd Bergmann 	if (size <= 0)
8567207b96SArnd Bergmann 		return -EFBIG;
8667207b96SArnd Bergmann 	*pos += size;
878b3d6663SArnd Bergmann 
888b3d6663SArnd Bergmann 	spu_acquire(ctx);
898b3d6663SArnd Bergmann 
908b3d6663SArnd Bergmann 	local_store = ctx->ops->get_ls(ctx);
918b3d6663SArnd Bergmann 	ret = copy_from_user(local_store + *pos - size,
9267207b96SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
938b3d6663SArnd Bergmann 
948b3d6663SArnd Bergmann 	spu_release(ctx);
958b3d6663SArnd Bergmann 	return ret;
9667207b96SArnd Bergmann }
9767207b96SArnd Bergmann 
988b3d6663SArnd Bergmann static struct page *
998b3d6663SArnd Bergmann spufs_mem_mmap_nopage(struct vm_area_struct *vma,
1008b3d6663SArnd Bergmann 		      unsigned long address, int *type)
1018b3d6663SArnd Bergmann {
1028b3d6663SArnd Bergmann 	struct page *page = NOPAGE_SIGBUS;
1038b3d6663SArnd Bergmann 
1048b3d6663SArnd Bergmann 	struct spu_context *ctx = vma->vm_file->private_data;
1058b3d6663SArnd Bergmann 	unsigned long offset = address - vma->vm_start;
1068b3d6663SArnd Bergmann 	offset += vma->vm_pgoff << PAGE_SHIFT;
1078b3d6663SArnd Bergmann 
1088b3d6663SArnd Bergmann 	spu_acquire(ctx);
1098b3d6663SArnd Bergmann 
110ac91cb8dSArnd Bergmann 	if (ctx->state == SPU_STATE_SAVED) {
111ac91cb8dSArnd Bergmann 		vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
112932f535dSArnd Bergmann 							& ~_PAGE_NO_CACHE);
1138b3d6663SArnd Bergmann 		page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
114ac91cb8dSArnd Bergmann 	} else {
115ac91cb8dSArnd Bergmann 		vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
116932f535dSArnd Bergmann 							| _PAGE_NO_CACHE);
1178b3d6663SArnd Bergmann 		page = pfn_to_page((ctx->spu->local_store_phys + offset)
1188b3d6663SArnd Bergmann 				   >> PAGE_SHIFT);
119ac91cb8dSArnd Bergmann 	}
1208b3d6663SArnd Bergmann 	spu_release(ctx);
1218b3d6663SArnd Bergmann 
1228b3d6663SArnd Bergmann 	if (type)
1238b3d6663SArnd Bergmann 		*type = VM_FAULT_MINOR;
1248b3d6663SArnd Bergmann 
125d88cfffaSArnd Bergmann 	page_cache_get(page);
1268b3d6663SArnd Bergmann 	return page;
1278b3d6663SArnd Bergmann }
1288b3d6663SArnd Bergmann 
1298b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = {
1308b3d6663SArnd Bergmann 	.nopage = spufs_mem_mmap_nopage,
1318b3d6663SArnd Bergmann };
1328b3d6663SArnd Bergmann 
13367207b96SArnd Bergmann static int
13467207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
13567207b96SArnd Bergmann {
1368b3d6663SArnd Bergmann 	if (!(vma->vm_flags & VM_SHARED))
1378b3d6663SArnd Bergmann 		return -EINVAL;
13867207b96SArnd Bergmann 
1395c3ecd65SChristoph Hellwig 	vma->vm_flags |= VM_IO;
14067207b96SArnd Bergmann 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
14167207b96SArnd Bergmann 				     | _PAGE_NO_CACHE);
1428b3d6663SArnd Bergmann 
1438b3d6663SArnd Bergmann 	vma->vm_ops = &spufs_mem_mmap_vmops;
14467207b96SArnd Bergmann 	return 0;
14567207b96SArnd Bergmann }
14667207b96SArnd Bergmann 
1475dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = {
14867207b96SArnd Bergmann 	.open	 = spufs_mem_open,
14967207b96SArnd Bergmann 	.read    = spufs_mem_read,
15067207b96SArnd Bergmann 	.write   = spufs_mem_write,
1518b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
15267207b96SArnd Bergmann 	.mmap    = spufs_mem_mmap,
1538b3d6663SArnd Bergmann };
1548b3d6663SArnd Bergmann 
1556df10a82SMark Nutter static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
1566df10a82SMark Nutter 				    unsigned long address,
15727d5bf2aSBenjamin Herrenschmidt 				    int *type, unsigned long ps_offs,
15827d5bf2aSBenjamin Herrenschmidt 				    unsigned long ps_size)
1596df10a82SMark Nutter {
1606df10a82SMark Nutter 	struct page *page = NOPAGE_SIGBUS;
1616df10a82SMark Nutter 	int fault_type = VM_FAULT_SIGBUS;
1626df10a82SMark Nutter 	struct spu_context *ctx = vma->vm_file->private_data;
1636df10a82SMark Nutter 	unsigned long offset = address - vma->vm_start;
1646df10a82SMark Nutter 	unsigned long area;
1656df10a82SMark Nutter 	int ret;
1666df10a82SMark Nutter 
1676df10a82SMark Nutter 	offset += vma->vm_pgoff << PAGE_SHIFT;
16827d5bf2aSBenjamin Herrenschmidt 	if (offset >= ps_size)
1696df10a82SMark Nutter 		goto out;
1706df10a82SMark Nutter 
1716df10a82SMark Nutter 	ret = spu_acquire_runnable(ctx);
1726df10a82SMark Nutter 	if (ret)
1736df10a82SMark Nutter 		goto out;
1746df10a82SMark Nutter 
1756df10a82SMark Nutter 	area = ctx->spu->problem_phys + ps_offs;
1766df10a82SMark Nutter 	page = pfn_to_page((area + offset) >> PAGE_SHIFT);
1776df10a82SMark Nutter 	fault_type = VM_FAULT_MINOR;
1786df10a82SMark Nutter 	page_cache_get(page);
1796df10a82SMark Nutter 
1806df10a82SMark Nutter 	spu_release(ctx);
1816df10a82SMark Nutter 
1826df10a82SMark Nutter       out:
1836df10a82SMark Nutter 	if (type)
1846df10a82SMark Nutter 		*type = fault_type;
1856df10a82SMark Nutter 
1866df10a82SMark Nutter 	return page;
1876df10a82SMark Nutter }
1886df10a82SMark Nutter 
18927d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K
1906df10a82SMark Nutter static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
1916df10a82SMark Nutter 					   unsigned long address, int *type)
1926df10a82SMark Nutter {
19327d5bf2aSBenjamin Herrenschmidt 	return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000);
1946df10a82SMark Nutter }
1956df10a82SMark Nutter 
1966df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = {
1976df10a82SMark Nutter 	.nopage = spufs_cntl_mmap_nopage,
1986df10a82SMark Nutter };
1996df10a82SMark Nutter 
2006df10a82SMark Nutter /*
2016df10a82SMark Nutter  * mmap support for problem state control area [0x4000 - 0x4fff].
2026df10a82SMark Nutter  */
2036df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
2046df10a82SMark Nutter {
2056df10a82SMark Nutter 	if (!(vma->vm_flags & VM_SHARED))
2066df10a82SMark Nutter 		return -EINVAL;
2076df10a82SMark Nutter 
2085c3ecd65SChristoph Hellwig 	vma->vm_flags |= VM_IO;
2096df10a82SMark Nutter 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
21023cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
2116df10a82SMark Nutter 
2126df10a82SMark Nutter 	vma->vm_ops = &spufs_cntl_mmap_vmops;
2136df10a82SMark Nutter 	return 0;
2146df10a82SMark Nutter }
21527d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */
21627d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL
21727d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */
2186df10a82SMark Nutter 
219e1dbff2bSArnd Bergmann static u64 spufs_cntl_get(void *data)
220e1dbff2bSArnd Bergmann {
221e1dbff2bSArnd Bergmann 	struct spu_context *ctx = data;
222e1dbff2bSArnd Bergmann 	u64 val;
223e1dbff2bSArnd Bergmann 
224e1dbff2bSArnd Bergmann 	spu_acquire(ctx);
225e1dbff2bSArnd Bergmann 	val = ctx->ops->status_read(ctx);
226e1dbff2bSArnd Bergmann 	spu_release(ctx);
227e1dbff2bSArnd Bergmann 
228e1dbff2bSArnd Bergmann 	return val;
229e1dbff2bSArnd Bergmann }
230e1dbff2bSArnd Bergmann 
231e1dbff2bSArnd Bergmann static void spufs_cntl_set(void *data, u64 val)
232e1dbff2bSArnd Bergmann {
233e1dbff2bSArnd Bergmann 	struct spu_context *ctx = data;
234e1dbff2bSArnd Bergmann 
235e1dbff2bSArnd Bergmann 	spu_acquire(ctx);
236e1dbff2bSArnd Bergmann 	ctx->ops->runcntl_write(ctx, val);
237e1dbff2bSArnd Bergmann 	spu_release(ctx);
238e1dbff2bSArnd Bergmann }
239e1dbff2bSArnd Bergmann 
2406df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file)
2416df10a82SMark Nutter {
2426df10a82SMark Nutter 	struct spufs_inode_info *i = SPUFS_I(inode);
2436df10a82SMark Nutter 	struct spu_context *ctx = i->i_ctx;
2446df10a82SMark Nutter 
2456df10a82SMark Nutter 	file->private_data = ctx;
2466df10a82SMark Nutter 	file->f_mapping = inode->i_mapping;
2476df10a82SMark Nutter 	ctx->cntl = inode->i_mapping;
248e1dbff2bSArnd Bergmann 	return simple_attr_open(inode, file, spufs_cntl_get,
249e1dbff2bSArnd Bergmann 					spufs_cntl_set, "0x%08lx");
2506df10a82SMark Nutter }
2516df10a82SMark Nutter 
2525dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = {
2536df10a82SMark Nutter 	.open = spufs_cntl_open,
254654e4aeeSNoguchi, Masato 	.release = simple_attr_close,
255e1dbff2bSArnd Bergmann 	.read = simple_attr_read,
256e1dbff2bSArnd Bergmann 	.write = simple_attr_write,
2576df10a82SMark Nutter 	.mmap = spufs_cntl_mmap,
2586df10a82SMark Nutter };
2596df10a82SMark Nutter 
2608b3d6663SArnd Bergmann static int
2618b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file)
2628b3d6663SArnd Bergmann {
2638b3d6663SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
2648b3d6663SArnd Bergmann 	file->private_data = i->i_ctx;
2658b3d6663SArnd Bergmann 	return 0;
2668b3d6663SArnd Bergmann }
2678b3d6663SArnd Bergmann 
2688b3d6663SArnd Bergmann static ssize_t
269bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer,
270bf1ab978SDwayne Grant McConnell 			size_t size, loff_t *pos)
271bf1ab978SDwayne Grant McConnell {
272bf1ab978SDwayne Grant McConnell 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
273bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buffer, size, pos,
274bf1ab978SDwayne Grant McConnell 				      lscsa->gprs, sizeof lscsa->gprs);
275bf1ab978SDwayne Grant McConnell }
276bf1ab978SDwayne Grant McConnell 
277bf1ab978SDwayne Grant McConnell static ssize_t
2788b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer,
2798b3d6663SArnd Bergmann 		size_t size, loff_t *pos)
2808b3d6663SArnd Bergmann {
2818b3d6663SArnd Bergmann 	int ret;
282bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
2838b3d6663SArnd Bergmann 
2848b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
285bf1ab978SDwayne Grant McConnell 	ret = __spufs_regs_read(ctx, buffer, size, pos);
2868b3d6663SArnd Bergmann 	spu_release(ctx);
2878b3d6663SArnd Bergmann 	return ret;
2888b3d6663SArnd Bergmann }
2898b3d6663SArnd Bergmann 
2908b3d6663SArnd Bergmann static ssize_t
2918b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer,
2928b3d6663SArnd Bergmann 		 size_t size, loff_t *pos)
2938b3d6663SArnd Bergmann {
2948b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
2958b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
2968b3d6663SArnd Bergmann 	int ret;
2978b3d6663SArnd Bergmann 
2988b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
2998b3d6663SArnd Bergmann 	if (size <= 0)
3008b3d6663SArnd Bergmann 		return -EFBIG;
3018b3d6663SArnd Bergmann 	*pos += size;
3028b3d6663SArnd Bergmann 
3038b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
3048b3d6663SArnd Bergmann 
3058b3d6663SArnd Bergmann 	ret = copy_from_user(lscsa->gprs + *pos - size,
3068b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
3078b3d6663SArnd Bergmann 
3088b3d6663SArnd Bergmann 	spu_release(ctx);
3098b3d6663SArnd Bergmann 	return ret;
3108b3d6663SArnd Bergmann }
3118b3d6663SArnd Bergmann 
3125dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = {
3138b3d6663SArnd Bergmann 	.open	 = spufs_regs_open,
3148b3d6663SArnd Bergmann 	.read    = spufs_regs_read,
3158b3d6663SArnd Bergmann 	.write   = spufs_regs_write,
3168b3d6663SArnd Bergmann 	.llseek  = generic_file_llseek,
3178b3d6663SArnd Bergmann };
3188b3d6663SArnd Bergmann 
3198b3d6663SArnd Bergmann static ssize_t
320bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer,
321bf1ab978SDwayne Grant McConnell 			size_t size, loff_t * pos)
322bf1ab978SDwayne Grant McConnell {
323bf1ab978SDwayne Grant McConnell 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
324bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buffer, size, pos,
325bf1ab978SDwayne Grant McConnell 				      &lscsa->fpcr, sizeof(lscsa->fpcr));
326bf1ab978SDwayne Grant McConnell }
327bf1ab978SDwayne Grant McConnell 
328bf1ab978SDwayne Grant McConnell static ssize_t
3298b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer,
3308b3d6663SArnd Bergmann 		size_t size, loff_t * pos)
3318b3d6663SArnd Bergmann {
3328b3d6663SArnd Bergmann 	int ret;
333bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
3348b3d6663SArnd Bergmann 
3358b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
336bf1ab978SDwayne Grant McConnell 	ret = __spufs_fpcr_read(ctx, buffer, size, pos);
3378b3d6663SArnd Bergmann 	spu_release(ctx);
3388b3d6663SArnd Bergmann 	return ret;
3398b3d6663SArnd Bergmann }
3408b3d6663SArnd Bergmann 
3418b3d6663SArnd Bergmann static ssize_t
3428b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer,
3438b3d6663SArnd Bergmann 		 size_t size, loff_t * pos)
3448b3d6663SArnd Bergmann {
3458b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
3468b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
3478b3d6663SArnd Bergmann 	int ret;
3488b3d6663SArnd Bergmann 
3498b3d6663SArnd Bergmann 	size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
3508b3d6663SArnd Bergmann 	if (size <= 0)
3518b3d6663SArnd Bergmann 		return -EFBIG;
3528b3d6663SArnd Bergmann 	*pos += size;
3538b3d6663SArnd Bergmann 
3548b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
3558b3d6663SArnd Bergmann 
3568b3d6663SArnd Bergmann 	ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
3578b3d6663SArnd Bergmann 			     buffer, size) ? -EFAULT : size;
3588b3d6663SArnd Bergmann 
3598b3d6663SArnd Bergmann 	spu_release(ctx);
3608b3d6663SArnd Bergmann 	return ret;
3618b3d6663SArnd Bergmann }
3628b3d6663SArnd Bergmann 
3635dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = {
3648b3d6663SArnd Bergmann 	.open = spufs_regs_open,
3658b3d6663SArnd Bergmann 	.read = spufs_fpcr_read,
3668b3d6663SArnd Bergmann 	.write = spufs_fpcr_write,
36767207b96SArnd Bergmann 	.llseek = generic_file_llseek,
36867207b96SArnd Bergmann };
36967207b96SArnd Bergmann 
37067207b96SArnd Bergmann /* generic open function for all pipe-like files */
37167207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file)
37267207b96SArnd Bergmann {
37367207b96SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
37467207b96SArnd Bergmann 	file->private_data = i->i_ctx;
37567207b96SArnd Bergmann 
37667207b96SArnd Bergmann 	return nonseekable_open(inode, file);
37767207b96SArnd Bergmann }
37867207b96SArnd Bergmann 
379cdcc89bbSArnd Bergmann /*
380cdcc89bbSArnd Bergmann  * Read as many bytes from the mailbox as possible, until
381cdcc89bbSArnd Bergmann  * one of the conditions becomes true:
382cdcc89bbSArnd Bergmann  *
383cdcc89bbSArnd Bergmann  * - no more data available in the mailbox
384cdcc89bbSArnd Bergmann  * - end of the user provided buffer
385cdcc89bbSArnd Bergmann  * - end of the mapped area
386cdcc89bbSArnd Bergmann  */
38767207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
38867207b96SArnd Bergmann 			size_t len, loff_t *pos)
38967207b96SArnd Bergmann {
3908b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
391cdcc89bbSArnd Bergmann 	u32 mbox_data, __user *udata;
392cdcc89bbSArnd Bergmann 	ssize_t count;
39367207b96SArnd Bergmann 
39467207b96SArnd Bergmann 	if (len < 4)
39567207b96SArnd Bergmann 		return -EINVAL;
39667207b96SArnd Bergmann 
397cdcc89bbSArnd Bergmann 	if (!access_ok(VERIFY_WRITE, buf, len))
39867207b96SArnd Bergmann 		return -EFAULT;
39967207b96SArnd Bergmann 
400cdcc89bbSArnd Bergmann 	udata = (void __user *)buf;
401cdcc89bbSArnd Bergmann 
402cdcc89bbSArnd Bergmann 	spu_acquire(ctx);
403274cef5eSArnd Bergmann 	for (count = 0; (count + 4) <= len; count += 4, udata++) {
404cdcc89bbSArnd Bergmann 		int ret;
405cdcc89bbSArnd Bergmann 		ret = ctx->ops->mbox_read(ctx, &mbox_data);
406cdcc89bbSArnd Bergmann 		if (ret == 0)
407cdcc89bbSArnd Bergmann 			break;
408cdcc89bbSArnd Bergmann 
409cdcc89bbSArnd Bergmann 		/*
410cdcc89bbSArnd Bergmann 		 * at the end of the mapped area, we can fault
411cdcc89bbSArnd Bergmann 		 * but still need to return the data we have
412cdcc89bbSArnd Bergmann 		 * read successfully so far.
413cdcc89bbSArnd Bergmann 		 */
414cdcc89bbSArnd Bergmann 		ret = __put_user(mbox_data, udata);
415cdcc89bbSArnd Bergmann 		if (ret) {
416cdcc89bbSArnd Bergmann 			if (!count)
417cdcc89bbSArnd Bergmann 				count = -EFAULT;
418cdcc89bbSArnd Bergmann 			break;
419cdcc89bbSArnd Bergmann 		}
420cdcc89bbSArnd Bergmann 	}
421cdcc89bbSArnd Bergmann 	spu_release(ctx);
422cdcc89bbSArnd Bergmann 
423cdcc89bbSArnd Bergmann 	if (!count)
424cdcc89bbSArnd Bergmann 		count = -EAGAIN;
425cdcc89bbSArnd Bergmann 
426cdcc89bbSArnd Bergmann 	return count;
42767207b96SArnd Bergmann }
42867207b96SArnd Bergmann 
4295dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = {
43067207b96SArnd Bergmann 	.open	= spufs_pipe_open,
43167207b96SArnd Bergmann 	.read	= spufs_mbox_read,
43267207b96SArnd Bergmann };
43367207b96SArnd Bergmann 
43467207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
43567207b96SArnd Bergmann 			size_t len, loff_t *pos)
43667207b96SArnd Bergmann {
4378b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
43867207b96SArnd Bergmann 	u32 mbox_stat;
43967207b96SArnd Bergmann 
44067207b96SArnd Bergmann 	if (len < 4)
44167207b96SArnd Bergmann 		return -EINVAL;
44267207b96SArnd Bergmann 
4438b3d6663SArnd Bergmann 	spu_acquire(ctx);
4448b3d6663SArnd Bergmann 
4458b3d6663SArnd Bergmann 	mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
4468b3d6663SArnd Bergmann 
4478b3d6663SArnd Bergmann 	spu_release(ctx);
44867207b96SArnd Bergmann 
44967207b96SArnd Bergmann 	if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
45067207b96SArnd Bergmann 		return -EFAULT;
45167207b96SArnd Bergmann 
45267207b96SArnd Bergmann 	return 4;
45367207b96SArnd Bergmann }
45467207b96SArnd Bergmann 
4555dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = {
45667207b96SArnd Bergmann 	.open	= spufs_pipe_open,
45767207b96SArnd Bergmann 	.read	= spufs_mbox_stat_read,
45867207b96SArnd Bergmann };
45967207b96SArnd Bergmann 
46067207b96SArnd Bergmann /* low-level ibox access function */
4618b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
46267207b96SArnd Bergmann {
4638b3d6663SArnd Bergmann 	return ctx->ops->ibox_read(ctx, data);
46467207b96SArnd Bergmann }
46567207b96SArnd Bergmann 
46667207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on)
46767207b96SArnd Bergmann {
4688b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
4698b3d6663SArnd Bergmann 
4708b3d6663SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->ibox_fasync);
4718b3d6663SArnd Bergmann }
4728b3d6663SArnd Bergmann 
4738b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */
4748b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu)
4758b3d6663SArnd Bergmann {
4768b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
4778b3d6663SArnd Bergmann 
4788b3d6663SArnd Bergmann 	wake_up_all(&ctx->ibox_wq);
4798b3d6663SArnd Bergmann 	kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
48067207b96SArnd Bergmann }
48167207b96SArnd Bergmann 
482cdcc89bbSArnd Bergmann /*
483cdcc89bbSArnd Bergmann  * Read as many bytes from the interrupt mailbox as possible, until
484cdcc89bbSArnd Bergmann  * one of the conditions becomes true:
485cdcc89bbSArnd Bergmann  *
486cdcc89bbSArnd Bergmann  * - no more data available in the mailbox
487cdcc89bbSArnd Bergmann  * - end of the user provided buffer
488cdcc89bbSArnd Bergmann  * - end of the mapped area
489cdcc89bbSArnd Bergmann  *
490cdcc89bbSArnd Bergmann  * If the file is opened without O_NONBLOCK, we wait here until
491cdcc89bbSArnd Bergmann  * any data is available, but return when we have been able to
492cdcc89bbSArnd Bergmann  * read something.
493cdcc89bbSArnd Bergmann  */
49467207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
49567207b96SArnd Bergmann 			size_t len, loff_t *pos)
49667207b96SArnd Bergmann {
4978b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
498cdcc89bbSArnd Bergmann 	u32 ibox_data, __user *udata;
499cdcc89bbSArnd Bergmann 	ssize_t count;
50067207b96SArnd Bergmann 
50167207b96SArnd Bergmann 	if (len < 4)
50267207b96SArnd Bergmann 		return -EINVAL;
50367207b96SArnd Bergmann 
504cdcc89bbSArnd Bergmann 	if (!access_ok(VERIFY_WRITE, buf, len))
505cdcc89bbSArnd Bergmann 		return -EFAULT;
506cdcc89bbSArnd Bergmann 
507cdcc89bbSArnd Bergmann 	udata = (void __user *)buf;
508cdcc89bbSArnd Bergmann 
5098b3d6663SArnd Bergmann 	spu_acquire(ctx);
51067207b96SArnd Bergmann 
511cdcc89bbSArnd Bergmann 	/* wait only for the first element */
512cdcc89bbSArnd Bergmann 	count = 0;
51367207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
5148b3d6663SArnd Bergmann 		if (!spu_ibox_read(ctx, &ibox_data))
515cdcc89bbSArnd Bergmann 			count = -EAGAIN;
51667207b96SArnd Bergmann 	} else {
517cdcc89bbSArnd Bergmann 		count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
518cdcc89bbSArnd Bergmann 	}
519cdcc89bbSArnd Bergmann 	if (count)
520cdcc89bbSArnd Bergmann 		goto out;
521cdcc89bbSArnd Bergmann 
522cdcc89bbSArnd Bergmann 	/* if we can't write at all, return -EFAULT */
523cdcc89bbSArnd Bergmann 	count = __put_user(ibox_data, udata);
524cdcc89bbSArnd Bergmann 	if (count)
525cdcc89bbSArnd Bergmann 		goto out;
526cdcc89bbSArnd Bergmann 
527cdcc89bbSArnd Bergmann 	for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
528cdcc89bbSArnd Bergmann 		int ret;
529cdcc89bbSArnd Bergmann 		ret = ctx->ops->ibox_read(ctx, &ibox_data);
530cdcc89bbSArnd Bergmann 		if (ret == 0)
531cdcc89bbSArnd Bergmann 			break;
532cdcc89bbSArnd Bergmann 		/*
533cdcc89bbSArnd Bergmann 		 * at the end of the mapped area, we can fault
534cdcc89bbSArnd Bergmann 		 * but still need to return the data we have
535cdcc89bbSArnd Bergmann 		 * read successfully so far.
536cdcc89bbSArnd Bergmann 		 */
537cdcc89bbSArnd Bergmann 		ret = __put_user(ibox_data, udata);
538cdcc89bbSArnd Bergmann 		if (ret)
539cdcc89bbSArnd Bergmann 			break;
54067207b96SArnd Bergmann 	}
54167207b96SArnd Bergmann 
542cdcc89bbSArnd Bergmann out:
5438b3d6663SArnd Bergmann 	spu_release(ctx);
5448b3d6663SArnd Bergmann 
545cdcc89bbSArnd Bergmann 	return count;
54667207b96SArnd Bergmann }
54767207b96SArnd Bergmann 
54867207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
54967207b96SArnd Bergmann {
5508b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
55167207b96SArnd Bergmann 	unsigned int mask;
55267207b96SArnd Bergmann 
5538b3d6663SArnd Bergmann 	poll_wait(file, &ctx->ibox_wq, wait);
55467207b96SArnd Bergmann 
5553a843d7cSArnd Bergmann 	spu_acquire(ctx);
5563a843d7cSArnd Bergmann 	mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM);
5573a843d7cSArnd Bergmann 	spu_release(ctx);
55867207b96SArnd Bergmann 
55967207b96SArnd Bergmann 	return mask;
56067207b96SArnd Bergmann }
56167207b96SArnd Bergmann 
5625dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = {
56367207b96SArnd Bergmann 	.open	= spufs_pipe_open,
56467207b96SArnd Bergmann 	.read	= spufs_ibox_read,
56567207b96SArnd Bergmann 	.poll	= spufs_ibox_poll,
56667207b96SArnd Bergmann 	.fasync	= spufs_ibox_fasync,
56767207b96SArnd Bergmann };
56867207b96SArnd Bergmann 
56967207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
57067207b96SArnd Bergmann 			size_t len, loff_t *pos)
57167207b96SArnd Bergmann {
5728b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
57367207b96SArnd Bergmann 	u32 ibox_stat;
57467207b96SArnd Bergmann 
57567207b96SArnd Bergmann 	if (len < 4)
57667207b96SArnd Bergmann 		return -EINVAL;
57767207b96SArnd Bergmann 
5788b3d6663SArnd Bergmann 	spu_acquire(ctx);
5798b3d6663SArnd Bergmann 	ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
5808b3d6663SArnd Bergmann 	spu_release(ctx);
58167207b96SArnd Bergmann 
58267207b96SArnd Bergmann 	if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
58367207b96SArnd Bergmann 		return -EFAULT;
58467207b96SArnd Bergmann 
58567207b96SArnd Bergmann 	return 4;
58667207b96SArnd Bergmann }
58767207b96SArnd Bergmann 
5885dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = {
58967207b96SArnd Bergmann 	.open	= spufs_pipe_open,
59067207b96SArnd Bergmann 	.read	= spufs_ibox_stat_read,
59167207b96SArnd Bergmann };
59267207b96SArnd Bergmann 
59367207b96SArnd Bergmann /* low-level mailbox write */
5948b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data)
59567207b96SArnd Bergmann {
5968b3d6663SArnd Bergmann 	return ctx->ops->wbox_write(ctx, data);
59767207b96SArnd Bergmann }
59867207b96SArnd Bergmann 
59967207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on)
60067207b96SArnd Bergmann {
6018b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
6028b3d6663SArnd Bergmann 	int ret;
6038b3d6663SArnd Bergmann 
6048b3d6663SArnd Bergmann 	ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
6058b3d6663SArnd Bergmann 
6068b3d6663SArnd Bergmann 	return ret;
6078b3d6663SArnd Bergmann }
6088b3d6663SArnd Bergmann 
6098b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */
6108b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu)
6118b3d6663SArnd Bergmann {
6128b3d6663SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
6138b3d6663SArnd Bergmann 
6148b3d6663SArnd Bergmann 	wake_up_all(&ctx->wbox_wq);
6158b3d6663SArnd Bergmann 	kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
61667207b96SArnd Bergmann }
61767207b96SArnd Bergmann 
618cdcc89bbSArnd Bergmann /*
619cdcc89bbSArnd Bergmann  * Write as many bytes to the interrupt mailbox as possible, until
620cdcc89bbSArnd Bergmann  * one of the conditions becomes true:
621cdcc89bbSArnd Bergmann  *
622cdcc89bbSArnd Bergmann  * - the mailbox is full
623cdcc89bbSArnd Bergmann  * - end of the user provided buffer
624cdcc89bbSArnd Bergmann  * - end of the mapped area
625cdcc89bbSArnd Bergmann  *
626cdcc89bbSArnd Bergmann  * If the file is opened without O_NONBLOCK, we wait here until
627cdcc89bbSArnd Bergmann  * space is availabyl, but return when we have been able to
628cdcc89bbSArnd Bergmann  * write something.
629cdcc89bbSArnd Bergmann  */
63067207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
63167207b96SArnd Bergmann 			size_t len, loff_t *pos)
63267207b96SArnd Bergmann {
6338b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
634cdcc89bbSArnd Bergmann 	u32 wbox_data, __user *udata;
635cdcc89bbSArnd Bergmann 	ssize_t count;
63667207b96SArnd Bergmann 
63767207b96SArnd Bergmann 	if (len < 4)
63867207b96SArnd Bergmann 		return -EINVAL;
63967207b96SArnd Bergmann 
640cdcc89bbSArnd Bergmann 	udata = (void __user *)buf;
641cdcc89bbSArnd Bergmann 	if (!access_ok(VERIFY_READ, buf, len))
642cdcc89bbSArnd Bergmann 		return -EFAULT;
643cdcc89bbSArnd Bergmann 
644cdcc89bbSArnd Bergmann 	if (__get_user(wbox_data, udata))
64567207b96SArnd Bergmann 		return -EFAULT;
64667207b96SArnd Bergmann 
6478b3d6663SArnd Bergmann 	spu_acquire(ctx);
6488b3d6663SArnd Bergmann 
649cdcc89bbSArnd Bergmann 	/*
650cdcc89bbSArnd Bergmann 	 * make sure we can at least write one element, by waiting
651cdcc89bbSArnd Bergmann 	 * in case of !O_NONBLOCK
652cdcc89bbSArnd Bergmann 	 */
653cdcc89bbSArnd Bergmann 	count = 0;
65467207b96SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
6558b3d6663SArnd Bergmann 		if (!spu_wbox_write(ctx, wbox_data))
656cdcc89bbSArnd Bergmann 			count = -EAGAIN;
65767207b96SArnd Bergmann 	} else {
658cdcc89bbSArnd Bergmann 		count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
65967207b96SArnd Bergmann 	}
66067207b96SArnd Bergmann 
661cdcc89bbSArnd Bergmann 	if (count)
662cdcc89bbSArnd Bergmann 		goto out;
6638b3d6663SArnd Bergmann 
664cdcc89bbSArnd Bergmann 	/* write aѕ much as possible */
665cdcc89bbSArnd Bergmann 	for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
666cdcc89bbSArnd Bergmann 		int ret;
667cdcc89bbSArnd Bergmann 		ret = __get_user(wbox_data, udata);
668cdcc89bbSArnd Bergmann 		if (ret)
669cdcc89bbSArnd Bergmann 			break;
670cdcc89bbSArnd Bergmann 
671cdcc89bbSArnd Bergmann 		ret = spu_wbox_write(ctx, wbox_data);
672cdcc89bbSArnd Bergmann 		if (ret == 0)
673cdcc89bbSArnd Bergmann 			break;
674cdcc89bbSArnd Bergmann 	}
675cdcc89bbSArnd Bergmann 
676cdcc89bbSArnd Bergmann out:
677cdcc89bbSArnd Bergmann 	spu_release(ctx);
678cdcc89bbSArnd Bergmann 	return count;
67967207b96SArnd Bergmann }
68067207b96SArnd Bergmann 
68167207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
68267207b96SArnd Bergmann {
6838b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
68467207b96SArnd Bergmann 	unsigned int mask;
68567207b96SArnd Bergmann 
6868b3d6663SArnd Bergmann 	poll_wait(file, &ctx->wbox_wq, wait);
68767207b96SArnd Bergmann 
6883a843d7cSArnd Bergmann 	spu_acquire(ctx);
6893a843d7cSArnd Bergmann 	mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM);
6903a843d7cSArnd Bergmann 	spu_release(ctx);
69167207b96SArnd Bergmann 
69267207b96SArnd Bergmann 	return mask;
69367207b96SArnd Bergmann }
69467207b96SArnd Bergmann 
6955dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = {
69667207b96SArnd Bergmann 	.open	= spufs_pipe_open,
69767207b96SArnd Bergmann 	.write	= spufs_wbox_write,
69867207b96SArnd Bergmann 	.poll	= spufs_wbox_poll,
69967207b96SArnd Bergmann 	.fasync	= spufs_wbox_fasync,
70067207b96SArnd Bergmann };
70167207b96SArnd Bergmann 
70267207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
70367207b96SArnd Bergmann 			size_t len, loff_t *pos)
70467207b96SArnd Bergmann {
7058b3d6663SArnd Bergmann 	struct spu_context *ctx = file->private_data;
70667207b96SArnd Bergmann 	u32 wbox_stat;
70767207b96SArnd Bergmann 
70867207b96SArnd Bergmann 	if (len < 4)
70967207b96SArnd Bergmann 		return -EINVAL;
71067207b96SArnd Bergmann 
7118b3d6663SArnd Bergmann 	spu_acquire(ctx);
7128b3d6663SArnd Bergmann 	wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
7138b3d6663SArnd Bergmann 	spu_release(ctx);
71467207b96SArnd Bergmann 
71567207b96SArnd Bergmann 	if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
71667207b96SArnd Bergmann 		return -EFAULT;
71767207b96SArnd Bergmann 
71867207b96SArnd Bergmann 	return 4;
71967207b96SArnd Bergmann }
72067207b96SArnd Bergmann 
7215dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = {
72267207b96SArnd Bergmann 	.open	= spufs_pipe_open,
72367207b96SArnd Bergmann 	.read	= spufs_wbox_stat_read,
72467207b96SArnd Bergmann };
72567207b96SArnd Bergmann 
7266df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file)
7276df10a82SMark Nutter {
7286df10a82SMark Nutter 	struct spufs_inode_info *i = SPUFS_I(inode);
7296df10a82SMark Nutter 	struct spu_context *ctx = i->i_ctx;
7306df10a82SMark Nutter 	file->private_data = ctx;
7316df10a82SMark Nutter 	file->f_mapping = inode->i_mapping;
7326df10a82SMark Nutter 	ctx->signal1 = inode->i_mapping;
7336df10a82SMark Nutter 	return nonseekable_open(inode, file);
7346df10a82SMark Nutter }
7356df10a82SMark Nutter 
736bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
73767207b96SArnd Bergmann 			size_t len, loff_t *pos)
73867207b96SArnd Bergmann {
73917f88cebSDwayne Grant McConnell 	int ret = 0;
74067207b96SArnd Bergmann 	u32 data;
74167207b96SArnd Bergmann 
74267207b96SArnd Bergmann 	if (len < 4)
74367207b96SArnd Bergmann 		return -EINVAL;
74467207b96SArnd Bergmann 
74517f88cebSDwayne Grant McConnell 	if (ctx->csa.spu_chnlcnt_RW[3]) {
74617f88cebSDwayne Grant McConnell 		data = ctx->csa.spu_chnldata_RW[3];
74717f88cebSDwayne Grant McConnell 		ret = 4;
74817f88cebSDwayne Grant McConnell 	}
7498b3d6663SArnd Bergmann 
75017f88cebSDwayne Grant McConnell 	if (!ret)
75117f88cebSDwayne Grant McConnell 		goto out;
75217f88cebSDwayne Grant McConnell 
75367207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
75467207b96SArnd Bergmann 		return -EFAULT;
75567207b96SArnd Bergmann 
75617f88cebSDwayne Grant McConnell out:
75717f88cebSDwayne Grant McConnell 	return ret;
75867207b96SArnd Bergmann }
75967207b96SArnd Bergmann 
760bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
761bf1ab978SDwayne Grant McConnell 			size_t len, loff_t *pos)
762bf1ab978SDwayne Grant McConnell {
763bf1ab978SDwayne Grant McConnell 	int ret;
764bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
765bf1ab978SDwayne Grant McConnell 
766bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
767bf1ab978SDwayne Grant McConnell 	ret = __spufs_signal1_read(ctx, buf, len, pos);
768bf1ab978SDwayne Grant McConnell 	spu_release(ctx);
769bf1ab978SDwayne Grant McConnell 
770bf1ab978SDwayne Grant McConnell 	return ret;
771bf1ab978SDwayne Grant McConnell }
772bf1ab978SDwayne Grant McConnell 
77367207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
77467207b96SArnd Bergmann 			size_t len, loff_t *pos)
77567207b96SArnd Bergmann {
77667207b96SArnd Bergmann 	struct spu_context *ctx;
77767207b96SArnd Bergmann 	u32 data;
77867207b96SArnd Bergmann 
77967207b96SArnd Bergmann 	ctx = file->private_data;
78067207b96SArnd Bergmann 
78167207b96SArnd Bergmann 	if (len < 4)
78267207b96SArnd Bergmann 		return -EINVAL;
78367207b96SArnd Bergmann 
78467207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
78567207b96SArnd Bergmann 		return -EFAULT;
78667207b96SArnd Bergmann 
7878b3d6663SArnd Bergmann 	spu_acquire(ctx);
7888b3d6663SArnd Bergmann 	ctx->ops->signal1_write(ctx, data);
7898b3d6663SArnd Bergmann 	spu_release(ctx);
79067207b96SArnd Bergmann 
79167207b96SArnd Bergmann 	return 4;
79267207b96SArnd Bergmann }
79367207b96SArnd Bergmann 
7946df10a82SMark Nutter static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
7956df10a82SMark Nutter 					      unsigned long address, int *type)
7966df10a82SMark Nutter {
79727d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000
79827d5bf2aSBenjamin Herrenschmidt 	return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000);
79927d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000
80027d5bf2aSBenjamin Herrenschmidt 	/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
80127d5bf2aSBenjamin Herrenschmidt 	 * signal 1 and 2 area
80227d5bf2aSBenjamin Herrenschmidt 	 */
80327d5bf2aSBenjamin Herrenschmidt 	return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
80427d5bf2aSBenjamin Herrenschmidt #else
80527d5bf2aSBenjamin Herrenschmidt #error unsupported page size
80627d5bf2aSBenjamin Herrenschmidt #endif
8076df10a82SMark Nutter }
8086df10a82SMark Nutter 
8096df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = {
8106df10a82SMark Nutter 	.nopage = spufs_signal1_mmap_nopage,
8116df10a82SMark Nutter };
8126df10a82SMark Nutter 
8136df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
8146df10a82SMark Nutter {
8156df10a82SMark Nutter 	if (!(vma->vm_flags & VM_SHARED))
8166df10a82SMark Nutter 		return -EINVAL;
8176df10a82SMark Nutter 
8185c3ecd65SChristoph Hellwig 	vma->vm_flags |= VM_IO;
8196df10a82SMark Nutter 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
82023cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
8216df10a82SMark Nutter 
8226df10a82SMark Nutter 	vma->vm_ops = &spufs_signal1_mmap_vmops;
8236df10a82SMark Nutter 	return 0;
8246df10a82SMark Nutter }
8256df10a82SMark Nutter 
8265dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = {
8276df10a82SMark Nutter 	.open = spufs_signal1_open,
82867207b96SArnd Bergmann 	.read = spufs_signal1_read,
82967207b96SArnd Bergmann 	.write = spufs_signal1_write,
8306df10a82SMark Nutter 	.mmap = spufs_signal1_mmap,
83167207b96SArnd Bergmann };
83267207b96SArnd Bergmann 
8336df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file)
8346df10a82SMark Nutter {
8356df10a82SMark Nutter 	struct spufs_inode_info *i = SPUFS_I(inode);
8366df10a82SMark Nutter 	struct spu_context *ctx = i->i_ctx;
8376df10a82SMark Nutter 	file->private_data = ctx;
8386df10a82SMark Nutter 	file->f_mapping = inode->i_mapping;
8396df10a82SMark Nutter 	ctx->signal2 = inode->i_mapping;
8406df10a82SMark Nutter 	return nonseekable_open(inode, file);
8416df10a82SMark Nutter }
8426df10a82SMark Nutter 
843bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
84467207b96SArnd Bergmann 			size_t len, loff_t *pos)
84567207b96SArnd Bergmann {
84617f88cebSDwayne Grant McConnell 	int ret = 0;
84767207b96SArnd Bergmann 	u32 data;
84867207b96SArnd Bergmann 
84967207b96SArnd Bergmann 	if (len < 4)
85067207b96SArnd Bergmann 		return -EINVAL;
85167207b96SArnd Bergmann 
85217f88cebSDwayne Grant McConnell 	if (ctx->csa.spu_chnlcnt_RW[4]) {
85317f88cebSDwayne Grant McConnell 		data =  ctx->csa.spu_chnldata_RW[4];
85417f88cebSDwayne Grant McConnell 		ret = 4;
85517f88cebSDwayne Grant McConnell 	}
8568b3d6663SArnd Bergmann 
85717f88cebSDwayne Grant McConnell 	if (!ret)
85817f88cebSDwayne Grant McConnell 		goto out;
85917f88cebSDwayne Grant McConnell 
86067207b96SArnd Bergmann 	if (copy_to_user(buf, &data, 4))
86167207b96SArnd Bergmann 		return -EFAULT;
86267207b96SArnd Bergmann 
86317f88cebSDwayne Grant McConnell out:
864bf1ab978SDwayne Grant McConnell 	return ret;
865bf1ab978SDwayne Grant McConnell }
866bf1ab978SDwayne Grant McConnell 
867bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
868bf1ab978SDwayne Grant McConnell 			size_t len, loff_t *pos)
869bf1ab978SDwayne Grant McConnell {
870bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
871bf1ab978SDwayne Grant McConnell 	int ret;
872bf1ab978SDwayne Grant McConnell 
873bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
874bf1ab978SDwayne Grant McConnell 	ret = __spufs_signal2_read(ctx, buf, len, pos);
875bf1ab978SDwayne Grant McConnell 	spu_release(ctx);
876bf1ab978SDwayne Grant McConnell 
877bf1ab978SDwayne Grant McConnell 	return ret;
87867207b96SArnd Bergmann }
87967207b96SArnd Bergmann 
88067207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
88167207b96SArnd Bergmann 			size_t len, loff_t *pos)
88267207b96SArnd Bergmann {
88367207b96SArnd Bergmann 	struct spu_context *ctx;
88467207b96SArnd Bergmann 	u32 data;
88567207b96SArnd Bergmann 
88667207b96SArnd Bergmann 	ctx = file->private_data;
88767207b96SArnd Bergmann 
88867207b96SArnd Bergmann 	if (len < 4)
88967207b96SArnd Bergmann 		return -EINVAL;
89067207b96SArnd Bergmann 
89167207b96SArnd Bergmann 	if (copy_from_user(&data, buf, 4))
89267207b96SArnd Bergmann 		return -EFAULT;
89367207b96SArnd Bergmann 
8948b3d6663SArnd Bergmann 	spu_acquire(ctx);
8958b3d6663SArnd Bergmann 	ctx->ops->signal2_write(ctx, data);
8968b3d6663SArnd Bergmann 	spu_release(ctx);
89767207b96SArnd Bergmann 
89867207b96SArnd Bergmann 	return 4;
89967207b96SArnd Bergmann }
90067207b96SArnd Bergmann 
90127d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K
9026df10a82SMark Nutter static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
9036df10a82SMark Nutter 					      unsigned long address, int *type)
9046df10a82SMark Nutter {
90527d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000
90627d5bf2aSBenjamin Herrenschmidt 	return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000);
90727d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000
90827d5bf2aSBenjamin Herrenschmidt 	/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
90927d5bf2aSBenjamin Herrenschmidt 	 * signal 1 and 2 area
91027d5bf2aSBenjamin Herrenschmidt 	 */
91127d5bf2aSBenjamin Herrenschmidt 	return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
91227d5bf2aSBenjamin Herrenschmidt #else
91327d5bf2aSBenjamin Herrenschmidt #error unsupported page size
91427d5bf2aSBenjamin Herrenschmidt #endif
9156df10a82SMark Nutter }
9166df10a82SMark Nutter 
9176df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = {
9186df10a82SMark Nutter 	.nopage = spufs_signal2_mmap_nopage,
9196df10a82SMark Nutter };
9206df10a82SMark Nutter 
9216df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
9226df10a82SMark Nutter {
9236df10a82SMark Nutter 	if (!(vma->vm_flags & VM_SHARED))
9246df10a82SMark Nutter 		return -EINVAL;
9256df10a82SMark Nutter 
9265c3ecd65SChristoph Hellwig 	vma->vm_flags |= VM_IO;
9276df10a82SMark Nutter 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
92823cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
9296df10a82SMark Nutter 
9306df10a82SMark Nutter 	vma->vm_ops = &spufs_signal2_mmap_vmops;
9316df10a82SMark Nutter 	return 0;
9326df10a82SMark Nutter }
93327d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */
93427d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL
93527d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */
9366df10a82SMark Nutter 
9375dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = {
9386df10a82SMark Nutter 	.open = spufs_signal2_open,
93967207b96SArnd Bergmann 	.read = spufs_signal2_read,
94067207b96SArnd Bergmann 	.write = spufs_signal2_write,
9416df10a82SMark Nutter 	.mmap = spufs_signal2_mmap,
94267207b96SArnd Bergmann };
94367207b96SArnd Bergmann 
94467207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val)
94567207b96SArnd Bergmann {
94667207b96SArnd Bergmann 	struct spu_context *ctx = data;
94767207b96SArnd Bergmann 
9488b3d6663SArnd Bergmann 	spu_acquire(ctx);
9498b3d6663SArnd Bergmann 	ctx->ops->signal1_type_set(ctx, val);
9508b3d6663SArnd Bergmann 	spu_release(ctx);
95167207b96SArnd Bergmann }
95267207b96SArnd Bergmann 
953bf1ab978SDwayne Grant McConnell static u64 __spufs_signal1_type_get(void *data)
954bf1ab978SDwayne Grant McConnell {
955bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
956bf1ab978SDwayne Grant McConnell 	return ctx->ops->signal1_type_get(ctx);
957bf1ab978SDwayne Grant McConnell }
958bf1ab978SDwayne Grant McConnell 
95967207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data)
96067207b96SArnd Bergmann {
96167207b96SArnd Bergmann 	struct spu_context *ctx = data;
9628b3d6663SArnd Bergmann 	u64 ret;
9638b3d6663SArnd Bergmann 
9648b3d6663SArnd Bergmann 	spu_acquire(ctx);
965bf1ab978SDwayne Grant McConnell 	ret = __spufs_signal1_type_get(data);
9668b3d6663SArnd Bergmann 	spu_release(ctx);
9678b3d6663SArnd Bergmann 
9688b3d6663SArnd Bergmann 	return ret;
96967207b96SArnd Bergmann }
97067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
97167207b96SArnd Bergmann 					spufs_signal1_type_set, "%llu");
97267207b96SArnd Bergmann 
97367207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val)
97467207b96SArnd Bergmann {
97567207b96SArnd Bergmann 	struct spu_context *ctx = data;
97667207b96SArnd Bergmann 
9778b3d6663SArnd Bergmann 	spu_acquire(ctx);
9788b3d6663SArnd Bergmann 	ctx->ops->signal2_type_set(ctx, val);
9798b3d6663SArnd Bergmann 	spu_release(ctx);
98067207b96SArnd Bergmann }
98167207b96SArnd Bergmann 
982bf1ab978SDwayne Grant McConnell static u64 __spufs_signal2_type_get(void *data)
983bf1ab978SDwayne Grant McConnell {
984bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
985bf1ab978SDwayne Grant McConnell 	return ctx->ops->signal2_type_get(ctx);
986bf1ab978SDwayne Grant McConnell }
987bf1ab978SDwayne Grant McConnell 
98867207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data)
98967207b96SArnd Bergmann {
99067207b96SArnd Bergmann 	struct spu_context *ctx = data;
9918b3d6663SArnd Bergmann 	u64 ret;
9928b3d6663SArnd Bergmann 
9938b3d6663SArnd Bergmann 	spu_acquire(ctx);
994bf1ab978SDwayne Grant McConnell 	ret = __spufs_signal2_type_get(data);
9958b3d6663SArnd Bergmann 	spu_release(ctx);
9968b3d6663SArnd Bergmann 
9978b3d6663SArnd Bergmann 	return ret;
99867207b96SArnd Bergmann }
99967207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
100067207b96SArnd Bergmann 					spufs_signal2_type_set, "%llu");
100167207b96SArnd Bergmann 
100227d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K
1003d9379c4bSarnd@arndb.de static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma,
1004d9379c4bSarnd@arndb.de 					   unsigned long address, int *type)
1005d9379c4bSarnd@arndb.de {
100627d5bf2aSBenjamin Herrenschmidt 	return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000);
1007d9379c4bSarnd@arndb.de }
1008d9379c4bSarnd@arndb.de 
1009d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = {
1010d9379c4bSarnd@arndb.de 	.nopage = spufs_mss_mmap_nopage,
1011d9379c4bSarnd@arndb.de };
1012d9379c4bSarnd@arndb.de 
1013d9379c4bSarnd@arndb.de /*
1014d9379c4bSarnd@arndb.de  * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
1015d9379c4bSarnd@arndb.de  */
1016d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
1017d9379c4bSarnd@arndb.de {
1018d9379c4bSarnd@arndb.de 	if (!(vma->vm_flags & VM_SHARED))
1019d9379c4bSarnd@arndb.de 		return -EINVAL;
1020d9379c4bSarnd@arndb.de 
10215c3ecd65SChristoph Hellwig 	vma->vm_flags |= VM_IO;
1022d9379c4bSarnd@arndb.de 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
102323cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
1024d9379c4bSarnd@arndb.de 
1025d9379c4bSarnd@arndb.de 	vma->vm_ops = &spufs_mss_mmap_vmops;
1026d9379c4bSarnd@arndb.de 	return 0;
1027d9379c4bSarnd@arndb.de }
102827d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */
102927d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL
103027d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */
1031d9379c4bSarnd@arndb.de 
1032d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file)
1033d9379c4bSarnd@arndb.de {
1034d9379c4bSarnd@arndb.de 	struct spufs_inode_info *i = SPUFS_I(inode);
1035d9379c4bSarnd@arndb.de 
1036d9379c4bSarnd@arndb.de 	file->private_data = i->i_ctx;
1037d9379c4bSarnd@arndb.de 	return nonseekable_open(inode, file);
1038d9379c4bSarnd@arndb.de }
1039d9379c4bSarnd@arndb.de 
10405dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = {
1041d9379c4bSarnd@arndb.de 	.open	 = spufs_mss_open,
1042d9379c4bSarnd@arndb.de 	.mmap	 = spufs_mss_mmap,
104327d5bf2aSBenjamin Herrenschmidt };
104427d5bf2aSBenjamin Herrenschmidt 
104527d5bf2aSBenjamin Herrenschmidt static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma,
104627d5bf2aSBenjamin Herrenschmidt 					   unsigned long address, int *type)
104727d5bf2aSBenjamin Herrenschmidt {
104827d5bf2aSBenjamin Herrenschmidt 	return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000);
104927d5bf2aSBenjamin Herrenschmidt }
105027d5bf2aSBenjamin Herrenschmidt 
105127d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = {
105227d5bf2aSBenjamin Herrenschmidt 	.nopage = spufs_psmap_mmap_nopage,
105327d5bf2aSBenjamin Herrenschmidt };
105427d5bf2aSBenjamin Herrenschmidt 
105527d5bf2aSBenjamin Herrenschmidt /*
105627d5bf2aSBenjamin Herrenschmidt  * mmap support for full problem state area [0x00000 - 0x1ffff].
105727d5bf2aSBenjamin Herrenschmidt  */
105827d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma)
105927d5bf2aSBenjamin Herrenschmidt {
106027d5bf2aSBenjamin Herrenschmidt 	if (!(vma->vm_flags & VM_SHARED))
106127d5bf2aSBenjamin Herrenschmidt 		return -EINVAL;
106227d5bf2aSBenjamin Herrenschmidt 
10635c3ecd65SChristoph Hellwig 	vma->vm_flags |= VM_IO;
106427d5bf2aSBenjamin Herrenschmidt 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
106527d5bf2aSBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
106627d5bf2aSBenjamin Herrenschmidt 
106727d5bf2aSBenjamin Herrenschmidt 	vma->vm_ops = &spufs_psmap_mmap_vmops;
106827d5bf2aSBenjamin Herrenschmidt 	return 0;
106927d5bf2aSBenjamin Herrenschmidt }
107027d5bf2aSBenjamin Herrenschmidt 
107127d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file)
107227d5bf2aSBenjamin Herrenschmidt {
107327d5bf2aSBenjamin Herrenschmidt 	struct spufs_inode_info *i = SPUFS_I(inode);
107427d5bf2aSBenjamin Herrenschmidt 
107527d5bf2aSBenjamin Herrenschmidt 	file->private_data = i->i_ctx;
107627d5bf2aSBenjamin Herrenschmidt 	return nonseekable_open(inode, file);
107727d5bf2aSBenjamin Herrenschmidt }
107827d5bf2aSBenjamin Herrenschmidt 
10795dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = {
108027d5bf2aSBenjamin Herrenschmidt 	.open	 = spufs_psmap_open,
108127d5bf2aSBenjamin Herrenschmidt 	.mmap	 = spufs_psmap_mmap,
1082d9379c4bSarnd@arndb.de };
1083d9379c4bSarnd@arndb.de 
1084d9379c4bSarnd@arndb.de 
108527d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K
10866df10a82SMark Nutter static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
10876df10a82SMark Nutter 					   unsigned long address, int *type)
10886df10a82SMark Nutter {
108927d5bf2aSBenjamin Herrenschmidt 	return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000);
10906df10a82SMark Nutter }
10916df10a82SMark Nutter 
10926df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = {
10936df10a82SMark Nutter 	.nopage = spufs_mfc_mmap_nopage,
10946df10a82SMark Nutter };
10956df10a82SMark Nutter 
10966df10a82SMark Nutter /*
10976df10a82SMark Nutter  * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
10986df10a82SMark Nutter  */
10996df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
11006df10a82SMark Nutter {
11016df10a82SMark Nutter 	if (!(vma->vm_flags & VM_SHARED))
11026df10a82SMark Nutter 		return -EINVAL;
11036df10a82SMark Nutter 
11045c3ecd65SChristoph Hellwig 	vma->vm_flags |= VM_IO;
11056df10a82SMark Nutter 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
110623cc7701SBenjamin Herrenschmidt 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
11076df10a82SMark Nutter 
11086df10a82SMark Nutter 	vma->vm_ops = &spufs_mfc_mmap_vmops;
11096df10a82SMark Nutter 	return 0;
11106df10a82SMark Nutter }
111127d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */
111227d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL
111327d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */
1114a33a7d73SArnd Bergmann 
1115a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file)
1116a33a7d73SArnd Bergmann {
1117a33a7d73SArnd Bergmann 	struct spufs_inode_info *i = SPUFS_I(inode);
1118a33a7d73SArnd Bergmann 	struct spu_context *ctx = i->i_ctx;
1119a33a7d73SArnd Bergmann 
1120a33a7d73SArnd Bergmann 	/* we don't want to deal with DMA into other processes */
1121a33a7d73SArnd Bergmann 	if (ctx->owner != current->mm)
1122a33a7d73SArnd Bergmann 		return -EINVAL;
1123a33a7d73SArnd Bergmann 
1124a33a7d73SArnd Bergmann 	if (atomic_read(&inode->i_count) != 1)
1125a33a7d73SArnd Bergmann 		return -EBUSY;
1126a33a7d73SArnd Bergmann 
1127a33a7d73SArnd Bergmann 	file->private_data = ctx;
1128a33a7d73SArnd Bergmann 	return nonseekable_open(inode, file);
1129a33a7d73SArnd Bergmann }
1130a33a7d73SArnd Bergmann 
1131a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */
1132a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu)
1133a33a7d73SArnd Bergmann {
1134a33a7d73SArnd Bergmann 	struct spu_context *ctx = spu->ctx;
1135a33a7d73SArnd Bergmann 
1136a33a7d73SArnd Bergmann 	wake_up_all(&ctx->mfc_wq);
1137a33a7d73SArnd Bergmann 
1138a33a7d73SArnd Bergmann 	pr_debug("%s %s\n", __FUNCTION__, spu->name);
1139a33a7d73SArnd Bergmann 	if (ctx->mfc_fasync) {
1140a33a7d73SArnd Bergmann 		u32 free_elements, tagstatus;
1141a33a7d73SArnd Bergmann 		unsigned int mask;
1142a33a7d73SArnd Bergmann 
1143a33a7d73SArnd Bergmann 		/* no need for spu_acquire in interrupt context */
1144a33a7d73SArnd Bergmann 		free_elements = ctx->ops->get_mfc_free_elements(ctx);
1145a33a7d73SArnd Bergmann 		tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
1146a33a7d73SArnd Bergmann 
1147a33a7d73SArnd Bergmann 		mask = 0;
1148a33a7d73SArnd Bergmann 		if (free_elements & 0xffff)
1149a33a7d73SArnd Bergmann 			mask |= POLLOUT;
1150a33a7d73SArnd Bergmann 		if (tagstatus & ctx->tagwait)
1151a33a7d73SArnd Bergmann 			mask |= POLLIN;
1152a33a7d73SArnd Bergmann 
1153a33a7d73SArnd Bergmann 		kill_fasync(&ctx->mfc_fasync, SIGIO, mask);
1154a33a7d73SArnd Bergmann 	}
1155a33a7d73SArnd Bergmann }
1156a33a7d73SArnd Bergmann 
1157a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status)
1158a33a7d73SArnd Bergmann {
1159a33a7d73SArnd Bergmann 	/* See if there is one tag group is complete */
1160a33a7d73SArnd Bergmann 	/* FIXME we need locking around tagwait */
1161a33a7d73SArnd Bergmann 	*status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait;
1162a33a7d73SArnd Bergmann 	ctx->tagwait &= ~*status;
1163a33a7d73SArnd Bergmann 	if (*status)
1164a33a7d73SArnd Bergmann 		return 1;
1165a33a7d73SArnd Bergmann 
1166a33a7d73SArnd Bergmann 	/* enable interrupt waiting for any tag group,
1167a33a7d73SArnd Bergmann 	   may silently fail if interrupts are already enabled */
1168a33a7d73SArnd Bergmann 	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
1169a33a7d73SArnd Bergmann 	return 0;
1170a33a7d73SArnd Bergmann }
1171a33a7d73SArnd Bergmann 
1172a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer,
1173a33a7d73SArnd Bergmann 			size_t size, loff_t *pos)
1174a33a7d73SArnd Bergmann {
1175a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1176a33a7d73SArnd Bergmann 	int ret = -EINVAL;
1177a33a7d73SArnd Bergmann 	u32 status;
1178a33a7d73SArnd Bergmann 
1179a33a7d73SArnd Bergmann 	if (size != 4)
1180a33a7d73SArnd Bergmann 		goto out;
1181a33a7d73SArnd Bergmann 
1182a33a7d73SArnd Bergmann 	spu_acquire(ctx);
1183a33a7d73SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
1184a33a7d73SArnd Bergmann 		status = ctx->ops->read_mfc_tagstatus(ctx);
1185a33a7d73SArnd Bergmann 		if (!(status & ctx->tagwait))
1186a33a7d73SArnd Bergmann 			ret = -EAGAIN;
1187a33a7d73SArnd Bergmann 		else
1188a33a7d73SArnd Bergmann 			ctx->tagwait &= ~status;
1189a33a7d73SArnd Bergmann 	} else {
1190a33a7d73SArnd Bergmann 		ret = spufs_wait(ctx->mfc_wq,
1191a33a7d73SArnd Bergmann 			   spufs_read_mfc_tagstatus(ctx, &status));
1192a33a7d73SArnd Bergmann 	}
1193a33a7d73SArnd Bergmann 	spu_release(ctx);
1194a33a7d73SArnd Bergmann 
1195a33a7d73SArnd Bergmann 	if (ret)
1196a33a7d73SArnd Bergmann 		goto out;
1197a33a7d73SArnd Bergmann 
1198a33a7d73SArnd Bergmann 	ret = 4;
1199a33a7d73SArnd Bergmann 	if (copy_to_user(buffer, &status, 4))
1200a33a7d73SArnd Bergmann 		ret = -EFAULT;
1201a33a7d73SArnd Bergmann 
1202a33a7d73SArnd Bergmann out:
1203a33a7d73SArnd Bergmann 	return ret;
1204a33a7d73SArnd Bergmann }
1205a33a7d73SArnd Bergmann 
1206a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd)
1207a33a7d73SArnd Bergmann {
1208a33a7d73SArnd Bergmann 	pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa,
1209a33a7d73SArnd Bergmann 		 cmd->ea, cmd->size, cmd->tag, cmd->cmd);
1210a33a7d73SArnd Bergmann 
1211a33a7d73SArnd Bergmann 	switch (cmd->cmd) {
1212a33a7d73SArnd Bergmann 	case MFC_PUT_CMD:
1213a33a7d73SArnd Bergmann 	case MFC_PUTF_CMD:
1214a33a7d73SArnd Bergmann 	case MFC_PUTB_CMD:
1215a33a7d73SArnd Bergmann 	case MFC_GET_CMD:
1216a33a7d73SArnd Bergmann 	case MFC_GETF_CMD:
1217a33a7d73SArnd Bergmann 	case MFC_GETB_CMD:
1218a33a7d73SArnd Bergmann 		break;
1219a33a7d73SArnd Bergmann 	default:
1220a33a7d73SArnd Bergmann 		pr_debug("invalid DMA opcode %x\n", cmd->cmd);
1221a33a7d73SArnd Bergmann 		return -EIO;
1222a33a7d73SArnd Bergmann 	}
1223a33a7d73SArnd Bergmann 
1224a33a7d73SArnd Bergmann 	if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) {
1225a33a7d73SArnd Bergmann 		pr_debug("invalid DMA alignment, ea %lx lsa %x\n",
1226a33a7d73SArnd Bergmann 				cmd->ea, cmd->lsa);
1227a33a7d73SArnd Bergmann 		return -EIO;
1228a33a7d73SArnd Bergmann 	}
1229a33a7d73SArnd Bergmann 
1230a33a7d73SArnd Bergmann 	switch (cmd->size & 0xf) {
1231a33a7d73SArnd Bergmann 	case 1:
1232a33a7d73SArnd Bergmann 		break;
1233a33a7d73SArnd Bergmann 	case 2:
1234a33a7d73SArnd Bergmann 		if (cmd->lsa & 1)
1235a33a7d73SArnd Bergmann 			goto error;
1236a33a7d73SArnd Bergmann 		break;
1237a33a7d73SArnd Bergmann 	case 4:
1238a33a7d73SArnd Bergmann 		if (cmd->lsa & 3)
1239a33a7d73SArnd Bergmann 			goto error;
1240a33a7d73SArnd Bergmann 		break;
1241a33a7d73SArnd Bergmann 	case 8:
1242a33a7d73SArnd Bergmann 		if (cmd->lsa & 7)
1243a33a7d73SArnd Bergmann 			goto error;
1244a33a7d73SArnd Bergmann 		break;
1245a33a7d73SArnd Bergmann 	case 0:
1246a33a7d73SArnd Bergmann 		if (cmd->lsa & 15)
1247a33a7d73SArnd Bergmann 			goto error;
1248a33a7d73SArnd Bergmann 		break;
1249a33a7d73SArnd Bergmann 	error:
1250a33a7d73SArnd Bergmann 	default:
1251a33a7d73SArnd Bergmann 		pr_debug("invalid DMA alignment %x for size %x\n",
1252a33a7d73SArnd Bergmann 			cmd->lsa & 0xf, cmd->size);
1253a33a7d73SArnd Bergmann 		return -EIO;
1254a33a7d73SArnd Bergmann 	}
1255a33a7d73SArnd Bergmann 
1256a33a7d73SArnd Bergmann 	if (cmd->size > 16 * 1024) {
1257a33a7d73SArnd Bergmann 		pr_debug("invalid DMA size %x\n", cmd->size);
1258a33a7d73SArnd Bergmann 		return -EIO;
1259a33a7d73SArnd Bergmann 	}
1260a33a7d73SArnd Bergmann 
1261a33a7d73SArnd Bergmann 	if (cmd->tag & 0xfff0) {
1262a33a7d73SArnd Bergmann 		/* we reserve the higher tag numbers for kernel use */
1263a33a7d73SArnd Bergmann 		pr_debug("invalid DMA tag\n");
1264a33a7d73SArnd Bergmann 		return -EIO;
1265a33a7d73SArnd Bergmann 	}
1266a33a7d73SArnd Bergmann 
1267a33a7d73SArnd Bergmann 	if (cmd->class) {
1268a33a7d73SArnd Bergmann 		/* not supported in this version */
1269a33a7d73SArnd Bergmann 		pr_debug("invalid DMA class\n");
1270a33a7d73SArnd Bergmann 		return -EIO;
1271a33a7d73SArnd Bergmann 	}
1272a33a7d73SArnd Bergmann 
1273a33a7d73SArnd Bergmann 	return 0;
1274a33a7d73SArnd Bergmann }
1275a33a7d73SArnd Bergmann 
1276a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx,
1277a33a7d73SArnd Bergmann 				struct mfc_dma_command cmd,
1278a33a7d73SArnd Bergmann 				int *error)
1279a33a7d73SArnd Bergmann {
1280a33a7d73SArnd Bergmann 	*error = ctx->ops->send_mfc_command(ctx, &cmd);
1281a33a7d73SArnd Bergmann 	if (*error == -EAGAIN) {
1282a33a7d73SArnd Bergmann 		/* wait for any tag group to complete
1283a33a7d73SArnd Bergmann 		   so we have space for the new command */
1284a33a7d73SArnd Bergmann 		ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
1285a33a7d73SArnd Bergmann 		/* try again, because the queue might be
1286a33a7d73SArnd Bergmann 		   empty again */
1287a33a7d73SArnd Bergmann 		*error = ctx->ops->send_mfc_command(ctx, &cmd);
1288a33a7d73SArnd Bergmann 		if (*error == -EAGAIN)
1289a33a7d73SArnd Bergmann 			return 0;
1290a33a7d73SArnd Bergmann 	}
1291a33a7d73SArnd Bergmann 	return 1;
1292a33a7d73SArnd Bergmann }
1293a33a7d73SArnd Bergmann 
1294a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
1295a33a7d73SArnd Bergmann 			size_t size, loff_t *pos)
1296a33a7d73SArnd Bergmann {
1297a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1298a33a7d73SArnd Bergmann 	struct mfc_dma_command cmd;
1299a33a7d73SArnd Bergmann 	int ret = -EINVAL;
1300a33a7d73SArnd Bergmann 
1301a33a7d73SArnd Bergmann 	if (size != sizeof cmd)
1302a33a7d73SArnd Bergmann 		goto out;
1303a33a7d73SArnd Bergmann 
1304a33a7d73SArnd Bergmann 	ret = -EFAULT;
1305a33a7d73SArnd Bergmann 	if (copy_from_user(&cmd, buffer, sizeof cmd))
1306a33a7d73SArnd Bergmann 		goto out;
1307a33a7d73SArnd Bergmann 
1308a33a7d73SArnd Bergmann 	ret = spufs_check_valid_dma(&cmd);
1309a33a7d73SArnd Bergmann 	if (ret)
1310a33a7d73SArnd Bergmann 		goto out;
1311a33a7d73SArnd Bergmann 
1312a33a7d73SArnd Bergmann 	spu_acquire_runnable(ctx);
1313a33a7d73SArnd Bergmann 	if (file->f_flags & O_NONBLOCK) {
1314a33a7d73SArnd Bergmann 		ret = ctx->ops->send_mfc_command(ctx, &cmd);
1315a33a7d73SArnd Bergmann 	} else {
1316a33a7d73SArnd Bergmann 		int status;
1317a33a7d73SArnd Bergmann 		ret = spufs_wait(ctx->mfc_wq,
1318a33a7d73SArnd Bergmann 				 spu_send_mfc_command(ctx, cmd, &status));
1319a33a7d73SArnd Bergmann 		if (status)
1320a33a7d73SArnd Bergmann 			ret = status;
1321a33a7d73SArnd Bergmann 	}
1322a33a7d73SArnd Bergmann 	spu_release(ctx);
1323a33a7d73SArnd Bergmann 
1324a33a7d73SArnd Bergmann 	if (ret)
1325a33a7d73SArnd Bergmann 		goto out;
1326a33a7d73SArnd Bergmann 
1327a33a7d73SArnd Bergmann 	ctx->tagwait |= 1 << cmd.tag;
13283692dc66SMasato Noguchi 	ret = size;
1329a33a7d73SArnd Bergmann 
1330a33a7d73SArnd Bergmann out:
1331a33a7d73SArnd Bergmann 	return ret;
1332a33a7d73SArnd Bergmann }
1333a33a7d73SArnd Bergmann 
1334a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait)
1335a33a7d73SArnd Bergmann {
1336a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1337a33a7d73SArnd Bergmann 	u32 free_elements, tagstatus;
1338a33a7d73SArnd Bergmann 	unsigned int mask;
1339a33a7d73SArnd Bergmann 
1340a33a7d73SArnd Bergmann 	spu_acquire(ctx);
1341a33a7d73SArnd Bergmann 	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
1342a33a7d73SArnd Bergmann 	free_elements = ctx->ops->get_mfc_free_elements(ctx);
1343a33a7d73SArnd Bergmann 	tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
1344a33a7d73SArnd Bergmann 	spu_release(ctx);
1345a33a7d73SArnd Bergmann 
1346a33a7d73SArnd Bergmann 	poll_wait(file, &ctx->mfc_wq, wait);
1347a33a7d73SArnd Bergmann 
1348a33a7d73SArnd Bergmann 	mask = 0;
1349a33a7d73SArnd Bergmann 	if (free_elements & 0xffff)
1350a33a7d73SArnd Bergmann 		mask |= POLLOUT | POLLWRNORM;
1351a33a7d73SArnd Bergmann 	if (tagstatus & ctx->tagwait)
1352a33a7d73SArnd Bergmann 		mask |= POLLIN | POLLRDNORM;
1353a33a7d73SArnd Bergmann 
1354a33a7d73SArnd Bergmann 	pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__,
1355a33a7d73SArnd Bergmann 		free_elements, tagstatus, ctx->tagwait);
1356a33a7d73SArnd Bergmann 
1357a33a7d73SArnd Bergmann 	return mask;
1358a33a7d73SArnd Bergmann }
1359a33a7d73SArnd Bergmann 
136073b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id)
1361a33a7d73SArnd Bergmann {
1362a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1363a33a7d73SArnd Bergmann 	int ret;
1364a33a7d73SArnd Bergmann 
1365a33a7d73SArnd Bergmann 	spu_acquire(ctx);
1366a33a7d73SArnd Bergmann #if 0
1367a33a7d73SArnd Bergmann /* this currently hangs */
1368a33a7d73SArnd Bergmann 	ret = spufs_wait(ctx->mfc_wq,
1369a33a7d73SArnd Bergmann 			 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2));
1370a33a7d73SArnd Bergmann 	if (ret)
1371a33a7d73SArnd Bergmann 		goto out;
1372a33a7d73SArnd Bergmann 	ret = spufs_wait(ctx->mfc_wq,
1373a33a7d73SArnd Bergmann 			 ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait);
1374a33a7d73SArnd Bergmann out:
1375a33a7d73SArnd Bergmann #else
1376a33a7d73SArnd Bergmann 	ret = 0;
1377a33a7d73SArnd Bergmann #endif
1378a33a7d73SArnd Bergmann 	spu_release(ctx);
1379a33a7d73SArnd Bergmann 
1380a33a7d73SArnd Bergmann 	return ret;
1381a33a7d73SArnd Bergmann }
1382a33a7d73SArnd Bergmann 
1383a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
1384a33a7d73SArnd Bergmann 			   int datasync)
1385a33a7d73SArnd Bergmann {
138673b6af8aSAl Viro 	return spufs_mfc_flush(file, NULL);
1387a33a7d73SArnd Bergmann }
1388a33a7d73SArnd Bergmann 
1389a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on)
1390a33a7d73SArnd Bergmann {
1391a33a7d73SArnd Bergmann 	struct spu_context *ctx = file->private_data;
1392a33a7d73SArnd Bergmann 
1393a33a7d73SArnd Bergmann 	return fasync_helper(fd, file, on, &ctx->mfc_fasync);
1394a33a7d73SArnd Bergmann }
1395a33a7d73SArnd Bergmann 
13965dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = {
1397a33a7d73SArnd Bergmann 	.open	 = spufs_mfc_open,
1398a33a7d73SArnd Bergmann 	.read	 = spufs_mfc_read,
1399a33a7d73SArnd Bergmann 	.write	 = spufs_mfc_write,
1400a33a7d73SArnd Bergmann 	.poll	 = spufs_mfc_poll,
1401a33a7d73SArnd Bergmann 	.flush	 = spufs_mfc_flush,
1402a33a7d73SArnd Bergmann 	.fsync	 = spufs_mfc_fsync,
1403a33a7d73SArnd Bergmann 	.fasync	 = spufs_mfc_fasync,
14046df10a82SMark Nutter 	.mmap	 = spufs_mfc_mmap,
1405a33a7d73SArnd Bergmann };
1406a33a7d73SArnd Bergmann 
140767207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val)
140867207b96SArnd Bergmann {
140967207b96SArnd Bergmann 	struct spu_context *ctx = data;
14108b3d6663SArnd Bergmann 	spu_acquire(ctx);
14118b3d6663SArnd Bergmann 	ctx->ops->npc_write(ctx, val);
14128b3d6663SArnd Bergmann 	spu_release(ctx);
141367207b96SArnd Bergmann }
141467207b96SArnd Bergmann 
141567207b96SArnd Bergmann static u64 spufs_npc_get(void *data)
141667207b96SArnd Bergmann {
141767207b96SArnd Bergmann 	struct spu_context *ctx = data;
141867207b96SArnd Bergmann 	u64 ret;
14198b3d6663SArnd Bergmann 	spu_acquire(ctx);
14208b3d6663SArnd Bergmann 	ret = ctx->ops->npc_read(ctx);
14218b3d6663SArnd Bergmann 	spu_release(ctx);
142267207b96SArnd Bergmann 	return ret;
142367207b96SArnd Bergmann }
14249b5047e2SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set,
14259b5047e2SDwayne Grant McConnell 			"0x%llx\n")
142667207b96SArnd Bergmann 
14278b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val)
14288b3d6663SArnd Bergmann {
14298b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
14308b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
14318b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
14328b3d6663SArnd Bergmann 	lscsa->decr.slot[0] = (u32) val;
14338b3d6663SArnd Bergmann 	spu_release(ctx);
14348b3d6663SArnd Bergmann }
14358b3d6663SArnd Bergmann 
1436bf1ab978SDwayne Grant McConnell static u64 __spufs_decr_get(void *data)
14378b3d6663SArnd Bergmann {
14388b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
14398b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1440bf1ab978SDwayne Grant McConnell 	return lscsa->decr.slot[0];
1441bf1ab978SDwayne Grant McConnell }
1442bf1ab978SDwayne Grant McConnell 
1443bf1ab978SDwayne Grant McConnell static u64 spufs_decr_get(void *data)
1444bf1ab978SDwayne Grant McConnell {
1445bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
14468b3d6663SArnd Bergmann 	u64 ret;
14478b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1448bf1ab978SDwayne Grant McConnell 	ret = __spufs_decr_get(data);
14498b3d6663SArnd Bergmann 	spu_release(ctx);
14508b3d6663SArnd Bergmann 	return ret;
14518b3d6663SArnd Bergmann }
14528b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
14539b5047e2SDwayne Grant McConnell 			"0x%llx\n")
14548b3d6663SArnd Bergmann 
14558b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val)
14568b3d6663SArnd Bergmann {
14578b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
14588b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
14598b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
14608b3d6663SArnd Bergmann 	lscsa->decr_status.slot[0] = (u32) val;
14618b3d6663SArnd Bergmann 	spu_release(ctx);
14628b3d6663SArnd Bergmann }
14638b3d6663SArnd Bergmann 
1464bf1ab978SDwayne Grant McConnell static u64 __spufs_decr_status_get(void *data)
14658b3d6663SArnd Bergmann {
14668b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
14678b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1468bf1ab978SDwayne Grant McConnell 	return lscsa->decr_status.slot[0];
1469bf1ab978SDwayne Grant McConnell }
1470bf1ab978SDwayne Grant McConnell 
1471bf1ab978SDwayne Grant McConnell static u64 spufs_decr_status_get(void *data)
1472bf1ab978SDwayne Grant McConnell {
1473bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
14748b3d6663SArnd Bergmann 	u64 ret;
14758b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1476bf1ab978SDwayne Grant McConnell 	ret = __spufs_decr_status_get(data);
14778b3d6663SArnd Bergmann 	spu_release(ctx);
14788b3d6663SArnd Bergmann 	return ret;
14798b3d6663SArnd Bergmann }
14808b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
14819b5047e2SDwayne Grant McConnell 			spufs_decr_status_set, "0x%llx\n")
14828b3d6663SArnd Bergmann 
14838b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val)
14848b3d6663SArnd Bergmann {
14858b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
14868b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
14878b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
14888b3d6663SArnd Bergmann 	lscsa->event_mask.slot[0] = (u32) val;
14898b3d6663SArnd Bergmann 	spu_release(ctx);
14908b3d6663SArnd Bergmann }
14918b3d6663SArnd Bergmann 
1492bf1ab978SDwayne Grant McConnell static u64 __spufs_event_mask_get(void *data)
14938b3d6663SArnd Bergmann {
14948b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
14958b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
1496bf1ab978SDwayne Grant McConnell 	return lscsa->event_mask.slot[0];
1497bf1ab978SDwayne Grant McConnell }
1498bf1ab978SDwayne Grant McConnell 
1499bf1ab978SDwayne Grant McConnell static u64 spufs_event_mask_get(void *data)
1500bf1ab978SDwayne Grant McConnell {
1501bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
15028b3d6663SArnd Bergmann 	u64 ret;
15038b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
1504bf1ab978SDwayne Grant McConnell 	ret = __spufs_event_mask_get(data);
15058b3d6663SArnd Bergmann 	spu_release(ctx);
15068b3d6663SArnd Bergmann 	return ret;
15078b3d6663SArnd Bergmann }
15088b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
15099b5047e2SDwayne Grant McConnell 			spufs_event_mask_set, "0x%llx\n")
15108b3d6663SArnd Bergmann 
1511bf1ab978SDwayne Grant McConnell static u64 __spufs_event_status_get(void *data)
1512b9e3bd77SDwayne Grant McConnell {
1513b9e3bd77SDwayne Grant McConnell 	struct spu_context *ctx = data;
1514b9e3bd77SDwayne Grant McConnell 	struct spu_state *state = &ctx->csa;
1515b9e3bd77SDwayne Grant McConnell 	u64 stat;
1516b9e3bd77SDwayne Grant McConnell 	stat = state->spu_chnlcnt_RW[0];
1517b9e3bd77SDwayne Grant McConnell 	if (stat)
1518bf1ab978SDwayne Grant McConnell 		return state->spu_chnldata_RW[0];
1519bf1ab978SDwayne Grant McConnell 	return 0;
1520bf1ab978SDwayne Grant McConnell }
1521bf1ab978SDwayne Grant McConnell 
1522bf1ab978SDwayne Grant McConnell static u64 spufs_event_status_get(void *data)
1523bf1ab978SDwayne Grant McConnell {
1524bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
1525bf1ab978SDwayne Grant McConnell 	u64 ret = 0;
1526bf1ab978SDwayne Grant McConnell 
1527bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
1528bf1ab978SDwayne Grant McConnell 	ret = __spufs_event_status_get(data);
1529b9e3bd77SDwayne Grant McConnell 	spu_release(ctx);
1530b9e3bd77SDwayne Grant McConnell 	return ret;
1531b9e3bd77SDwayne Grant McConnell }
1532b9e3bd77SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
1533b9e3bd77SDwayne Grant McConnell 			NULL, "0x%llx\n")
1534b9e3bd77SDwayne Grant McConnell 
15358b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val)
15368b3d6663SArnd Bergmann {
15378b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
15388b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
15398b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
15408b3d6663SArnd Bergmann 	lscsa->srr0.slot[0] = (u32) val;
15418b3d6663SArnd Bergmann 	spu_release(ctx);
15428b3d6663SArnd Bergmann }
15438b3d6663SArnd Bergmann 
15448b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data)
15458b3d6663SArnd Bergmann {
15468b3d6663SArnd Bergmann 	struct spu_context *ctx = data;
15478b3d6663SArnd Bergmann 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
15488b3d6663SArnd Bergmann 	u64 ret;
15498b3d6663SArnd Bergmann 	spu_acquire_saved(ctx);
15508b3d6663SArnd Bergmann 	ret = lscsa->srr0.slot[0];
15518b3d6663SArnd Bergmann 	spu_release(ctx);
15528b3d6663SArnd Bergmann 	return ret;
15538b3d6663SArnd Bergmann }
15548b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
15559b5047e2SDwayne Grant McConnell 			"0x%llx\n")
15568b3d6663SArnd Bergmann 
15577b1a7014Sarnd@arndb.de static u64 spufs_id_get(void *data)
15587b1a7014Sarnd@arndb.de {
15597b1a7014Sarnd@arndb.de 	struct spu_context *ctx = data;
15607b1a7014Sarnd@arndb.de 	u64 num;
15617b1a7014Sarnd@arndb.de 
15627b1a7014Sarnd@arndb.de 	spu_acquire(ctx);
15637b1a7014Sarnd@arndb.de 	if (ctx->state == SPU_STATE_RUNNABLE)
15647b1a7014Sarnd@arndb.de 		num = ctx->spu->number;
15657b1a7014Sarnd@arndb.de 	else
15667b1a7014Sarnd@arndb.de 		num = (unsigned int)-1;
15677b1a7014Sarnd@arndb.de 	spu_release(ctx);
15687b1a7014Sarnd@arndb.de 
15697b1a7014Sarnd@arndb.de 	return num;
15707b1a7014Sarnd@arndb.de }
1571e45d6634SAl Viro DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n")
15727b1a7014Sarnd@arndb.de 
1573bf1ab978SDwayne Grant McConnell static u64 __spufs_object_id_get(void *data)
157486767277SArnd Bergmann {
157586767277SArnd Bergmann 	struct spu_context *ctx = data;
157686767277SArnd Bergmann 	return ctx->object_id;
157786767277SArnd Bergmann }
157886767277SArnd Bergmann 
1579bf1ab978SDwayne Grant McConnell static u64 spufs_object_id_get(void *data)
1580bf1ab978SDwayne Grant McConnell {
1581bf1ab978SDwayne Grant McConnell 	/* FIXME: Should there really be no locking here? */
1582bf1ab978SDwayne Grant McConnell 	return __spufs_object_id_get(data);
1583bf1ab978SDwayne Grant McConnell }
1584bf1ab978SDwayne Grant McConnell 
158586767277SArnd Bergmann static void spufs_object_id_set(void *data, u64 id)
158686767277SArnd Bergmann {
158786767277SArnd Bergmann 	struct spu_context *ctx = data;
158886767277SArnd Bergmann 	ctx->object_id = id;
158986767277SArnd Bergmann }
159086767277SArnd Bergmann 
159186767277SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get,
159286767277SArnd Bergmann 		spufs_object_id_set, "0x%llx\n");
159386767277SArnd Bergmann 
1594bf1ab978SDwayne Grant McConnell static u64 __spufs_lslr_get(void *data)
1595bf1ab978SDwayne Grant McConnell {
1596bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = data;
1597bf1ab978SDwayne Grant McConnell 	return ctx->csa.priv2.spu_lslr_RW;
1598bf1ab978SDwayne Grant McConnell }
1599bf1ab978SDwayne Grant McConnell 
1600b9e3bd77SDwayne Grant McConnell static u64 spufs_lslr_get(void *data)
1601b9e3bd77SDwayne Grant McConnell {
1602b9e3bd77SDwayne Grant McConnell 	struct spu_context *ctx = data;
1603b9e3bd77SDwayne Grant McConnell 	u64 ret;
1604b9e3bd77SDwayne Grant McConnell 
1605b9e3bd77SDwayne Grant McConnell 	spu_acquire_saved(ctx);
1606bf1ab978SDwayne Grant McConnell 	ret = __spufs_lslr_get(data);
1607b9e3bd77SDwayne Grant McConnell 	spu_release(ctx);
1608b9e3bd77SDwayne Grant McConnell 
1609b9e3bd77SDwayne Grant McConnell 	return ret;
1610b9e3bd77SDwayne Grant McConnell }
1611b9e3bd77SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n")
1612b9e3bd77SDwayne Grant McConnell 
1613b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file)
1614b9e3bd77SDwayne Grant McConnell {
1615b9e3bd77SDwayne Grant McConnell 	struct spufs_inode_info *i = SPUFS_I(inode);
1616b9e3bd77SDwayne Grant McConnell 	struct spu_context *ctx = i->i_ctx;
1617b9e3bd77SDwayne Grant McConnell 	file->private_data = ctx;
1618b9e3bd77SDwayne Grant McConnell 	return 0;
1619b9e3bd77SDwayne Grant McConnell }
1620b9e3bd77SDwayne Grant McConnell 
1621bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
1622bf1ab978SDwayne Grant McConnell 			char __user *buf, size_t len, loff_t *pos)
1623bf1ab978SDwayne Grant McConnell {
1624bf1ab978SDwayne Grant McConnell 	u32 mbox_stat;
1625bf1ab978SDwayne Grant McConnell 	u32 data;
1626bf1ab978SDwayne Grant McConnell 
1627bf1ab978SDwayne Grant McConnell 	mbox_stat = ctx->csa.prob.mb_stat_R;
1628bf1ab978SDwayne Grant McConnell 	if (mbox_stat & 0x0000ff) {
1629bf1ab978SDwayne Grant McConnell 		data = ctx->csa.prob.pu_mb_R;
1630bf1ab978SDwayne Grant McConnell 	}
1631bf1ab978SDwayne Grant McConnell 
1632bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
1633bf1ab978SDwayne Grant McConnell }
1634bf1ab978SDwayne Grant McConnell 
163569a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
163669a2f00cSDwayne Grant McConnell 				   size_t len, loff_t *pos)
163769a2f00cSDwayne Grant McConnell {
1638bf1ab978SDwayne Grant McConnell 	int ret;
163969a2f00cSDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
164069a2f00cSDwayne Grant McConnell 
164169a2f00cSDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
164269a2f00cSDwayne Grant McConnell 		return -EFAULT;
164369a2f00cSDwayne Grant McConnell 
164469a2f00cSDwayne Grant McConnell 	spu_acquire_saved(ctx);
164569a2f00cSDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1646bf1ab978SDwayne Grant McConnell 	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
164769a2f00cSDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
164869a2f00cSDwayne Grant McConnell 	spu_release(ctx);
164969a2f00cSDwayne Grant McConnell 
1650bf1ab978SDwayne Grant McConnell 	return ret;
165169a2f00cSDwayne Grant McConnell }
165269a2f00cSDwayne Grant McConnell 
16535dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = {
165469a2f00cSDwayne Grant McConnell 	.open = spufs_info_open,
165569a2f00cSDwayne Grant McConnell 	.read = spufs_mbox_info_read,
165669a2f00cSDwayne Grant McConnell 	.llseek  = generic_file_llseek,
165769a2f00cSDwayne Grant McConnell };
165869a2f00cSDwayne Grant McConnell 
1659bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx,
1660bf1ab978SDwayne Grant McConnell 				char __user *buf, size_t len, loff_t *pos)
1661bf1ab978SDwayne Grant McConnell {
1662bf1ab978SDwayne Grant McConnell 	u32 ibox_stat;
1663bf1ab978SDwayne Grant McConnell 	u32 data;
1664bf1ab978SDwayne Grant McConnell 
1665bf1ab978SDwayne Grant McConnell 	ibox_stat = ctx->csa.prob.mb_stat_R;
1666bf1ab978SDwayne Grant McConnell 	if (ibox_stat & 0xff0000) {
1667bf1ab978SDwayne Grant McConnell 		data = ctx->csa.priv2.puint_mb_R;
1668bf1ab978SDwayne Grant McConnell 	}
1669bf1ab978SDwayne Grant McConnell 
1670bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
1671bf1ab978SDwayne Grant McConnell }
1672bf1ab978SDwayne Grant McConnell 
167369a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
167469a2f00cSDwayne Grant McConnell 				   size_t len, loff_t *pos)
167569a2f00cSDwayne Grant McConnell {
167669a2f00cSDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
1677bf1ab978SDwayne Grant McConnell 	int ret;
167869a2f00cSDwayne Grant McConnell 
167969a2f00cSDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
168069a2f00cSDwayne Grant McConnell 		return -EFAULT;
168169a2f00cSDwayne Grant McConnell 
168269a2f00cSDwayne Grant McConnell 	spu_acquire_saved(ctx);
168369a2f00cSDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1684bf1ab978SDwayne Grant McConnell 	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
168569a2f00cSDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
168669a2f00cSDwayne Grant McConnell 	spu_release(ctx);
168769a2f00cSDwayne Grant McConnell 
1688bf1ab978SDwayne Grant McConnell 	return ret;
168969a2f00cSDwayne Grant McConnell }
169069a2f00cSDwayne Grant McConnell 
16915dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = {
169269a2f00cSDwayne Grant McConnell 	.open = spufs_info_open,
169369a2f00cSDwayne Grant McConnell 	.read = spufs_ibox_info_read,
169469a2f00cSDwayne Grant McConnell 	.llseek  = generic_file_llseek,
169569a2f00cSDwayne Grant McConnell };
169669a2f00cSDwayne Grant McConnell 
1697bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
1698bf1ab978SDwayne Grant McConnell 			char __user *buf, size_t len, loff_t *pos)
1699bf1ab978SDwayne Grant McConnell {
1700bf1ab978SDwayne Grant McConnell 	int i, cnt;
1701bf1ab978SDwayne Grant McConnell 	u32 data[4];
1702bf1ab978SDwayne Grant McConnell 	u32 wbox_stat;
1703bf1ab978SDwayne Grant McConnell 
1704bf1ab978SDwayne Grant McConnell 	wbox_stat = ctx->csa.prob.mb_stat_R;
1705bf1ab978SDwayne Grant McConnell 	cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
1706bf1ab978SDwayne Grant McConnell 	for (i = 0; i < cnt; i++) {
1707bf1ab978SDwayne Grant McConnell 		data[i] = ctx->csa.spu_mailbox_data[i];
1708bf1ab978SDwayne Grant McConnell 	}
1709bf1ab978SDwayne Grant McConnell 
1710bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &data,
1711bf1ab978SDwayne Grant McConnell 				cnt * sizeof(u32));
1712bf1ab978SDwayne Grant McConnell }
1713bf1ab978SDwayne Grant McConnell 
171469a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
171569a2f00cSDwayne Grant McConnell 				   size_t len, loff_t *pos)
171669a2f00cSDwayne Grant McConnell {
171769a2f00cSDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
1718bf1ab978SDwayne Grant McConnell 	int ret;
171969a2f00cSDwayne Grant McConnell 
172069a2f00cSDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
172169a2f00cSDwayne Grant McConnell 		return -EFAULT;
172269a2f00cSDwayne Grant McConnell 
172369a2f00cSDwayne Grant McConnell 	spu_acquire_saved(ctx);
172469a2f00cSDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1725bf1ab978SDwayne Grant McConnell 	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
172669a2f00cSDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
172769a2f00cSDwayne Grant McConnell 	spu_release(ctx);
172869a2f00cSDwayne Grant McConnell 
1729bf1ab978SDwayne Grant McConnell 	return ret;
173069a2f00cSDwayne Grant McConnell }
173169a2f00cSDwayne Grant McConnell 
17325dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = {
173369a2f00cSDwayne Grant McConnell 	.open = spufs_info_open,
173469a2f00cSDwayne Grant McConnell 	.read = spufs_wbox_info_read,
173569a2f00cSDwayne Grant McConnell 	.llseek  = generic_file_llseek,
173669a2f00cSDwayne Grant McConnell };
173769a2f00cSDwayne Grant McConnell 
1738bf1ab978SDwayne Grant McConnell static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
1739bf1ab978SDwayne Grant McConnell 			char __user *buf, size_t len, loff_t *pos)
1740b9e3bd77SDwayne Grant McConnell {
1741b9e3bd77SDwayne Grant McConnell 	struct spu_dma_info info;
1742b9e3bd77SDwayne Grant McConnell 	struct mfc_cq_sr *qp, *spuqp;
1743b9e3bd77SDwayne Grant McConnell 	int i;
1744b9e3bd77SDwayne Grant McConnell 
1745b9e3bd77SDwayne Grant McConnell 	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
1746b9e3bd77SDwayne Grant McConnell 	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
1747b9e3bd77SDwayne Grant McConnell 	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
1748b9e3bd77SDwayne Grant McConnell 	info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
1749b9e3bd77SDwayne Grant McConnell 	info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
1750b9e3bd77SDwayne Grant McConnell 	for (i = 0; i < 16; i++) {
1751b9e3bd77SDwayne Grant McConnell 		qp = &info.dma_info_command_data[i];
1752b9e3bd77SDwayne Grant McConnell 		spuqp = &ctx->csa.priv2.spuq[i];
1753b9e3bd77SDwayne Grant McConnell 
1754b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
1755b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
1756b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
1757b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
1758b9e3bd77SDwayne Grant McConnell 	}
1759b9e3bd77SDwayne Grant McConnell 
1760b9e3bd77SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &info,
1761b9e3bd77SDwayne Grant McConnell 				sizeof info);
1762b9e3bd77SDwayne Grant McConnell }
1763b9e3bd77SDwayne Grant McConnell 
1764bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
1765bf1ab978SDwayne Grant McConnell 			      size_t len, loff_t *pos)
1766bf1ab978SDwayne Grant McConnell {
1767bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
1768bf1ab978SDwayne Grant McConnell 	int ret;
1769bf1ab978SDwayne Grant McConnell 
1770bf1ab978SDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
1771bf1ab978SDwayne Grant McConnell 		return -EFAULT;
1772bf1ab978SDwayne Grant McConnell 
1773bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
1774bf1ab978SDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1775bf1ab978SDwayne Grant McConnell 	ret = __spufs_dma_info_read(ctx, buf, len, pos);
1776bf1ab978SDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
1777bf1ab978SDwayne Grant McConnell 	spu_release(ctx);
1778bf1ab978SDwayne Grant McConnell 
1779bf1ab978SDwayne Grant McConnell 	return ret;
1780bf1ab978SDwayne Grant McConnell }
1781bf1ab978SDwayne Grant McConnell 
17825dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = {
1783b9e3bd77SDwayne Grant McConnell 	.open = spufs_info_open,
1784b9e3bd77SDwayne Grant McConnell 	.read = spufs_dma_info_read,
1785b9e3bd77SDwayne Grant McConnell };
1786b9e3bd77SDwayne Grant McConnell 
1787bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
1788bf1ab978SDwayne Grant McConnell 			char __user *buf, size_t len, loff_t *pos)
1789b9e3bd77SDwayne Grant McConnell {
1790b9e3bd77SDwayne Grant McConnell 	struct spu_proxydma_info info;
1791b9e3bd77SDwayne Grant McConnell 	struct mfc_cq_sr *qp, *puqp;
1792bf1ab978SDwayne Grant McConnell 	int ret = sizeof info;
1793b9e3bd77SDwayne Grant McConnell 	int i;
1794b9e3bd77SDwayne Grant McConnell 
1795b9e3bd77SDwayne Grant McConnell 	if (len < ret)
1796b9e3bd77SDwayne Grant McConnell 		return -EINVAL;
1797b9e3bd77SDwayne Grant McConnell 
1798b9e3bd77SDwayne Grant McConnell 	if (!access_ok(VERIFY_WRITE, buf, len))
1799b9e3bd77SDwayne Grant McConnell 		return -EFAULT;
1800b9e3bd77SDwayne Grant McConnell 
1801b9e3bd77SDwayne Grant McConnell 	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
1802b9e3bd77SDwayne Grant McConnell 	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
1803b9e3bd77SDwayne Grant McConnell 	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
1804b9e3bd77SDwayne Grant McConnell 	for (i = 0; i < 8; i++) {
1805b9e3bd77SDwayne Grant McConnell 		qp = &info.proxydma_info_command_data[i];
1806b9e3bd77SDwayne Grant McConnell 		puqp = &ctx->csa.priv2.puq[i];
1807b9e3bd77SDwayne Grant McConnell 
1808b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
1809b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
1810b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
1811b9e3bd77SDwayne Grant McConnell 		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
1812b9e3bd77SDwayne Grant McConnell 	}
1813bf1ab978SDwayne Grant McConnell 
1814bf1ab978SDwayne Grant McConnell 	return simple_read_from_buffer(buf, len, pos, &info,
1815bf1ab978SDwayne Grant McConnell 				sizeof info);
1816bf1ab978SDwayne Grant McConnell }
1817bf1ab978SDwayne Grant McConnell 
1818bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
1819bf1ab978SDwayne Grant McConnell 				   size_t len, loff_t *pos)
1820bf1ab978SDwayne Grant McConnell {
1821bf1ab978SDwayne Grant McConnell 	struct spu_context *ctx = file->private_data;
1822bf1ab978SDwayne Grant McConnell 	int ret;
1823bf1ab978SDwayne Grant McConnell 
1824bf1ab978SDwayne Grant McConnell 	spu_acquire_saved(ctx);
1825bf1ab978SDwayne Grant McConnell 	spin_lock(&ctx->csa.register_lock);
1826bf1ab978SDwayne Grant McConnell 	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
1827b9e3bd77SDwayne Grant McConnell 	spin_unlock(&ctx->csa.register_lock);
1828b9e3bd77SDwayne Grant McConnell 	spu_release(ctx);
1829b9e3bd77SDwayne Grant McConnell 
1830b9e3bd77SDwayne Grant McConnell 	return ret;
1831b9e3bd77SDwayne Grant McConnell }
1832b9e3bd77SDwayne Grant McConnell 
18335dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = {
1834b9e3bd77SDwayne Grant McConnell 	.open = spufs_info_open,
1835b9e3bd77SDwayne Grant McConnell 	.read = spufs_proxydma_info_read,
1836b9e3bd77SDwayne Grant McConnell };
1837b9e3bd77SDwayne Grant McConnell 
183867207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = {
183967207b96SArnd Bergmann 	{ "mem",  &spufs_mem_fops,  0666, },
18408b3d6663SArnd Bergmann 	{ "regs", &spufs_regs_fops,  0666, },
184167207b96SArnd Bergmann 	{ "mbox", &spufs_mbox_fops, 0444, },
184267207b96SArnd Bergmann 	{ "ibox", &spufs_ibox_fops, 0444, },
184367207b96SArnd Bergmann 	{ "wbox", &spufs_wbox_fops, 0222, },
184467207b96SArnd Bergmann 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
184567207b96SArnd Bergmann 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
184667207b96SArnd Bergmann 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
184767207b96SArnd Bergmann 	{ "signal1", &spufs_signal1_fops, 0666, },
184867207b96SArnd Bergmann 	{ "signal2", &spufs_signal2_fops, 0666, },
184967207b96SArnd Bergmann 	{ "signal1_type", &spufs_signal1_type, 0666, },
185067207b96SArnd Bergmann 	{ "signal2_type", &spufs_signal2_type, 0666, },
18516df10a82SMark Nutter 	{ "cntl", &spufs_cntl_fops,  0666, },
18528b3d6663SArnd Bergmann 	{ "fpcr", &spufs_fpcr_fops, 0666, },
1853b9e3bd77SDwayne Grant McConnell 	{ "lslr", &spufs_lslr_ops, 0444, },
1854b9e3bd77SDwayne Grant McConnell 	{ "mfc", &spufs_mfc_fops, 0666, },
1855b9e3bd77SDwayne Grant McConnell 	{ "mss", &spufs_mss_fops, 0666, },
1856b9e3bd77SDwayne Grant McConnell 	{ "npc", &spufs_npc_ops, 0666, },
1857b9e3bd77SDwayne Grant McConnell 	{ "srr0", &spufs_srr0_ops, 0666, },
18588b3d6663SArnd Bergmann 	{ "decr", &spufs_decr_ops, 0666, },
18598b3d6663SArnd Bergmann 	{ "decr_status", &spufs_decr_status_ops, 0666, },
18608b3d6663SArnd Bergmann 	{ "event_mask", &spufs_event_mask_ops, 0666, },
1861b9e3bd77SDwayne Grant McConnell 	{ "event_status", &spufs_event_status_ops, 0444, },
186227d5bf2aSBenjamin Herrenschmidt 	{ "psmap", &spufs_psmap_fops, 0666, },
186386767277SArnd Bergmann 	{ "phys-id", &spufs_id_ops, 0666, },
186486767277SArnd Bergmann 	{ "object-id", &spufs_object_id_ops, 0666, },
186569a2f00cSDwayne Grant McConnell 	{ "mbox_info", &spufs_mbox_info_fops, 0444, },
186669a2f00cSDwayne Grant McConnell 	{ "ibox_info", &spufs_ibox_info_fops, 0444, },
186769a2f00cSDwayne Grant McConnell 	{ "wbox_info", &spufs_wbox_info_fops, 0444, },
1868b9e3bd77SDwayne Grant McConnell 	{ "dma_info", &spufs_dma_info_fops, 0444, },
1869b9e3bd77SDwayne Grant McConnell 	{ "proxydma_info", &spufs_proxydma_info_fops, 0444, },
187067207b96SArnd Bergmann 	{},
187167207b96SArnd Bergmann };
18725737edd1SMark Nutter 
18735737edd1SMark Nutter struct tree_descr spufs_dir_nosched_contents[] = {
18745737edd1SMark Nutter 	{ "mem",  &spufs_mem_fops,  0666, },
18755737edd1SMark Nutter 	{ "mbox", &spufs_mbox_fops, 0444, },
18765737edd1SMark Nutter 	{ "ibox", &spufs_ibox_fops, 0444, },
18775737edd1SMark Nutter 	{ "wbox", &spufs_wbox_fops, 0222, },
18785737edd1SMark Nutter 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
18795737edd1SMark Nutter 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
18805737edd1SMark Nutter 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
18815737edd1SMark Nutter 	{ "signal1", &spufs_signal1_fops, 0666, },
18825737edd1SMark Nutter 	{ "signal2", &spufs_signal2_fops, 0666, },
18835737edd1SMark Nutter 	{ "signal1_type", &spufs_signal1_type, 0666, },
18845737edd1SMark Nutter 	{ "signal2_type", &spufs_signal2_type, 0666, },
18855737edd1SMark Nutter 	{ "mss", &spufs_mss_fops, 0666, },
18865737edd1SMark Nutter 	{ "mfc", &spufs_mfc_fops, 0666, },
18875737edd1SMark Nutter 	{ "cntl", &spufs_cntl_fops,  0666, },
18885737edd1SMark Nutter 	{ "npc", &spufs_npc_ops, 0666, },
18895737edd1SMark Nutter 	{ "psmap", &spufs_psmap_fops, 0666, },
18905737edd1SMark Nutter 	{ "phys-id", &spufs_id_ops, 0666, },
18915737edd1SMark Nutter 	{ "object-id", &spufs_object_id_ops, 0666, },
18925737edd1SMark Nutter 	{},
18935737edd1SMark Nutter };
1894bf1ab978SDwayne Grant McConnell 
1895bf1ab978SDwayne Grant McConnell struct spufs_coredump_reader spufs_coredump_read[] = {
1896bf1ab978SDwayne Grant McConnell 	{ "regs", __spufs_regs_read, NULL, 128 * 16 },
1897bf1ab978SDwayne Grant McConnell 	{ "fpcr", __spufs_fpcr_read, NULL, 16 },
1898bf1ab978SDwayne Grant McConnell 	{ "lslr", NULL, __spufs_lslr_get, 11 },
1899bf1ab978SDwayne Grant McConnell 	{ "decr", NULL, __spufs_decr_get, 11 },
1900bf1ab978SDwayne Grant McConnell 	{ "decr_status", NULL, __spufs_decr_status_get, 11 },
1901bf1ab978SDwayne Grant McConnell 	{ "mem", __spufs_mem_read, NULL, 256 * 1024, },
1902bf1ab978SDwayne Grant McConnell 	{ "signal1", __spufs_signal1_read, NULL, 4 },
1903bf1ab978SDwayne Grant McConnell 	{ "signal1_type", NULL, __spufs_signal1_type_get, 2 },
1904bf1ab978SDwayne Grant McConnell 	{ "signal2", __spufs_signal2_read, NULL, 4 },
1905bf1ab978SDwayne Grant McConnell 	{ "signal2_type", NULL, __spufs_signal2_type_get, 2 },
1906bf1ab978SDwayne Grant McConnell 	{ "event_mask", NULL, __spufs_event_mask_get, 8 },
1907bf1ab978SDwayne Grant McConnell 	{ "event_status", NULL, __spufs_event_status_get, 8 },
1908bf1ab978SDwayne Grant McConnell 	{ "mbox_info", __spufs_mbox_info_read, NULL, 4 },
1909bf1ab978SDwayne Grant McConnell 	{ "ibox_info", __spufs_ibox_info_read, NULL, 4 },
1910bf1ab978SDwayne Grant McConnell 	{ "wbox_info", __spufs_wbox_info_read, NULL, 16 },
1911bf1ab978SDwayne Grant McConnell 	{ "dma_info", __spufs_dma_info_read, NULL, 69 * 8 },
1912bf1ab978SDwayne Grant McConnell 	{ "proxydma_info", __spufs_proxydma_info_read, NULL, 35 * 8 },
1913bf1ab978SDwayne Grant McConnell 	{ "object-id", NULL, __spufs_object_id_get, 19 },
1914bf1ab978SDwayne Grant McConnell 	{ },
1915bf1ab978SDwayne Grant McConnell };
1916bf1ab978SDwayne Grant McConnell int spufs_coredump_num_notes = ARRAY_SIZE(spufs_coredump_read) - 1;
1917bf1ab978SDwayne Grant McConnell 
1918