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