18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SPU file system -- file contents 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Arnd Bergmann <arndb@de.ibm.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#undef DEBUG 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/coredump.h> 138c2ecf20Sopenharmony_ci#include <linux/fs.h> 148c2ecf20Sopenharmony_ci#include <linux/ioctl.h> 158c2ecf20Sopenharmony_ci#include <linux/export.h> 168c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 178c2ecf20Sopenharmony_ci#include <linux/poll.h> 188c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 198c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/io.h> 238c2ecf20Sopenharmony_ci#include <asm/time.h> 248c2ecf20Sopenharmony_ci#include <asm/spu.h> 258c2ecf20Sopenharmony_ci#include <asm/spu_info.h> 268c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "spufs.h" 298c2ecf20Sopenharmony_ci#include "sputrace.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Simple attribute files */ 348c2ecf20Sopenharmony_cistruct spufs_attr { 358c2ecf20Sopenharmony_ci int (*get)(void *, u64 *); 368c2ecf20Sopenharmony_ci int (*set)(void *, u64); 378c2ecf20Sopenharmony_ci char get_buf[24]; /* enough to store a u64 and "\n\0" */ 388c2ecf20Sopenharmony_ci char set_buf[24]; 398c2ecf20Sopenharmony_ci void *data; 408c2ecf20Sopenharmony_ci const char *fmt; /* format for read operation */ 418c2ecf20Sopenharmony_ci struct mutex mutex; /* protects access to these buffers */ 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int spufs_attr_open(struct inode *inode, struct file *file, 458c2ecf20Sopenharmony_ci int (*get)(void *, u64 *), int (*set)(void *, u64), 468c2ecf20Sopenharmony_ci const char *fmt) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct spufs_attr *attr; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci attr = kmalloc(sizeof(*attr), GFP_KERNEL); 518c2ecf20Sopenharmony_ci if (!attr) 528c2ecf20Sopenharmony_ci return -ENOMEM; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci attr->get = get; 558c2ecf20Sopenharmony_ci attr->set = set; 568c2ecf20Sopenharmony_ci attr->data = inode->i_private; 578c2ecf20Sopenharmony_ci attr->fmt = fmt; 588c2ecf20Sopenharmony_ci mutex_init(&attr->mutex); 598c2ecf20Sopenharmony_ci file->private_data = attr; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int spufs_attr_release(struct inode *inode, struct file *file) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci kfree(file->private_data); 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic ssize_t spufs_attr_read(struct file *file, char __user *buf, 718c2ecf20Sopenharmony_ci size_t len, loff_t *ppos) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct spufs_attr *attr; 748c2ecf20Sopenharmony_ci size_t size; 758c2ecf20Sopenharmony_ci ssize_t ret; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci attr = file->private_data; 788c2ecf20Sopenharmony_ci if (!attr->get) 798c2ecf20Sopenharmony_ci return -EACCES; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&attr->mutex); 828c2ecf20Sopenharmony_ci if (ret) 838c2ecf20Sopenharmony_ci return ret; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (*ppos) { /* continued read */ 868c2ecf20Sopenharmony_ci size = strlen(attr->get_buf); 878c2ecf20Sopenharmony_ci } else { /* first read */ 888c2ecf20Sopenharmony_ci u64 val; 898c2ecf20Sopenharmony_ci ret = attr->get(attr->data, &val); 908c2ecf20Sopenharmony_ci if (ret) 918c2ecf20Sopenharmony_ci goto out; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci size = scnprintf(attr->get_buf, sizeof(attr->get_buf), 948c2ecf20Sopenharmony_ci attr->fmt, (unsigned long long)val); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); 988c2ecf20Sopenharmony_ciout: 998c2ecf20Sopenharmony_ci mutex_unlock(&attr->mutex); 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic ssize_t spufs_attr_write(struct file *file, const char __user *buf, 1048c2ecf20Sopenharmony_ci size_t len, loff_t *ppos) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct spufs_attr *attr; 1078c2ecf20Sopenharmony_ci u64 val; 1088c2ecf20Sopenharmony_ci size_t size; 1098c2ecf20Sopenharmony_ci ssize_t ret; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci attr = file->private_data; 1128c2ecf20Sopenharmony_ci if (!attr->set) 1138c2ecf20Sopenharmony_ci return -EACCES; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&attr->mutex); 1168c2ecf20Sopenharmony_ci if (ret) 1178c2ecf20Sopenharmony_ci return ret; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci ret = -EFAULT; 1208c2ecf20Sopenharmony_ci size = min(sizeof(attr->set_buf) - 1, len); 1218c2ecf20Sopenharmony_ci if (copy_from_user(attr->set_buf, buf, size)) 1228c2ecf20Sopenharmony_ci goto out; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci ret = len; /* claim we got the whole input */ 1258c2ecf20Sopenharmony_ci attr->set_buf[size] = '\0'; 1268c2ecf20Sopenharmony_ci val = simple_strtol(attr->set_buf, NULL, 0); 1278c2ecf20Sopenharmony_ci attr->set(attr->data, val); 1288c2ecf20Sopenharmony_ciout: 1298c2ecf20Sopenharmony_ci mutex_unlock(&attr->mutex); 1308c2ecf20Sopenharmony_ci return ret; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic ssize_t spufs_dump_emit(struct coredump_params *cprm, void *buf, 1348c2ecf20Sopenharmony_ci size_t size) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci if (!dump_emit(cprm, buf, size)) 1378c2ecf20Sopenharmony_ci return -EIO; 1388c2ecf20Sopenharmony_ci return size; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ 1428c2ecf20Sopenharmony_cistatic int __fops ## _open(struct inode *inode, struct file *file) \ 1438c2ecf20Sopenharmony_ci{ \ 1448c2ecf20Sopenharmony_ci __simple_attr_check_format(__fmt, 0ull); \ 1458c2ecf20Sopenharmony_ci return spufs_attr_open(inode, file, __get, __set, __fmt); \ 1468c2ecf20Sopenharmony_ci} \ 1478c2ecf20Sopenharmony_cistatic const struct file_operations __fops = { \ 1488c2ecf20Sopenharmony_ci .open = __fops ## _open, \ 1498c2ecf20Sopenharmony_ci .release = spufs_attr_release, \ 1508c2ecf20Sopenharmony_ci .read = spufs_attr_read, \ 1518c2ecf20Sopenharmony_ci .write = spufs_attr_write, \ 1528c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, \ 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int 1578c2ecf20Sopenharmony_cispufs_mem_open(struct inode *inode, struct file *file) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 1608c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 1638c2ecf20Sopenharmony_ci file->private_data = ctx; 1648c2ecf20Sopenharmony_ci if (!i->i_openers++) 1658c2ecf20Sopenharmony_ci ctx->local_store = inode->i_mapping; 1668c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int 1718c2ecf20Sopenharmony_cispufs_mem_release(struct inode *inode, struct file *file) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 1748c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 1778c2ecf20Sopenharmony_ci if (!--i->i_openers) 1788c2ecf20Sopenharmony_ci ctx->local_store = NULL; 1798c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic ssize_t 1848c2ecf20Sopenharmony_cispufs_mem_dump(struct spu_context *ctx, struct coredump_params *cprm) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, ctx->ops->get_ls(ctx), LS_SIZE); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic ssize_t 1908c2ecf20Sopenharmony_cispufs_mem_read(struct file *file, char __user *buffer, 1918c2ecf20Sopenharmony_ci size_t size, loff_t *pos) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 1948c2ecf20Sopenharmony_ci ssize_t ret; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 1978c2ecf20Sopenharmony_ci if (ret) 1988c2ecf20Sopenharmony_ci return ret; 1998c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(buffer, size, pos, ctx->ops->get_ls(ctx), 2008c2ecf20Sopenharmony_ci LS_SIZE); 2018c2ecf20Sopenharmony_ci spu_release(ctx); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return ret; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic ssize_t 2078c2ecf20Sopenharmony_cispufs_mem_write(struct file *file, const char __user *buffer, 2088c2ecf20Sopenharmony_ci size_t size, loff_t *ppos) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 2118c2ecf20Sopenharmony_ci char *local_store; 2128c2ecf20Sopenharmony_ci loff_t pos = *ppos; 2138c2ecf20Sopenharmony_ci int ret; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (pos > LS_SIZE) 2168c2ecf20Sopenharmony_ci return -EFBIG; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 2198c2ecf20Sopenharmony_ci if (ret) 2208c2ecf20Sopenharmony_ci return ret; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci local_store = ctx->ops->get_ls(ctx); 2238c2ecf20Sopenharmony_ci size = simple_write_to_buffer(local_store, LS_SIZE, ppos, buffer, size); 2248c2ecf20Sopenharmony_ci spu_release(ctx); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return size; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic vm_fault_t 2308c2ecf20Sopenharmony_cispufs_mem_mmap_fault(struct vm_fault *vmf) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct vm_area_struct *vma = vmf->vma; 2338c2ecf20Sopenharmony_ci struct spu_context *ctx = vma->vm_file->private_data; 2348c2ecf20Sopenharmony_ci unsigned long pfn, offset; 2358c2ecf20Sopenharmony_ci vm_fault_t ret; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci offset = vmf->pgoff << PAGE_SHIFT; 2388c2ecf20Sopenharmony_ci if (offset >= LS_SIZE) 2398c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci pr_debug("spufs_mem_mmap_fault address=0x%lx, offset=0x%lx\n", 2428c2ecf20Sopenharmony_ci vmf->address, offset); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (spu_acquire(ctx)) 2458c2ecf20Sopenharmony_ci return VM_FAULT_NOPAGE; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (ctx->state == SPU_STATE_SAVED) { 2488c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); 2498c2ecf20Sopenharmony_ci pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); 2508c2ecf20Sopenharmony_ci } else { 2518c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); 2528c2ecf20Sopenharmony_ci pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci ret = vmf_insert_pfn(vma, vmf->address, pfn); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci spu_release(ctx); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return ret; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int spufs_mem_mmap_access(struct vm_area_struct *vma, 2628c2ecf20Sopenharmony_ci unsigned long address, 2638c2ecf20Sopenharmony_ci void *buf, int len, int write) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct spu_context *ctx = vma->vm_file->private_data; 2668c2ecf20Sopenharmony_ci unsigned long offset = address - vma->vm_start; 2678c2ecf20Sopenharmony_ci char *local_store; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (write && !(vma->vm_flags & VM_WRITE)) 2708c2ecf20Sopenharmony_ci return -EACCES; 2718c2ecf20Sopenharmony_ci if (spu_acquire(ctx)) 2728c2ecf20Sopenharmony_ci return -EINTR; 2738c2ecf20Sopenharmony_ci if ((offset + len) > vma->vm_end) 2748c2ecf20Sopenharmony_ci len = vma->vm_end - offset; 2758c2ecf20Sopenharmony_ci local_store = ctx->ops->get_ls(ctx); 2768c2ecf20Sopenharmony_ci if (write) 2778c2ecf20Sopenharmony_ci memcpy_toio(local_store + offset, buf, len); 2788c2ecf20Sopenharmony_ci else 2798c2ecf20Sopenharmony_ci memcpy_fromio(buf, local_store + offset, len); 2808c2ecf20Sopenharmony_ci spu_release(ctx); 2818c2ecf20Sopenharmony_ci return len; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic const struct vm_operations_struct spufs_mem_mmap_vmops = { 2858c2ecf20Sopenharmony_ci .fault = spufs_mem_mmap_fault, 2868c2ecf20Sopenharmony_ci .access = spufs_mem_mmap_access, 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_SHARED)) 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci vma->vm_flags |= VM_IO | VM_PFNMAP; 2958c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci vma->vm_ops = &spufs_mem_mmap_vmops; 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic const struct file_operations spufs_mem_fops = { 3028c2ecf20Sopenharmony_ci .open = spufs_mem_open, 3038c2ecf20Sopenharmony_ci .release = spufs_mem_release, 3048c2ecf20Sopenharmony_ci .read = spufs_mem_read, 3058c2ecf20Sopenharmony_ci .write = spufs_mem_write, 3068c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 3078c2ecf20Sopenharmony_ci .mmap = spufs_mem_mmap, 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic vm_fault_t spufs_ps_fault(struct vm_fault *vmf, 3118c2ecf20Sopenharmony_ci unsigned long ps_offs, 3128c2ecf20Sopenharmony_ci unsigned long ps_size) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct spu_context *ctx = vmf->vma->vm_file->private_data; 3158c2ecf20Sopenharmony_ci unsigned long area, offset = vmf->pgoff << PAGE_SHIFT; 3168c2ecf20Sopenharmony_ci int err = 0; 3178c2ecf20Sopenharmony_ci vm_fault_t ret = VM_FAULT_NOPAGE; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci spu_context_nospu_trace(spufs_ps_fault__enter, ctx); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (offset >= ps_size) 3228c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) 3258c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* 3288c2ecf20Sopenharmony_ci * Because we release the mmap_lock, the context may be destroyed while 3298c2ecf20Sopenharmony_ci * we're in spu_wait. Grab an extra reference so it isn't destroyed 3308c2ecf20Sopenharmony_ci * in the meantime. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci get_spu_context(ctx); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * We have to wait for context to be loaded before we have 3368c2ecf20Sopenharmony_ci * pages to hand out to the user, but we don't want to wait 3378c2ecf20Sopenharmony_ci * with the mmap_lock held. 3388c2ecf20Sopenharmony_ci * It is possible to drop the mmap_lock here, but then we need 3398c2ecf20Sopenharmony_ci * to return VM_FAULT_NOPAGE because the mappings may have 3408c2ecf20Sopenharmony_ci * hanged. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci if (spu_acquire(ctx)) 3438c2ecf20Sopenharmony_ci goto refault; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (ctx->state == SPU_STATE_SAVED) { 3468c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 3478c2ecf20Sopenharmony_ci spu_context_nospu_trace(spufs_ps_fault__sleep, ctx); 3488c2ecf20Sopenharmony_ci err = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 3498c2ecf20Sopenharmony_ci spu_context_trace(spufs_ps_fault__wake, ctx, ctx->spu); 3508c2ecf20Sopenharmony_ci mmap_read_lock(current->mm); 3518c2ecf20Sopenharmony_ci } else { 3528c2ecf20Sopenharmony_ci area = ctx->spu->problem_phys + ps_offs; 3538c2ecf20Sopenharmony_ci ret = vmf_insert_pfn(vmf->vma, vmf->address, 3548c2ecf20Sopenharmony_ci (area + offset) >> PAGE_SHIFT); 3558c2ecf20Sopenharmony_ci spu_context_trace(spufs_ps_fault__insert, ctx, ctx->spu); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (!err) 3598c2ecf20Sopenharmony_ci spu_release(ctx); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cirefault: 3628c2ecf20Sopenharmony_ci put_spu_context(ctx); 3638c2ecf20Sopenharmony_ci return ret; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci#if SPUFS_MMAP_4K 3678c2ecf20Sopenharmony_cistatic vm_fault_t spufs_cntl_mmap_fault(struct vm_fault *vmf) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci return spufs_ps_fault(vmf, 0x4000, SPUFS_CNTL_MAP_SIZE); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic const struct vm_operations_struct spufs_cntl_mmap_vmops = { 3738c2ecf20Sopenharmony_ci .fault = spufs_cntl_mmap_fault, 3748c2ecf20Sopenharmony_ci}; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/* 3778c2ecf20Sopenharmony_ci * mmap support for problem state control area [0x4000 - 0x4fff]. 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_cistatic int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_SHARED)) 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci vma->vm_flags |= VM_IO | VM_PFNMAP; 3858c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci vma->vm_ops = &spufs_cntl_mmap_vmops; 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci#else /* SPUFS_MMAP_4K */ 3918c2ecf20Sopenharmony_ci#define spufs_cntl_mmap NULL 3928c2ecf20Sopenharmony_ci#endif /* !SPUFS_MMAP_4K */ 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int spufs_cntl_get(void *data, u64 *val) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 3978c2ecf20Sopenharmony_ci int ret; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 4008c2ecf20Sopenharmony_ci if (ret) 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci *val = ctx->ops->status_read(ctx); 4038c2ecf20Sopenharmony_ci spu_release(ctx); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int spufs_cntl_set(void *data, u64 val) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 4118c2ecf20Sopenharmony_ci int ret; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 4148c2ecf20Sopenharmony_ci if (ret) 4158c2ecf20Sopenharmony_ci return ret; 4168c2ecf20Sopenharmony_ci ctx->ops->runcntl_write(ctx, val); 4178c2ecf20Sopenharmony_ci spu_release(ctx); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic int spufs_cntl_open(struct inode *inode, struct file *file) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 4258c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 4288c2ecf20Sopenharmony_ci file->private_data = ctx; 4298c2ecf20Sopenharmony_ci if (!i->i_openers++) 4308c2ecf20Sopenharmony_ci ctx->cntl = inode->i_mapping; 4318c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 4328c2ecf20Sopenharmony_ci return simple_attr_open(inode, file, spufs_cntl_get, 4338c2ecf20Sopenharmony_ci spufs_cntl_set, "0x%08lx"); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int 4378c2ecf20Sopenharmony_cispufs_cntl_release(struct inode *inode, struct file *file) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 4408c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci simple_attr_release(inode, file); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 4458c2ecf20Sopenharmony_ci if (!--i->i_openers) 4468c2ecf20Sopenharmony_ci ctx->cntl = NULL; 4478c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic const struct file_operations spufs_cntl_fops = { 4528c2ecf20Sopenharmony_ci .open = spufs_cntl_open, 4538c2ecf20Sopenharmony_ci .release = spufs_cntl_release, 4548c2ecf20Sopenharmony_ci .read = simple_attr_read, 4558c2ecf20Sopenharmony_ci .write = simple_attr_write, 4568c2ecf20Sopenharmony_ci .llseek = no_llseek, 4578c2ecf20Sopenharmony_ci .mmap = spufs_cntl_mmap, 4588c2ecf20Sopenharmony_ci}; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic int 4618c2ecf20Sopenharmony_cispufs_regs_open(struct inode *inode, struct file *file) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 4648c2ecf20Sopenharmony_ci file->private_data = i->i_ctx; 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic ssize_t 4698c2ecf20Sopenharmony_cispufs_regs_dump(struct spu_context *ctx, struct coredump_params *cprm) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, ctx->csa.lscsa->gprs, 4728c2ecf20Sopenharmony_ci sizeof(ctx->csa.lscsa->gprs)); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic ssize_t 4768c2ecf20Sopenharmony_cispufs_regs_read(struct file *file, char __user *buffer, 4778c2ecf20Sopenharmony_ci size_t size, loff_t *pos) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci int ret; 4808c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* pre-check for file position: if we'd return EOF, there's no point 4838c2ecf20Sopenharmony_ci * causing a deschedule */ 4848c2ecf20Sopenharmony_ci if (*pos >= sizeof(ctx->csa.lscsa->gprs)) 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 4888c2ecf20Sopenharmony_ci if (ret) 4898c2ecf20Sopenharmony_ci return ret; 4908c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(buffer, size, pos, ctx->csa.lscsa->gprs, 4918c2ecf20Sopenharmony_ci sizeof(ctx->csa.lscsa->gprs)); 4928c2ecf20Sopenharmony_ci spu_release_saved(ctx); 4938c2ecf20Sopenharmony_ci return ret; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic ssize_t 4978c2ecf20Sopenharmony_cispufs_regs_write(struct file *file, const char __user *buffer, 4988c2ecf20Sopenharmony_ci size_t size, loff_t *pos) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 5018c2ecf20Sopenharmony_ci struct spu_lscsa *lscsa = ctx->csa.lscsa; 5028c2ecf20Sopenharmony_ci int ret; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (*pos >= sizeof(lscsa->gprs)) 5058c2ecf20Sopenharmony_ci return -EFBIG; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 5088c2ecf20Sopenharmony_ci if (ret) 5098c2ecf20Sopenharmony_ci return ret; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci size = simple_write_to_buffer(lscsa->gprs, sizeof(lscsa->gprs), pos, 5128c2ecf20Sopenharmony_ci buffer, size); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci spu_release_saved(ctx); 5158c2ecf20Sopenharmony_ci return size; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic const struct file_operations spufs_regs_fops = { 5198c2ecf20Sopenharmony_ci .open = spufs_regs_open, 5208c2ecf20Sopenharmony_ci .read = spufs_regs_read, 5218c2ecf20Sopenharmony_ci .write = spufs_regs_write, 5228c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 5238c2ecf20Sopenharmony_ci}; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic ssize_t 5268c2ecf20Sopenharmony_cispufs_fpcr_dump(struct spu_context *ctx, struct coredump_params *cprm) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, &ctx->csa.lscsa->fpcr, 5298c2ecf20Sopenharmony_ci sizeof(ctx->csa.lscsa->fpcr)); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic ssize_t 5338c2ecf20Sopenharmony_cispufs_fpcr_read(struct file *file, char __user * buffer, 5348c2ecf20Sopenharmony_ci size_t size, loff_t * pos) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci int ret; 5378c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 5408c2ecf20Sopenharmony_ci if (ret) 5418c2ecf20Sopenharmony_ci return ret; 5428c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(buffer, size, pos, &ctx->csa.lscsa->fpcr, 5438c2ecf20Sopenharmony_ci sizeof(ctx->csa.lscsa->fpcr)); 5448c2ecf20Sopenharmony_ci spu_release_saved(ctx); 5458c2ecf20Sopenharmony_ci return ret; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic ssize_t 5498c2ecf20Sopenharmony_cispufs_fpcr_write(struct file *file, const char __user * buffer, 5508c2ecf20Sopenharmony_ci size_t size, loff_t * pos) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 5538c2ecf20Sopenharmony_ci struct spu_lscsa *lscsa = ctx->csa.lscsa; 5548c2ecf20Sopenharmony_ci int ret; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (*pos >= sizeof(lscsa->fpcr)) 5578c2ecf20Sopenharmony_ci return -EFBIG; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 5608c2ecf20Sopenharmony_ci if (ret) 5618c2ecf20Sopenharmony_ci return ret; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci size = simple_write_to_buffer(&lscsa->fpcr, sizeof(lscsa->fpcr), pos, 5648c2ecf20Sopenharmony_ci buffer, size); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci spu_release_saved(ctx); 5678c2ecf20Sopenharmony_ci return size; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic const struct file_operations spufs_fpcr_fops = { 5718c2ecf20Sopenharmony_ci .open = spufs_regs_open, 5728c2ecf20Sopenharmony_ci .read = spufs_fpcr_read, 5738c2ecf20Sopenharmony_ci .write = spufs_fpcr_write, 5748c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/* generic open function for all pipe-like files */ 5788c2ecf20Sopenharmony_cistatic int spufs_pipe_open(struct inode *inode, struct file *file) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 5818c2ecf20Sopenharmony_ci file->private_data = i->i_ctx; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return stream_open(inode, file); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci/* 5878c2ecf20Sopenharmony_ci * Read as many bytes from the mailbox as possible, until 5888c2ecf20Sopenharmony_ci * one of the conditions becomes true: 5898c2ecf20Sopenharmony_ci * 5908c2ecf20Sopenharmony_ci * - no more data available in the mailbox 5918c2ecf20Sopenharmony_ci * - end of the user provided buffer 5928c2ecf20Sopenharmony_ci * - end of the mapped area 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_cistatic ssize_t spufs_mbox_read(struct file *file, char __user *buf, 5958c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 5988c2ecf20Sopenharmony_ci u32 mbox_data, __user *udata = (void __user *)buf; 5998c2ecf20Sopenharmony_ci ssize_t count; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (len < 4) 6028c2ecf20Sopenharmony_ci return -EINVAL; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci count = spu_acquire(ctx); 6058c2ecf20Sopenharmony_ci if (count) 6068c2ecf20Sopenharmony_ci return count; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci for (count = 0; (count + 4) <= len; count += 4, udata++) { 6098c2ecf20Sopenharmony_ci int ret; 6108c2ecf20Sopenharmony_ci ret = ctx->ops->mbox_read(ctx, &mbox_data); 6118c2ecf20Sopenharmony_ci if (ret == 0) 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * at the end of the mapped area, we can fault 6168c2ecf20Sopenharmony_ci * but still need to return the data we have 6178c2ecf20Sopenharmony_ci * read successfully so far. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci ret = put_user(mbox_data, udata); 6208c2ecf20Sopenharmony_ci if (ret) { 6218c2ecf20Sopenharmony_ci if (!count) 6228c2ecf20Sopenharmony_ci count = -EFAULT; 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci spu_release(ctx); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (!count) 6298c2ecf20Sopenharmony_ci count = -EAGAIN; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return count; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic const struct file_operations spufs_mbox_fops = { 6358c2ecf20Sopenharmony_ci .open = spufs_pipe_open, 6368c2ecf20Sopenharmony_ci .read = spufs_mbox_read, 6378c2ecf20Sopenharmony_ci .llseek = no_llseek, 6388c2ecf20Sopenharmony_ci}; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 6418c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 6448c2ecf20Sopenharmony_ci ssize_t ret; 6458c2ecf20Sopenharmony_ci u32 mbox_stat; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (len < 4) 6488c2ecf20Sopenharmony_ci return -EINVAL; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 6518c2ecf20Sopenharmony_ci if (ret) 6528c2ecf20Sopenharmony_ci return ret; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci spu_release(ctx); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 6598c2ecf20Sopenharmony_ci return -EFAULT; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci return 4; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic const struct file_operations spufs_mbox_stat_fops = { 6658c2ecf20Sopenharmony_ci .open = spufs_pipe_open, 6668c2ecf20Sopenharmony_ci .read = spufs_mbox_stat_read, 6678c2ecf20Sopenharmony_ci .llseek = no_llseek, 6688c2ecf20Sopenharmony_ci}; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci/* low-level ibox access function */ 6718c2ecf20Sopenharmony_cisize_t spu_ibox_read(struct spu_context *ctx, u32 *data) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci return ctx->ops->ibox_read(ctx, data); 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci/* interrupt-level ibox callback function. */ 6778c2ecf20Sopenharmony_civoid spufs_ibox_callback(struct spu *spu) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct spu_context *ctx = spu->ctx; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (ctx) 6828c2ecf20Sopenharmony_ci wake_up_all(&ctx->ibox_wq); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci/* 6868c2ecf20Sopenharmony_ci * Read as many bytes from the interrupt mailbox as possible, until 6878c2ecf20Sopenharmony_ci * one of the conditions becomes true: 6888c2ecf20Sopenharmony_ci * 6898c2ecf20Sopenharmony_ci * - no more data available in the mailbox 6908c2ecf20Sopenharmony_ci * - end of the user provided buffer 6918c2ecf20Sopenharmony_ci * - end of the mapped area 6928c2ecf20Sopenharmony_ci * 6938c2ecf20Sopenharmony_ci * If the file is opened without O_NONBLOCK, we wait here until 6948c2ecf20Sopenharmony_ci * any data is available, but return when we have been able to 6958c2ecf20Sopenharmony_ci * read something. 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_cistatic ssize_t spufs_ibox_read(struct file *file, char __user *buf, 6988c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 7018c2ecf20Sopenharmony_ci u32 ibox_data, __user *udata = (void __user *)buf; 7028c2ecf20Sopenharmony_ci ssize_t count; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (len < 4) 7058c2ecf20Sopenharmony_ci return -EINVAL; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci count = spu_acquire(ctx); 7088c2ecf20Sopenharmony_ci if (count) 7098c2ecf20Sopenharmony_ci goto out; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* wait only for the first element */ 7128c2ecf20Sopenharmony_ci count = 0; 7138c2ecf20Sopenharmony_ci if (file->f_flags & O_NONBLOCK) { 7148c2ecf20Sopenharmony_ci if (!spu_ibox_read(ctx, &ibox_data)) { 7158c2ecf20Sopenharmony_ci count = -EAGAIN; 7168c2ecf20Sopenharmony_ci goto out_unlock; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci } else { 7198c2ecf20Sopenharmony_ci count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 7208c2ecf20Sopenharmony_ci if (count) 7218c2ecf20Sopenharmony_ci goto out; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* if we can't write at all, return -EFAULT */ 7258c2ecf20Sopenharmony_ci count = put_user(ibox_data, udata); 7268c2ecf20Sopenharmony_ci if (count) 7278c2ecf20Sopenharmony_ci goto out_unlock; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 7308c2ecf20Sopenharmony_ci int ret; 7318c2ecf20Sopenharmony_ci ret = ctx->ops->ibox_read(ctx, &ibox_data); 7328c2ecf20Sopenharmony_ci if (ret == 0) 7338c2ecf20Sopenharmony_ci break; 7348c2ecf20Sopenharmony_ci /* 7358c2ecf20Sopenharmony_ci * at the end of the mapped area, we can fault 7368c2ecf20Sopenharmony_ci * but still need to return the data we have 7378c2ecf20Sopenharmony_ci * read successfully so far. 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_ci ret = put_user(ibox_data, udata); 7408c2ecf20Sopenharmony_ci if (ret) 7418c2ecf20Sopenharmony_ci break; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ciout_unlock: 7458c2ecf20Sopenharmony_ci spu_release(ctx); 7468c2ecf20Sopenharmony_ciout: 7478c2ecf20Sopenharmony_ci return count; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic __poll_t spufs_ibox_poll(struct file *file, poll_table *wait) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 7538c2ecf20Sopenharmony_ci __poll_t mask; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci poll_wait(file, &ctx->ibox_wq, wait); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* 7588c2ecf20Sopenharmony_ci * For now keep this uninterruptible and also ignore the rule 7598c2ecf20Sopenharmony_ci * that poll should not sleep. Will be fixed later. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci mutex_lock(&ctx->state_mutex); 7628c2ecf20Sopenharmony_ci mask = ctx->ops->mbox_stat_poll(ctx, EPOLLIN | EPOLLRDNORM); 7638c2ecf20Sopenharmony_ci spu_release(ctx); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return mask; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic const struct file_operations spufs_ibox_fops = { 7698c2ecf20Sopenharmony_ci .open = spufs_pipe_open, 7708c2ecf20Sopenharmony_ci .read = spufs_ibox_read, 7718c2ecf20Sopenharmony_ci .poll = spufs_ibox_poll, 7728c2ecf20Sopenharmony_ci .llseek = no_llseek, 7738c2ecf20Sopenharmony_ci}; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 7768c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 7798c2ecf20Sopenharmony_ci ssize_t ret; 7808c2ecf20Sopenharmony_ci u32 ibox_stat; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (len < 4) 7838c2ecf20Sopenharmony_ci return -EINVAL; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 7868c2ecf20Sopenharmony_ci if (ret) 7878c2ecf20Sopenharmony_ci return ret; 7888c2ecf20Sopenharmony_ci ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 7898c2ecf20Sopenharmony_ci spu_release(ctx); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 7928c2ecf20Sopenharmony_ci return -EFAULT; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return 4; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic const struct file_operations spufs_ibox_stat_fops = { 7988c2ecf20Sopenharmony_ci .open = spufs_pipe_open, 7998c2ecf20Sopenharmony_ci .read = spufs_ibox_stat_read, 8008c2ecf20Sopenharmony_ci .llseek = no_llseek, 8018c2ecf20Sopenharmony_ci}; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci/* low-level mailbox write */ 8048c2ecf20Sopenharmony_cisize_t spu_wbox_write(struct spu_context *ctx, u32 data) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci return ctx->ops->wbox_write(ctx, data); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci/* interrupt-level wbox callback function. */ 8108c2ecf20Sopenharmony_civoid spufs_wbox_callback(struct spu *spu) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct spu_context *ctx = spu->ctx; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (ctx) 8158c2ecf20Sopenharmony_ci wake_up_all(&ctx->wbox_wq); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci/* 8198c2ecf20Sopenharmony_ci * Write as many bytes to the interrupt mailbox as possible, until 8208c2ecf20Sopenharmony_ci * one of the conditions becomes true: 8218c2ecf20Sopenharmony_ci * 8228c2ecf20Sopenharmony_ci * - the mailbox is full 8238c2ecf20Sopenharmony_ci * - end of the user provided buffer 8248c2ecf20Sopenharmony_ci * - end of the mapped area 8258c2ecf20Sopenharmony_ci * 8268c2ecf20Sopenharmony_ci * If the file is opened without O_NONBLOCK, we wait here until 8278c2ecf20Sopenharmony_ci * space is available, but return when we have been able to 8288c2ecf20Sopenharmony_ci * write something. 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_cistatic ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 8318c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 8348c2ecf20Sopenharmony_ci u32 wbox_data, __user *udata = (void __user *)buf; 8358c2ecf20Sopenharmony_ci ssize_t count; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (len < 4) 8388c2ecf20Sopenharmony_ci return -EINVAL; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (get_user(wbox_data, udata)) 8418c2ecf20Sopenharmony_ci return -EFAULT; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci count = spu_acquire(ctx); 8448c2ecf20Sopenharmony_ci if (count) 8458c2ecf20Sopenharmony_ci goto out; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* 8488c2ecf20Sopenharmony_ci * make sure we can at least write one element, by waiting 8498c2ecf20Sopenharmony_ci * in case of !O_NONBLOCK 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ci count = 0; 8528c2ecf20Sopenharmony_ci if (file->f_flags & O_NONBLOCK) { 8538c2ecf20Sopenharmony_ci if (!spu_wbox_write(ctx, wbox_data)) { 8548c2ecf20Sopenharmony_ci count = -EAGAIN; 8558c2ecf20Sopenharmony_ci goto out_unlock; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci } else { 8588c2ecf20Sopenharmony_ci count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 8598c2ecf20Sopenharmony_ci if (count) 8608c2ecf20Sopenharmony_ci goto out; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* write as much as possible */ 8658c2ecf20Sopenharmony_ci for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 8668c2ecf20Sopenharmony_ci int ret; 8678c2ecf20Sopenharmony_ci ret = get_user(wbox_data, udata); 8688c2ecf20Sopenharmony_ci if (ret) 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci ret = spu_wbox_write(ctx, wbox_data); 8728c2ecf20Sopenharmony_ci if (ret == 0) 8738c2ecf20Sopenharmony_ci break; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ciout_unlock: 8778c2ecf20Sopenharmony_ci spu_release(ctx); 8788c2ecf20Sopenharmony_ciout: 8798c2ecf20Sopenharmony_ci return count; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic __poll_t spufs_wbox_poll(struct file *file, poll_table *wait) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 8858c2ecf20Sopenharmony_ci __poll_t mask; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci poll_wait(file, &ctx->wbox_wq, wait); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* 8908c2ecf20Sopenharmony_ci * For now keep this uninterruptible and also ignore the rule 8918c2ecf20Sopenharmony_ci * that poll should not sleep. Will be fixed later. 8928c2ecf20Sopenharmony_ci */ 8938c2ecf20Sopenharmony_ci mutex_lock(&ctx->state_mutex); 8948c2ecf20Sopenharmony_ci mask = ctx->ops->mbox_stat_poll(ctx, EPOLLOUT | EPOLLWRNORM); 8958c2ecf20Sopenharmony_ci spu_release(ctx); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return mask; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic const struct file_operations spufs_wbox_fops = { 9018c2ecf20Sopenharmony_ci .open = spufs_pipe_open, 9028c2ecf20Sopenharmony_ci .write = spufs_wbox_write, 9038c2ecf20Sopenharmony_ci .poll = spufs_wbox_poll, 9048c2ecf20Sopenharmony_ci .llseek = no_llseek, 9058c2ecf20Sopenharmony_ci}; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 9088c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 9118c2ecf20Sopenharmony_ci ssize_t ret; 9128c2ecf20Sopenharmony_ci u32 wbox_stat; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (len < 4) 9158c2ecf20Sopenharmony_ci return -EINVAL; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 9188c2ecf20Sopenharmony_ci if (ret) 9198c2ecf20Sopenharmony_ci return ret; 9208c2ecf20Sopenharmony_ci wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 9218c2ecf20Sopenharmony_ci spu_release(ctx); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 9248c2ecf20Sopenharmony_ci return -EFAULT; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci return 4; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic const struct file_operations spufs_wbox_stat_fops = { 9308c2ecf20Sopenharmony_ci .open = spufs_pipe_open, 9318c2ecf20Sopenharmony_ci .read = spufs_wbox_stat_read, 9328c2ecf20Sopenharmony_ci .llseek = no_llseek, 9338c2ecf20Sopenharmony_ci}; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int spufs_signal1_open(struct inode *inode, struct file *file) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 9388c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 9418c2ecf20Sopenharmony_ci file->private_data = ctx; 9428c2ecf20Sopenharmony_ci if (!i->i_openers++) 9438c2ecf20Sopenharmony_ci ctx->signal1 = inode->i_mapping; 9448c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 9458c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic int 9498c2ecf20Sopenharmony_cispufs_signal1_release(struct inode *inode, struct file *file) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 9528c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 9558c2ecf20Sopenharmony_ci if (!--i->i_openers) 9568c2ecf20Sopenharmony_ci ctx->signal1 = NULL; 9578c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 9588c2ecf20Sopenharmony_ci return 0; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic ssize_t spufs_signal1_dump(struct spu_context *ctx, 9628c2ecf20Sopenharmony_ci struct coredump_params *cprm) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci if (!ctx->csa.spu_chnlcnt_RW[3]) 9658c2ecf20Sopenharmony_ci return 0; 9668c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[3], 9678c2ecf20Sopenharmony_ci sizeof(ctx->csa.spu_chnldata_RW[3])); 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 9718c2ecf20Sopenharmony_ci size_t len) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci if (len < sizeof(ctx->csa.spu_chnldata_RW[3])) 9748c2ecf20Sopenharmony_ci return -EINVAL; 9758c2ecf20Sopenharmony_ci if (!ctx->csa.spu_chnlcnt_RW[3]) 9768c2ecf20Sopenharmony_ci return 0; 9778c2ecf20Sopenharmony_ci if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[3], 9788c2ecf20Sopenharmony_ci sizeof(ctx->csa.spu_chnldata_RW[3]))) 9798c2ecf20Sopenharmony_ci return -EFAULT; 9808c2ecf20Sopenharmony_ci return sizeof(ctx->csa.spu_chnldata_RW[3]); 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic ssize_t spufs_signal1_read(struct file *file, char __user *buf, 9848c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci int ret; 9878c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 9908c2ecf20Sopenharmony_ci if (ret) 9918c2ecf20Sopenharmony_ci return ret; 9928c2ecf20Sopenharmony_ci ret = __spufs_signal1_read(ctx, buf, len); 9938c2ecf20Sopenharmony_ci spu_release_saved(ctx); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return ret; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 9998c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci struct spu_context *ctx; 10028c2ecf20Sopenharmony_ci ssize_t ret; 10038c2ecf20Sopenharmony_ci u32 data; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci ctx = file->private_data; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (len < 4) 10088c2ecf20Sopenharmony_ci return -EINVAL; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci if (copy_from_user(&data, buf, 4)) 10118c2ecf20Sopenharmony_ci return -EFAULT; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 10148c2ecf20Sopenharmony_ci if (ret) 10158c2ecf20Sopenharmony_ci return ret; 10168c2ecf20Sopenharmony_ci ctx->ops->signal1_write(ctx, data); 10178c2ecf20Sopenharmony_ci spu_release(ctx); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci return 4; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic vm_fault_t 10238c2ecf20Sopenharmony_cispufs_signal1_mmap_fault(struct vm_fault *vmf) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci#if SPUFS_SIGNAL_MAP_SIZE == 0x1000 10268c2ecf20Sopenharmony_ci return spufs_ps_fault(vmf, 0x14000, SPUFS_SIGNAL_MAP_SIZE); 10278c2ecf20Sopenharmony_ci#elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 10288c2ecf20Sopenharmony_ci /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 10298c2ecf20Sopenharmony_ci * signal 1 and 2 area 10308c2ecf20Sopenharmony_ci */ 10318c2ecf20Sopenharmony_ci return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); 10328c2ecf20Sopenharmony_ci#else 10338c2ecf20Sopenharmony_ci#error unsupported page size 10348c2ecf20Sopenharmony_ci#endif 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic const struct vm_operations_struct spufs_signal1_mmap_vmops = { 10388c2ecf20Sopenharmony_ci .fault = spufs_signal1_mmap_fault, 10398c2ecf20Sopenharmony_ci}; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_SHARED)) 10448c2ecf20Sopenharmony_ci return -EINVAL; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci vma->vm_flags |= VM_IO | VM_PFNMAP; 10478c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci vma->vm_ops = &spufs_signal1_mmap_vmops; 10508c2ecf20Sopenharmony_ci return 0; 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic const struct file_operations spufs_signal1_fops = { 10548c2ecf20Sopenharmony_ci .open = spufs_signal1_open, 10558c2ecf20Sopenharmony_ci .release = spufs_signal1_release, 10568c2ecf20Sopenharmony_ci .read = spufs_signal1_read, 10578c2ecf20Sopenharmony_ci .write = spufs_signal1_write, 10588c2ecf20Sopenharmony_ci .mmap = spufs_signal1_mmap, 10598c2ecf20Sopenharmony_ci .llseek = no_llseek, 10608c2ecf20Sopenharmony_ci}; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic const struct file_operations spufs_signal1_nosched_fops = { 10638c2ecf20Sopenharmony_ci .open = spufs_signal1_open, 10648c2ecf20Sopenharmony_ci .release = spufs_signal1_release, 10658c2ecf20Sopenharmony_ci .write = spufs_signal1_write, 10668c2ecf20Sopenharmony_ci .mmap = spufs_signal1_mmap, 10678c2ecf20Sopenharmony_ci .llseek = no_llseek, 10688c2ecf20Sopenharmony_ci}; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cistatic int spufs_signal2_open(struct inode *inode, struct file *file) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 10738c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 10768c2ecf20Sopenharmony_ci file->private_data = ctx; 10778c2ecf20Sopenharmony_ci if (!i->i_openers++) 10788c2ecf20Sopenharmony_ci ctx->signal2 = inode->i_mapping; 10798c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 10808c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic int 10848c2ecf20Sopenharmony_cispufs_signal2_release(struct inode *inode, struct file *file) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 10878c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 10908c2ecf20Sopenharmony_ci if (!--i->i_openers) 10918c2ecf20Sopenharmony_ci ctx->signal2 = NULL; 10928c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 10938c2ecf20Sopenharmony_ci return 0; 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic ssize_t spufs_signal2_dump(struct spu_context *ctx, 10978c2ecf20Sopenharmony_ci struct coredump_params *cprm) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci if (!ctx->csa.spu_chnlcnt_RW[4]) 11008c2ecf20Sopenharmony_ci return 0; 11018c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[4], 11028c2ecf20Sopenharmony_ci sizeof(ctx->csa.spu_chnldata_RW[4])); 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_cistatic ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 11068c2ecf20Sopenharmony_ci size_t len) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci if (len < sizeof(ctx->csa.spu_chnldata_RW[4])) 11098c2ecf20Sopenharmony_ci return -EINVAL; 11108c2ecf20Sopenharmony_ci if (!ctx->csa.spu_chnlcnt_RW[4]) 11118c2ecf20Sopenharmony_ci return 0; 11128c2ecf20Sopenharmony_ci if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[4], 11138c2ecf20Sopenharmony_ci sizeof(ctx->csa.spu_chnldata_RW[4]))) 11148c2ecf20Sopenharmony_ci return -EFAULT; 11158c2ecf20Sopenharmony_ci return sizeof(ctx->csa.spu_chnldata_RW[4]); 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cistatic ssize_t spufs_signal2_read(struct file *file, char __user *buf, 11198c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 11228c2ecf20Sopenharmony_ci int ret; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 11258c2ecf20Sopenharmony_ci if (ret) 11268c2ecf20Sopenharmony_ci return ret; 11278c2ecf20Sopenharmony_ci ret = __spufs_signal2_read(ctx, buf, len); 11288c2ecf20Sopenharmony_ci spu_release_saved(ctx); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci return ret; 11318c2ecf20Sopenharmony_ci} 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_cistatic ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 11348c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci struct spu_context *ctx; 11378c2ecf20Sopenharmony_ci ssize_t ret; 11388c2ecf20Sopenharmony_ci u32 data; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci ctx = file->private_data; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (len < 4) 11438c2ecf20Sopenharmony_ci return -EINVAL; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (copy_from_user(&data, buf, 4)) 11468c2ecf20Sopenharmony_ci return -EFAULT; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 11498c2ecf20Sopenharmony_ci if (ret) 11508c2ecf20Sopenharmony_ci return ret; 11518c2ecf20Sopenharmony_ci ctx->ops->signal2_write(ctx, data); 11528c2ecf20Sopenharmony_ci spu_release(ctx); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return 4; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci#if SPUFS_MMAP_4K 11588c2ecf20Sopenharmony_cistatic vm_fault_t 11598c2ecf20Sopenharmony_cispufs_signal2_mmap_fault(struct vm_fault *vmf) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci#if SPUFS_SIGNAL_MAP_SIZE == 0x1000 11628c2ecf20Sopenharmony_ci return spufs_ps_fault(vmf, 0x1c000, SPUFS_SIGNAL_MAP_SIZE); 11638c2ecf20Sopenharmony_ci#elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 11648c2ecf20Sopenharmony_ci /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 11658c2ecf20Sopenharmony_ci * signal 1 and 2 area 11668c2ecf20Sopenharmony_ci */ 11678c2ecf20Sopenharmony_ci return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); 11688c2ecf20Sopenharmony_ci#else 11698c2ecf20Sopenharmony_ci#error unsupported page size 11708c2ecf20Sopenharmony_ci#endif 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cistatic const struct vm_operations_struct spufs_signal2_mmap_vmops = { 11748c2ecf20Sopenharmony_ci .fault = spufs_signal2_mmap_fault, 11758c2ecf20Sopenharmony_ci}; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_SHARED)) 11808c2ecf20Sopenharmony_ci return -EINVAL; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci vma->vm_flags |= VM_IO | VM_PFNMAP; 11838c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci vma->vm_ops = &spufs_signal2_mmap_vmops; 11868c2ecf20Sopenharmony_ci return 0; 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci#else /* SPUFS_MMAP_4K */ 11898c2ecf20Sopenharmony_ci#define spufs_signal2_mmap NULL 11908c2ecf20Sopenharmony_ci#endif /* !SPUFS_MMAP_4K */ 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic const struct file_operations spufs_signal2_fops = { 11938c2ecf20Sopenharmony_ci .open = spufs_signal2_open, 11948c2ecf20Sopenharmony_ci .release = spufs_signal2_release, 11958c2ecf20Sopenharmony_ci .read = spufs_signal2_read, 11968c2ecf20Sopenharmony_ci .write = spufs_signal2_write, 11978c2ecf20Sopenharmony_ci .mmap = spufs_signal2_mmap, 11988c2ecf20Sopenharmony_ci .llseek = no_llseek, 11998c2ecf20Sopenharmony_ci}; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic const struct file_operations spufs_signal2_nosched_fops = { 12028c2ecf20Sopenharmony_ci .open = spufs_signal2_open, 12038c2ecf20Sopenharmony_ci .release = spufs_signal2_release, 12048c2ecf20Sopenharmony_ci .write = spufs_signal2_write, 12058c2ecf20Sopenharmony_ci .mmap = spufs_signal2_mmap, 12068c2ecf20Sopenharmony_ci .llseek = no_llseek, 12078c2ecf20Sopenharmony_ci}; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci/* 12108c2ecf20Sopenharmony_ci * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the 12118c2ecf20Sopenharmony_ci * work of acquiring (or not) the SPU context before calling through 12128c2ecf20Sopenharmony_ci * to the actual get routine. The set routine is called directly. 12138c2ecf20Sopenharmony_ci */ 12148c2ecf20Sopenharmony_ci#define SPU_ATTR_NOACQUIRE 0 12158c2ecf20Sopenharmony_ci#define SPU_ATTR_ACQUIRE 1 12168c2ecf20Sopenharmony_ci#define SPU_ATTR_ACQUIRE_SAVED 2 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci#define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ 12198c2ecf20Sopenharmony_cistatic int __##__get(void *data, u64 *val) \ 12208c2ecf20Sopenharmony_ci{ \ 12218c2ecf20Sopenharmony_ci struct spu_context *ctx = data; \ 12228c2ecf20Sopenharmony_ci int ret = 0; \ 12238c2ecf20Sopenharmony_ci \ 12248c2ecf20Sopenharmony_ci if (__acquire == SPU_ATTR_ACQUIRE) { \ 12258c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); \ 12268c2ecf20Sopenharmony_ci if (ret) \ 12278c2ecf20Sopenharmony_ci return ret; \ 12288c2ecf20Sopenharmony_ci *val = __get(ctx); \ 12298c2ecf20Sopenharmony_ci spu_release(ctx); \ 12308c2ecf20Sopenharmony_ci } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ 12318c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); \ 12328c2ecf20Sopenharmony_ci if (ret) \ 12338c2ecf20Sopenharmony_ci return ret; \ 12348c2ecf20Sopenharmony_ci *val = __get(ctx); \ 12358c2ecf20Sopenharmony_ci spu_release_saved(ctx); \ 12368c2ecf20Sopenharmony_ci } else \ 12378c2ecf20Sopenharmony_ci *val = __get(ctx); \ 12388c2ecf20Sopenharmony_ci \ 12398c2ecf20Sopenharmony_ci return 0; \ 12408c2ecf20Sopenharmony_ci} \ 12418c2ecf20Sopenharmony_ciDEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cistatic int spufs_signal1_type_set(void *data, u64 val) 12448c2ecf20Sopenharmony_ci{ 12458c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 12468c2ecf20Sopenharmony_ci int ret; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 12498c2ecf20Sopenharmony_ci if (ret) 12508c2ecf20Sopenharmony_ci return ret; 12518c2ecf20Sopenharmony_ci ctx->ops->signal1_type_set(ctx, val); 12528c2ecf20Sopenharmony_ci spu_release(ctx); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci return 0; 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic u64 spufs_signal1_type_get(struct spu_context *ctx) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci return ctx->ops->signal1_type_get(ctx); 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 12628c2ecf20Sopenharmony_ci spufs_signal1_type_set, "%llu\n", SPU_ATTR_ACQUIRE); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_cistatic int spufs_signal2_type_set(void *data, u64 val) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 12688c2ecf20Sopenharmony_ci int ret; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 12718c2ecf20Sopenharmony_ci if (ret) 12728c2ecf20Sopenharmony_ci return ret; 12738c2ecf20Sopenharmony_ci ctx->ops->signal2_type_set(ctx, val); 12748c2ecf20Sopenharmony_ci spu_release(ctx); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci return 0; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic u64 spufs_signal2_type_get(struct spu_context *ctx) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci return ctx->ops->signal2_type_get(ctx); 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 12848c2ecf20Sopenharmony_ci spufs_signal2_type_set, "%llu\n", SPU_ATTR_ACQUIRE); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci#if SPUFS_MMAP_4K 12878c2ecf20Sopenharmony_cistatic vm_fault_t 12888c2ecf20Sopenharmony_cispufs_mss_mmap_fault(struct vm_fault *vmf) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci return spufs_ps_fault(vmf, 0x0000, SPUFS_MSS_MAP_SIZE); 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic const struct vm_operations_struct spufs_mss_mmap_vmops = { 12948c2ecf20Sopenharmony_ci .fault = spufs_mss_mmap_fault, 12958c2ecf20Sopenharmony_ci}; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci/* 12988c2ecf20Sopenharmony_ci * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 12998c2ecf20Sopenharmony_ci */ 13008c2ecf20Sopenharmony_cistatic int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_SHARED)) 13038c2ecf20Sopenharmony_ci return -EINVAL; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci vma->vm_flags |= VM_IO | VM_PFNMAP; 13068c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci vma->vm_ops = &spufs_mss_mmap_vmops; 13098c2ecf20Sopenharmony_ci return 0; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci#else /* SPUFS_MMAP_4K */ 13128c2ecf20Sopenharmony_ci#define spufs_mss_mmap NULL 13138c2ecf20Sopenharmony_ci#endif /* !SPUFS_MMAP_4K */ 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic int spufs_mss_open(struct inode *inode, struct file *file) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 13188c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci file->private_data = i->i_ctx; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 13238c2ecf20Sopenharmony_ci if (!i->i_openers++) 13248c2ecf20Sopenharmony_ci ctx->mss = inode->i_mapping; 13258c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 13268c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistatic int 13308c2ecf20Sopenharmony_cispufs_mss_release(struct inode *inode, struct file *file) 13318c2ecf20Sopenharmony_ci{ 13328c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 13338c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 13368c2ecf20Sopenharmony_ci if (!--i->i_openers) 13378c2ecf20Sopenharmony_ci ctx->mss = NULL; 13388c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 13398c2ecf20Sopenharmony_ci return 0; 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic const struct file_operations spufs_mss_fops = { 13438c2ecf20Sopenharmony_ci .open = spufs_mss_open, 13448c2ecf20Sopenharmony_ci .release = spufs_mss_release, 13458c2ecf20Sopenharmony_ci .mmap = spufs_mss_mmap, 13468c2ecf20Sopenharmony_ci .llseek = no_llseek, 13478c2ecf20Sopenharmony_ci}; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic vm_fault_t 13508c2ecf20Sopenharmony_cispufs_psmap_mmap_fault(struct vm_fault *vmf) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci return spufs_ps_fault(vmf, 0x0000, SPUFS_PS_MAP_SIZE); 13538c2ecf20Sopenharmony_ci} 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_cistatic const struct vm_operations_struct spufs_psmap_mmap_vmops = { 13568c2ecf20Sopenharmony_ci .fault = spufs_psmap_mmap_fault, 13578c2ecf20Sopenharmony_ci}; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci/* 13608c2ecf20Sopenharmony_ci * mmap support for full problem state area [0x00000 - 0x1ffff]. 13618c2ecf20Sopenharmony_ci */ 13628c2ecf20Sopenharmony_cistatic int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_SHARED)) 13658c2ecf20Sopenharmony_ci return -EINVAL; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci vma->vm_flags |= VM_IO | VM_PFNMAP; 13688c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci vma->vm_ops = &spufs_psmap_mmap_vmops; 13718c2ecf20Sopenharmony_ci return 0; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic int spufs_psmap_open(struct inode *inode, struct file *file) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 13778c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 13808c2ecf20Sopenharmony_ci file->private_data = i->i_ctx; 13818c2ecf20Sopenharmony_ci if (!i->i_openers++) 13828c2ecf20Sopenharmony_ci ctx->psmap = inode->i_mapping; 13838c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 13848c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic int 13888c2ecf20Sopenharmony_cispufs_psmap_release(struct inode *inode, struct file *file) 13898c2ecf20Sopenharmony_ci{ 13908c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 13918c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 13948c2ecf20Sopenharmony_ci if (!--i->i_openers) 13958c2ecf20Sopenharmony_ci ctx->psmap = NULL; 13968c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 13978c2ecf20Sopenharmony_ci return 0; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic const struct file_operations spufs_psmap_fops = { 14018c2ecf20Sopenharmony_ci .open = spufs_psmap_open, 14028c2ecf20Sopenharmony_ci .release = spufs_psmap_release, 14038c2ecf20Sopenharmony_ci .mmap = spufs_psmap_mmap, 14048c2ecf20Sopenharmony_ci .llseek = no_llseek, 14058c2ecf20Sopenharmony_ci}; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci#if SPUFS_MMAP_4K 14098c2ecf20Sopenharmony_cistatic vm_fault_t 14108c2ecf20Sopenharmony_cispufs_mfc_mmap_fault(struct vm_fault *vmf) 14118c2ecf20Sopenharmony_ci{ 14128c2ecf20Sopenharmony_ci return spufs_ps_fault(vmf, 0x3000, SPUFS_MFC_MAP_SIZE); 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic const struct vm_operations_struct spufs_mfc_mmap_vmops = { 14168c2ecf20Sopenharmony_ci .fault = spufs_mfc_mmap_fault, 14178c2ecf20Sopenharmony_ci}; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci/* 14208c2ecf20Sopenharmony_ci * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 14218c2ecf20Sopenharmony_ci */ 14228c2ecf20Sopenharmony_cistatic int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_SHARED)) 14258c2ecf20Sopenharmony_ci return -EINVAL; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci vma->vm_flags |= VM_IO | VM_PFNMAP; 14288c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci vma->vm_ops = &spufs_mfc_mmap_vmops; 14318c2ecf20Sopenharmony_ci return 0; 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci#else /* SPUFS_MMAP_4K */ 14348c2ecf20Sopenharmony_ci#define spufs_mfc_mmap NULL 14358c2ecf20Sopenharmony_ci#endif /* !SPUFS_MMAP_4K */ 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cistatic int spufs_mfc_open(struct inode *inode, struct file *file) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 14408c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci /* we don't want to deal with DMA into other processes */ 14438c2ecf20Sopenharmony_ci if (ctx->owner != current->mm) 14448c2ecf20Sopenharmony_ci return -EINVAL; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci if (atomic_read(&inode->i_count) != 1) 14478c2ecf20Sopenharmony_ci return -EBUSY; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 14508c2ecf20Sopenharmony_ci file->private_data = ctx; 14518c2ecf20Sopenharmony_ci if (!i->i_openers++) 14528c2ecf20Sopenharmony_ci ctx->mfc = inode->i_mapping; 14538c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 14548c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic int 14588c2ecf20Sopenharmony_cispufs_mfc_release(struct inode *inode, struct file *file) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 14618c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci mutex_lock(&ctx->mapping_lock); 14648c2ecf20Sopenharmony_ci if (!--i->i_openers) 14658c2ecf20Sopenharmony_ci ctx->mfc = NULL; 14668c2ecf20Sopenharmony_ci mutex_unlock(&ctx->mapping_lock); 14678c2ecf20Sopenharmony_ci return 0; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci/* interrupt-level mfc callback function. */ 14718c2ecf20Sopenharmony_civoid spufs_mfc_callback(struct spu *spu) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci struct spu_context *ctx = spu->ctx; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if (ctx) 14768c2ecf20Sopenharmony_ci wake_up_all(&ctx->mfc_wq); 14778c2ecf20Sopenharmony_ci} 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci /* See if there is one tag group is complete */ 14828c2ecf20Sopenharmony_ci /* FIXME we need locking around tagwait */ 14838c2ecf20Sopenharmony_ci *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 14848c2ecf20Sopenharmony_ci ctx->tagwait &= ~*status; 14858c2ecf20Sopenharmony_ci if (*status) 14868c2ecf20Sopenharmony_ci return 1; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* enable interrupt waiting for any tag group, 14898c2ecf20Sopenharmony_ci may silently fail if interrupts are already enabled */ 14908c2ecf20Sopenharmony_ci ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 14918c2ecf20Sopenharmony_ci return 0; 14928c2ecf20Sopenharmony_ci} 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_cistatic ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 14958c2ecf20Sopenharmony_ci size_t size, loff_t *pos) 14968c2ecf20Sopenharmony_ci{ 14978c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 14988c2ecf20Sopenharmony_ci int ret = -EINVAL; 14998c2ecf20Sopenharmony_ci u32 status; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (size != 4) 15028c2ecf20Sopenharmony_ci goto out; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 15058c2ecf20Sopenharmony_ci if (ret) 15068c2ecf20Sopenharmony_ci return ret; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci ret = -EINVAL; 15098c2ecf20Sopenharmony_ci if (file->f_flags & O_NONBLOCK) { 15108c2ecf20Sopenharmony_ci status = ctx->ops->read_mfc_tagstatus(ctx); 15118c2ecf20Sopenharmony_ci if (!(status & ctx->tagwait)) 15128c2ecf20Sopenharmony_ci ret = -EAGAIN; 15138c2ecf20Sopenharmony_ci else 15148c2ecf20Sopenharmony_ci /* XXX(hch): shouldn't we clear ret here? */ 15158c2ecf20Sopenharmony_ci ctx->tagwait &= ~status; 15168c2ecf20Sopenharmony_ci } else { 15178c2ecf20Sopenharmony_ci ret = spufs_wait(ctx->mfc_wq, 15188c2ecf20Sopenharmony_ci spufs_read_mfc_tagstatus(ctx, &status)); 15198c2ecf20Sopenharmony_ci if (ret) 15208c2ecf20Sopenharmony_ci goto out; 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci spu_release(ctx); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci ret = 4; 15258c2ecf20Sopenharmony_ci if (copy_to_user(buffer, &status, 4)) 15268c2ecf20Sopenharmony_ci ret = -EFAULT; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ciout: 15298c2ecf20Sopenharmony_ci return ret; 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_cistatic int spufs_check_valid_dma(struct mfc_dma_command *cmd) 15338c2ecf20Sopenharmony_ci{ 15348c2ecf20Sopenharmony_ci pr_debug("queueing DMA %x %llx %x %x %x\n", cmd->lsa, 15358c2ecf20Sopenharmony_ci cmd->ea, cmd->size, cmd->tag, cmd->cmd); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci switch (cmd->cmd) { 15388c2ecf20Sopenharmony_ci case MFC_PUT_CMD: 15398c2ecf20Sopenharmony_ci case MFC_PUTF_CMD: 15408c2ecf20Sopenharmony_ci case MFC_PUTB_CMD: 15418c2ecf20Sopenharmony_ci case MFC_GET_CMD: 15428c2ecf20Sopenharmony_ci case MFC_GETF_CMD: 15438c2ecf20Sopenharmony_ci case MFC_GETB_CMD: 15448c2ecf20Sopenharmony_ci break; 15458c2ecf20Sopenharmony_ci default: 15468c2ecf20Sopenharmony_ci pr_debug("invalid DMA opcode %x\n", cmd->cmd); 15478c2ecf20Sopenharmony_ci return -EIO; 15488c2ecf20Sopenharmony_ci } 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 15518c2ecf20Sopenharmony_ci pr_debug("invalid DMA alignment, ea %llx lsa %x\n", 15528c2ecf20Sopenharmony_ci cmd->ea, cmd->lsa); 15538c2ecf20Sopenharmony_ci return -EIO; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci switch (cmd->size & 0xf) { 15578c2ecf20Sopenharmony_ci case 1: 15588c2ecf20Sopenharmony_ci break; 15598c2ecf20Sopenharmony_ci case 2: 15608c2ecf20Sopenharmony_ci if (cmd->lsa & 1) 15618c2ecf20Sopenharmony_ci goto error; 15628c2ecf20Sopenharmony_ci break; 15638c2ecf20Sopenharmony_ci case 4: 15648c2ecf20Sopenharmony_ci if (cmd->lsa & 3) 15658c2ecf20Sopenharmony_ci goto error; 15668c2ecf20Sopenharmony_ci break; 15678c2ecf20Sopenharmony_ci case 8: 15688c2ecf20Sopenharmony_ci if (cmd->lsa & 7) 15698c2ecf20Sopenharmony_ci goto error; 15708c2ecf20Sopenharmony_ci break; 15718c2ecf20Sopenharmony_ci case 0: 15728c2ecf20Sopenharmony_ci if (cmd->lsa & 15) 15738c2ecf20Sopenharmony_ci goto error; 15748c2ecf20Sopenharmony_ci break; 15758c2ecf20Sopenharmony_ci error: 15768c2ecf20Sopenharmony_ci default: 15778c2ecf20Sopenharmony_ci pr_debug("invalid DMA alignment %x for size %x\n", 15788c2ecf20Sopenharmony_ci cmd->lsa & 0xf, cmd->size); 15798c2ecf20Sopenharmony_ci return -EIO; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (cmd->size > 16 * 1024) { 15838c2ecf20Sopenharmony_ci pr_debug("invalid DMA size %x\n", cmd->size); 15848c2ecf20Sopenharmony_ci return -EIO; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (cmd->tag & 0xfff0) { 15888c2ecf20Sopenharmony_ci /* we reserve the higher tag numbers for kernel use */ 15898c2ecf20Sopenharmony_ci pr_debug("invalid DMA tag\n"); 15908c2ecf20Sopenharmony_ci return -EIO; 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (cmd->class) { 15948c2ecf20Sopenharmony_ci /* not supported in this version */ 15958c2ecf20Sopenharmony_ci pr_debug("invalid DMA class\n"); 15968c2ecf20Sopenharmony_ci return -EIO; 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci return 0; 16008c2ecf20Sopenharmony_ci} 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_cistatic int spu_send_mfc_command(struct spu_context *ctx, 16038c2ecf20Sopenharmony_ci struct mfc_dma_command cmd, 16048c2ecf20Sopenharmony_ci int *error) 16058c2ecf20Sopenharmony_ci{ 16068c2ecf20Sopenharmony_ci *error = ctx->ops->send_mfc_command(ctx, &cmd); 16078c2ecf20Sopenharmony_ci if (*error == -EAGAIN) { 16088c2ecf20Sopenharmony_ci /* wait for any tag group to complete 16098c2ecf20Sopenharmony_ci so we have space for the new command */ 16108c2ecf20Sopenharmony_ci ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 16118c2ecf20Sopenharmony_ci /* try again, because the queue might be 16128c2ecf20Sopenharmony_ci empty again */ 16138c2ecf20Sopenharmony_ci *error = ctx->ops->send_mfc_command(ctx, &cmd); 16148c2ecf20Sopenharmony_ci if (*error == -EAGAIN) 16158c2ecf20Sopenharmony_ci return 0; 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci return 1; 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 16218c2ecf20Sopenharmony_ci size_t size, loff_t *pos) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 16248c2ecf20Sopenharmony_ci struct mfc_dma_command cmd; 16258c2ecf20Sopenharmony_ci int ret = -EINVAL; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (size != sizeof cmd) 16288c2ecf20Sopenharmony_ci goto out; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci ret = -EFAULT; 16318c2ecf20Sopenharmony_ci if (copy_from_user(&cmd, buffer, sizeof cmd)) 16328c2ecf20Sopenharmony_ci goto out; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci ret = spufs_check_valid_dma(&cmd); 16358c2ecf20Sopenharmony_ci if (ret) 16368c2ecf20Sopenharmony_ci goto out; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 16398c2ecf20Sopenharmony_ci if (ret) 16408c2ecf20Sopenharmony_ci goto out; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 16438c2ecf20Sopenharmony_ci if (ret) 16448c2ecf20Sopenharmony_ci goto out; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (file->f_flags & O_NONBLOCK) { 16478c2ecf20Sopenharmony_ci ret = ctx->ops->send_mfc_command(ctx, &cmd); 16488c2ecf20Sopenharmony_ci } else { 16498c2ecf20Sopenharmony_ci int status; 16508c2ecf20Sopenharmony_ci ret = spufs_wait(ctx->mfc_wq, 16518c2ecf20Sopenharmony_ci spu_send_mfc_command(ctx, cmd, &status)); 16528c2ecf20Sopenharmony_ci if (ret) 16538c2ecf20Sopenharmony_ci goto out; 16548c2ecf20Sopenharmony_ci if (status) 16558c2ecf20Sopenharmony_ci ret = status; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (ret) 16598c2ecf20Sopenharmony_ci goto out_unlock; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci ctx->tagwait |= 1 << cmd.tag; 16628c2ecf20Sopenharmony_ci ret = size; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ciout_unlock: 16658c2ecf20Sopenharmony_ci spu_release(ctx); 16668c2ecf20Sopenharmony_ciout: 16678c2ecf20Sopenharmony_ci return ret; 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_cistatic __poll_t spufs_mfc_poll(struct file *file,poll_table *wait) 16718c2ecf20Sopenharmony_ci{ 16728c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 16738c2ecf20Sopenharmony_ci u32 free_elements, tagstatus; 16748c2ecf20Sopenharmony_ci __poll_t mask; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci poll_wait(file, &ctx->mfc_wq, wait); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci /* 16798c2ecf20Sopenharmony_ci * For now keep this uninterruptible and also ignore the rule 16808c2ecf20Sopenharmony_ci * that poll should not sleep. Will be fixed later. 16818c2ecf20Sopenharmony_ci */ 16828c2ecf20Sopenharmony_ci mutex_lock(&ctx->state_mutex); 16838c2ecf20Sopenharmony_ci ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 16848c2ecf20Sopenharmony_ci free_elements = ctx->ops->get_mfc_free_elements(ctx); 16858c2ecf20Sopenharmony_ci tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 16868c2ecf20Sopenharmony_ci spu_release(ctx); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci mask = 0; 16898c2ecf20Sopenharmony_ci if (free_elements & 0xffff) 16908c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM; 16918c2ecf20Sopenharmony_ci if (tagstatus & ctx->tagwait) 16928c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci pr_debug("%s: free %d tagstatus %d tagwait %d\n", __func__, 16958c2ecf20Sopenharmony_ci free_elements, tagstatus, ctx->tagwait); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci return mask; 16988c2ecf20Sopenharmony_ci} 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_cistatic int spufs_mfc_flush(struct file *file, fl_owner_t id) 17018c2ecf20Sopenharmony_ci{ 17028c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 17038c2ecf20Sopenharmony_ci int ret; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 17068c2ecf20Sopenharmony_ci if (ret) 17078c2ecf20Sopenharmony_ci goto out; 17088c2ecf20Sopenharmony_ci#if 0 17098c2ecf20Sopenharmony_ci/* this currently hangs */ 17108c2ecf20Sopenharmony_ci ret = spufs_wait(ctx->mfc_wq, 17118c2ecf20Sopenharmony_ci ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 17128c2ecf20Sopenharmony_ci if (ret) 17138c2ecf20Sopenharmony_ci goto out; 17148c2ecf20Sopenharmony_ci ret = spufs_wait(ctx->mfc_wq, 17158c2ecf20Sopenharmony_ci ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 17168c2ecf20Sopenharmony_ci if (ret) 17178c2ecf20Sopenharmony_ci goto out; 17188c2ecf20Sopenharmony_ci#else 17198c2ecf20Sopenharmony_ci ret = 0; 17208c2ecf20Sopenharmony_ci#endif 17218c2ecf20Sopenharmony_ci spu_release(ctx); 17228c2ecf20Sopenharmony_ciout: 17238c2ecf20Sopenharmony_ci return ret; 17248c2ecf20Sopenharmony_ci} 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_cistatic int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync) 17278c2ecf20Sopenharmony_ci{ 17288c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 17298c2ecf20Sopenharmony_ci int err = file_write_and_wait_range(file, start, end); 17308c2ecf20Sopenharmony_ci if (!err) { 17318c2ecf20Sopenharmony_ci inode_lock(inode); 17328c2ecf20Sopenharmony_ci err = spufs_mfc_flush(file, NULL); 17338c2ecf20Sopenharmony_ci inode_unlock(inode); 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci return err; 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistatic const struct file_operations spufs_mfc_fops = { 17398c2ecf20Sopenharmony_ci .open = spufs_mfc_open, 17408c2ecf20Sopenharmony_ci .release = spufs_mfc_release, 17418c2ecf20Sopenharmony_ci .read = spufs_mfc_read, 17428c2ecf20Sopenharmony_ci .write = spufs_mfc_write, 17438c2ecf20Sopenharmony_ci .poll = spufs_mfc_poll, 17448c2ecf20Sopenharmony_ci .flush = spufs_mfc_flush, 17458c2ecf20Sopenharmony_ci .fsync = spufs_mfc_fsync, 17468c2ecf20Sopenharmony_ci .mmap = spufs_mfc_mmap, 17478c2ecf20Sopenharmony_ci .llseek = no_llseek, 17488c2ecf20Sopenharmony_ci}; 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_cistatic int spufs_npc_set(void *data, u64 val) 17518c2ecf20Sopenharmony_ci{ 17528c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 17538c2ecf20Sopenharmony_ci int ret; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 17568c2ecf20Sopenharmony_ci if (ret) 17578c2ecf20Sopenharmony_ci return ret; 17588c2ecf20Sopenharmony_ci ctx->ops->npc_write(ctx, val); 17598c2ecf20Sopenharmony_ci spu_release(ctx); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci return 0; 17628c2ecf20Sopenharmony_ci} 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_cistatic u64 spufs_npc_get(struct spu_context *ctx) 17658c2ecf20Sopenharmony_ci{ 17668c2ecf20Sopenharmony_ci return ctx->ops->npc_read(ctx); 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 17698c2ecf20Sopenharmony_ci "0x%llx\n", SPU_ATTR_ACQUIRE); 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_cistatic int spufs_decr_set(void *data, u64 val) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 17748c2ecf20Sopenharmony_ci struct spu_lscsa *lscsa = ctx->csa.lscsa; 17758c2ecf20Sopenharmony_ci int ret; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 17788c2ecf20Sopenharmony_ci if (ret) 17798c2ecf20Sopenharmony_ci return ret; 17808c2ecf20Sopenharmony_ci lscsa->decr.slot[0] = (u32) val; 17818c2ecf20Sopenharmony_ci spu_release_saved(ctx); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci return 0; 17848c2ecf20Sopenharmony_ci} 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_cistatic u64 spufs_decr_get(struct spu_context *ctx) 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci struct spu_lscsa *lscsa = ctx->csa.lscsa; 17898c2ecf20Sopenharmony_ci return lscsa->decr.slot[0]; 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 17928c2ecf20Sopenharmony_ci "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_cistatic int spufs_decr_status_set(void *data, u64 val) 17958c2ecf20Sopenharmony_ci{ 17968c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 17978c2ecf20Sopenharmony_ci int ret; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 18008c2ecf20Sopenharmony_ci if (ret) 18018c2ecf20Sopenharmony_ci return ret; 18028c2ecf20Sopenharmony_ci if (val) 18038c2ecf20Sopenharmony_ci ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 18048c2ecf20Sopenharmony_ci else 18058c2ecf20Sopenharmony_ci ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 18068c2ecf20Sopenharmony_ci spu_release_saved(ctx); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci return 0; 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic u64 spufs_decr_status_get(struct spu_context *ctx) 18128c2ecf20Sopenharmony_ci{ 18138c2ecf20Sopenharmony_ci if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 18148c2ecf20Sopenharmony_ci return SPU_DECR_STATUS_RUNNING; 18158c2ecf20Sopenharmony_ci else 18168c2ecf20Sopenharmony_ci return 0; 18178c2ecf20Sopenharmony_ci} 18188c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 18198c2ecf20Sopenharmony_ci spufs_decr_status_set, "0x%llx\n", 18208c2ecf20Sopenharmony_ci SPU_ATTR_ACQUIRE_SAVED); 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_cistatic int spufs_event_mask_set(void *data, u64 val) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 18258c2ecf20Sopenharmony_ci struct spu_lscsa *lscsa = ctx->csa.lscsa; 18268c2ecf20Sopenharmony_ci int ret; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 18298c2ecf20Sopenharmony_ci if (ret) 18308c2ecf20Sopenharmony_ci return ret; 18318c2ecf20Sopenharmony_ci lscsa->event_mask.slot[0] = (u32) val; 18328c2ecf20Sopenharmony_ci spu_release_saved(ctx); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci return 0; 18358c2ecf20Sopenharmony_ci} 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_cistatic u64 spufs_event_mask_get(struct spu_context *ctx) 18388c2ecf20Sopenharmony_ci{ 18398c2ecf20Sopenharmony_ci struct spu_lscsa *lscsa = ctx->csa.lscsa; 18408c2ecf20Sopenharmony_ci return lscsa->event_mask.slot[0]; 18418c2ecf20Sopenharmony_ci} 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 18448c2ecf20Sopenharmony_ci spufs_event_mask_set, "0x%llx\n", 18458c2ecf20Sopenharmony_ci SPU_ATTR_ACQUIRE_SAVED); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_cistatic u64 spufs_event_status_get(struct spu_context *ctx) 18488c2ecf20Sopenharmony_ci{ 18498c2ecf20Sopenharmony_ci struct spu_state *state = &ctx->csa; 18508c2ecf20Sopenharmony_ci u64 stat; 18518c2ecf20Sopenharmony_ci stat = state->spu_chnlcnt_RW[0]; 18528c2ecf20Sopenharmony_ci if (stat) 18538c2ecf20Sopenharmony_ci return state->spu_chnldata_RW[0]; 18548c2ecf20Sopenharmony_ci return 0; 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 18578c2ecf20Sopenharmony_ci NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cistatic int spufs_srr0_set(void *data, u64 val) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 18628c2ecf20Sopenharmony_ci struct spu_lscsa *lscsa = ctx->csa.lscsa; 18638c2ecf20Sopenharmony_ci int ret; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 18668c2ecf20Sopenharmony_ci if (ret) 18678c2ecf20Sopenharmony_ci return ret; 18688c2ecf20Sopenharmony_ci lscsa->srr0.slot[0] = (u32) val; 18698c2ecf20Sopenharmony_ci spu_release_saved(ctx); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci return 0; 18728c2ecf20Sopenharmony_ci} 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_cistatic u64 spufs_srr0_get(struct spu_context *ctx) 18758c2ecf20Sopenharmony_ci{ 18768c2ecf20Sopenharmony_ci struct spu_lscsa *lscsa = ctx->csa.lscsa; 18778c2ecf20Sopenharmony_ci return lscsa->srr0.slot[0]; 18788c2ecf20Sopenharmony_ci} 18798c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 18808c2ecf20Sopenharmony_ci "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_cistatic u64 spufs_id_get(struct spu_context *ctx) 18838c2ecf20Sopenharmony_ci{ 18848c2ecf20Sopenharmony_ci u64 num; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci if (ctx->state == SPU_STATE_RUNNABLE) 18878c2ecf20Sopenharmony_ci num = ctx->spu->number; 18888c2ecf20Sopenharmony_ci else 18898c2ecf20Sopenharmony_ci num = (unsigned int)-1; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci return num; 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", 18948c2ecf20Sopenharmony_ci SPU_ATTR_ACQUIRE) 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic u64 spufs_object_id_get(struct spu_context *ctx) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci /* FIXME: Should there really be no locking here? */ 18998c2ecf20Sopenharmony_ci return ctx->object_id; 19008c2ecf20Sopenharmony_ci} 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_cistatic int spufs_object_id_set(void *data, u64 id) 19038c2ecf20Sopenharmony_ci{ 19048c2ecf20Sopenharmony_ci struct spu_context *ctx = data; 19058c2ecf20Sopenharmony_ci ctx->object_id = id; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci return 0; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 19118c2ecf20Sopenharmony_ci spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_cistatic u64 spufs_lslr_get(struct spu_context *ctx) 19148c2ecf20Sopenharmony_ci{ 19158c2ecf20Sopenharmony_ci return ctx->csa.priv2.spu_lslr_RW; 19168c2ecf20Sopenharmony_ci} 19178c2ecf20Sopenharmony_ciDEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", 19188c2ecf20Sopenharmony_ci SPU_ATTR_ACQUIRE_SAVED); 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_cistatic int spufs_info_open(struct inode *inode, struct file *file) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci struct spufs_inode_info *i = SPUFS_I(inode); 19238c2ecf20Sopenharmony_ci struct spu_context *ctx = i->i_ctx; 19248c2ecf20Sopenharmony_ci file->private_data = ctx; 19258c2ecf20Sopenharmony_ci return 0; 19268c2ecf20Sopenharmony_ci} 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_cistatic int spufs_caps_show(struct seq_file *s, void *private) 19298c2ecf20Sopenharmony_ci{ 19308c2ecf20Sopenharmony_ci struct spu_context *ctx = s->private; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci if (!(ctx->flags & SPU_CREATE_NOSCHED)) 19338c2ecf20Sopenharmony_ci seq_puts(s, "sched\n"); 19348c2ecf20Sopenharmony_ci if (!(ctx->flags & SPU_CREATE_ISOLATE)) 19358c2ecf20Sopenharmony_ci seq_puts(s, "step\n"); 19368c2ecf20Sopenharmony_ci return 0; 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_cistatic int spufs_caps_open(struct inode *inode, struct file *file) 19408c2ecf20Sopenharmony_ci{ 19418c2ecf20Sopenharmony_ci return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); 19428c2ecf20Sopenharmony_ci} 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_cistatic const struct file_operations spufs_caps_fops = { 19458c2ecf20Sopenharmony_ci .open = spufs_caps_open, 19468c2ecf20Sopenharmony_ci .read = seq_read, 19478c2ecf20Sopenharmony_ci .llseek = seq_lseek, 19488c2ecf20Sopenharmony_ci .release = single_release, 19498c2ecf20Sopenharmony_ci}; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_cistatic ssize_t spufs_mbox_info_dump(struct spu_context *ctx, 19528c2ecf20Sopenharmony_ci struct coredump_params *cprm) 19538c2ecf20Sopenharmony_ci{ 19548c2ecf20Sopenharmony_ci if (!(ctx->csa.prob.mb_stat_R & 0x0000ff)) 19558c2ecf20Sopenharmony_ci return 0; 19568c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, &ctx->csa.prob.pu_mb_R, 19578c2ecf20Sopenharmony_ci sizeof(ctx->csa.prob.pu_mb_R)); 19588c2ecf20Sopenharmony_ci} 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_cistatic ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 19618c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 19628c2ecf20Sopenharmony_ci{ 19638c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 19648c2ecf20Sopenharmony_ci u32 stat, data; 19658c2ecf20Sopenharmony_ci int ret; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 19688c2ecf20Sopenharmony_ci if (ret) 19698c2ecf20Sopenharmony_ci return ret; 19708c2ecf20Sopenharmony_ci spin_lock(&ctx->csa.register_lock); 19718c2ecf20Sopenharmony_ci stat = ctx->csa.prob.mb_stat_R; 19728c2ecf20Sopenharmony_ci data = ctx->csa.prob.pu_mb_R; 19738c2ecf20Sopenharmony_ci spin_unlock(&ctx->csa.register_lock); 19748c2ecf20Sopenharmony_ci spu_release_saved(ctx); 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci /* EOF if there's no entry in the mbox */ 19778c2ecf20Sopenharmony_ci if (!(stat & 0x0000ff)) 19788c2ecf20Sopenharmony_ci return 0; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, len, pos, &data, sizeof(data)); 19818c2ecf20Sopenharmony_ci} 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_cistatic const struct file_operations spufs_mbox_info_fops = { 19848c2ecf20Sopenharmony_ci .open = spufs_info_open, 19858c2ecf20Sopenharmony_ci .read = spufs_mbox_info_read, 19868c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 19878c2ecf20Sopenharmony_ci}; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_cistatic ssize_t spufs_ibox_info_dump(struct spu_context *ctx, 19908c2ecf20Sopenharmony_ci struct coredump_params *cprm) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) 19938c2ecf20Sopenharmony_ci return 0; 19948c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, &ctx->csa.priv2.puint_mb_R, 19958c2ecf20Sopenharmony_ci sizeof(ctx->csa.priv2.puint_mb_R)); 19968c2ecf20Sopenharmony_ci} 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_cistatic ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 19998c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 20008c2ecf20Sopenharmony_ci{ 20018c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 20028c2ecf20Sopenharmony_ci u32 stat, data; 20038c2ecf20Sopenharmony_ci int ret; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 20068c2ecf20Sopenharmony_ci if (ret) 20078c2ecf20Sopenharmony_ci return ret; 20088c2ecf20Sopenharmony_ci spin_lock(&ctx->csa.register_lock); 20098c2ecf20Sopenharmony_ci stat = ctx->csa.prob.mb_stat_R; 20108c2ecf20Sopenharmony_ci data = ctx->csa.priv2.puint_mb_R; 20118c2ecf20Sopenharmony_ci spin_unlock(&ctx->csa.register_lock); 20128c2ecf20Sopenharmony_ci spu_release_saved(ctx); 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci /* EOF if there's no entry in the ibox */ 20158c2ecf20Sopenharmony_ci if (!(stat & 0xff0000)) 20168c2ecf20Sopenharmony_ci return 0; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, len, pos, &data, sizeof(data)); 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_cistatic const struct file_operations spufs_ibox_info_fops = { 20228c2ecf20Sopenharmony_ci .open = spufs_info_open, 20238c2ecf20Sopenharmony_ci .read = spufs_ibox_info_read, 20248c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 20258c2ecf20Sopenharmony_ci}; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_cistatic size_t spufs_wbox_info_cnt(struct spu_context *ctx) 20288c2ecf20Sopenharmony_ci{ 20298c2ecf20Sopenharmony_ci return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32); 20308c2ecf20Sopenharmony_ci} 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_cistatic ssize_t spufs_wbox_info_dump(struct spu_context *ctx, 20338c2ecf20Sopenharmony_ci struct coredump_params *cprm) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, &ctx->csa.spu_mailbox_data, 20368c2ecf20Sopenharmony_ci spufs_wbox_info_cnt(ctx)); 20378c2ecf20Sopenharmony_ci} 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_cistatic ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 20408c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 20418c2ecf20Sopenharmony_ci{ 20428c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 20438c2ecf20Sopenharmony_ci u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)]; 20448c2ecf20Sopenharmony_ci int ret, count; 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 20478c2ecf20Sopenharmony_ci if (ret) 20488c2ecf20Sopenharmony_ci return ret; 20498c2ecf20Sopenharmony_ci spin_lock(&ctx->csa.register_lock); 20508c2ecf20Sopenharmony_ci count = spufs_wbox_info_cnt(ctx); 20518c2ecf20Sopenharmony_ci memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data)); 20528c2ecf20Sopenharmony_ci spin_unlock(&ctx->csa.register_lock); 20538c2ecf20Sopenharmony_ci spu_release_saved(ctx); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, len, pos, &data, 20568c2ecf20Sopenharmony_ci count * sizeof(u32)); 20578c2ecf20Sopenharmony_ci} 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_cistatic const struct file_operations spufs_wbox_info_fops = { 20608c2ecf20Sopenharmony_ci .open = spufs_info_open, 20618c2ecf20Sopenharmony_ci .read = spufs_wbox_info_read, 20628c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 20638c2ecf20Sopenharmony_ci}; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_cistatic void spufs_get_dma_info(struct spu_context *ctx, 20668c2ecf20Sopenharmony_ci struct spu_dma_info *info) 20678c2ecf20Sopenharmony_ci{ 20688c2ecf20Sopenharmony_ci int i; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 20718c2ecf20Sopenharmony_ci info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 20728c2ecf20Sopenharmony_ci info->dma_info_status = ctx->csa.spu_chnldata_RW[24]; 20738c2ecf20Sopenharmony_ci info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 20748c2ecf20Sopenharmony_ci info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 20758c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 20768c2ecf20Sopenharmony_ci struct mfc_cq_sr *qp = &info->dma_info_command_data[i]; 20778c2ecf20Sopenharmony_ci struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i]; 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 20808c2ecf20Sopenharmony_ci qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 20818c2ecf20Sopenharmony_ci qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 20828c2ecf20Sopenharmony_ci qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 20838c2ecf20Sopenharmony_ci } 20848c2ecf20Sopenharmony_ci} 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_cistatic ssize_t spufs_dma_info_dump(struct spu_context *ctx, 20878c2ecf20Sopenharmony_ci struct coredump_params *cprm) 20888c2ecf20Sopenharmony_ci{ 20898c2ecf20Sopenharmony_ci struct spu_dma_info info; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci spufs_get_dma_info(ctx, &info); 20928c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, &info, sizeof(info)); 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 20968c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 20998c2ecf20Sopenharmony_ci struct spu_dma_info info; 21008c2ecf20Sopenharmony_ci int ret; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 21038c2ecf20Sopenharmony_ci if (ret) 21048c2ecf20Sopenharmony_ci return ret; 21058c2ecf20Sopenharmony_ci spin_lock(&ctx->csa.register_lock); 21068c2ecf20Sopenharmony_ci spufs_get_dma_info(ctx, &info); 21078c2ecf20Sopenharmony_ci spin_unlock(&ctx->csa.register_lock); 21088c2ecf20Sopenharmony_ci spu_release_saved(ctx); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, len, pos, &info, 21118c2ecf20Sopenharmony_ci sizeof(info)); 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_cistatic const struct file_operations spufs_dma_info_fops = { 21158c2ecf20Sopenharmony_ci .open = spufs_info_open, 21168c2ecf20Sopenharmony_ci .read = spufs_dma_info_read, 21178c2ecf20Sopenharmony_ci .llseek = no_llseek, 21188c2ecf20Sopenharmony_ci}; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_cistatic void spufs_get_proxydma_info(struct spu_context *ctx, 21218c2ecf20Sopenharmony_ci struct spu_proxydma_info *info) 21228c2ecf20Sopenharmony_ci{ 21238c2ecf20Sopenharmony_ci int i; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 21268c2ecf20Sopenharmony_ci info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 21278c2ecf20Sopenharmony_ci info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 21308c2ecf20Sopenharmony_ci struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i]; 21318c2ecf20Sopenharmony_ci struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i]; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 21348c2ecf20Sopenharmony_ci qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 21358c2ecf20Sopenharmony_ci qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 21368c2ecf20Sopenharmony_ci qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_cistatic ssize_t spufs_proxydma_info_dump(struct spu_context *ctx, 21418c2ecf20Sopenharmony_ci struct coredump_params *cprm) 21428c2ecf20Sopenharmony_ci{ 21438c2ecf20Sopenharmony_ci struct spu_proxydma_info info; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci spufs_get_proxydma_info(ctx, &info); 21468c2ecf20Sopenharmony_ci return spufs_dump_emit(cprm, &info, sizeof(info)); 21478c2ecf20Sopenharmony_ci} 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_cistatic ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 21508c2ecf20Sopenharmony_ci size_t len, loff_t *pos) 21518c2ecf20Sopenharmony_ci{ 21528c2ecf20Sopenharmony_ci struct spu_context *ctx = file->private_data; 21538c2ecf20Sopenharmony_ci struct spu_proxydma_info info; 21548c2ecf20Sopenharmony_ci int ret; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci if (len < sizeof(info)) 21578c2ecf20Sopenharmony_ci return -EINVAL; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci ret = spu_acquire_saved(ctx); 21608c2ecf20Sopenharmony_ci if (ret) 21618c2ecf20Sopenharmony_ci return ret; 21628c2ecf20Sopenharmony_ci spin_lock(&ctx->csa.register_lock); 21638c2ecf20Sopenharmony_ci spufs_get_proxydma_info(ctx, &info); 21648c2ecf20Sopenharmony_ci spin_unlock(&ctx->csa.register_lock); 21658c2ecf20Sopenharmony_ci spu_release_saved(ctx); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, len, pos, &info, 21688c2ecf20Sopenharmony_ci sizeof(info)); 21698c2ecf20Sopenharmony_ci} 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_cistatic const struct file_operations spufs_proxydma_info_fops = { 21728c2ecf20Sopenharmony_ci .open = spufs_info_open, 21738c2ecf20Sopenharmony_ci .read = spufs_proxydma_info_read, 21748c2ecf20Sopenharmony_ci .llseek = no_llseek, 21758c2ecf20Sopenharmony_ci}; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_cistatic int spufs_show_tid(struct seq_file *s, void *private) 21788c2ecf20Sopenharmony_ci{ 21798c2ecf20Sopenharmony_ci struct spu_context *ctx = s->private; 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci seq_printf(s, "%d\n", ctx->tid); 21828c2ecf20Sopenharmony_ci return 0; 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_cistatic int spufs_tid_open(struct inode *inode, struct file *file) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); 21888c2ecf20Sopenharmony_ci} 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_cistatic const struct file_operations spufs_tid_fops = { 21918c2ecf20Sopenharmony_ci .open = spufs_tid_open, 21928c2ecf20Sopenharmony_ci .read = seq_read, 21938c2ecf20Sopenharmony_ci .llseek = seq_lseek, 21948c2ecf20Sopenharmony_ci .release = single_release, 21958c2ecf20Sopenharmony_ci}; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_cistatic const char *ctx_state_names[] = { 21988c2ecf20Sopenharmony_ci "user", "system", "iowait", "loaded" 21998c2ecf20Sopenharmony_ci}; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_cistatic unsigned long long spufs_acct_time(struct spu_context *ctx, 22028c2ecf20Sopenharmony_ci enum spu_utilization_state state) 22038c2ecf20Sopenharmony_ci{ 22048c2ecf20Sopenharmony_ci unsigned long long time = ctx->stats.times[state]; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci /* 22078c2ecf20Sopenharmony_ci * In general, utilization statistics are updated by the controlling 22088c2ecf20Sopenharmony_ci * thread as the spu context moves through various well defined 22098c2ecf20Sopenharmony_ci * state transitions, but if the context is lazily loaded its 22108c2ecf20Sopenharmony_ci * utilization statistics are not updated as the controlling thread 22118c2ecf20Sopenharmony_ci * is not tightly coupled with the execution of the spu context. We 22128c2ecf20Sopenharmony_ci * calculate and apply the time delta from the last recorded state 22138c2ecf20Sopenharmony_ci * of the spu context. 22148c2ecf20Sopenharmony_ci */ 22158c2ecf20Sopenharmony_ci if (ctx->spu && ctx->stats.util_state == state) { 22168c2ecf20Sopenharmony_ci time += ktime_get_ns() - ctx->stats.tstamp; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci return time / NSEC_PER_MSEC; 22208c2ecf20Sopenharmony_ci} 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_cistatic unsigned long long spufs_slb_flts(struct spu_context *ctx) 22238c2ecf20Sopenharmony_ci{ 22248c2ecf20Sopenharmony_ci unsigned long long slb_flts = ctx->stats.slb_flt; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci if (ctx->state == SPU_STATE_RUNNABLE) { 22278c2ecf20Sopenharmony_ci slb_flts += (ctx->spu->stats.slb_flt - 22288c2ecf20Sopenharmony_ci ctx->stats.slb_flt_base); 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci return slb_flts; 22328c2ecf20Sopenharmony_ci} 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_cistatic unsigned long long spufs_class2_intrs(struct spu_context *ctx) 22358c2ecf20Sopenharmony_ci{ 22368c2ecf20Sopenharmony_ci unsigned long long class2_intrs = ctx->stats.class2_intr; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci if (ctx->state == SPU_STATE_RUNNABLE) { 22398c2ecf20Sopenharmony_ci class2_intrs += (ctx->spu->stats.class2_intr - 22408c2ecf20Sopenharmony_ci ctx->stats.class2_intr_base); 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci return class2_intrs; 22448c2ecf20Sopenharmony_ci} 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_cistatic int spufs_show_stat(struct seq_file *s, void *private) 22488c2ecf20Sopenharmony_ci{ 22498c2ecf20Sopenharmony_ci struct spu_context *ctx = s->private; 22508c2ecf20Sopenharmony_ci int ret; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci ret = spu_acquire(ctx); 22538c2ecf20Sopenharmony_ci if (ret) 22548c2ecf20Sopenharmony_ci return ret; 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci seq_printf(s, "%s %llu %llu %llu %llu " 22578c2ecf20Sopenharmony_ci "%llu %llu %llu %llu %llu %llu %llu %llu\n", 22588c2ecf20Sopenharmony_ci ctx_state_names[ctx->stats.util_state], 22598c2ecf20Sopenharmony_ci spufs_acct_time(ctx, SPU_UTIL_USER), 22608c2ecf20Sopenharmony_ci spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 22618c2ecf20Sopenharmony_ci spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 22628c2ecf20Sopenharmony_ci spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 22638c2ecf20Sopenharmony_ci ctx->stats.vol_ctx_switch, 22648c2ecf20Sopenharmony_ci ctx->stats.invol_ctx_switch, 22658c2ecf20Sopenharmony_ci spufs_slb_flts(ctx), 22668c2ecf20Sopenharmony_ci ctx->stats.hash_flt, 22678c2ecf20Sopenharmony_ci ctx->stats.min_flt, 22688c2ecf20Sopenharmony_ci ctx->stats.maj_flt, 22698c2ecf20Sopenharmony_ci spufs_class2_intrs(ctx), 22708c2ecf20Sopenharmony_ci ctx->stats.libassist); 22718c2ecf20Sopenharmony_ci spu_release(ctx); 22728c2ecf20Sopenharmony_ci return 0; 22738c2ecf20Sopenharmony_ci} 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_cistatic int spufs_stat_open(struct inode *inode, struct file *file) 22768c2ecf20Sopenharmony_ci{ 22778c2ecf20Sopenharmony_ci return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_cistatic const struct file_operations spufs_stat_fops = { 22818c2ecf20Sopenharmony_ci .open = spufs_stat_open, 22828c2ecf20Sopenharmony_ci .read = seq_read, 22838c2ecf20Sopenharmony_ci .llseek = seq_lseek, 22848c2ecf20Sopenharmony_ci .release = single_release, 22858c2ecf20Sopenharmony_ci}; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_cistatic inline int spufs_switch_log_used(struct spu_context *ctx) 22888c2ecf20Sopenharmony_ci{ 22898c2ecf20Sopenharmony_ci return (ctx->switch_log->head - ctx->switch_log->tail) % 22908c2ecf20Sopenharmony_ci SWITCH_LOG_BUFSIZE; 22918c2ecf20Sopenharmony_ci} 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_cistatic inline int spufs_switch_log_avail(struct spu_context *ctx) 22948c2ecf20Sopenharmony_ci{ 22958c2ecf20Sopenharmony_ci return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx); 22968c2ecf20Sopenharmony_ci} 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_cistatic int spufs_switch_log_open(struct inode *inode, struct file *file) 22998c2ecf20Sopenharmony_ci{ 23008c2ecf20Sopenharmony_ci struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 23018c2ecf20Sopenharmony_ci int rc; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci rc = spu_acquire(ctx); 23048c2ecf20Sopenharmony_ci if (rc) 23058c2ecf20Sopenharmony_ci return rc; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci if (ctx->switch_log) { 23088c2ecf20Sopenharmony_ci rc = -EBUSY; 23098c2ecf20Sopenharmony_ci goto out; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci ctx->switch_log = kmalloc(struct_size(ctx->switch_log, log, 23138c2ecf20Sopenharmony_ci SWITCH_LOG_BUFSIZE), GFP_KERNEL); 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci if (!ctx->switch_log) { 23168c2ecf20Sopenharmony_ci rc = -ENOMEM; 23178c2ecf20Sopenharmony_ci goto out; 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci ctx->switch_log->head = ctx->switch_log->tail = 0; 23218c2ecf20Sopenharmony_ci init_waitqueue_head(&ctx->switch_log->wait); 23228c2ecf20Sopenharmony_ci rc = 0; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ciout: 23258c2ecf20Sopenharmony_ci spu_release(ctx); 23268c2ecf20Sopenharmony_ci return rc; 23278c2ecf20Sopenharmony_ci} 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_cistatic int spufs_switch_log_release(struct inode *inode, struct file *file) 23308c2ecf20Sopenharmony_ci{ 23318c2ecf20Sopenharmony_ci struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 23328c2ecf20Sopenharmony_ci int rc; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci rc = spu_acquire(ctx); 23358c2ecf20Sopenharmony_ci if (rc) 23368c2ecf20Sopenharmony_ci return rc; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci kfree(ctx->switch_log); 23398c2ecf20Sopenharmony_ci ctx->switch_log = NULL; 23408c2ecf20Sopenharmony_ci spu_release(ctx); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci return 0; 23438c2ecf20Sopenharmony_ci} 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_cistatic int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) 23468c2ecf20Sopenharmony_ci{ 23478c2ecf20Sopenharmony_ci struct switch_log_entry *p; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci return snprintf(tbuf, n, "%llu.%09u %d %u %u %llu\n", 23528c2ecf20Sopenharmony_ci (unsigned long long) p->tstamp.tv_sec, 23538c2ecf20Sopenharmony_ci (unsigned int) p->tstamp.tv_nsec, 23548c2ecf20Sopenharmony_ci p->spu_id, 23558c2ecf20Sopenharmony_ci (unsigned int) p->type, 23568c2ecf20Sopenharmony_ci (unsigned int) p->val, 23578c2ecf20Sopenharmony_ci (unsigned long long) p->timebase); 23588c2ecf20Sopenharmony_ci} 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_cistatic ssize_t spufs_switch_log_read(struct file *file, char __user *buf, 23618c2ecf20Sopenharmony_ci size_t len, loff_t *ppos) 23628c2ecf20Sopenharmony_ci{ 23638c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 23648c2ecf20Sopenharmony_ci struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 23658c2ecf20Sopenharmony_ci int error = 0, cnt = 0; 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci if (!buf) 23688c2ecf20Sopenharmony_ci return -EINVAL; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci error = spu_acquire(ctx); 23718c2ecf20Sopenharmony_ci if (error) 23728c2ecf20Sopenharmony_ci return error; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci while (cnt < len) { 23758c2ecf20Sopenharmony_ci char tbuf[128]; 23768c2ecf20Sopenharmony_ci int width; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci if (spufs_switch_log_used(ctx) == 0) { 23798c2ecf20Sopenharmony_ci if (cnt > 0) { 23808c2ecf20Sopenharmony_ci /* If there's data ready to go, we can 23818c2ecf20Sopenharmony_ci * just return straight away */ 23828c2ecf20Sopenharmony_ci break; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci } else if (file->f_flags & O_NONBLOCK) { 23858c2ecf20Sopenharmony_ci error = -EAGAIN; 23868c2ecf20Sopenharmony_ci break; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci } else { 23898c2ecf20Sopenharmony_ci /* spufs_wait will drop the mutex and 23908c2ecf20Sopenharmony_ci * re-acquire, but since we're in read(), the 23918c2ecf20Sopenharmony_ci * file cannot be _released (and so 23928c2ecf20Sopenharmony_ci * ctx->switch_log is stable). 23938c2ecf20Sopenharmony_ci */ 23948c2ecf20Sopenharmony_ci error = spufs_wait(ctx->switch_log->wait, 23958c2ecf20Sopenharmony_ci spufs_switch_log_used(ctx) > 0); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci /* On error, spufs_wait returns without the 23988c2ecf20Sopenharmony_ci * state mutex held */ 23998c2ecf20Sopenharmony_ci if (error) 24008c2ecf20Sopenharmony_ci return error; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci /* We may have had entries read from underneath 24038c2ecf20Sopenharmony_ci * us while we dropped the mutex in spufs_wait, 24048c2ecf20Sopenharmony_ci * so re-check */ 24058c2ecf20Sopenharmony_ci if (spufs_switch_log_used(ctx) == 0) 24068c2ecf20Sopenharmony_ci continue; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); 24118c2ecf20Sopenharmony_ci if (width < len) 24128c2ecf20Sopenharmony_ci ctx->switch_log->tail = 24138c2ecf20Sopenharmony_ci (ctx->switch_log->tail + 1) % 24148c2ecf20Sopenharmony_ci SWITCH_LOG_BUFSIZE; 24158c2ecf20Sopenharmony_ci else 24168c2ecf20Sopenharmony_ci /* If the record is greater than space available return 24178c2ecf20Sopenharmony_ci * partial buffer (so far) */ 24188c2ecf20Sopenharmony_ci break; 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci error = copy_to_user(buf + cnt, tbuf, width); 24218c2ecf20Sopenharmony_ci if (error) 24228c2ecf20Sopenharmony_ci break; 24238c2ecf20Sopenharmony_ci cnt += width; 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci spu_release(ctx); 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci return cnt == 0 ? error : cnt; 24298c2ecf20Sopenharmony_ci} 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_cistatic __poll_t spufs_switch_log_poll(struct file *file, poll_table *wait) 24328c2ecf20Sopenharmony_ci{ 24338c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 24348c2ecf20Sopenharmony_ci struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 24358c2ecf20Sopenharmony_ci __poll_t mask = 0; 24368c2ecf20Sopenharmony_ci int rc; 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci poll_wait(file, &ctx->switch_log->wait, wait); 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci rc = spu_acquire(ctx); 24418c2ecf20Sopenharmony_ci if (rc) 24428c2ecf20Sopenharmony_ci return rc; 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci if (spufs_switch_log_used(ctx) > 0) 24458c2ecf20Sopenharmony_ci mask |= EPOLLIN; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci spu_release(ctx); 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci return mask; 24508c2ecf20Sopenharmony_ci} 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_cistatic const struct file_operations spufs_switch_log_fops = { 24538c2ecf20Sopenharmony_ci .open = spufs_switch_log_open, 24548c2ecf20Sopenharmony_ci .read = spufs_switch_log_read, 24558c2ecf20Sopenharmony_ci .poll = spufs_switch_log_poll, 24568c2ecf20Sopenharmony_ci .release = spufs_switch_log_release, 24578c2ecf20Sopenharmony_ci .llseek = no_llseek, 24588c2ecf20Sopenharmony_ci}; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci/** 24618c2ecf20Sopenharmony_ci * Log a context switch event to a switch log reader. 24628c2ecf20Sopenharmony_ci * 24638c2ecf20Sopenharmony_ci * Must be called with ctx->state_mutex held. 24648c2ecf20Sopenharmony_ci */ 24658c2ecf20Sopenharmony_civoid spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, 24668c2ecf20Sopenharmony_ci u32 type, u32 val) 24678c2ecf20Sopenharmony_ci{ 24688c2ecf20Sopenharmony_ci if (!ctx->switch_log) 24698c2ecf20Sopenharmony_ci return; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci if (spufs_switch_log_avail(ctx) > 1) { 24728c2ecf20Sopenharmony_ci struct switch_log_entry *p; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci p = ctx->switch_log->log + ctx->switch_log->head; 24758c2ecf20Sopenharmony_ci ktime_get_ts64(&p->tstamp); 24768c2ecf20Sopenharmony_ci p->timebase = get_tb(); 24778c2ecf20Sopenharmony_ci p->spu_id = spu ? spu->number : -1; 24788c2ecf20Sopenharmony_ci p->type = type; 24798c2ecf20Sopenharmony_ci p->val = val; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci ctx->switch_log->head = 24828c2ecf20Sopenharmony_ci (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE; 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci wake_up(&ctx->switch_log->wait); 24868c2ecf20Sopenharmony_ci} 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_cistatic int spufs_show_ctx(struct seq_file *s, void *private) 24898c2ecf20Sopenharmony_ci{ 24908c2ecf20Sopenharmony_ci struct spu_context *ctx = s->private; 24918c2ecf20Sopenharmony_ci u64 mfc_control_RW; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci mutex_lock(&ctx->state_mutex); 24948c2ecf20Sopenharmony_ci if (ctx->spu) { 24958c2ecf20Sopenharmony_ci struct spu *spu = ctx->spu; 24968c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci spin_lock_irq(&spu->register_lock); 24998c2ecf20Sopenharmony_ci mfc_control_RW = in_be64(&priv2->mfc_control_RW); 25008c2ecf20Sopenharmony_ci spin_unlock_irq(&spu->register_lock); 25018c2ecf20Sopenharmony_ci } else { 25028c2ecf20Sopenharmony_ci struct spu_state *csa = &ctx->csa; 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci mfc_control_RW = csa->priv2.mfc_control_RW; 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci seq_printf(s, "%c flgs(%lx) sflgs(%lx) pri(%d) ts(%d) spu(%02d)" 25088c2ecf20Sopenharmony_ci " %c %llx %llx %llx %llx %x %x\n", 25098c2ecf20Sopenharmony_ci ctx->state == SPU_STATE_SAVED ? 'S' : 'R', 25108c2ecf20Sopenharmony_ci ctx->flags, 25118c2ecf20Sopenharmony_ci ctx->sched_flags, 25128c2ecf20Sopenharmony_ci ctx->prio, 25138c2ecf20Sopenharmony_ci ctx->time_slice, 25148c2ecf20Sopenharmony_ci ctx->spu ? ctx->spu->number : -1, 25158c2ecf20Sopenharmony_ci !list_empty(&ctx->rq) ? 'q' : ' ', 25168c2ecf20Sopenharmony_ci ctx->csa.class_0_pending, 25178c2ecf20Sopenharmony_ci ctx->csa.class_0_dar, 25188c2ecf20Sopenharmony_ci ctx->csa.class_1_dsisr, 25198c2ecf20Sopenharmony_ci mfc_control_RW, 25208c2ecf20Sopenharmony_ci ctx->ops->runcntl_read(ctx), 25218c2ecf20Sopenharmony_ci ctx->ops->status_read(ctx)); 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci mutex_unlock(&ctx->state_mutex); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci return 0; 25268c2ecf20Sopenharmony_ci} 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_cistatic int spufs_ctx_open(struct inode *inode, struct file *file) 25298c2ecf20Sopenharmony_ci{ 25308c2ecf20Sopenharmony_ci return single_open(file, spufs_show_ctx, SPUFS_I(inode)->i_ctx); 25318c2ecf20Sopenharmony_ci} 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_cistatic const struct file_operations spufs_ctx_fops = { 25348c2ecf20Sopenharmony_ci .open = spufs_ctx_open, 25358c2ecf20Sopenharmony_ci .read = seq_read, 25368c2ecf20Sopenharmony_ci .llseek = seq_lseek, 25378c2ecf20Sopenharmony_ci .release = single_release, 25388c2ecf20Sopenharmony_ci}; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ciconst struct spufs_tree_descr spufs_dir_contents[] = { 25418c2ecf20Sopenharmony_ci { "capabilities", &spufs_caps_fops, 0444, }, 25428c2ecf20Sopenharmony_ci { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, 25438c2ecf20Sopenharmony_ci { "regs", &spufs_regs_fops, 0666, sizeof(struct spu_reg128[128]), }, 25448c2ecf20Sopenharmony_ci { "mbox", &spufs_mbox_fops, 0444, }, 25458c2ecf20Sopenharmony_ci { "ibox", &spufs_ibox_fops, 0444, }, 25468c2ecf20Sopenharmony_ci { "wbox", &spufs_wbox_fops, 0222, }, 25478c2ecf20Sopenharmony_ci { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, 25488c2ecf20Sopenharmony_ci { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, 25498c2ecf20Sopenharmony_ci { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, 25508c2ecf20Sopenharmony_ci { "signal1", &spufs_signal1_fops, 0666, }, 25518c2ecf20Sopenharmony_ci { "signal2", &spufs_signal2_fops, 0666, }, 25528c2ecf20Sopenharmony_ci { "signal1_type", &spufs_signal1_type, 0666, }, 25538c2ecf20Sopenharmony_ci { "signal2_type", &spufs_signal2_type, 0666, }, 25548c2ecf20Sopenharmony_ci { "cntl", &spufs_cntl_fops, 0666, }, 25558c2ecf20Sopenharmony_ci { "fpcr", &spufs_fpcr_fops, 0666, sizeof(struct spu_reg128), }, 25568c2ecf20Sopenharmony_ci { "lslr", &spufs_lslr_ops, 0444, }, 25578c2ecf20Sopenharmony_ci { "mfc", &spufs_mfc_fops, 0666, }, 25588c2ecf20Sopenharmony_ci { "mss", &spufs_mss_fops, 0666, }, 25598c2ecf20Sopenharmony_ci { "npc", &spufs_npc_ops, 0666, }, 25608c2ecf20Sopenharmony_ci { "srr0", &spufs_srr0_ops, 0666, }, 25618c2ecf20Sopenharmony_ci { "decr", &spufs_decr_ops, 0666, }, 25628c2ecf20Sopenharmony_ci { "decr_status", &spufs_decr_status_ops, 0666, }, 25638c2ecf20Sopenharmony_ci { "event_mask", &spufs_event_mask_ops, 0666, }, 25648c2ecf20Sopenharmony_ci { "event_status", &spufs_event_status_ops, 0444, }, 25658c2ecf20Sopenharmony_ci { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, 25668c2ecf20Sopenharmony_ci { "phys-id", &spufs_id_ops, 0666, }, 25678c2ecf20Sopenharmony_ci { "object-id", &spufs_object_id_ops, 0666, }, 25688c2ecf20Sopenharmony_ci { "mbox_info", &spufs_mbox_info_fops, 0444, sizeof(u32), }, 25698c2ecf20Sopenharmony_ci { "ibox_info", &spufs_ibox_info_fops, 0444, sizeof(u32), }, 25708c2ecf20Sopenharmony_ci { "wbox_info", &spufs_wbox_info_fops, 0444, sizeof(u32), }, 25718c2ecf20Sopenharmony_ci { "dma_info", &spufs_dma_info_fops, 0444, 25728c2ecf20Sopenharmony_ci sizeof(struct spu_dma_info), }, 25738c2ecf20Sopenharmony_ci { "proxydma_info", &spufs_proxydma_info_fops, 0444, 25748c2ecf20Sopenharmony_ci sizeof(struct spu_proxydma_info)}, 25758c2ecf20Sopenharmony_ci { "tid", &spufs_tid_fops, 0444, }, 25768c2ecf20Sopenharmony_ci { "stat", &spufs_stat_fops, 0444, }, 25778c2ecf20Sopenharmony_ci { "switch_log", &spufs_switch_log_fops, 0444 }, 25788c2ecf20Sopenharmony_ci {}, 25798c2ecf20Sopenharmony_ci}; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ciconst struct spufs_tree_descr spufs_dir_nosched_contents[] = { 25828c2ecf20Sopenharmony_ci { "capabilities", &spufs_caps_fops, 0444, }, 25838c2ecf20Sopenharmony_ci { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, 25848c2ecf20Sopenharmony_ci { "mbox", &spufs_mbox_fops, 0444, }, 25858c2ecf20Sopenharmony_ci { "ibox", &spufs_ibox_fops, 0444, }, 25868c2ecf20Sopenharmony_ci { "wbox", &spufs_wbox_fops, 0222, }, 25878c2ecf20Sopenharmony_ci { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, 25888c2ecf20Sopenharmony_ci { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, 25898c2ecf20Sopenharmony_ci { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, 25908c2ecf20Sopenharmony_ci { "signal1", &spufs_signal1_nosched_fops, 0222, }, 25918c2ecf20Sopenharmony_ci { "signal2", &spufs_signal2_nosched_fops, 0222, }, 25928c2ecf20Sopenharmony_ci { "signal1_type", &spufs_signal1_type, 0666, }, 25938c2ecf20Sopenharmony_ci { "signal2_type", &spufs_signal2_type, 0666, }, 25948c2ecf20Sopenharmony_ci { "mss", &spufs_mss_fops, 0666, }, 25958c2ecf20Sopenharmony_ci { "mfc", &spufs_mfc_fops, 0666, }, 25968c2ecf20Sopenharmony_ci { "cntl", &spufs_cntl_fops, 0666, }, 25978c2ecf20Sopenharmony_ci { "npc", &spufs_npc_ops, 0666, }, 25988c2ecf20Sopenharmony_ci { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, 25998c2ecf20Sopenharmony_ci { "phys-id", &spufs_id_ops, 0666, }, 26008c2ecf20Sopenharmony_ci { "object-id", &spufs_object_id_ops, 0666, }, 26018c2ecf20Sopenharmony_ci { "tid", &spufs_tid_fops, 0444, }, 26028c2ecf20Sopenharmony_ci { "stat", &spufs_stat_fops, 0444, }, 26038c2ecf20Sopenharmony_ci {}, 26048c2ecf20Sopenharmony_ci}; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ciconst struct spufs_tree_descr spufs_dir_debug_contents[] = { 26078c2ecf20Sopenharmony_ci { ".ctx", &spufs_ctx_fops, 0444, }, 26088c2ecf20Sopenharmony_ci {}, 26098c2ecf20Sopenharmony_ci}; 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ciconst struct spufs_coredump_reader spufs_coredump_read[] = { 26128c2ecf20Sopenharmony_ci { "regs", spufs_regs_dump, NULL, sizeof(struct spu_reg128[128])}, 26138c2ecf20Sopenharmony_ci { "fpcr", spufs_fpcr_dump, NULL, sizeof(struct spu_reg128) }, 26148c2ecf20Sopenharmony_ci { "lslr", NULL, spufs_lslr_get, 19 }, 26158c2ecf20Sopenharmony_ci { "decr", NULL, spufs_decr_get, 19 }, 26168c2ecf20Sopenharmony_ci { "decr_status", NULL, spufs_decr_status_get, 19 }, 26178c2ecf20Sopenharmony_ci { "mem", spufs_mem_dump, NULL, LS_SIZE, }, 26188c2ecf20Sopenharmony_ci { "signal1", spufs_signal1_dump, NULL, sizeof(u32) }, 26198c2ecf20Sopenharmony_ci { "signal1_type", NULL, spufs_signal1_type_get, 19 }, 26208c2ecf20Sopenharmony_ci { "signal2", spufs_signal2_dump, NULL, sizeof(u32) }, 26218c2ecf20Sopenharmony_ci { "signal2_type", NULL, spufs_signal2_type_get, 19 }, 26228c2ecf20Sopenharmony_ci { "event_mask", NULL, spufs_event_mask_get, 19 }, 26238c2ecf20Sopenharmony_ci { "event_status", NULL, spufs_event_status_get, 19 }, 26248c2ecf20Sopenharmony_ci { "mbox_info", spufs_mbox_info_dump, NULL, sizeof(u32) }, 26258c2ecf20Sopenharmony_ci { "ibox_info", spufs_ibox_info_dump, NULL, sizeof(u32) }, 26268c2ecf20Sopenharmony_ci { "wbox_info", spufs_wbox_info_dump, NULL, 4 * sizeof(u32)}, 26278c2ecf20Sopenharmony_ci { "dma_info", spufs_dma_info_dump, NULL, sizeof(struct spu_dma_info)}, 26288c2ecf20Sopenharmony_ci { "proxydma_info", spufs_proxydma_info_dump, 26298c2ecf20Sopenharmony_ci NULL, sizeof(struct spu_proxydma_info)}, 26308c2ecf20Sopenharmony_ci { "object-id", NULL, spufs_object_id_get, 19 }, 26318c2ecf20Sopenharmony_ci { "npc", NULL, spufs_npc_get, 19 }, 26328c2ecf20Sopenharmony_ci { NULL }, 26338c2ecf20Sopenharmony_ci}; 2634