162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SPU file system -- file contents
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Arnd Bergmann <arndb@de.ibm.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#undef DEBUG
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/coredump.h>
1362306a36Sopenharmony_ci#include <linux/fs.h>
1462306a36Sopenharmony_ci#include <linux/ioctl.h>
1562306a36Sopenharmony_ci#include <linux/export.h>
1662306a36Sopenharmony_ci#include <linux/pagemap.h>
1762306a36Sopenharmony_ci#include <linux/poll.h>
1862306a36Sopenharmony_ci#include <linux/ptrace.h>
1962306a36Sopenharmony_ci#include <linux/seq_file.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <asm/io.h>
2362306a36Sopenharmony_ci#include <asm/time.h>
2462306a36Sopenharmony_ci#include <asm/spu.h>
2562306a36Sopenharmony_ci#include <asm/spu_info.h>
2662306a36Sopenharmony_ci#include <linux/uaccess.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "spufs.h"
2962306a36Sopenharmony_ci#include "sputrace.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Simple attribute files */
3462306a36Sopenharmony_cistruct spufs_attr {
3562306a36Sopenharmony_ci	int (*get)(void *, u64 *);
3662306a36Sopenharmony_ci	int (*set)(void *, u64);
3762306a36Sopenharmony_ci	char get_buf[24];       /* enough to store a u64 and "\n\0" */
3862306a36Sopenharmony_ci	char set_buf[24];
3962306a36Sopenharmony_ci	void *data;
4062306a36Sopenharmony_ci	const char *fmt;        /* format for read operation */
4162306a36Sopenharmony_ci	struct mutex mutex;     /* protects access to these buffers */
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int spufs_attr_open(struct inode *inode, struct file *file,
4562306a36Sopenharmony_ci		int (*get)(void *, u64 *), int (*set)(void *, u64),
4662306a36Sopenharmony_ci		const char *fmt)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct spufs_attr *attr;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	attr = kmalloc(sizeof(*attr), GFP_KERNEL);
5162306a36Sopenharmony_ci	if (!attr)
5262306a36Sopenharmony_ci		return -ENOMEM;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	attr->get = get;
5562306a36Sopenharmony_ci	attr->set = set;
5662306a36Sopenharmony_ci	attr->data = inode->i_private;
5762306a36Sopenharmony_ci	attr->fmt = fmt;
5862306a36Sopenharmony_ci	mutex_init(&attr->mutex);
5962306a36Sopenharmony_ci	file->private_data = attr;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return nonseekable_open(inode, file);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic int spufs_attr_release(struct inode *inode, struct file *file)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci       kfree(file->private_data);
6762306a36Sopenharmony_ci	return 0;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic ssize_t spufs_attr_read(struct file *file, char __user *buf,
7162306a36Sopenharmony_ci		size_t len, loff_t *ppos)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct spufs_attr *attr;
7462306a36Sopenharmony_ci	size_t size;
7562306a36Sopenharmony_ci	ssize_t ret;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	attr = file->private_data;
7862306a36Sopenharmony_ci	if (!attr->get)
7962306a36Sopenharmony_ci		return -EACCES;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	ret = mutex_lock_interruptible(&attr->mutex);
8262306a36Sopenharmony_ci	if (ret)
8362306a36Sopenharmony_ci		return ret;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (*ppos) {		/* continued read */
8662306a36Sopenharmony_ci		size = strlen(attr->get_buf);
8762306a36Sopenharmony_ci	} else {		/* first read */
8862306a36Sopenharmony_ci		u64 val;
8962306a36Sopenharmony_ci		ret = attr->get(attr->data, &val);
9062306a36Sopenharmony_ci		if (ret)
9162306a36Sopenharmony_ci			goto out;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		size = scnprintf(attr->get_buf, sizeof(attr->get_buf),
9462306a36Sopenharmony_ci				 attr->fmt, (unsigned long long)val);
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size);
9862306a36Sopenharmony_ciout:
9962306a36Sopenharmony_ci	mutex_unlock(&attr->mutex);
10062306a36Sopenharmony_ci	return ret;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic ssize_t spufs_attr_write(struct file *file, const char __user *buf,
10462306a36Sopenharmony_ci		size_t len, loff_t *ppos)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct spufs_attr *attr;
10762306a36Sopenharmony_ci	u64 val;
10862306a36Sopenharmony_ci	size_t size;
10962306a36Sopenharmony_ci	ssize_t ret;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	attr = file->private_data;
11262306a36Sopenharmony_ci	if (!attr->set)
11362306a36Sopenharmony_ci		return -EACCES;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	ret = mutex_lock_interruptible(&attr->mutex);
11662306a36Sopenharmony_ci	if (ret)
11762306a36Sopenharmony_ci		return ret;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	ret = -EFAULT;
12062306a36Sopenharmony_ci	size = min(sizeof(attr->set_buf) - 1, len);
12162306a36Sopenharmony_ci	if (copy_from_user(attr->set_buf, buf, size))
12262306a36Sopenharmony_ci		goto out;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	ret = len; /* claim we got the whole input */
12562306a36Sopenharmony_ci	attr->set_buf[size] = '\0';
12662306a36Sopenharmony_ci	val = simple_strtol(attr->set_buf, NULL, 0);
12762306a36Sopenharmony_ci	attr->set(attr->data, val);
12862306a36Sopenharmony_ciout:
12962306a36Sopenharmony_ci	mutex_unlock(&attr->mutex);
13062306a36Sopenharmony_ci	return ret;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic ssize_t spufs_dump_emit(struct coredump_params *cprm, void *buf,
13462306a36Sopenharmony_ci		size_t size)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	if (!dump_emit(cprm, buf, size))
13762306a36Sopenharmony_ci		return -EIO;
13862306a36Sopenharmony_ci	return size;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)	\
14262306a36Sopenharmony_cistatic int __fops ## _open(struct inode *inode, struct file *file)	\
14362306a36Sopenharmony_ci{									\
14462306a36Sopenharmony_ci	__simple_attr_check_format(__fmt, 0ull);			\
14562306a36Sopenharmony_ci	return spufs_attr_open(inode, file, __get, __set, __fmt);	\
14662306a36Sopenharmony_ci}									\
14762306a36Sopenharmony_cistatic const struct file_operations __fops = {				\
14862306a36Sopenharmony_ci	.open	 = __fops ## _open,					\
14962306a36Sopenharmony_ci	.release = spufs_attr_release,					\
15062306a36Sopenharmony_ci	.read	 = spufs_attr_read,					\
15162306a36Sopenharmony_ci	.write	 = spufs_attr_write,					\
15262306a36Sopenharmony_ci	.llseek  = generic_file_llseek,					\
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int
15762306a36Sopenharmony_cispufs_mem_open(struct inode *inode, struct file *file)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
16062306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
16362306a36Sopenharmony_ci	file->private_data = ctx;
16462306a36Sopenharmony_ci	if (!i->i_openers++)
16562306a36Sopenharmony_ci		ctx->local_store = inode->i_mapping;
16662306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int
17162306a36Sopenharmony_cispufs_mem_release(struct inode *inode, struct file *file)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
17462306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
17762306a36Sopenharmony_ci	if (!--i->i_openers)
17862306a36Sopenharmony_ci		ctx->local_store = NULL;
17962306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic ssize_t
18462306a36Sopenharmony_cispufs_mem_dump(struct spu_context *ctx, struct coredump_params *cprm)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	return spufs_dump_emit(cprm, ctx->ops->get_ls(ctx), LS_SIZE);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic ssize_t
19062306a36Sopenharmony_cispufs_mem_read(struct file *file, char __user *buffer,
19162306a36Sopenharmony_ci				size_t size, loff_t *pos)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
19462306a36Sopenharmony_ci	ssize_t ret;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	ret = spu_acquire(ctx);
19762306a36Sopenharmony_ci	if (ret)
19862306a36Sopenharmony_ci		return ret;
19962306a36Sopenharmony_ci	ret = simple_read_from_buffer(buffer, size, pos, ctx->ops->get_ls(ctx),
20062306a36Sopenharmony_ci				      LS_SIZE);
20162306a36Sopenharmony_ci	spu_release(ctx);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return ret;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic ssize_t
20762306a36Sopenharmony_cispufs_mem_write(struct file *file, const char __user *buffer,
20862306a36Sopenharmony_ci					size_t size, loff_t *ppos)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
21162306a36Sopenharmony_ci	char *local_store;
21262306a36Sopenharmony_ci	loff_t pos = *ppos;
21362306a36Sopenharmony_ci	int ret;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (pos > LS_SIZE)
21662306a36Sopenharmony_ci		return -EFBIG;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ret = spu_acquire(ctx);
21962306a36Sopenharmony_ci	if (ret)
22062306a36Sopenharmony_ci		return ret;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	local_store = ctx->ops->get_ls(ctx);
22362306a36Sopenharmony_ci	size = simple_write_to_buffer(local_store, LS_SIZE, ppos, buffer, size);
22462306a36Sopenharmony_ci	spu_release(ctx);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return size;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic vm_fault_t
23062306a36Sopenharmony_cispufs_mem_mmap_fault(struct vm_fault *vmf)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct vm_area_struct *vma = vmf->vma;
23362306a36Sopenharmony_ci	struct spu_context *ctx	= vma->vm_file->private_data;
23462306a36Sopenharmony_ci	unsigned long pfn, offset;
23562306a36Sopenharmony_ci	vm_fault_t ret;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	offset = vmf->pgoff << PAGE_SHIFT;
23862306a36Sopenharmony_ci	if (offset >= LS_SIZE)
23962306a36Sopenharmony_ci		return VM_FAULT_SIGBUS;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	pr_debug("spufs_mem_mmap_fault address=0x%lx, offset=0x%lx\n",
24262306a36Sopenharmony_ci			vmf->address, offset);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (spu_acquire(ctx))
24562306a36Sopenharmony_ci		return VM_FAULT_NOPAGE;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (ctx->state == SPU_STATE_SAVED) {
24862306a36Sopenharmony_ci		vma->vm_page_prot = pgprot_cached(vma->vm_page_prot);
24962306a36Sopenharmony_ci		pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset);
25062306a36Sopenharmony_ci	} else {
25162306a36Sopenharmony_ci		vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot);
25262306a36Sopenharmony_ci		pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci	ret = vmf_insert_pfn(vma, vmf->address, pfn);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	spu_release(ctx);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return ret;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int spufs_mem_mmap_access(struct vm_area_struct *vma,
26262306a36Sopenharmony_ci				unsigned long address,
26362306a36Sopenharmony_ci				void *buf, int len, int write)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct spu_context *ctx = vma->vm_file->private_data;
26662306a36Sopenharmony_ci	unsigned long offset = address - vma->vm_start;
26762306a36Sopenharmony_ci	char *local_store;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (write && !(vma->vm_flags & VM_WRITE))
27062306a36Sopenharmony_ci		return -EACCES;
27162306a36Sopenharmony_ci	if (spu_acquire(ctx))
27262306a36Sopenharmony_ci		return -EINTR;
27362306a36Sopenharmony_ci	if ((offset + len) > vma->vm_end)
27462306a36Sopenharmony_ci		len = vma->vm_end - offset;
27562306a36Sopenharmony_ci	local_store = ctx->ops->get_ls(ctx);
27662306a36Sopenharmony_ci	if (write)
27762306a36Sopenharmony_ci		memcpy_toio(local_store + offset, buf, len);
27862306a36Sopenharmony_ci	else
27962306a36Sopenharmony_ci		memcpy_fromio(buf, local_store + offset, len);
28062306a36Sopenharmony_ci	spu_release(ctx);
28162306a36Sopenharmony_ci	return len;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic const struct vm_operations_struct spufs_mem_mmap_vmops = {
28562306a36Sopenharmony_ci	.fault = spufs_mem_mmap_fault,
28662306a36Sopenharmony_ci	.access = spufs_mem_mmap_access,
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	if (!(vma->vm_flags & VM_SHARED))
29262306a36Sopenharmony_ci		return -EINVAL;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO | VM_PFNMAP);
29562306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	vma->vm_ops = &spufs_mem_mmap_vmops;
29862306a36Sopenharmony_ci	return 0;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic const struct file_operations spufs_mem_fops = {
30262306a36Sopenharmony_ci	.open			= spufs_mem_open,
30362306a36Sopenharmony_ci	.release		= spufs_mem_release,
30462306a36Sopenharmony_ci	.read			= spufs_mem_read,
30562306a36Sopenharmony_ci	.write			= spufs_mem_write,
30662306a36Sopenharmony_ci	.llseek			= generic_file_llseek,
30762306a36Sopenharmony_ci	.mmap			= spufs_mem_mmap,
30862306a36Sopenharmony_ci};
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic vm_fault_t spufs_ps_fault(struct vm_fault *vmf,
31162306a36Sopenharmony_ci				    unsigned long ps_offs,
31262306a36Sopenharmony_ci				    unsigned long ps_size)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct spu_context *ctx = vmf->vma->vm_file->private_data;
31562306a36Sopenharmony_ci	unsigned long area, offset = vmf->pgoff << PAGE_SHIFT;
31662306a36Sopenharmony_ci	int err = 0;
31762306a36Sopenharmony_ci	vm_fault_t ret = VM_FAULT_NOPAGE;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	spu_context_nospu_trace(spufs_ps_fault__enter, ctx);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (offset >= ps_size)
32262306a36Sopenharmony_ci		return VM_FAULT_SIGBUS;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (fatal_signal_pending(current))
32562306a36Sopenharmony_ci		return VM_FAULT_SIGBUS;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/*
32862306a36Sopenharmony_ci	 * Because we release the mmap_lock, the context may be destroyed while
32962306a36Sopenharmony_ci	 * we're in spu_wait. Grab an extra reference so it isn't destroyed
33062306a36Sopenharmony_ci	 * in the meantime.
33162306a36Sopenharmony_ci	 */
33262306a36Sopenharmony_ci	get_spu_context(ctx);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/*
33562306a36Sopenharmony_ci	 * We have to wait for context to be loaded before we have
33662306a36Sopenharmony_ci	 * pages to hand out to the user, but we don't want to wait
33762306a36Sopenharmony_ci	 * with the mmap_lock held.
33862306a36Sopenharmony_ci	 * It is possible to drop the mmap_lock here, but then we need
33962306a36Sopenharmony_ci	 * to return VM_FAULT_NOPAGE because the mappings may have
34062306a36Sopenharmony_ci	 * hanged.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	if (spu_acquire(ctx))
34362306a36Sopenharmony_ci		goto refault;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (ctx->state == SPU_STATE_SAVED) {
34662306a36Sopenharmony_ci		mmap_read_unlock(current->mm);
34762306a36Sopenharmony_ci		spu_context_nospu_trace(spufs_ps_fault__sleep, ctx);
34862306a36Sopenharmony_ci		err = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE);
34962306a36Sopenharmony_ci		spu_context_trace(spufs_ps_fault__wake, ctx, ctx->spu);
35062306a36Sopenharmony_ci		mmap_read_lock(current->mm);
35162306a36Sopenharmony_ci	} else {
35262306a36Sopenharmony_ci		area = ctx->spu->problem_phys + ps_offs;
35362306a36Sopenharmony_ci		ret = vmf_insert_pfn(vmf->vma, vmf->address,
35462306a36Sopenharmony_ci				(area + offset) >> PAGE_SHIFT);
35562306a36Sopenharmony_ci		spu_context_trace(spufs_ps_fault__insert, ctx, ctx->spu);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (!err)
35962306a36Sopenharmony_ci		spu_release(ctx);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cirefault:
36262306a36Sopenharmony_ci	put_spu_context(ctx);
36362306a36Sopenharmony_ci	return ret;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci#if SPUFS_MMAP_4K
36762306a36Sopenharmony_cistatic vm_fault_t spufs_cntl_mmap_fault(struct vm_fault *vmf)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	return spufs_ps_fault(vmf, 0x4000, SPUFS_CNTL_MAP_SIZE);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic const struct vm_operations_struct spufs_cntl_mmap_vmops = {
37362306a36Sopenharmony_ci	.fault = spufs_cntl_mmap_fault,
37462306a36Sopenharmony_ci};
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/*
37762306a36Sopenharmony_ci * mmap support for problem state control area [0x4000 - 0x4fff].
37862306a36Sopenharmony_ci */
37962306a36Sopenharmony_cistatic int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	if (!(vma->vm_flags & VM_SHARED))
38262306a36Sopenharmony_ci		return -EINVAL;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO | VM_PFNMAP);
38562306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	vma->vm_ops = &spufs_cntl_mmap_vmops;
38862306a36Sopenharmony_ci	return 0;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci#else /* SPUFS_MMAP_4K */
39162306a36Sopenharmony_ci#define spufs_cntl_mmap NULL
39262306a36Sopenharmony_ci#endif /* !SPUFS_MMAP_4K */
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic int spufs_cntl_get(void *data, u64 *val)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct spu_context *ctx = data;
39762306a36Sopenharmony_ci	int ret;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	ret = spu_acquire(ctx);
40062306a36Sopenharmony_ci	if (ret)
40162306a36Sopenharmony_ci		return ret;
40262306a36Sopenharmony_ci	*val = ctx->ops->status_read(ctx);
40362306a36Sopenharmony_ci	spu_release(ctx);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return 0;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic int spufs_cntl_set(void *data, u64 val)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct spu_context *ctx = data;
41162306a36Sopenharmony_ci	int ret;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	ret = spu_acquire(ctx);
41462306a36Sopenharmony_ci	if (ret)
41562306a36Sopenharmony_ci		return ret;
41662306a36Sopenharmony_ci	ctx->ops->runcntl_write(ctx, val);
41762306a36Sopenharmony_ci	spu_release(ctx);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int spufs_cntl_open(struct inode *inode, struct file *file)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
42562306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
42862306a36Sopenharmony_ci	file->private_data = ctx;
42962306a36Sopenharmony_ci	if (!i->i_openers++)
43062306a36Sopenharmony_ci		ctx->cntl = inode->i_mapping;
43162306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
43262306a36Sopenharmony_ci	return simple_attr_open(inode, file, spufs_cntl_get,
43362306a36Sopenharmony_ci					spufs_cntl_set, "0x%08lx");
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int
43762306a36Sopenharmony_cispufs_cntl_release(struct inode *inode, struct file *file)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
44062306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	simple_attr_release(inode, file);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
44562306a36Sopenharmony_ci	if (!--i->i_openers)
44662306a36Sopenharmony_ci		ctx->cntl = NULL;
44762306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
44862306a36Sopenharmony_ci	return 0;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic const struct file_operations spufs_cntl_fops = {
45262306a36Sopenharmony_ci	.open = spufs_cntl_open,
45362306a36Sopenharmony_ci	.release = spufs_cntl_release,
45462306a36Sopenharmony_ci	.read = simple_attr_read,
45562306a36Sopenharmony_ci	.write = simple_attr_write,
45662306a36Sopenharmony_ci	.llseek	= no_llseek,
45762306a36Sopenharmony_ci	.mmap = spufs_cntl_mmap,
45862306a36Sopenharmony_ci};
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic int
46162306a36Sopenharmony_cispufs_regs_open(struct inode *inode, struct file *file)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
46462306a36Sopenharmony_ci	file->private_data = i->i_ctx;
46562306a36Sopenharmony_ci	return 0;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic ssize_t
46962306a36Sopenharmony_cispufs_regs_dump(struct spu_context *ctx, struct coredump_params *cprm)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	return spufs_dump_emit(cprm, ctx->csa.lscsa->gprs,
47262306a36Sopenharmony_ci			       sizeof(ctx->csa.lscsa->gprs));
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic ssize_t
47662306a36Sopenharmony_cispufs_regs_read(struct file *file, char __user *buffer,
47762306a36Sopenharmony_ci		size_t size, loff_t *pos)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	int ret;
48062306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/* pre-check for file position: if we'd return EOF, there's no point
48362306a36Sopenharmony_ci	 * causing a deschedule */
48462306a36Sopenharmony_ci	if (*pos >= sizeof(ctx->csa.lscsa->gprs))
48562306a36Sopenharmony_ci		return 0;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
48862306a36Sopenharmony_ci	if (ret)
48962306a36Sopenharmony_ci		return ret;
49062306a36Sopenharmony_ci	ret = simple_read_from_buffer(buffer, size, pos, ctx->csa.lscsa->gprs,
49162306a36Sopenharmony_ci				      sizeof(ctx->csa.lscsa->gprs));
49262306a36Sopenharmony_ci	spu_release_saved(ctx);
49362306a36Sopenharmony_ci	return ret;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic ssize_t
49762306a36Sopenharmony_cispufs_regs_write(struct file *file, const char __user *buffer,
49862306a36Sopenharmony_ci		 size_t size, loff_t *pos)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
50162306a36Sopenharmony_ci	struct spu_lscsa *lscsa = ctx->csa.lscsa;
50262306a36Sopenharmony_ci	int ret;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (*pos >= sizeof(lscsa->gprs))
50562306a36Sopenharmony_ci		return -EFBIG;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
50862306a36Sopenharmony_ci	if (ret)
50962306a36Sopenharmony_ci		return ret;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	size = simple_write_to_buffer(lscsa->gprs, sizeof(lscsa->gprs), pos,
51262306a36Sopenharmony_ci					buffer, size);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	spu_release_saved(ctx);
51562306a36Sopenharmony_ci	return size;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic const struct file_operations spufs_regs_fops = {
51962306a36Sopenharmony_ci	.open	 = spufs_regs_open,
52062306a36Sopenharmony_ci	.read    = spufs_regs_read,
52162306a36Sopenharmony_ci	.write   = spufs_regs_write,
52262306a36Sopenharmony_ci	.llseek  = generic_file_llseek,
52362306a36Sopenharmony_ci};
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic ssize_t
52662306a36Sopenharmony_cispufs_fpcr_dump(struct spu_context *ctx, struct coredump_params *cprm)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	return spufs_dump_emit(cprm, &ctx->csa.lscsa->fpcr,
52962306a36Sopenharmony_ci			       sizeof(ctx->csa.lscsa->fpcr));
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic ssize_t
53362306a36Sopenharmony_cispufs_fpcr_read(struct file *file, char __user * buffer,
53462306a36Sopenharmony_ci		size_t size, loff_t * pos)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	int ret;
53762306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
54062306a36Sopenharmony_ci	if (ret)
54162306a36Sopenharmony_ci		return ret;
54262306a36Sopenharmony_ci	ret = simple_read_from_buffer(buffer, size, pos, &ctx->csa.lscsa->fpcr,
54362306a36Sopenharmony_ci				      sizeof(ctx->csa.lscsa->fpcr));
54462306a36Sopenharmony_ci	spu_release_saved(ctx);
54562306a36Sopenharmony_ci	return ret;
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic ssize_t
54962306a36Sopenharmony_cispufs_fpcr_write(struct file *file, const char __user * buffer,
55062306a36Sopenharmony_ci		 size_t size, loff_t * pos)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
55362306a36Sopenharmony_ci	struct spu_lscsa *lscsa = ctx->csa.lscsa;
55462306a36Sopenharmony_ci	int ret;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (*pos >= sizeof(lscsa->fpcr))
55762306a36Sopenharmony_ci		return -EFBIG;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
56062306a36Sopenharmony_ci	if (ret)
56162306a36Sopenharmony_ci		return ret;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	size = simple_write_to_buffer(&lscsa->fpcr, sizeof(lscsa->fpcr), pos,
56462306a36Sopenharmony_ci					buffer, size);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	spu_release_saved(ctx);
56762306a36Sopenharmony_ci	return size;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic const struct file_operations spufs_fpcr_fops = {
57162306a36Sopenharmony_ci	.open = spufs_regs_open,
57262306a36Sopenharmony_ci	.read = spufs_fpcr_read,
57362306a36Sopenharmony_ci	.write = spufs_fpcr_write,
57462306a36Sopenharmony_ci	.llseek = generic_file_llseek,
57562306a36Sopenharmony_ci};
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/* generic open function for all pipe-like files */
57862306a36Sopenharmony_cistatic int spufs_pipe_open(struct inode *inode, struct file *file)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
58162306a36Sopenharmony_ci	file->private_data = i->i_ctx;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return stream_open(inode, file);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci/*
58762306a36Sopenharmony_ci * Read as many bytes from the mailbox as possible, until
58862306a36Sopenharmony_ci * one of the conditions becomes true:
58962306a36Sopenharmony_ci *
59062306a36Sopenharmony_ci * - no more data available in the mailbox
59162306a36Sopenharmony_ci * - end of the user provided buffer
59262306a36Sopenharmony_ci * - end of the mapped area
59362306a36Sopenharmony_ci */
59462306a36Sopenharmony_cistatic ssize_t spufs_mbox_read(struct file *file, char __user *buf,
59562306a36Sopenharmony_ci			size_t len, loff_t *pos)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
59862306a36Sopenharmony_ci	u32 mbox_data, __user *udata = (void __user *)buf;
59962306a36Sopenharmony_ci	ssize_t count;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (len < 4)
60262306a36Sopenharmony_ci		return -EINVAL;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	count = spu_acquire(ctx);
60562306a36Sopenharmony_ci	if (count)
60662306a36Sopenharmony_ci		return count;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	for (count = 0; (count + 4) <= len; count += 4, udata++) {
60962306a36Sopenharmony_ci		int ret;
61062306a36Sopenharmony_ci		ret = ctx->ops->mbox_read(ctx, &mbox_data);
61162306a36Sopenharmony_ci		if (ret == 0)
61262306a36Sopenharmony_ci			break;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		/*
61562306a36Sopenharmony_ci		 * at the end of the mapped area, we can fault
61662306a36Sopenharmony_ci		 * but still need to return the data we have
61762306a36Sopenharmony_ci		 * read successfully so far.
61862306a36Sopenharmony_ci		 */
61962306a36Sopenharmony_ci		ret = put_user(mbox_data, udata);
62062306a36Sopenharmony_ci		if (ret) {
62162306a36Sopenharmony_ci			if (!count)
62262306a36Sopenharmony_ci				count = -EFAULT;
62362306a36Sopenharmony_ci			break;
62462306a36Sopenharmony_ci		}
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci	spu_release(ctx);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (!count)
62962306a36Sopenharmony_ci		count = -EAGAIN;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return count;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic const struct file_operations spufs_mbox_fops = {
63562306a36Sopenharmony_ci	.open	= spufs_pipe_open,
63662306a36Sopenharmony_ci	.read	= spufs_mbox_read,
63762306a36Sopenharmony_ci	.llseek	= no_llseek,
63862306a36Sopenharmony_ci};
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
64162306a36Sopenharmony_ci			size_t len, loff_t *pos)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
64462306a36Sopenharmony_ci	ssize_t ret;
64562306a36Sopenharmony_ci	u32 mbox_stat;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (len < 4)
64862306a36Sopenharmony_ci		return -EINVAL;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	ret = spu_acquire(ctx);
65162306a36Sopenharmony_ci	if (ret)
65262306a36Sopenharmony_ci		return ret;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	spu_release(ctx);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
65962306a36Sopenharmony_ci		return -EFAULT;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	return 4;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic const struct file_operations spufs_mbox_stat_fops = {
66562306a36Sopenharmony_ci	.open	= spufs_pipe_open,
66662306a36Sopenharmony_ci	.read	= spufs_mbox_stat_read,
66762306a36Sopenharmony_ci	.llseek = no_llseek,
66862306a36Sopenharmony_ci};
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci/* low-level ibox access function */
67162306a36Sopenharmony_cisize_t spu_ibox_read(struct spu_context *ctx, u32 *data)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	return ctx->ops->ibox_read(ctx, data);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci/* interrupt-level ibox callback function. */
67762306a36Sopenharmony_civoid spufs_ibox_callback(struct spu *spu)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct spu_context *ctx = spu->ctx;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (ctx)
68262306a36Sopenharmony_ci		wake_up_all(&ctx->ibox_wq);
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci/*
68662306a36Sopenharmony_ci * Read as many bytes from the interrupt mailbox as possible, until
68762306a36Sopenharmony_ci * one of the conditions becomes true:
68862306a36Sopenharmony_ci *
68962306a36Sopenharmony_ci * - no more data available in the mailbox
69062306a36Sopenharmony_ci * - end of the user provided buffer
69162306a36Sopenharmony_ci * - end of the mapped area
69262306a36Sopenharmony_ci *
69362306a36Sopenharmony_ci * If the file is opened without O_NONBLOCK, we wait here until
69462306a36Sopenharmony_ci * any data is available, but return when we have been able to
69562306a36Sopenharmony_ci * read something.
69662306a36Sopenharmony_ci */
69762306a36Sopenharmony_cistatic ssize_t spufs_ibox_read(struct file *file, char __user *buf,
69862306a36Sopenharmony_ci			size_t len, loff_t *pos)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
70162306a36Sopenharmony_ci	u32 ibox_data, __user *udata = (void __user *)buf;
70262306a36Sopenharmony_ci	ssize_t count;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (len < 4)
70562306a36Sopenharmony_ci		return -EINVAL;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	count = spu_acquire(ctx);
70862306a36Sopenharmony_ci	if (count)
70962306a36Sopenharmony_ci		goto out;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/* wait only for the first element */
71262306a36Sopenharmony_ci	count = 0;
71362306a36Sopenharmony_ci	if (file->f_flags & O_NONBLOCK) {
71462306a36Sopenharmony_ci		if (!spu_ibox_read(ctx, &ibox_data)) {
71562306a36Sopenharmony_ci			count = -EAGAIN;
71662306a36Sopenharmony_ci			goto out_unlock;
71762306a36Sopenharmony_ci		}
71862306a36Sopenharmony_ci	} else {
71962306a36Sopenharmony_ci		count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
72062306a36Sopenharmony_ci		if (count)
72162306a36Sopenharmony_ci			goto out;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* if we can't write at all, return -EFAULT */
72562306a36Sopenharmony_ci	count = put_user(ibox_data, udata);
72662306a36Sopenharmony_ci	if (count)
72762306a36Sopenharmony_ci		goto out_unlock;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
73062306a36Sopenharmony_ci		int ret;
73162306a36Sopenharmony_ci		ret = ctx->ops->ibox_read(ctx, &ibox_data);
73262306a36Sopenharmony_ci		if (ret == 0)
73362306a36Sopenharmony_ci			break;
73462306a36Sopenharmony_ci		/*
73562306a36Sopenharmony_ci		 * at the end of the mapped area, we can fault
73662306a36Sopenharmony_ci		 * but still need to return the data we have
73762306a36Sopenharmony_ci		 * read successfully so far.
73862306a36Sopenharmony_ci		 */
73962306a36Sopenharmony_ci		ret = put_user(ibox_data, udata);
74062306a36Sopenharmony_ci		if (ret)
74162306a36Sopenharmony_ci			break;
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ciout_unlock:
74562306a36Sopenharmony_ci	spu_release(ctx);
74662306a36Sopenharmony_ciout:
74762306a36Sopenharmony_ci	return count;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic __poll_t spufs_ibox_poll(struct file *file, poll_table *wait)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
75362306a36Sopenharmony_ci	__poll_t mask;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	poll_wait(file, &ctx->ibox_wq, wait);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/*
75862306a36Sopenharmony_ci	 * For now keep this uninterruptible and also ignore the rule
75962306a36Sopenharmony_ci	 * that poll should not sleep.  Will be fixed later.
76062306a36Sopenharmony_ci	 */
76162306a36Sopenharmony_ci	mutex_lock(&ctx->state_mutex);
76262306a36Sopenharmony_ci	mask = ctx->ops->mbox_stat_poll(ctx, EPOLLIN | EPOLLRDNORM);
76362306a36Sopenharmony_ci	spu_release(ctx);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	return mask;
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic const struct file_operations spufs_ibox_fops = {
76962306a36Sopenharmony_ci	.open	= spufs_pipe_open,
77062306a36Sopenharmony_ci	.read	= spufs_ibox_read,
77162306a36Sopenharmony_ci	.poll	= spufs_ibox_poll,
77262306a36Sopenharmony_ci	.llseek = no_llseek,
77362306a36Sopenharmony_ci};
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
77662306a36Sopenharmony_ci			size_t len, loff_t *pos)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
77962306a36Sopenharmony_ci	ssize_t ret;
78062306a36Sopenharmony_ci	u32 ibox_stat;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (len < 4)
78362306a36Sopenharmony_ci		return -EINVAL;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	ret = spu_acquire(ctx);
78662306a36Sopenharmony_ci	if (ret)
78762306a36Sopenharmony_ci		return ret;
78862306a36Sopenharmony_ci	ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
78962306a36Sopenharmony_ci	spu_release(ctx);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
79262306a36Sopenharmony_ci		return -EFAULT;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	return 4;
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic const struct file_operations spufs_ibox_stat_fops = {
79862306a36Sopenharmony_ci	.open	= spufs_pipe_open,
79962306a36Sopenharmony_ci	.read	= spufs_ibox_stat_read,
80062306a36Sopenharmony_ci	.llseek = no_llseek,
80162306a36Sopenharmony_ci};
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci/* low-level mailbox write */
80462306a36Sopenharmony_cisize_t spu_wbox_write(struct spu_context *ctx, u32 data)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	return ctx->ops->wbox_write(ctx, data);
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci/* interrupt-level wbox callback function. */
81062306a36Sopenharmony_civoid spufs_wbox_callback(struct spu *spu)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	struct spu_context *ctx = spu->ctx;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (ctx)
81562306a36Sopenharmony_ci		wake_up_all(&ctx->wbox_wq);
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci/*
81962306a36Sopenharmony_ci * Write as many bytes to the interrupt mailbox as possible, until
82062306a36Sopenharmony_ci * one of the conditions becomes true:
82162306a36Sopenharmony_ci *
82262306a36Sopenharmony_ci * - the mailbox is full
82362306a36Sopenharmony_ci * - end of the user provided buffer
82462306a36Sopenharmony_ci * - end of the mapped area
82562306a36Sopenharmony_ci *
82662306a36Sopenharmony_ci * If the file is opened without O_NONBLOCK, we wait here until
82762306a36Sopenharmony_ci * space is available, but return when we have been able to
82862306a36Sopenharmony_ci * write something.
82962306a36Sopenharmony_ci */
83062306a36Sopenharmony_cistatic ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
83162306a36Sopenharmony_ci			size_t len, loff_t *pos)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
83462306a36Sopenharmony_ci	u32 wbox_data, __user *udata = (void __user *)buf;
83562306a36Sopenharmony_ci	ssize_t count;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	if (len < 4)
83862306a36Sopenharmony_ci		return -EINVAL;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if (get_user(wbox_data, udata))
84162306a36Sopenharmony_ci		return -EFAULT;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	count = spu_acquire(ctx);
84462306a36Sopenharmony_ci	if (count)
84562306a36Sopenharmony_ci		goto out;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	/*
84862306a36Sopenharmony_ci	 * make sure we can at least write one element, by waiting
84962306a36Sopenharmony_ci	 * in case of !O_NONBLOCK
85062306a36Sopenharmony_ci	 */
85162306a36Sopenharmony_ci	count = 0;
85262306a36Sopenharmony_ci	if (file->f_flags & O_NONBLOCK) {
85362306a36Sopenharmony_ci		if (!spu_wbox_write(ctx, wbox_data)) {
85462306a36Sopenharmony_ci			count = -EAGAIN;
85562306a36Sopenharmony_ci			goto out_unlock;
85662306a36Sopenharmony_ci		}
85762306a36Sopenharmony_ci	} else {
85862306a36Sopenharmony_ci		count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
85962306a36Sopenharmony_ci		if (count)
86062306a36Sopenharmony_ci			goto out;
86162306a36Sopenharmony_ci	}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	/* write as much as possible */
86562306a36Sopenharmony_ci	for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
86662306a36Sopenharmony_ci		int ret;
86762306a36Sopenharmony_ci		ret = get_user(wbox_data, udata);
86862306a36Sopenharmony_ci		if (ret)
86962306a36Sopenharmony_ci			break;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		ret = spu_wbox_write(ctx, wbox_data);
87262306a36Sopenharmony_ci		if (ret == 0)
87362306a36Sopenharmony_ci			break;
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ciout_unlock:
87762306a36Sopenharmony_ci	spu_release(ctx);
87862306a36Sopenharmony_ciout:
87962306a36Sopenharmony_ci	return count;
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic __poll_t spufs_wbox_poll(struct file *file, poll_table *wait)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
88562306a36Sopenharmony_ci	__poll_t mask;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	poll_wait(file, &ctx->wbox_wq, wait);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/*
89062306a36Sopenharmony_ci	 * For now keep this uninterruptible and also ignore the rule
89162306a36Sopenharmony_ci	 * that poll should not sleep.  Will be fixed later.
89262306a36Sopenharmony_ci	 */
89362306a36Sopenharmony_ci	mutex_lock(&ctx->state_mutex);
89462306a36Sopenharmony_ci	mask = ctx->ops->mbox_stat_poll(ctx, EPOLLOUT | EPOLLWRNORM);
89562306a36Sopenharmony_ci	spu_release(ctx);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	return mask;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic const struct file_operations spufs_wbox_fops = {
90162306a36Sopenharmony_ci	.open	= spufs_pipe_open,
90262306a36Sopenharmony_ci	.write	= spufs_wbox_write,
90362306a36Sopenharmony_ci	.poll	= spufs_wbox_poll,
90462306a36Sopenharmony_ci	.llseek = no_llseek,
90562306a36Sopenharmony_ci};
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
90862306a36Sopenharmony_ci			size_t len, loff_t *pos)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
91162306a36Sopenharmony_ci	ssize_t ret;
91262306a36Sopenharmony_ci	u32 wbox_stat;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	if (len < 4)
91562306a36Sopenharmony_ci		return -EINVAL;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	ret = spu_acquire(ctx);
91862306a36Sopenharmony_ci	if (ret)
91962306a36Sopenharmony_ci		return ret;
92062306a36Sopenharmony_ci	wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
92162306a36Sopenharmony_ci	spu_release(ctx);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
92462306a36Sopenharmony_ci		return -EFAULT;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	return 4;
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_cistatic const struct file_operations spufs_wbox_stat_fops = {
93062306a36Sopenharmony_ci	.open	= spufs_pipe_open,
93162306a36Sopenharmony_ci	.read	= spufs_wbox_stat_read,
93262306a36Sopenharmony_ci	.llseek = no_llseek,
93362306a36Sopenharmony_ci};
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_cistatic int spufs_signal1_open(struct inode *inode, struct file *file)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
93862306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
94162306a36Sopenharmony_ci	file->private_data = ctx;
94262306a36Sopenharmony_ci	if (!i->i_openers++)
94362306a36Sopenharmony_ci		ctx->signal1 = inode->i_mapping;
94462306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
94562306a36Sopenharmony_ci	return nonseekable_open(inode, file);
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cistatic int
94962306a36Sopenharmony_cispufs_signal1_release(struct inode *inode, struct file *file)
95062306a36Sopenharmony_ci{
95162306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
95262306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
95562306a36Sopenharmony_ci	if (!--i->i_openers)
95662306a36Sopenharmony_ci		ctx->signal1 = NULL;
95762306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
95862306a36Sopenharmony_ci	return 0;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic ssize_t spufs_signal1_dump(struct spu_context *ctx,
96262306a36Sopenharmony_ci		struct coredump_params *cprm)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	if (!ctx->csa.spu_chnlcnt_RW[3])
96562306a36Sopenharmony_ci		return 0;
96662306a36Sopenharmony_ci	return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[3],
96762306a36Sopenharmony_ci			       sizeof(ctx->csa.spu_chnldata_RW[3]));
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
97162306a36Sopenharmony_ci			size_t len)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	if (len < sizeof(ctx->csa.spu_chnldata_RW[3]))
97462306a36Sopenharmony_ci		return -EINVAL;
97562306a36Sopenharmony_ci	if (!ctx->csa.spu_chnlcnt_RW[3])
97662306a36Sopenharmony_ci		return 0;
97762306a36Sopenharmony_ci	if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[3],
97862306a36Sopenharmony_ci			 sizeof(ctx->csa.spu_chnldata_RW[3])))
97962306a36Sopenharmony_ci		return -EFAULT;
98062306a36Sopenharmony_ci	return sizeof(ctx->csa.spu_chnldata_RW[3]);
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cistatic ssize_t spufs_signal1_read(struct file *file, char __user *buf,
98462306a36Sopenharmony_ci			size_t len, loff_t *pos)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	int ret;
98762306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
99062306a36Sopenharmony_ci	if (ret)
99162306a36Sopenharmony_ci		return ret;
99262306a36Sopenharmony_ci	ret = __spufs_signal1_read(ctx, buf, len);
99362306a36Sopenharmony_ci	spu_release_saved(ctx);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	return ret;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
99962306a36Sopenharmony_ci			size_t len, loff_t *pos)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	struct spu_context *ctx;
100262306a36Sopenharmony_ci	ssize_t ret;
100362306a36Sopenharmony_ci	u32 data;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	ctx = file->private_data;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (len < 4)
100862306a36Sopenharmony_ci		return -EINVAL;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	if (copy_from_user(&data, buf, 4))
101162306a36Sopenharmony_ci		return -EFAULT;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	ret = spu_acquire(ctx);
101462306a36Sopenharmony_ci	if (ret)
101562306a36Sopenharmony_ci		return ret;
101662306a36Sopenharmony_ci	ctx->ops->signal1_write(ctx, data);
101762306a36Sopenharmony_ci	spu_release(ctx);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	return 4;
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_cistatic vm_fault_t
102362306a36Sopenharmony_cispufs_signal1_mmap_fault(struct vm_fault *vmf)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci#if SPUFS_SIGNAL_MAP_SIZE == 0x1000
102662306a36Sopenharmony_ci	return spufs_ps_fault(vmf, 0x14000, SPUFS_SIGNAL_MAP_SIZE);
102762306a36Sopenharmony_ci#elif SPUFS_SIGNAL_MAP_SIZE == 0x10000
102862306a36Sopenharmony_ci	/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
102962306a36Sopenharmony_ci	 * signal 1 and 2 area
103062306a36Sopenharmony_ci	 */
103162306a36Sopenharmony_ci	return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE);
103262306a36Sopenharmony_ci#else
103362306a36Sopenharmony_ci#error unsupported page size
103462306a36Sopenharmony_ci#endif
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic const struct vm_operations_struct spufs_signal1_mmap_vmops = {
103862306a36Sopenharmony_ci	.fault = spufs_signal1_mmap_fault,
103962306a36Sopenharmony_ci};
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	if (!(vma->vm_flags & VM_SHARED))
104462306a36Sopenharmony_ci		return -EINVAL;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO | VM_PFNMAP);
104762306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	vma->vm_ops = &spufs_signal1_mmap_vmops;
105062306a36Sopenharmony_ci	return 0;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic const struct file_operations spufs_signal1_fops = {
105462306a36Sopenharmony_ci	.open = spufs_signal1_open,
105562306a36Sopenharmony_ci	.release = spufs_signal1_release,
105662306a36Sopenharmony_ci	.read = spufs_signal1_read,
105762306a36Sopenharmony_ci	.write = spufs_signal1_write,
105862306a36Sopenharmony_ci	.mmap = spufs_signal1_mmap,
105962306a36Sopenharmony_ci	.llseek = no_llseek,
106062306a36Sopenharmony_ci};
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic const struct file_operations spufs_signal1_nosched_fops = {
106362306a36Sopenharmony_ci	.open = spufs_signal1_open,
106462306a36Sopenharmony_ci	.release = spufs_signal1_release,
106562306a36Sopenharmony_ci	.write = spufs_signal1_write,
106662306a36Sopenharmony_ci	.mmap = spufs_signal1_mmap,
106762306a36Sopenharmony_ci	.llseek = no_llseek,
106862306a36Sopenharmony_ci};
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic int spufs_signal2_open(struct inode *inode, struct file *file)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
107362306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
107662306a36Sopenharmony_ci	file->private_data = ctx;
107762306a36Sopenharmony_ci	if (!i->i_openers++)
107862306a36Sopenharmony_ci		ctx->signal2 = inode->i_mapping;
107962306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
108062306a36Sopenharmony_ci	return nonseekable_open(inode, file);
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic int
108462306a36Sopenharmony_cispufs_signal2_release(struct inode *inode, struct file *file)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
108762306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
109062306a36Sopenharmony_ci	if (!--i->i_openers)
109162306a36Sopenharmony_ci		ctx->signal2 = NULL;
109262306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
109362306a36Sopenharmony_ci	return 0;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic ssize_t spufs_signal2_dump(struct spu_context *ctx,
109762306a36Sopenharmony_ci		struct coredump_params *cprm)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	if (!ctx->csa.spu_chnlcnt_RW[4])
110062306a36Sopenharmony_ci		return 0;
110162306a36Sopenharmony_ci	return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[4],
110262306a36Sopenharmony_ci			       sizeof(ctx->csa.spu_chnldata_RW[4]));
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
110662306a36Sopenharmony_ci			size_t len)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	if (len < sizeof(ctx->csa.spu_chnldata_RW[4]))
110962306a36Sopenharmony_ci		return -EINVAL;
111062306a36Sopenharmony_ci	if (!ctx->csa.spu_chnlcnt_RW[4])
111162306a36Sopenharmony_ci		return 0;
111262306a36Sopenharmony_ci	if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[4],
111362306a36Sopenharmony_ci			 sizeof(ctx->csa.spu_chnldata_RW[4])))
111462306a36Sopenharmony_ci		return -EFAULT;
111562306a36Sopenharmony_ci	return sizeof(ctx->csa.spu_chnldata_RW[4]);
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cistatic ssize_t spufs_signal2_read(struct file *file, char __user *buf,
111962306a36Sopenharmony_ci			size_t len, loff_t *pos)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
112262306a36Sopenharmony_ci	int ret;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
112562306a36Sopenharmony_ci	if (ret)
112662306a36Sopenharmony_ci		return ret;
112762306a36Sopenharmony_ci	ret = __spufs_signal2_read(ctx, buf, len);
112862306a36Sopenharmony_ci	spu_release_saved(ctx);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	return ret;
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
113462306a36Sopenharmony_ci			size_t len, loff_t *pos)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	struct spu_context *ctx;
113762306a36Sopenharmony_ci	ssize_t ret;
113862306a36Sopenharmony_ci	u32 data;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	ctx = file->private_data;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	if (len < 4)
114362306a36Sopenharmony_ci		return -EINVAL;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	if (copy_from_user(&data, buf, 4))
114662306a36Sopenharmony_ci		return -EFAULT;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	ret = spu_acquire(ctx);
114962306a36Sopenharmony_ci	if (ret)
115062306a36Sopenharmony_ci		return ret;
115162306a36Sopenharmony_ci	ctx->ops->signal2_write(ctx, data);
115262306a36Sopenharmony_ci	spu_release(ctx);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	return 4;
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci#if SPUFS_MMAP_4K
115862306a36Sopenharmony_cistatic vm_fault_t
115962306a36Sopenharmony_cispufs_signal2_mmap_fault(struct vm_fault *vmf)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci#if SPUFS_SIGNAL_MAP_SIZE == 0x1000
116262306a36Sopenharmony_ci	return spufs_ps_fault(vmf, 0x1c000, SPUFS_SIGNAL_MAP_SIZE);
116362306a36Sopenharmony_ci#elif SPUFS_SIGNAL_MAP_SIZE == 0x10000
116462306a36Sopenharmony_ci	/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
116562306a36Sopenharmony_ci	 * signal 1 and 2 area
116662306a36Sopenharmony_ci	 */
116762306a36Sopenharmony_ci	return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE);
116862306a36Sopenharmony_ci#else
116962306a36Sopenharmony_ci#error unsupported page size
117062306a36Sopenharmony_ci#endif
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic const struct vm_operations_struct spufs_signal2_mmap_vmops = {
117462306a36Sopenharmony_ci	.fault = spufs_signal2_mmap_fault,
117562306a36Sopenharmony_ci};
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_cistatic int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
117862306a36Sopenharmony_ci{
117962306a36Sopenharmony_ci	if (!(vma->vm_flags & VM_SHARED))
118062306a36Sopenharmony_ci		return -EINVAL;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO | VM_PFNMAP);
118362306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	vma->vm_ops = &spufs_signal2_mmap_vmops;
118662306a36Sopenharmony_ci	return 0;
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci#else /* SPUFS_MMAP_4K */
118962306a36Sopenharmony_ci#define spufs_signal2_mmap NULL
119062306a36Sopenharmony_ci#endif /* !SPUFS_MMAP_4K */
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic const struct file_operations spufs_signal2_fops = {
119362306a36Sopenharmony_ci	.open = spufs_signal2_open,
119462306a36Sopenharmony_ci	.release = spufs_signal2_release,
119562306a36Sopenharmony_ci	.read = spufs_signal2_read,
119662306a36Sopenharmony_ci	.write = spufs_signal2_write,
119762306a36Sopenharmony_ci	.mmap = spufs_signal2_mmap,
119862306a36Sopenharmony_ci	.llseek = no_llseek,
119962306a36Sopenharmony_ci};
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_cistatic const struct file_operations spufs_signal2_nosched_fops = {
120262306a36Sopenharmony_ci	.open = spufs_signal2_open,
120362306a36Sopenharmony_ci	.release = spufs_signal2_release,
120462306a36Sopenharmony_ci	.write = spufs_signal2_write,
120562306a36Sopenharmony_ci	.mmap = spufs_signal2_mmap,
120662306a36Sopenharmony_ci	.llseek = no_llseek,
120762306a36Sopenharmony_ci};
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci/*
121062306a36Sopenharmony_ci * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the
121162306a36Sopenharmony_ci * work of acquiring (or not) the SPU context before calling through
121262306a36Sopenharmony_ci * to the actual get routine. The set routine is called directly.
121362306a36Sopenharmony_ci */
121462306a36Sopenharmony_ci#define SPU_ATTR_NOACQUIRE	0
121562306a36Sopenharmony_ci#define SPU_ATTR_ACQUIRE	1
121662306a36Sopenharmony_ci#define SPU_ATTR_ACQUIRE_SAVED	2
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci#define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire)	\
121962306a36Sopenharmony_cistatic int __##__get(void *data, u64 *val)				\
122062306a36Sopenharmony_ci{									\
122162306a36Sopenharmony_ci	struct spu_context *ctx = data;					\
122262306a36Sopenharmony_ci	int ret = 0;							\
122362306a36Sopenharmony_ci									\
122462306a36Sopenharmony_ci	if (__acquire == SPU_ATTR_ACQUIRE) {				\
122562306a36Sopenharmony_ci		ret = spu_acquire(ctx);					\
122662306a36Sopenharmony_ci		if (ret)						\
122762306a36Sopenharmony_ci			return ret;					\
122862306a36Sopenharmony_ci		*val = __get(ctx);					\
122962306a36Sopenharmony_ci		spu_release(ctx);					\
123062306a36Sopenharmony_ci	} else if (__acquire == SPU_ATTR_ACQUIRE_SAVED)	{		\
123162306a36Sopenharmony_ci		ret = spu_acquire_saved(ctx);				\
123262306a36Sopenharmony_ci		if (ret)						\
123362306a36Sopenharmony_ci			return ret;					\
123462306a36Sopenharmony_ci		*val = __get(ctx);					\
123562306a36Sopenharmony_ci		spu_release_saved(ctx);					\
123662306a36Sopenharmony_ci	} else								\
123762306a36Sopenharmony_ci		*val = __get(ctx);					\
123862306a36Sopenharmony_ci									\
123962306a36Sopenharmony_ci	return 0;							\
124062306a36Sopenharmony_ci}									\
124162306a36Sopenharmony_ciDEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic int spufs_signal1_type_set(void *data, u64 val)
124462306a36Sopenharmony_ci{
124562306a36Sopenharmony_ci	struct spu_context *ctx = data;
124662306a36Sopenharmony_ci	int ret;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	ret = spu_acquire(ctx);
124962306a36Sopenharmony_ci	if (ret)
125062306a36Sopenharmony_ci		return ret;
125162306a36Sopenharmony_ci	ctx->ops->signal1_type_set(ctx, val);
125262306a36Sopenharmony_ci	spu_release(ctx);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	return 0;
125562306a36Sopenharmony_ci}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic u64 spufs_signal1_type_get(struct spu_context *ctx)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	return ctx->ops->signal1_type_get(ctx);
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
126262306a36Sopenharmony_ci		       spufs_signal1_type_set, "%llu\n", SPU_ATTR_ACQUIRE);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic int spufs_signal2_type_set(void *data, u64 val)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	struct spu_context *ctx = data;
126862306a36Sopenharmony_ci	int ret;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	ret = spu_acquire(ctx);
127162306a36Sopenharmony_ci	if (ret)
127262306a36Sopenharmony_ci		return ret;
127362306a36Sopenharmony_ci	ctx->ops->signal2_type_set(ctx, val);
127462306a36Sopenharmony_ci	spu_release(ctx);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	return 0;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cistatic u64 spufs_signal2_type_get(struct spu_context *ctx)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	return ctx->ops->signal2_type_get(ctx);
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
128462306a36Sopenharmony_ci		       spufs_signal2_type_set, "%llu\n", SPU_ATTR_ACQUIRE);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci#if SPUFS_MMAP_4K
128762306a36Sopenharmony_cistatic vm_fault_t
128862306a36Sopenharmony_cispufs_mss_mmap_fault(struct vm_fault *vmf)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	return spufs_ps_fault(vmf, 0x0000, SPUFS_MSS_MAP_SIZE);
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_cistatic const struct vm_operations_struct spufs_mss_mmap_vmops = {
129462306a36Sopenharmony_ci	.fault = spufs_mss_mmap_fault,
129562306a36Sopenharmony_ci};
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci/*
129862306a36Sopenharmony_ci * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
129962306a36Sopenharmony_ci */
130062306a36Sopenharmony_cistatic int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
130162306a36Sopenharmony_ci{
130262306a36Sopenharmony_ci	if (!(vma->vm_flags & VM_SHARED))
130362306a36Sopenharmony_ci		return -EINVAL;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO | VM_PFNMAP);
130662306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	vma->vm_ops = &spufs_mss_mmap_vmops;
130962306a36Sopenharmony_ci	return 0;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci#else /* SPUFS_MMAP_4K */
131262306a36Sopenharmony_ci#define spufs_mss_mmap NULL
131362306a36Sopenharmony_ci#endif /* !SPUFS_MMAP_4K */
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic int spufs_mss_open(struct inode *inode, struct file *file)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
131862306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	file->private_data = i->i_ctx;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
132362306a36Sopenharmony_ci	if (!i->i_openers++)
132462306a36Sopenharmony_ci		ctx->mss = inode->i_mapping;
132562306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
132662306a36Sopenharmony_ci	return nonseekable_open(inode, file);
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cistatic int
133062306a36Sopenharmony_cispufs_mss_release(struct inode *inode, struct file *file)
133162306a36Sopenharmony_ci{
133262306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
133362306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
133662306a36Sopenharmony_ci	if (!--i->i_openers)
133762306a36Sopenharmony_ci		ctx->mss = NULL;
133862306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
133962306a36Sopenharmony_ci	return 0;
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic const struct file_operations spufs_mss_fops = {
134362306a36Sopenharmony_ci	.open	 = spufs_mss_open,
134462306a36Sopenharmony_ci	.release = spufs_mss_release,
134562306a36Sopenharmony_ci	.mmap	 = spufs_mss_mmap,
134662306a36Sopenharmony_ci	.llseek  = no_llseek,
134762306a36Sopenharmony_ci};
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_cistatic vm_fault_t
135062306a36Sopenharmony_cispufs_psmap_mmap_fault(struct vm_fault *vmf)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	return spufs_ps_fault(vmf, 0x0000, SPUFS_PS_MAP_SIZE);
135362306a36Sopenharmony_ci}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_cistatic const struct vm_operations_struct spufs_psmap_mmap_vmops = {
135662306a36Sopenharmony_ci	.fault = spufs_psmap_mmap_fault,
135762306a36Sopenharmony_ci};
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci/*
136062306a36Sopenharmony_ci * mmap support for full problem state area [0x00000 - 0x1ffff].
136162306a36Sopenharmony_ci */
136262306a36Sopenharmony_cistatic int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma)
136362306a36Sopenharmony_ci{
136462306a36Sopenharmony_ci	if (!(vma->vm_flags & VM_SHARED))
136562306a36Sopenharmony_ci		return -EINVAL;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO | VM_PFNMAP);
136862306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	vma->vm_ops = &spufs_psmap_mmap_vmops;
137162306a36Sopenharmony_ci	return 0;
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_cistatic int spufs_psmap_open(struct inode *inode, struct file *file)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
137762306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
138062306a36Sopenharmony_ci	file->private_data = i->i_ctx;
138162306a36Sopenharmony_ci	if (!i->i_openers++)
138262306a36Sopenharmony_ci		ctx->psmap = inode->i_mapping;
138362306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
138462306a36Sopenharmony_ci	return nonseekable_open(inode, file);
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_cistatic int
138862306a36Sopenharmony_cispufs_psmap_release(struct inode *inode, struct file *file)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
139162306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
139462306a36Sopenharmony_ci	if (!--i->i_openers)
139562306a36Sopenharmony_ci		ctx->psmap = NULL;
139662306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
139762306a36Sopenharmony_ci	return 0;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic const struct file_operations spufs_psmap_fops = {
140162306a36Sopenharmony_ci	.open	 = spufs_psmap_open,
140262306a36Sopenharmony_ci	.release = spufs_psmap_release,
140362306a36Sopenharmony_ci	.mmap	 = spufs_psmap_mmap,
140462306a36Sopenharmony_ci	.llseek  = no_llseek,
140562306a36Sopenharmony_ci};
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci#if SPUFS_MMAP_4K
140962306a36Sopenharmony_cistatic vm_fault_t
141062306a36Sopenharmony_cispufs_mfc_mmap_fault(struct vm_fault *vmf)
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci	return spufs_ps_fault(vmf, 0x3000, SPUFS_MFC_MAP_SIZE);
141362306a36Sopenharmony_ci}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_cistatic const struct vm_operations_struct spufs_mfc_mmap_vmops = {
141662306a36Sopenharmony_ci	.fault = spufs_mfc_mmap_fault,
141762306a36Sopenharmony_ci};
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci/*
142062306a36Sopenharmony_ci * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
142162306a36Sopenharmony_ci */
142262306a36Sopenharmony_cistatic int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
142362306a36Sopenharmony_ci{
142462306a36Sopenharmony_ci	if (!(vma->vm_flags & VM_SHARED))
142562306a36Sopenharmony_ci		return -EINVAL;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO | VM_PFNMAP);
142862306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	vma->vm_ops = &spufs_mfc_mmap_vmops;
143162306a36Sopenharmony_ci	return 0;
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci#else /* SPUFS_MMAP_4K */
143462306a36Sopenharmony_ci#define spufs_mfc_mmap NULL
143562306a36Sopenharmony_ci#endif /* !SPUFS_MMAP_4K */
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cistatic int spufs_mfc_open(struct inode *inode, struct file *file)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
144062306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	/* we don't want to deal with DMA into other processes */
144362306a36Sopenharmony_ci	if (ctx->owner != current->mm)
144462306a36Sopenharmony_ci		return -EINVAL;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (atomic_read(&inode->i_count) != 1)
144762306a36Sopenharmony_ci		return -EBUSY;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
145062306a36Sopenharmony_ci	file->private_data = ctx;
145162306a36Sopenharmony_ci	if (!i->i_openers++)
145262306a36Sopenharmony_ci		ctx->mfc = inode->i_mapping;
145362306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
145462306a36Sopenharmony_ci	return nonseekable_open(inode, file);
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic int
145862306a36Sopenharmony_cispufs_mfc_release(struct inode *inode, struct file *file)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
146162306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	mutex_lock(&ctx->mapping_lock);
146462306a36Sopenharmony_ci	if (!--i->i_openers)
146562306a36Sopenharmony_ci		ctx->mfc = NULL;
146662306a36Sopenharmony_ci	mutex_unlock(&ctx->mapping_lock);
146762306a36Sopenharmony_ci	return 0;
146862306a36Sopenharmony_ci}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci/* interrupt-level mfc callback function. */
147162306a36Sopenharmony_civoid spufs_mfc_callback(struct spu *spu)
147262306a36Sopenharmony_ci{
147362306a36Sopenharmony_ci	struct spu_context *ctx = spu->ctx;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	if (ctx)
147662306a36Sopenharmony_ci		wake_up_all(&ctx->mfc_wq);
147762306a36Sopenharmony_ci}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cistatic int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	/* See if there is one tag group is complete */
148262306a36Sopenharmony_ci	/* FIXME we need locking around tagwait */
148362306a36Sopenharmony_ci	*status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait;
148462306a36Sopenharmony_ci	ctx->tagwait &= ~*status;
148562306a36Sopenharmony_ci	if (*status)
148662306a36Sopenharmony_ci		return 1;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	/* enable interrupt waiting for any tag group,
148962306a36Sopenharmony_ci	   may silently fail if interrupts are already enabled */
149062306a36Sopenharmony_ci	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
149162306a36Sopenharmony_ci	return 0;
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_cistatic ssize_t spufs_mfc_read(struct file *file, char __user *buffer,
149562306a36Sopenharmony_ci			size_t size, loff_t *pos)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
149862306a36Sopenharmony_ci	int ret = -EINVAL;
149962306a36Sopenharmony_ci	u32 status;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	if (size != 4)
150262306a36Sopenharmony_ci		goto out;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	ret = spu_acquire(ctx);
150562306a36Sopenharmony_ci	if (ret)
150662306a36Sopenharmony_ci		return ret;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	ret = -EINVAL;
150962306a36Sopenharmony_ci	if (file->f_flags & O_NONBLOCK) {
151062306a36Sopenharmony_ci		status = ctx->ops->read_mfc_tagstatus(ctx);
151162306a36Sopenharmony_ci		if (!(status & ctx->tagwait))
151262306a36Sopenharmony_ci			ret = -EAGAIN;
151362306a36Sopenharmony_ci		else
151462306a36Sopenharmony_ci			/* XXX(hch): shouldn't we clear ret here? */
151562306a36Sopenharmony_ci			ctx->tagwait &= ~status;
151662306a36Sopenharmony_ci	} else {
151762306a36Sopenharmony_ci		ret = spufs_wait(ctx->mfc_wq,
151862306a36Sopenharmony_ci			   spufs_read_mfc_tagstatus(ctx, &status));
151962306a36Sopenharmony_ci		if (ret)
152062306a36Sopenharmony_ci			goto out;
152162306a36Sopenharmony_ci	}
152262306a36Sopenharmony_ci	spu_release(ctx);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	ret = 4;
152562306a36Sopenharmony_ci	if (copy_to_user(buffer, &status, 4))
152662306a36Sopenharmony_ci		ret = -EFAULT;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ciout:
152962306a36Sopenharmony_ci	return ret;
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_cistatic int spufs_check_valid_dma(struct mfc_dma_command *cmd)
153362306a36Sopenharmony_ci{
153462306a36Sopenharmony_ci	pr_debug("queueing DMA %x %llx %x %x %x\n", cmd->lsa,
153562306a36Sopenharmony_ci		 cmd->ea, cmd->size, cmd->tag, cmd->cmd);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	switch (cmd->cmd) {
153862306a36Sopenharmony_ci	case MFC_PUT_CMD:
153962306a36Sopenharmony_ci	case MFC_PUTF_CMD:
154062306a36Sopenharmony_ci	case MFC_PUTB_CMD:
154162306a36Sopenharmony_ci	case MFC_GET_CMD:
154262306a36Sopenharmony_ci	case MFC_GETF_CMD:
154362306a36Sopenharmony_ci	case MFC_GETB_CMD:
154462306a36Sopenharmony_ci		break;
154562306a36Sopenharmony_ci	default:
154662306a36Sopenharmony_ci		pr_debug("invalid DMA opcode %x\n", cmd->cmd);
154762306a36Sopenharmony_ci		return -EIO;
154862306a36Sopenharmony_ci	}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) {
155162306a36Sopenharmony_ci		pr_debug("invalid DMA alignment, ea %llx lsa %x\n",
155262306a36Sopenharmony_ci				cmd->ea, cmd->lsa);
155362306a36Sopenharmony_ci		return -EIO;
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	switch (cmd->size & 0xf) {
155762306a36Sopenharmony_ci	case 1:
155862306a36Sopenharmony_ci		break;
155962306a36Sopenharmony_ci	case 2:
156062306a36Sopenharmony_ci		if (cmd->lsa & 1)
156162306a36Sopenharmony_ci			goto error;
156262306a36Sopenharmony_ci		break;
156362306a36Sopenharmony_ci	case 4:
156462306a36Sopenharmony_ci		if (cmd->lsa & 3)
156562306a36Sopenharmony_ci			goto error;
156662306a36Sopenharmony_ci		break;
156762306a36Sopenharmony_ci	case 8:
156862306a36Sopenharmony_ci		if (cmd->lsa & 7)
156962306a36Sopenharmony_ci			goto error;
157062306a36Sopenharmony_ci		break;
157162306a36Sopenharmony_ci	case 0:
157262306a36Sopenharmony_ci		if (cmd->lsa & 15)
157362306a36Sopenharmony_ci			goto error;
157462306a36Sopenharmony_ci		break;
157562306a36Sopenharmony_ci	error:
157662306a36Sopenharmony_ci	default:
157762306a36Sopenharmony_ci		pr_debug("invalid DMA alignment %x for size %x\n",
157862306a36Sopenharmony_ci			cmd->lsa & 0xf, cmd->size);
157962306a36Sopenharmony_ci		return -EIO;
158062306a36Sopenharmony_ci	}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	if (cmd->size > 16 * 1024) {
158362306a36Sopenharmony_ci		pr_debug("invalid DMA size %x\n", cmd->size);
158462306a36Sopenharmony_ci		return -EIO;
158562306a36Sopenharmony_ci	}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	if (cmd->tag & 0xfff0) {
158862306a36Sopenharmony_ci		/* we reserve the higher tag numbers for kernel use */
158962306a36Sopenharmony_ci		pr_debug("invalid DMA tag\n");
159062306a36Sopenharmony_ci		return -EIO;
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	if (cmd->class) {
159462306a36Sopenharmony_ci		/* not supported in this version */
159562306a36Sopenharmony_ci		pr_debug("invalid DMA class\n");
159662306a36Sopenharmony_ci		return -EIO;
159762306a36Sopenharmony_ci	}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	return 0;
160062306a36Sopenharmony_ci}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_cistatic int spu_send_mfc_command(struct spu_context *ctx,
160362306a36Sopenharmony_ci				struct mfc_dma_command cmd,
160462306a36Sopenharmony_ci				int *error)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	*error = ctx->ops->send_mfc_command(ctx, &cmd);
160762306a36Sopenharmony_ci	if (*error == -EAGAIN) {
160862306a36Sopenharmony_ci		/* wait for any tag group to complete
160962306a36Sopenharmony_ci		   so we have space for the new command */
161062306a36Sopenharmony_ci		ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
161162306a36Sopenharmony_ci		/* try again, because the queue might be
161262306a36Sopenharmony_ci		   empty again */
161362306a36Sopenharmony_ci		*error = ctx->ops->send_mfc_command(ctx, &cmd);
161462306a36Sopenharmony_ci		if (*error == -EAGAIN)
161562306a36Sopenharmony_ci			return 0;
161662306a36Sopenharmony_ci	}
161762306a36Sopenharmony_ci	return 1;
161862306a36Sopenharmony_ci}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_cistatic ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
162162306a36Sopenharmony_ci			size_t size, loff_t *pos)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
162462306a36Sopenharmony_ci	struct mfc_dma_command cmd;
162562306a36Sopenharmony_ci	int ret = -EINVAL;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	if (size != sizeof cmd)
162862306a36Sopenharmony_ci		goto out;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	ret = -EFAULT;
163162306a36Sopenharmony_ci	if (copy_from_user(&cmd, buffer, sizeof cmd))
163262306a36Sopenharmony_ci		goto out;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	ret = spufs_check_valid_dma(&cmd);
163562306a36Sopenharmony_ci	if (ret)
163662306a36Sopenharmony_ci		goto out;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	ret = spu_acquire(ctx);
163962306a36Sopenharmony_ci	if (ret)
164062306a36Sopenharmony_ci		goto out;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE);
164362306a36Sopenharmony_ci	if (ret)
164462306a36Sopenharmony_ci		goto out;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	if (file->f_flags & O_NONBLOCK) {
164762306a36Sopenharmony_ci		ret = ctx->ops->send_mfc_command(ctx, &cmd);
164862306a36Sopenharmony_ci	} else {
164962306a36Sopenharmony_ci		int status;
165062306a36Sopenharmony_ci		ret = spufs_wait(ctx->mfc_wq,
165162306a36Sopenharmony_ci				 spu_send_mfc_command(ctx, cmd, &status));
165262306a36Sopenharmony_ci		if (ret)
165362306a36Sopenharmony_ci			goto out;
165462306a36Sopenharmony_ci		if (status)
165562306a36Sopenharmony_ci			ret = status;
165662306a36Sopenharmony_ci	}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	if (ret)
165962306a36Sopenharmony_ci		goto out_unlock;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	ctx->tagwait |= 1 << cmd.tag;
166262306a36Sopenharmony_ci	ret = size;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ciout_unlock:
166562306a36Sopenharmony_ci	spu_release(ctx);
166662306a36Sopenharmony_ciout:
166762306a36Sopenharmony_ci	return ret;
166862306a36Sopenharmony_ci}
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_cistatic __poll_t spufs_mfc_poll(struct file *file,poll_table *wait)
167162306a36Sopenharmony_ci{
167262306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
167362306a36Sopenharmony_ci	u32 free_elements, tagstatus;
167462306a36Sopenharmony_ci	__poll_t mask;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	poll_wait(file, &ctx->mfc_wq, wait);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	/*
167962306a36Sopenharmony_ci	 * For now keep this uninterruptible and also ignore the rule
168062306a36Sopenharmony_ci	 * that poll should not sleep.  Will be fixed later.
168162306a36Sopenharmony_ci	 */
168262306a36Sopenharmony_ci	mutex_lock(&ctx->state_mutex);
168362306a36Sopenharmony_ci	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
168462306a36Sopenharmony_ci	free_elements = ctx->ops->get_mfc_free_elements(ctx);
168562306a36Sopenharmony_ci	tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
168662306a36Sopenharmony_ci	spu_release(ctx);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	mask = 0;
168962306a36Sopenharmony_ci	if (free_elements & 0xffff)
169062306a36Sopenharmony_ci		mask |= EPOLLOUT | EPOLLWRNORM;
169162306a36Sopenharmony_ci	if (tagstatus & ctx->tagwait)
169262306a36Sopenharmony_ci		mask |= EPOLLIN | EPOLLRDNORM;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	pr_debug("%s: free %d tagstatus %d tagwait %d\n", __func__,
169562306a36Sopenharmony_ci		free_elements, tagstatus, ctx->tagwait);
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	return mask;
169862306a36Sopenharmony_ci}
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_cistatic int spufs_mfc_flush(struct file *file, fl_owner_t id)
170162306a36Sopenharmony_ci{
170262306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
170362306a36Sopenharmony_ci	int ret;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	ret = spu_acquire(ctx);
170662306a36Sopenharmony_ci	if (ret)
170762306a36Sopenharmony_ci		goto out;
170862306a36Sopenharmony_ci#if 0
170962306a36Sopenharmony_ci/* this currently hangs */
171062306a36Sopenharmony_ci	ret = spufs_wait(ctx->mfc_wq,
171162306a36Sopenharmony_ci			 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2));
171262306a36Sopenharmony_ci	if (ret)
171362306a36Sopenharmony_ci		goto out;
171462306a36Sopenharmony_ci	ret = spufs_wait(ctx->mfc_wq,
171562306a36Sopenharmony_ci			 ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait);
171662306a36Sopenharmony_ci	if (ret)
171762306a36Sopenharmony_ci		goto out;
171862306a36Sopenharmony_ci#else
171962306a36Sopenharmony_ci	ret = 0;
172062306a36Sopenharmony_ci#endif
172162306a36Sopenharmony_ci	spu_release(ctx);
172262306a36Sopenharmony_ciout:
172362306a36Sopenharmony_ci	return ret;
172462306a36Sopenharmony_ci}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_cistatic int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync)
172762306a36Sopenharmony_ci{
172862306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
172962306a36Sopenharmony_ci	int err = file_write_and_wait_range(file, start, end);
173062306a36Sopenharmony_ci	if (!err) {
173162306a36Sopenharmony_ci		inode_lock(inode);
173262306a36Sopenharmony_ci		err = spufs_mfc_flush(file, NULL);
173362306a36Sopenharmony_ci		inode_unlock(inode);
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci	return err;
173662306a36Sopenharmony_ci}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_cistatic const struct file_operations spufs_mfc_fops = {
173962306a36Sopenharmony_ci	.open	 = spufs_mfc_open,
174062306a36Sopenharmony_ci	.release = spufs_mfc_release,
174162306a36Sopenharmony_ci	.read	 = spufs_mfc_read,
174262306a36Sopenharmony_ci	.write	 = spufs_mfc_write,
174362306a36Sopenharmony_ci	.poll	 = spufs_mfc_poll,
174462306a36Sopenharmony_ci	.flush	 = spufs_mfc_flush,
174562306a36Sopenharmony_ci	.fsync	 = spufs_mfc_fsync,
174662306a36Sopenharmony_ci	.mmap	 = spufs_mfc_mmap,
174762306a36Sopenharmony_ci	.llseek  = no_llseek,
174862306a36Sopenharmony_ci};
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_cistatic int spufs_npc_set(void *data, u64 val)
175162306a36Sopenharmony_ci{
175262306a36Sopenharmony_ci	struct spu_context *ctx = data;
175362306a36Sopenharmony_ci	int ret;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	ret = spu_acquire(ctx);
175662306a36Sopenharmony_ci	if (ret)
175762306a36Sopenharmony_ci		return ret;
175862306a36Sopenharmony_ci	ctx->ops->npc_write(ctx, val);
175962306a36Sopenharmony_ci	spu_release(ctx);
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	return 0;
176262306a36Sopenharmony_ci}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_cistatic u64 spufs_npc_get(struct spu_context *ctx)
176562306a36Sopenharmony_ci{
176662306a36Sopenharmony_ci	return ctx->ops->npc_read(ctx);
176762306a36Sopenharmony_ci}
176862306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set,
176962306a36Sopenharmony_ci		       "0x%llx\n", SPU_ATTR_ACQUIRE);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_cistatic int spufs_decr_set(void *data, u64 val)
177262306a36Sopenharmony_ci{
177362306a36Sopenharmony_ci	struct spu_context *ctx = data;
177462306a36Sopenharmony_ci	struct spu_lscsa *lscsa = ctx->csa.lscsa;
177562306a36Sopenharmony_ci	int ret;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
177862306a36Sopenharmony_ci	if (ret)
177962306a36Sopenharmony_ci		return ret;
178062306a36Sopenharmony_ci	lscsa->decr.slot[0] = (u32) val;
178162306a36Sopenharmony_ci	spu_release_saved(ctx);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	return 0;
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cistatic u64 spufs_decr_get(struct spu_context *ctx)
178762306a36Sopenharmony_ci{
178862306a36Sopenharmony_ci	struct spu_lscsa *lscsa = ctx->csa.lscsa;
178962306a36Sopenharmony_ci	return lscsa->decr.slot[0];
179062306a36Sopenharmony_ci}
179162306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
179262306a36Sopenharmony_ci		       "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED);
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_cistatic int spufs_decr_status_set(void *data, u64 val)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	struct spu_context *ctx = data;
179762306a36Sopenharmony_ci	int ret;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
180062306a36Sopenharmony_ci	if (ret)
180162306a36Sopenharmony_ci		return ret;
180262306a36Sopenharmony_ci	if (val)
180362306a36Sopenharmony_ci		ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
180462306a36Sopenharmony_ci	else
180562306a36Sopenharmony_ci		ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
180662306a36Sopenharmony_ci	spu_release_saved(ctx);
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	return 0;
180962306a36Sopenharmony_ci}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_cistatic u64 spufs_decr_status_get(struct spu_context *ctx)
181262306a36Sopenharmony_ci{
181362306a36Sopenharmony_ci	if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING)
181462306a36Sopenharmony_ci		return SPU_DECR_STATUS_RUNNING;
181562306a36Sopenharmony_ci	else
181662306a36Sopenharmony_ci		return 0;
181762306a36Sopenharmony_ci}
181862306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
181962306a36Sopenharmony_ci		       spufs_decr_status_set, "0x%llx\n",
182062306a36Sopenharmony_ci		       SPU_ATTR_ACQUIRE_SAVED);
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_cistatic int spufs_event_mask_set(void *data, u64 val)
182362306a36Sopenharmony_ci{
182462306a36Sopenharmony_ci	struct spu_context *ctx = data;
182562306a36Sopenharmony_ci	struct spu_lscsa *lscsa = ctx->csa.lscsa;
182662306a36Sopenharmony_ci	int ret;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
182962306a36Sopenharmony_ci	if (ret)
183062306a36Sopenharmony_ci		return ret;
183162306a36Sopenharmony_ci	lscsa->event_mask.slot[0] = (u32) val;
183262306a36Sopenharmony_ci	spu_release_saved(ctx);
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	return 0;
183562306a36Sopenharmony_ci}
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_cistatic u64 spufs_event_mask_get(struct spu_context *ctx)
183862306a36Sopenharmony_ci{
183962306a36Sopenharmony_ci	struct spu_lscsa *lscsa = ctx->csa.lscsa;
184062306a36Sopenharmony_ci	return lscsa->event_mask.slot[0];
184162306a36Sopenharmony_ci}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
184462306a36Sopenharmony_ci		       spufs_event_mask_set, "0x%llx\n",
184562306a36Sopenharmony_ci		       SPU_ATTR_ACQUIRE_SAVED);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_cistatic u64 spufs_event_status_get(struct spu_context *ctx)
184862306a36Sopenharmony_ci{
184962306a36Sopenharmony_ci	struct spu_state *state = &ctx->csa;
185062306a36Sopenharmony_ci	u64 stat;
185162306a36Sopenharmony_ci	stat = state->spu_chnlcnt_RW[0];
185262306a36Sopenharmony_ci	if (stat)
185362306a36Sopenharmony_ci		return state->spu_chnldata_RW[0];
185462306a36Sopenharmony_ci	return 0;
185562306a36Sopenharmony_ci}
185662306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
185762306a36Sopenharmony_ci		       NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED)
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_cistatic int spufs_srr0_set(void *data, u64 val)
186062306a36Sopenharmony_ci{
186162306a36Sopenharmony_ci	struct spu_context *ctx = data;
186262306a36Sopenharmony_ci	struct spu_lscsa *lscsa = ctx->csa.lscsa;
186362306a36Sopenharmony_ci	int ret;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
186662306a36Sopenharmony_ci	if (ret)
186762306a36Sopenharmony_ci		return ret;
186862306a36Sopenharmony_ci	lscsa->srr0.slot[0] = (u32) val;
186962306a36Sopenharmony_ci	spu_release_saved(ctx);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	return 0;
187262306a36Sopenharmony_ci}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_cistatic u64 spufs_srr0_get(struct spu_context *ctx)
187562306a36Sopenharmony_ci{
187662306a36Sopenharmony_ci	struct spu_lscsa *lscsa = ctx->csa.lscsa;
187762306a36Sopenharmony_ci	return lscsa->srr0.slot[0];
187862306a36Sopenharmony_ci}
187962306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
188062306a36Sopenharmony_ci		       "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED)
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_cistatic u64 spufs_id_get(struct spu_context *ctx)
188362306a36Sopenharmony_ci{
188462306a36Sopenharmony_ci	u64 num;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	if (ctx->state == SPU_STATE_RUNNABLE)
188762306a36Sopenharmony_ci		num = ctx->spu->number;
188862306a36Sopenharmony_ci	else
188962306a36Sopenharmony_ci		num = (unsigned int)-1;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	return num;
189262306a36Sopenharmony_ci}
189362306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n",
189462306a36Sopenharmony_ci		       SPU_ATTR_ACQUIRE)
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_cistatic u64 spufs_object_id_get(struct spu_context *ctx)
189762306a36Sopenharmony_ci{
189862306a36Sopenharmony_ci	/* FIXME: Should there really be no locking here? */
189962306a36Sopenharmony_ci	return ctx->object_id;
190062306a36Sopenharmony_ci}
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_cistatic int spufs_object_id_set(void *data, u64 id)
190362306a36Sopenharmony_ci{
190462306a36Sopenharmony_ci	struct spu_context *ctx = data;
190562306a36Sopenharmony_ci	ctx->object_id = id;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	return 0;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get,
191162306a36Sopenharmony_ci		       spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_cistatic u64 spufs_lslr_get(struct spu_context *ctx)
191462306a36Sopenharmony_ci{
191562306a36Sopenharmony_ci	return ctx->csa.priv2.spu_lslr_RW;
191662306a36Sopenharmony_ci}
191762306a36Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n",
191862306a36Sopenharmony_ci		       SPU_ATTR_ACQUIRE_SAVED);
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_cistatic int spufs_info_open(struct inode *inode, struct file *file)
192162306a36Sopenharmony_ci{
192262306a36Sopenharmony_ci	struct spufs_inode_info *i = SPUFS_I(inode);
192362306a36Sopenharmony_ci	struct spu_context *ctx = i->i_ctx;
192462306a36Sopenharmony_ci	file->private_data = ctx;
192562306a36Sopenharmony_ci	return 0;
192662306a36Sopenharmony_ci}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_cistatic int spufs_caps_show(struct seq_file *s, void *private)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	struct spu_context *ctx = s->private;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (!(ctx->flags & SPU_CREATE_NOSCHED))
193362306a36Sopenharmony_ci		seq_puts(s, "sched\n");
193462306a36Sopenharmony_ci	if (!(ctx->flags & SPU_CREATE_ISOLATE))
193562306a36Sopenharmony_ci		seq_puts(s, "step\n");
193662306a36Sopenharmony_ci	return 0;
193762306a36Sopenharmony_ci}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_cistatic int spufs_caps_open(struct inode *inode, struct file *file)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx);
194262306a36Sopenharmony_ci}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_cistatic const struct file_operations spufs_caps_fops = {
194562306a36Sopenharmony_ci	.open		= spufs_caps_open,
194662306a36Sopenharmony_ci	.read		= seq_read,
194762306a36Sopenharmony_ci	.llseek		= seq_lseek,
194862306a36Sopenharmony_ci	.release	= single_release,
194962306a36Sopenharmony_ci};
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_cistatic ssize_t spufs_mbox_info_dump(struct spu_context *ctx,
195262306a36Sopenharmony_ci		struct coredump_params *cprm)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	if (!(ctx->csa.prob.mb_stat_R & 0x0000ff))
195562306a36Sopenharmony_ci		return 0;
195662306a36Sopenharmony_ci	return spufs_dump_emit(cprm, &ctx->csa.prob.pu_mb_R,
195762306a36Sopenharmony_ci			       sizeof(ctx->csa.prob.pu_mb_R));
195862306a36Sopenharmony_ci}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_cistatic ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
196162306a36Sopenharmony_ci				   size_t len, loff_t *pos)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
196462306a36Sopenharmony_ci	u32 stat, data;
196562306a36Sopenharmony_ci	int ret;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
196862306a36Sopenharmony_ci	if (ret)
196962306a36Sopenharmony_ci		return ret;
197062306a36Sopenharmony_ci	spin_lock(&ctx->csa.register_lock);
197162306a36Sopenharmony_ci	stat = ctx->csa.prob.mb_stat_R;
197262306a36Sopenharmony_ci	data = ctx->csa.prob.pu_mb_R;
197362306a36Sopenharmony_ci	spin_unlock(&ctx->csa.register_lock);
197462306a36Sopenharmony_ci	spu_release_saved(ctx);
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	/* EOF if there's no entry in the mbox */
197762306a36Sopenharmony_ci	if (!(stat & 0x0000ff))
197862306a36Sopenharmony_ci		return 0;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_cistatic const struct file_operations spufs_mbox_info_fops = {
198462306a36Sopenharmony_ci	.open = spufs_info_open,
198562306a36Sopenharmony_ci	.read = spufs_mbox_info_read,
198662306a36Sopenharmony_ci	.llseek  = generic_file_llseek,
198762306a36Sopenharmony_ci};
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_cistatic ssize_t spufs_ibox_info_dump(struct spu_context *ctx,
199062306a36Sopenharmony_ci		struct coredump_params *cprm)
199162306a36Sopenharmony_ci{
199262306a36Sopenharmony_ci	if (!(ctx->csa.prob.mb_stat_R & 0xff0000))
199362306a36Sopenharmony_ci		return 0;
199462306a36Sopenharmony_ci	return spufs_dump_emit(cprm, &ctx->csa.priv2.puint_mb_R,
199562306a36Sopenharmony_ci			       sizeof(ctx->csa.priv2.puint_mb_R));
199662306a36Sopenharmony_ci}
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_cistatic ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
199962306a36Sopenharmony_ci				   size_t len, loff_t *pos)
200062306a36Sopenharmony_ci{
200162306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
200262306a36Sopenharmony_ci	u32 stat, data;
200362306a36Sopenharmony_ci	int ret;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
200662306a36Sopenharmony_ci	if (ret)
200762306a36Sopenharmony_ci		return ret;
200862306a36Sopenharmony_ci	spin_lock(&ctx->csa.register_lock);
200962306a36Sopenharmony_ci	stat = ctx->csa.prob.mb_stat_R;
201062306a36Sopenharmony_ci	data = ctx->csa.priv2.puint_mb_R;
201162306a36Sopenharmony_ci	spin_unlock(&ctx->csa.register_lock);
201262306a36Sopenharmony_ci	spu_release_saved(ctx);
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	/* EOF if there's no entry in the ibox */
201562306a36Sopenharmony_ci	if (!(stat & 0xff0000))
201662306a36Sopenharmony_ci		return 0;
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
201962306a36Sopenharmony_ci}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_cistatic const struct file_operations spufs_ibox_info_fops = {
202262306a36Sopenharmony_ci	.open = spufs_info_open,
202362306a36Sopenharmony_ci	.read = spufs_ibox_info_read,
202462306a36Sopenharmony_ci	.llseek  = generic_file_llseek,
202562306a36Sopenharmony_ci};
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_cistatic size_t spufs_wbox_info_cnt(struct spu_context *ctx)
202862306a36Sopenharmony_ci{
202962306a36Sopenharmony_ci	return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
203062306a36Sopenharmony_ci}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_cistatic ssize_t spufs_wbox_info_dump(struct spu_context *ctx,
203362306a36Sopenharmony_ci		struct coredump_params *cprm)
203462306a36Sopenharmony_ci{
203562306a36Sopenharmony_ci	return spufs_dump_emit(cprm, &ctx->csa.spu_mailbox_data,
203662306a36Sopenharmony_ci			spufs_wbox_info_cnt(ctx));
203762306a36Sopenharmony_ci}
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_cistatic ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
204062306a36Sopenharmony_ci				   size_t len, loff_t *pos)
204162306a36Sopenharmony_ci{
204262306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
204362306a36Sopenharmony_ci	u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
204462306a36Sopenharmony_ci	int ret, count;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
204762306a36Sopenharmony_ci	if (ret)
204862306a36Sopenharmony_ci		return ret;
204962306a36Sopenharmony_ci	spin_lock(&ctx->csa.register_lock);
205062306a36Sopenharmony_ci	count = spufs_wbox_info_cnt(ctx);
205162306a36Sopenharmony_ci	memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
205262306a36Sopenharmony_ci	spin_unlock(&ctx->csa.register_lock);
205362306a36Sopenharmony_ci	spu_release_saved(ctx);
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	return simple_read_from_buffer(buf, len, pos, &data,
205662306a36Sopenharmony_ci				count * sizeof(u32));
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_cistatic const struct file_operations spufs_wbox_info_fops = {
206062306a36Sopenharmony_ci	.open = spufs_info_open,
206162306a36Sopenharmony_ci	.read = spufs_wbox_info_read,
206262306a36Sopenharmony_ci	.llseek  = generic_file_llseek,
206362306a36Sopenharmony_ci};
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_cistatic void spufs_get_dma_info(struct spu_context *ctx,
206662306a36Sopenharmony_ci		struct spu_dma_info *info)
206762306a36Sopenharmony_ci{
206862306a36Sopenharmony_ci	int i;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
207162306a36Sopenharmony_ci	info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
207262306a36Sopenharmony_ci	info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
207362306a36Sopenharmony_ci	info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
207462306a36Sopenharmony_ci	info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
207562306a36Sopenharmony_ci	for (i = 0; i < 16; i++) {
207662306a36Sopenharmony_ci		struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
207762306a36Sopenharmony_ci		struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
208062306a36Sopenharmony_ci		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
208162306a36Sopenharmony_ci		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
208262306a36Sopenharmony_ci		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
208362306a36Sopenharmony_ci	}
208462306a36Sopenharmony_ci}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_cistatic ssize_t spufs_dma_info_dump(struct spu_context *ctx,
208762306a36Sopenharmony_ci		struct coredump_params *cprm)
208862306a36Sopenharmony_ci{
208962306a36Sopenharmony_ci	struct spu_dma_info info;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	spufs_get_dma_info(ctx, &info);
209262306a36Sopenharmony_ci	return spufs_dump_emit(cprm, &info, sizeof(info));
209362306a36Sopenharmony_ci}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_cistatic ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
209662306a36Sopenharmony_ci			      size_t len, loff_t *pos)
209762306a36Sopenharmony_ci{
209862306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
209962306a36Sopenharmony_ci	struct spu_dma_info info;
210062306a36Sopenharmony_ci	int ret;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
210362306a36Sopenharmony_ci	if (ret)
210462306a36Sopenharmony_ci		return ret;
210562306a36Sopenharmony_ci	spin_lock(&ctx->csa.register_lock);
210662306a36Sopenharmony_ci	spufs_get_dma_info(ctx, &info);
210762306a36Sopenharmony_ci	spin_unlock(&ctx->csa.register_lock);
210862306a36Sopenharmony_ci	spu_release_saved(ctx);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	return simple_read_from_buffer(buf, len, pos, &info,
211162306a36Sopenharmony_ci				sizeof(info));
211262306a36Sopenharmony_ci}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_cistatic const struct file_operations spufs_dma_info_fops = {
211562306a36Sopenharmony_ci	.open = spufs_info_open,
211662306a36Sopenharmony_ci	.read = spufs_dma_info_read,
211762306a36Sopenharmony_ci	.llseek = no_llseek,
211862306a36Sopenharmony_ci};
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_cistatic void spufs_get_proxydma_info(struct spu_context *ctx,
212162306a36Sopenharmony_ci		struct spu_proxydma_info *info)
212262306a36Sopenharmony_ci{
212362306a36Sopenharmony_ci	int i;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
212662306a36Sopenharmony_ci	info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
212762306a36Sopenharmony_ci	info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
213062306a36Sopenharmony_ci		struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
213162306a36Sopenharmony_ci		struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
213462306a36Sopenharmony_ci		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
213562306a36Sopenharmony_ci		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
213662306a36Sopenharmony_ci		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
213762306a36Sopenharmony_ci	}
213862306a36Sopenharmony_ci}
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_cistatic ssize_t spufs_proxydma_info_dump(struct spu_context *ctx,
214162306a36Sopenharmony_ci		struct coredump_params *cprm)
214262306a36Sopenharmony_ci{
214362306a36Sopenharmony_ci	struct spu_proxydma_info info;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	spufs_get_proxydma_info(ctx, &info);
214662306a36Sopenharmony_ci	return spufs_dump_emit(cprm, &info, sizeof(info));
214762306a36Sopenharmony_ci}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_cistatic ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
215062306a36Sopenharmony_ci				   size_t len, loff_t *pos)
215162306a36Sopenharmony_ci{
215262306a36Sopenharmony_ci	struct spu_context *ctx = file->private_data;
215362306a36Sopenharmony_ci	struct spu_proxydma_info info;
215462306a36Sopenharmony_ci	int ret;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	if (len < sizeof(info))
215762306a36Sopenharmony_ci		return -EINVAL;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	ret = spu_acquire_saved(ctx);
216062306a36Sopenharmony_ci	if (ret)
216162306a36Sopenharmony_ci		return ret;
216262306a36Sopenharmony_ci	spin_lock(&ctx->csa.register_lock);
216362306a36Sopenharmony_ci	spufs_get_proxydma_info(ctx, &info);
216462306a36Sopenharmony_ci	spin_unlock(&ctx->csa.register_lock);
216562306a36Sopenharmony_ci	spu_release_saved(ctx);
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	return simple_read_from_buffer(buf, len, pos, &info,
216862306a36Sopenharmony_ci				sizeof(info));
216962306a36Sopenharmony_ci}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_cistatic const struct file_operations spufs_proxydma_info_fops = {
217262306a36Sopenharmony_ci	.open = spufs_info_open,
217362306a36Sopenharmony_ci	.read = spufs_proxydma_info_read,
217462306a36Sopenharmony_ci	.llseek = no_llseek,
217562306a36Sopenharmony_ci};
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_cistatic int spufs_show_tid(struct seq_file *s, void *private)
217862306a36Sopenharmony_ci{
217962306a36Sopenharmony_ci	struct spu_context *ctx = s->private;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	seq_printf(s, "%d\n", ctx->tid);
218262306a36Sopenharmony_ci	return 0;
218362306a36Sopenharmony_ci}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_cistatic int spufs_tid_open(struct inode *inode, struct file *file)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci	return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx);
218862306a36Sopenharmony_ci}
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_cistatic const struct file_operations spufs_tid_fops = {
219162306a36Sopenharmony_ci	.open		= spufs_tid_open,
219262306a36Sopenharmony_ci	.read		= seq_read,
219362306a36Sopenharmony_ci	.llseek		= seq_lseek,
219462306a36Sopenharmony_ci	.release	= single_release,
219562306a36Sopenharmony_ci};
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_cistatic const char *ctx_state_names[] = {
219862306a36Sopenharmony_ci	"user", "system", "iowait", "loaded"
219962306a36Sopenharmony_ci};
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_cistatic unsigned long long spufs_acct_time(struct spu_context *ctx,
220262306a36Sopenharmony_ci		enum spu_utilization_state state)
220362306a36Sopenharmony_ci{
220462306a36Sopenharmony_ci	unsigned long long time = ctx->stats.times[state];
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	/*
220762306a36Sopenharmony_ci	 * In general, utilization statistics are updated by the controlling
220862306a36Sopenharmony_ci	 * thread as the spu context moves through various well defined
220962306a36Sopenharmony_ci	 * state transitions, but if the context is lazily loaded its
221062306a36Sopenharmony_ci	 * utilization statistics are not updated as the controlling thread
221162306a36Sopenharmony_ci	 * is not tightly coupled with the execution of the spu context.  We
221262306a36Sopenharmony_ci	 * calculate and apply the time delta from the last recorded state
221362306a36Sopenharmony_ci	 * of the spu context.
221462306a36Sopenharmony_ci	 */
221562306a36Sopenharmony_ci	if (ctx->spu && ctx->stats.util_state == state) {
221662306a36Sopenharmony_ci		time += ktime_get_ns() - ctx->stats.tstamp;
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	return time / NSEC_PER_MSEC;
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_cistatic unsigned long long spufs_slb_flts(struct spu_context *ctx)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	unsigned long long slb_flts = ctx->stats.slb_flt;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	if (ctx->state == SPU_STATE_RUNNABLE) {
222762306a36Sopenharmony_ci		slb_flts += (ctx->spu->stats.slb_flt -
222862306a36Sopenharmony_ci			     ctx->stats.slb_flt_base);
222962306a36Sopenharmony_ci	}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	return slb_flts;
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_cistatic unsigned long long spufs_class2_intrs(struct spu_context *ctx)
223562306a36Sopenharmony_ci{
223662306a36Sopenharmony_ci	unsigned long long class2_intrs = ctx->stats.class2_intr;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	if (ctx->state == SPU_STATE_RUNNABLE) {
223962306a36Sopenharmony_ci		class2_intrs += (ctx->spu->stats.class2_intr -
224062306a36Sopenharmony_ci				 ctx->stats.class2_intr_base);
224162306a36Sopenharmony_ci	}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	return class2_intrs;
224462306a36Sopenharmony_ci}
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_cistatic int spufs_show_stat(struct seq_file *s, void *private)
224862306a36Sopenharmony_ci{
224962306a36Sopenharmony_ci	struct spu_context *ctx = s->private;
225062306a36Sopenharmony_ci	int ret;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	ret = spu_acquire(ctx);
225362306a36Sopenharmony_ci	if (ret)
225462306a36Sopenharmony_ci		return ret;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	seq_printf(s, "%s %llu %llu %llu %llu "
225762306a36Sopenharmony_ci		      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
225862306a36Sopenharmony_ci		ctx_state_names[ctx->stats.util_state],
225962306a36Sopenharmony_ci		spufs_acct_time(ctx, SPU_UTIL_USER),
226062306a36Sopenharmony_ci		spufs_acct_time(ctx, SPU_UTIL_SYSTEM),
226162306a36Sopenharmony_ci		spufs_acct_time(ctx, SPU_UTIL_IOWAIT),
226262306a36Sopenharmony_ci		spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED),
226362306a36Sopenharmony_ci		ctx->stats.vol_ctx_switch,
226462306a36Sopenharmony_ci		ctx->stats.invol_ctx_switch,
226562306a36Sopenharmony_ci		spufs_slb_flts(ctx),
226662306a36Sopenharmony_ci		ctx->stats.hash_flt,
226762306a36Sopenharmony_ci		ctx->stats.min_flt,
226862306a36Sopenharmony_ci		ctx->stats.maj_flt,
226962306a36Sopenharmony_ci		spufs_class2_intrs(ctx),
227062306a36Sopenharmony_ci		ctx->stats.libassist);
227162306a36Sopenharmony_ci	spu_release(ctx);
227262306a36Sopenharmony_ci	return 0;
227362306a36Sopenharmony_ci}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_cistatic int spufs_stat_open(struct inode *inode, struct file *file)
227662306a36Sopenharmony_ci{
227762306a36Sopenharmony_ci	return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx);
227862306a36Sopenharmony_ci}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_cistatic const struct file_operations spufs_stat_fops = {
228162306a36Sopenharmony_ci	.open		= spufs_stat_open,
228262306a36Sopenharmony_ci	.read		= seq_read,
228362306a36Sopenharmony_ci	.llseek		= seq_lseek,
228462306a36Sopenharmony_ci	.release	= single_release,
228562306a36Sopenharmony_ci};
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_cistatic inline int spufs_switch_log_used(struct spu_context *ctx)
228862306a36Sopenharmony_ci{
228962306a36Sopenharmony_ci	return (ctx->switch_log->head - ctx->switch_log->tail) %
229062306a36Sopenharmony_ci		SWITCH_LOG_BUFSIZE;
229162306a36Sopenharmony_ci}
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_cistatic inline int spufs_switch_log_avail(struct spu_context *ctx)
229462306a36Sopenharmony_ci{
229562306a36Sopenharmony_ci	return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx);
229662306a36Sopenharmony_ci}
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_cistatic int spufs_switch_log_open(struct inode *inode, struct file *file)
229962306a36Sopenharmony_ci{
230062306a36Sopenharmony_ci	struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
230162306a36Sopenharmony_ci	int rc;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	rc = spu_acquire(ctx);
230462306a36Sopenharmony_ci	if (rc)
230562306a36Sopenharmony_ci		return rc;
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	if (ctx->switch_log) {
230862306a36Sopenharmony_ci		rc = -EBUSY;
230962306a36Sopenharmony_ci		goto out;
231062306a36Sopenharmony_ci	}
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	ctx->switch_log = kmalloc(struct_size(ctx->switch_log, log,
231362306a36Sopenharmony_ci				  SWITCH_LOG_BUFSIZE), GFP_KERNEL);
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	if (!ctx->switch_log) {
231662306a36Sopenharmony_ci		rc = -ENOMEM;
231762306a36Sopenharmony_ci		goto out;
231862306a36Sopenharmony_ci	}
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci	ctx->switch_log->head = ctx->switch_log->tail = 0;
232162306a36Sopenharmony_ci	init_waitqueue_head(&ctx->switch_log->wait);
232262306a36Sopenharmony_ci	rc = 0;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ciout:
232562306a36Sopenharmony_ci	spu_release(ctx);
232662306a36Sopenharmony_ci	return rc;
232762306a36Sopenharmony_ci}
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_cistatic int spufs_switch_log_release(struct inode *inode, struct file *file)
233062306a36Sopenharmony_ci{
233162306a36Sopenharmony_ci	struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
233262306a36Sopenharmony_ci	int rc;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	rc = spu_acquire(ctx);
233562306a36Sopenharmony_ci	if (rc)
233662306a36Sopenharmony_ci		return rc;
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	kfree(ctx->switch_log);
233962306a36Sopenharmony_ci	ctx->switch_log = NULL;
234062306a36Sopenharmony_ci	spu_release(ctx);
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci	return 0;
234362306a36Sopenharmony_ci}
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_cistatic int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n)
234662306a36Sopenharmony_ci{
234762306a36Sopenharmony_ci	struct switch_log_entry *p;
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	return snprintf(tbuf, n, "%llu.%09u %d %u %u %llu\n",
235262306a36Sopenharmony_ci			(unsigned long long) p->tstamp.tv_sec,
235362306a36Sopenharmony_ci			(unsigned int) p->tstamp.tv_nsec,
235462306a36Sopenharmony_ci			p->spu_id,
235562306a36Sopenharmony_ci			(unsigned int) p->type,
235662306a36Sopenharmony_ci			(unsigned int) p->val,
235762306a36Sopenharmony_ci			(unsigned long long) p->timebase);
235862306a36Sopenharmony_ci}
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_cistatic ssize_t spufs_switch_log_read(struct file *file, char __user *buf,
236162306a36Sopenharmony_ci			     size_t len, loff_t *ppos)
236262306a36Sopenharmony_ci{
236362306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
236462306a36Sopenharmony_ci	struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
236562306a36Sopenharmony_ci	int error = 0, cnt = 0;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	if (!buf)
236862306a36Sopenharmony_ci		return -EINVAL;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	error = spu_acquire(ctx);
237162306a36Sopenharmony_ci	if (error)
237262306a36Sopenharmony_ci		return error;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	while (cnt < len) {
237562306a36Sopenharmony_ci		char tbuf[128];
237662306a36Sopenharmony_ci		int width;
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci		if (spufs_switch_log_used(ctx) == 0) {
237962306a36Sopenharmony_ci			if (cnt > 0) {
238062306a36Sopenharmony_ci				/* If there's data ready to go, we can
238162306a36Sopenharmony_ci				 * just return straight away */
238262306a36Sopenharmony_ci				break;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci			} else if (file->f_flags & O_NONBLOCK) {
238562306a36Sopenharmony_ci				error = -EAGAIN;
238662306a36Sopenharmony_ci				break;
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci			} else {
238962306a36Sopenharmony_ci				/* spufs_wait will drop the mutex and
239062306a36Sopenharmony_ci				 * re-acquire, but since we're in read(), the
239162306a36Sopenharmony_ci				 * file cannot be _released (and so
239262306a36Sopenharmony_ci				 * ctx->switch_log is stable).
239362306a36Sopenharmony_ci				 */
239462306a36Sopenharmony_ci				error = spufs_wait(ctx->switch_log->wait,
239562306a36Sopenharmony_ci						spufs_switch_log_used(ctx) > 0);
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci				/* On error, spufs_wait returns without the
239862306a36Sopenharmony_ci				 * state mutex held */
239962306a36Sopenharmony_ci				if (error)
240062306a36Sopenharmony_ci					return error;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci				/* We may have had entries read from underneath
240362306a36Sopenharmony_ci				 * us while we dropped the mutex in spufs_wait,
240462306a36Sopenharmony_ci				 * so re-check */
240562306a36Sopenharmony_ci				if (spufs_switch_log_used(ctx) == 0)
240662306a36Sopenharmony_ci					continue;
240762306a36Sopenharmony_ci			}
240862306a36Sopenharmony_ci		}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci		width = switch_log_sprint(ctx, tbuf, sizeof(tbuf));
241162306a36Sopenharmony_ci		if (width < len)
241262306a36Sopenharmony_ci			ctx->switch_log->tail =
241362306a36Sopenharmony_ci				(ctx->switch_log->tail + 1) %
241462306a36Sopenharmony_ci				 SWITCH_LOG_BUFSIZE;
241562306a36Sopenharmony_ci		else
241662306a36Sopenharmony_ci			/* If the record is greater than space available return
241762306a36Sopenharmony_ci			 * partial buffer (so far) */
241862306a36Sopenharmony_ci			break;
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci		error = copy_to_user(buf + cnt, tbuf, width);
242162306a36Sopenharmony_ci		if (error)
242262306a36Sopenharmony_ci			break;
242362306a36Sopenharmony_ci		cnt += width;
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	spu_release(ctx);
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	return cnt == 0 ? error : cnt;
242962306a36Sopenharmony_ci}
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_cistatic __poll_t spufs_switch_log_poll(struct file *file, poll_table *wait)
243262306a36Sopenharmony_ci{
243362306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
243462306a36Sopenharmony_ci	struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
243562306a36Sopenharmony_ci	__poll_t mask = 0;
243662306a36Sopenharmony_ci	int rc;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	poll_wait(file, &ctx->switch_log->wait, wait);
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	rc = spu_acquire(ctx);
244162306a36Sopenharmony_ci	if (rc)
244262306a36Sopenharmony_ci		return rc;
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	if (spufs_switch_log_used(ctx) > 0)
244562306a36Sopenharmony_ci		mask |= EPOLLIN;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	spu_release(ctx);
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	return mask;
245062306a36Sopenharmony_ci}
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_cistatic const struct file_operations spufs_switch_log_fops = {
245362306a36Sopenharmony_ci	.open		= spufs_switch_log_open,
245462306a36Sopenharmony_ci	.read		= spufs_switch_log_read,
245562306a36Sopenharmony_ci	.poll		= spufs_switch_log_poll,
245662306a36Sopenharmony_ci	.release	= spufs_switch_log_release,
245762306a36Sopenharmony_ci	.llseek		= no_llseek,
245862306a36Sopenharmony_ci};
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci/**
246162306a36Sopenharmony_ci * Log a context switch event to a switch log reader.
246262306a36Sopenharmony_ci *
246362306a36Sopenharmony_ci * Must be called with ctx->state_mutex held.
246462306a36Sopenharmony_ci */
246562306a36Sopenharmony_civoid spu_switch_log_notify(struct spu *spu, struct spu_context *ctx,
246662306a36Sopenharmony_ci		u32 type, u32 val)
246762306a36Sopenharmony_ci{
246862306a36Sopenharmony_ci	if (!ctx->switch_log)
246962306a36Sopenharmony_ci		return;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	if (spufs_switch_log_avail(ctx) > 1) {
247262306a36Sopenharmony_ci		struct switch_log_entry *p;
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci		p = ctx->switch_log->log + ctx->switch_log->head;
247562306a36Sopenharmony_ci		ktime_get_ts64(&p->tstamp);
247662306a36Sopenharmony_ci		p->timebase = get_tb();
247762306a36Sopenharmony_ci		p->spu_id = spu ? spu->number : -1;
247862306a36Sopenharmony_ci		p->type = type;
247962306a36Sopenharmony_ci		p->val = val;
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci		ctx->switch_log->head =
248262306a36Sopenharmony_ci			(ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE;
248362306a36Sopenharmony_ci	}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	wake_up(&ctx->switch_log->wait);
248662306a36Sopenharmony_ci}
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_cistatic int spufs_show_ctx(struct seq_file *s, void *private)
248962306a36Sopenharmony_ci{
249062306a36Sopenharmony_ci	struct spu_context *ctx = s->private;
249162306a36Sopenharmony_ci	u64 mfc_control_RW;
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	mutex_lock(&ctx->state_mutex);
249462306a36Sopenharmony_ci	if (ctx->spu) {
249562306a36Sopenharmony_ci		struct spu *spu = ctx->spu;
249662306a36Sopenharmony_ci		struct spu_priv2 __iomem *priv2 = spu->priv2;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci		spin_lock_irq(&spu->register_lock);
249962306a36Sopenharmony_ci		mfc_control_RW = in_be64(&priv2->mfc_control_RW);
250062306a36Sopenharmony_ci		spin_unlock_irq(&spu->register_lock);
250162306a36Sopenharmony_ci	} else {
250262306a36Sopenharmony_ci		struct spu_state *csa = &ctx->csa;
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci		mfc_control_RW = csa->priv2.mfc_control_RW;
250562306a36Sopenharmony_ci	}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	seq_printf(s, "%c flgs(%lx) sflgs(%lx) pri(%d) ts(%d) spu(%02d)"
250862306a36Sopenharmony_ci		" %c %llx %llx %llx %llx %x %x\n",
250962306a36Sopenharmony_ci		ctx->state == SPU_STATE_SAVED ? 'S' : 'R',
251062306a36Sopenharmony_ci		ctx->flags,
251162306a36Sopenharmony_ci		ctx->sched_flags,
251262306a36Sopenharmony_ci		ctx->prio,
251362306a36Sopenharmony_ci		ctx->time_slice,
251462306a36Sopenharmony_ci		ctx->spu ? ctx->spu->number : -1,
251562306a36Sopenharmony_ci		!list_empty(&ctx->rq) ? 'q' : ' ',
251662306a36Sopenharmony_ci		ctx->csa.class_0_pending,
251762306a36Sopenharmony_ci		ctx->csa.class_0_dar,
251862306a36Sopenharmony_ci		ctx->csa.class_1_dsisr,
251962306a36Sopenharmony_ci		mfc_control_RW,
252062306a36Sopenharmony_ci		ctx->ops->runcntl_read(ctx),
252162306a36Sopenharmony_ci		ctx->ops->status_read(ctx));
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	mutex_unlock(&ctx->state_mutex);
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	return 0;
252662306a36Sopenharmony_ci}
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_cistatic int spufs_ctx_open(struct inode *inode, struct file *file)
252962306a36Sopenharmony_ci{
253062306a36Sopenharmony_ci	return single_open(file, spufs_show_ctx, SPUFS_I(inode)->i_ctx);
253162306a36Sopenharmony_ci}
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_cistatic const struct file_operations spufs_ctx_fops = {
253462306a36Sopenharmony_ci	.open           = spufs_ctx_open,
253562306a36Sopenharmony_ci	.read           = seq_read,
253662306a36Sopenharmony_ci	.llseek         = seq_lseek,
253762306a36Sopenharmony_ci	.release        = single_release,
253862306a36Sopenharmony_ci};
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ciconst struct spufs_tree_descr spufs_dir_contents[] = {
254162306a36Sopenharmony_ci	{ "capabilities", &spufs_caps_fops, 0444, },
254262306a36Sopenharmony_ci	{ "mem",  &spufs_mem_fops,  0666, LS_SIZE, },
254362306a36Sopenharmony_ci	{ "regs", &spufs_regs_fops,  0666, sizeof(struct spu_reg128[128]), },
254462306a36Sopenharmony_ci	{ "mbox", &spufs_mbox_fops, 0444, },
254562306a36Sopenharmony_ci	{ "ibox", &spufs_ibox_fops, 0444, },
254662306a36Sopenharmony_ci	{ "wbox", &spufs_wbox_fops, 0222, },
254762306a36Sopenharmony_ci	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), },
254862306a36Sopenharmony_ci	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), },
254962306a36Sopenharmony_ci	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), },
255062306a36Sopenharmony_ci	{ "signal1", &spufs_signal1_fops, 0666, },
255162306a36Sopenharmony_ci	{ "signal2", &spufs_signal2_fops, 0666, },
255262306a36Sopenharmony_ci	{ "signal1_type", &spufs_signal1_type, 0666, },
255362306a36Sopenharmony_ci	{ "signal2_type", &spufs_signal2_type, 0666, },
255462306a36Sopenharmony_ci	{ "cntl", &spufs_cntl_fops,  0666, },
255562306a36Sopenharmony_ci	{ "fpcr", &spufs_fpcr_fops, 0666, sizeof(struct spu_reg128), },
255662306a36Sopenharmony_ci	{ "lslr", &spufs_lslr_ops, 0444, },
255762306a36Sopenharmony_ci	{ "mfc", &spufs_mfc_fops, 0666, },
255862306a36Sopenharmony_ci	{ "mss", &spufs_mss_fops, 0666, },
255962306a36Sopenharmony_ci	{ "npc", &spufs_npc_ops, 0666, },
256062306a36Sopenharmony_ci	{ "srr0", &spufs_srr0_ops, 0666, },
256162306a36Sopenharmony_ci	{ "decr", &spufs_decr_ops, 0666, },
256262306a36Sopenharmony_ci	{ "decr_status", &spufs_decr_status_ops, 0666, },
256362306a36Sopenharmony_ci	{ "event_mask", &spufs_event_mask_ops, 0666, },
256462306a36Sopenharmony_ci	{ "event_status", &spufs_event_status_ops, 0444, },
256562306a36Sopenharmony_ci	{ "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, },
256662306a36Sopenharmony_ci	{ "phys-id", &spufs_id_ops, 0666, },
256762306a36Sopenharmony_ci	{ "object-id", &spufs_object_id_ops, 0666, },
256862306a36Sopenharmony_ci	{ "mbox_info", &spufs_mbox_info_fops, 0444, sizeof(u32), },
256962306a36Sopenharmony_ci	{ "ibox_info", &spufs_ibox_info_fops, 0444, sizeof(u32), },
257062306a36Sopenharmony_ci	{ "wbox_info", &spufs_wbox_info_fops, 0444, sizeof(u32), },
257162306a36Sopenharmony_ci	{ "dma_info", &spufs_dma_info_fops, 0444,
257262306a36Sopenharmony_ci		sizeof(struct spu_dma_info), },
257362306a36Sopenharmony_ci	{ "proxydma_info", &spufs_proxydma_info_fops, 0444,
257462306a36Sopenharmony_ci		sizeof(struct spu_proxydma_info)},
257562306a36Sopenharmony_ci	{ "tid", &spufs_tid_fops, 0444, },
257662306a36Sopenharmony_ci	{ "stat", &spufs_stat_fops, 0444, },
257762306a36Sopenharmony_ci	{ "switch_log", &spufs_switch_log_fops, 0444 },
257862306a36Sopenharmony_ci	{},
257962306a36Sopenharmony_ci};
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ciconst struct spufs_tree_descr spufs_dir_nosched_contents[] = {
258262306a36Sopenharmony_ci	{ "capabilities", &spufs_caps_fops, 0444, },
258362306a36Sopenharmony_ci	{ "mem",  &spufs_mem_fops,  0666, LS_SIZE, },
258462306a36Sopenharmony_ci	{ "mbox", &spufs_mbox_fops, 0444, },
258562306a36Sopenharmony_ci	{ "ibox", &spufs_ibox_fops, 0444, },
258662306a36Sopenharmony_ci	{ "wbox", &spufs_wbox_fops, 0222, },
258762306a36Sopenharmony_ci	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), },
258862306a36Sopenharmony_ci	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), },
258962306a36Sopenharmony_ci	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), },
259062306a36Sopenharmony_ci	{ "signal1", &spufs_signal1_nosched_fops, 0222, },
259162306a36Sopenharmony_ci	{ "signal2", &spufs_signal2_nosched_fops, 0222, },
259262306a36Sopenharmony_ci	{ "signal1_type", &spufs_signal1_type, 0666, },
259362306a36Sopenharmony_ci	{ "signal2_type", &spufs_signal2_type, 0666, },
259462306a36Sopenharmony_ci	{ "mss", &spufs_mss_fops, 0666, },
259562306a36Sopenharmony_ci	{ "mfc", &spufs_mfc_fops, 0666, },
259662306a36Sopenharmony_ci	{ "cntl", &spufs_cntl_fops,  0666, },
259762306a36Sopenharmony_ci	{ "npc", &spufs_npc_ops, 0666, },
259862306a36Sopenharmony_ci	{ "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, },
259962306a36Sopenharmony_ci	{ "phys-id", &spufs_id_ops, 0666, },
260062306a36Sopenharmony_ci	{ "object-id", &spufs_object_id_ops, 0666, },
260162306a36Sopenharmony_ci	{ "tid", &spufs_tid_fops, 0444, },
260262306a36Sopenharmony_ci	{ "stat", &spufs_stat_fops, 0444, },
260362306a36Sopenharmony_ci	{},
260462306a36Sopenharmony_ci};
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ciconst struct spufs_tree_descr spufs_dir_debug_contents[] = {
260762306a36Sopenharmony_ci	{ ".ctx", &spufs_ctx_fops, 0444, },
260862306a36Sopenharmony_ci	{},
260962306a36Sopenharmony_ci};
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ciconst struct spufs_coredump_reader spufs_coredump_read[] = {
261262306a36Sopenharmony_ci	{ "regs", spufs_regs_dump, NULL, sizeof(struct spu_reg128[128])},
261362306a36Sopenharmony_ci	{ "fpcr", spufs_fpcr_dump, NULL, sizeof(struct spu_reg128) },
261462306a36Sopenharmony_ci	{ "lslr", NULL, spufs_lslr_get, 19 },
261562306a36Sopenharmony_ci	{ "decr", NULL, spufs_decr_get, 19 },
261662306a36Sopenharmony_ci	{ "decr_status", NULL, spufs_decr_status_get, 19 },
261762306a36Sopenharmony_ci	{ "mem", spufs_mem_dump, NULL, LS_SIZE, },
261862306a36Sopenharmony_ci	{ "signal1", spufs_signal1_dump, NULL, sizeof(u32) },
261962306a36Sopenharmony_ci	{ "signal1_type", NULL, spufs_signal1_type_get, 19 },
262062306a36Sopenharmony_ci	{ "signal2", spufs_signal2_dump, NULL, sizeof(u32) },
262162306a36Sopenharmony_ci	{ "signal2_type", NULL, spufs_signal2_type_get, 19 },
262262306a36Sopenharmony_ci	{ "event_mask", NULL, spufs_event_mask_get, 19 },
262362306a36Sopenharmony_ci	{ "event_status", NULL, spufs_event_status_get, 19 },
262462306a36Sopenharmony_ci	{ "mbox_info", spufs_mbox_info_dump, NULL, sizeof(u32) },
262562306a36Sopenharmony_ci	{ "ibox_info", spufs_ibox_info_dump, NULL, sizeof(u32) },
262662306a36Sopenharmony_ci	{ "wbox_info", spufs_wbox_info_dump, NULL, 4 * sizeof(u32)},
262762306a36Sopenharmony_ci	{ "dma_info", spufs_dma_info_dump, NULL, sizeof(struct spu_dma_info)},
262862306a36Sopenharmony_ci	{ "proxydma_info", spufs_proxydma_info_dump,
262962306a36Sopenharmony_ci			   NULL, sizeof(struct spu_proxydma_info)},
263062306a36Sopenharmony_ci	{ "object-id", NULL, spufs_object_id_get, 19 },
263162306a36Sopenharmony_ci	{ "npc", NULL, spufs_npc_get, 19 },
263262306a36Sopenharmony_ci	{ NULL },
263362306a36Sopenharmony_ci};
2634