167207b96SArnd Bergmann /* 267207b96SArnd Bergmann * SPU file system -- file contents 367207b96SArnd Bergmann * 467207b96SArnd Bergmann * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 567207b96SArnd Bergmann * 667207b96SArnd Bergmann * Author: Arnd Bergmann <arndb@de.ibm.com> 767207b96SArnd Bergmann * 867207b96SArnd Bergmann * This program is free software; you can redistribute it and/or modify 967207b96SArnd Bergmann * it under the terms of the GNU General Public License as published by 1067207b96SArnd Bergmann * the Free Software Foundation; either version 2, or (at your option) 1167207b96SArnd Bergmann * any later version. 1267207b96SArnd Bergmann * 1367207b96SArnd Bergmann * This program is distributed in the hope that it will be useful, 1467207b96SArnd Bergmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 1567207b96SArnd Bergmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1667207b96SArnd Bergmann * GNU General Public License for more details. 1767207b96SArnd Bergmann * 1867207b96SArnd Bergmann * You should have received a copy of the GNU General Public License 1967207b96SArnd Bergmann * along with this program; if not, write to the Free Software 2067207b96SArnd Bergmann * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2167207b96SArnd Bergmann */ 2267207b96SArnd Bergmann 23a33a7d73SArnd Bergmann #undef DEBUG 24a33a7d73SArnd Bergmann 2567207b96SArnd Bergmann #include <linux/fs.h> 2667207b96SArnd Bergmann #include <linux/ioctl.h> 2767207b96SArnd Bergmann #include <linux/module.h> 28d88cfffaSArnd Bergmann #include <linux/pagemap.h> 2967207b96SArnd Bergmann #include <linux/poll.h> 305110459fSArnd Bergmann #include <linux/ptrace.h> 31cbe709c1SBenjamin Herrenschmidt #include <linux/seq_file.h> 32038200cfSChristoph Hellwig #include <linux/marker.h> 3367207b96SArnd Bergmann 3467207b96SArnd Bergmann #include <asm/io.h> 3567207b96SArnd Bergmann #include <asm/semaphore.h> 3667207b96SArnd Bergmann #include <asm/spu.h> 37b9e3bd77SDwayne Grant McConnell #include <asm/spu_info.h> 3867207b96SArnd Bergmann #include <asm/uaccess.h> 3967207b96SArnd Bergmann 4067207b96SArnd Bergmann #include "spufs.h" 4167207b96SArnd Bergmann 4227d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 4327d5bf2aSBenjamin Herrenschmidt 44197b1a82SChristoph Hellwig /* Simple attribute files */ 45197b1a82SChristoph Hellwig struct spufs_attr { 46197b1a82SChristoph Hellwig int (*get)(void *, u64 *); 47197b1a82SChristoph Hellwig int (*set)(void *, u64); 48197b1a82SChristoph Hellwig char get_buf[24]; /* enough to store a u64 and "\n\0" */ 49197b1a82SChristoph Hellwig char set_buf[24]; 50197b1a82SChristoph Hellwig void *data; 51197b1a82SChristoph Hellwig const char *fmt; /* format for read operation */ 52197b1a82SChristoph Hellwig struct mutex mutex; /* protects access to these buffers */ 53197b1a82SChristoph Hellwig }; 54197b1a82SChristoph Hellwig 55197b1a82SChristoph Hellwig static int spufs_attr_open(struct inode *inode, struct file *file, 56197b1a82SChristoph Hellwig int (*get)(void *, u64 *), int (*set)(void *, u64), 57197b1a82SChristoph Hellwig const char *fmt) 58197b1a82SChristoph Hellwig { 59197b1a82SChristoph Hellwig struct spufs_attr *attr; 60197b1a82SChristoph Hellwig 61197b1a82SChristoph Hellwig attr = kmalloc(sizeof(*attr), GFP_KERNEL); 62197b1a82SChristoph Hellwig if (!attr) 63197b1a82SChristoph Hellwig return -ENOMEM; 64197b1a82SChristoph Hellwig 65197b1a82SChristoph Hellwig attr->get = get; 66197b1a82SChristoph Hellwig attr->set = set; 67197b1a82SChristoph Hellwig attr->data = inode->i_private; 68197b1a82SChristoph Hellwig attr->fmt = fmt; 69197b1a82SChristoph Hellwig mutex_init(&attr->mutex); 70197b1a82SChristoph Hellwig file->private_data = attr; 71197b1a82SChristoph Hellwig 72197b1a82SChristoph Hellwig return nonseekable_open(inode, file); 73197b1a82SChristoph Hellwig } 74197b1a82SChristoph Hellwig 75197b1a82SChristoph Hellwig static int spufs_attr_release(struct inode *inode, struct file *file) 76197b1a82SChristoph Hellwig { 77197b1a82SChristoph Hellwig kfree(file->private_data); 78197b1a82SChristoph Hellwig return 0; 79197b1a82SChristoph Hellwig } 80197b1a82SChristoph Hellwig 81197b1a82SChristoph Hellwig static ssize_t spufs_attr_read(struct file *file, char __user *buf, 82197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 83197b1a82SChristoph Hellwig { 84197b1a82SChristoph Hellwig struct spufs_attr *attr; 85197b1a82SChristoph Hellwig size_t size; 86197b1a82SChristoph Hellwig ssize_t ret; 87197b1a82SChristoph Hellwig 88197b1a82SChristoph Hellwig attr = file->private_data; 89197b1a82SChristoph Hellwig if (!attr->get) 90197b1a82SChristoph Hellwig return -EACCES; 91197b1a82SChristoph Hellwig 92197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 93197b1a82SChristoph Hellwig if (ret) 94197b1a82SChristoph Hellwig return ret; 95197b1a82SChristoph Hellwig 96197b1a82SChristoph Hellwig if (*ppos) { /* continued read */ 97197b1a82SChristoph Hellwig size = strlen(attr->get_buf); 98197b1a82SChristoph Hellwig } else { /* first read */ 99197b1a82SChristoph Hellwig u64 val; 100197b1a82SChristoph Hellwig ret = attr->get(attr->data, &val); 101197b1a82SChristoph Hellwig if (ret) 102197b1a82SChristoph Hellwig goto out; 103197b1a82SChristoph Hellwig 104197b1a82SChristoph Hellwig size = scnprintf(attr->get_buf, sizeof(attr->get_buf), 105197b1a82SChristoph Hellwig attr->fmt, (unsigned long long)val); 106197b1a82SChristoph Hellwig } 107197b1a82SChristoph Hellwig 108197b1a82SChristoph Hellwig ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); 109197b1a82SChristoph Hellwig out: 110197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 111197b1a82SChristoph Hellwig return ret; 112197b1a82SChristoph Hellwig } 113197b1a82SChristoph Hellwig 114197b1a82SChristoph Hellwig static ssize_t spufs_attr_write(struct file *file, const char __user *buf, 115197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 116197b1a82SChristoph Hellwig { 117197b1a82SChristoph Hellwig struct spufs_attr *attr; 118197b1a82SChristoph Hellwig u64 val; 119197b1a82SChristoph Hellwig size_t size; 120197b1a82SChristoph Hellwig ssize_t ret; 121197b1a82SChristoph Hellwig 122197b1a82SChristoph Hellwig attr = file->private_data; 123197b1a82SChristoph Hellwig if (!attr->set) 124197b1a82SChristoph Hellwig return -EACCES; 125197b1a82SChristoph Hellwig 126197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 127197b1a82SChristoph Hellwig if (ret) 128197b1a82SChristoph Hellwig return ret; 129197b1a82SChristoph Hellwig 130197b1a82SChristoph Hellwig ret = -EFAULT; 131197b1a82SChristoph Hellwig size = min(sizeof(attr->set_buf) - 1, len); 132197b1a82SChristoph Hellwig if (copy_from_user(attr->set_buf, buf, size)) 133197b1a82SChristoph Hellwig goto out; 134197b1a82SChristoph Hellwig 135197b1a82SChristoph Hellwig ret = len; /* claim we got the whole input */ 136197b1a82SChristoph Hellwig attr->set_buf[size] = '\0'; 137197b1a82SChristoph Hellwig val = simple_strtol(attr->set_buf, NULL, 0); 138197b1a82SChristoph Hellwig attr->set(attr->data, val); 139197b1a82SChristoph Hellwig out: 140197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 141197b1a82SChristoph Hellwig return ret; 142197b1a82SChristoph Hellwig } 143197b1a82SChristoph Hellwig 144197b1a82SChristoph Hellwig #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ 145197b1a82SChristoph Hellwig static int __fops ## _open(struct inode *inode, struct file *file) \ 146197b1a82SChristoph Hellwig { \ 147197b1a82SChristoph Hellwig __simple_attr_check_format(__fmt, 0ull); \ 148197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, __get, __set, __fmt); \ 149197b1a82SChristoph Hellwig } \ 150197b1a82SChristoph Hellwig static struct file_operations __fops = { \ 151197b1a82SChristoph Hellwig .owner = THIS_MODULE, \ 152197b1a82SChristoph Hellwig .open = __fops ## _open, \ 153197b1a82SChristoph Hellwig .release = spufs_attr_release, \ 154197b1a82SChristoph Hellwig .read = spufs_attr_read, \ 155197b1a82SChristoph Hellwig .write = spufs_attr_write, \ 156197b1a82SChristoph Hellwig }; 157197b1a82SChristoph Hellwig 158cbe709c1SBenjamin Herrenschmidt 15967207b96SArnd Bergmann static int 16067207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 16167207b96SArnd Bergmann { 16267207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1636df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 16443c2bbd9SChristoph Hellwig 16547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1666df10a82SMark Nutter file->private_data = ctx; 16743c2bbd9SChristoph Hellwig if (!i->i_openers++) 1686df10a82SMark Nutter ctx->local_store = inode->i_mapping; 16947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 17043c2bbd9SChristoph Hellwig return 0; 17143c2bbd9SChristoph Hellwig } 17243c2bbd9SChristoph Hellwig 17343c2bbd9SChristoph Hellwig static int 17443c2bbd9SChristoph Hellwig spufs_mem_release(struct inode *inode, struct file *file) 17543c2bbd9SChristoph Hellwig { 17643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 17743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 17843c2bbd9SChristoph Hellwig 17947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 18043c2bbd9SChristoph Hellwig if (!--i->i_openers) 18143c2bbd9SChristoph Hellwig ctx->local_store = NULL; 18247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 18367207b96SArnd Bergmann return 0; 18467207b96SArnd Bergmann } 18567207b96SArnd Bergmann 18667207b96SArnd Bergmann static ssize_t 187bf1ab978SDwayne Grant McConnell __spufs_mem_read(struct spu_context *ctx, char __user *buffer, 188bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 189bf1ab978SDwayne Grant McConnell { 190bf1ab978SDwayne Grant McConnell char *local_store = ctx->ops->get_ls(ctx); 191bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, local_store, 192bf1ab978SDwayne Grant McConnell LS_SIZE); 193bf1ab978SDwayne Grant McConnell } 194bf1ab978SDwayne Grant McConnell 195bf1ab978SDwayne Grant McConnell static ssize_t 19667207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 19767207b96SArnd Bergmann size_t size, loff_t *pos) 19867207b96SArnd Bergmann { 199bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 200aa0ed2bdSArnd Bergmann ssize_t ret; 20167207b96SArnd Bergmann 202c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 203c9101bdbSChristoph Hellwig if (ret) 204c9101bdbSChristoph Hellwig return ret; 205bf1ab978SDwayne Grant McConnell ret = __spufs_mem_read(ctx, buffer, size, pos); 2068b3d6663SArnd Bergmann spu_release(ctx); 207c9101bdbSChristoph Hellwig 20867207b96SArnd Bergmann return ret; 20967207b96SArnd Bergmann } 21067207b96SArnd Bergmann 21167207b96SArnd Bergmann static ssize_t 21267207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 213aa0ed2bdSArnd Bergmann size_t size, loff_t *ppos) 21467207b96SArnd Bergmann { 21567207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 2168b3d6663SArnd Bergmann char *local_store; 217aa0ed2bdSArnd Bergmann loff_t pos = *ppos; 2188b3d6663SArnd Bergmann int ret; 21967207b96SArnd Bergmann 220aa0ed2bdSArnd Bergmann if (pos < 0) 221aa0ed2bdSArnd Bergmann return -EINVAL; 222aa0ed2bdSArnd Bergmann if (pos > LS_SIZE) 22367207b96SArnd Bergmann return -EFBIG; 224aa0ed2bdSArnd Bergmann if (size > LS_SIZE - pos) 225aa0ed2bdSArnd Bergmann size = LS_SIZE - pos; 2268b3d6663SArnd Bergmann 227c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 228c9101bdbSChristoph Hellwig if (ret) 229c9101bdbSChristoph Hellwig return ret; 230c9101bdbSChristoph Hellwig 2318b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 232aa0ed2bdSArnd Bergmann ret = copy_from_user(local_store + pos, buffer, size); 2338b3d6663SArnd Bergmann spu_release(ctx); 234aa0ed2bdSArnd Bergmann 235aa0ed2bdSArnd Bergmann if (ret) 236aa0ed2bdSArnd Bergmann return -EFAULT; 237aa0ed2bdSArnd Bergmann *ppos = pos + size; 238aa0ed2bdSArnd Bergmann return size; 23967207b96SArnd Bergmann } 24067207b96SArnd Bergmann 24178bde53eSBenjamin Herrenschmidt static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, 24278bde53eSBenjamin Herrenschmidt unsigned long address) 2438b3d6663SArnd Bergmann { 2448b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 245f1fa74f4SBenjamin Herrenschmidt unsigned long pfn, offset, addr0 = address; 246f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 247f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 248f1fa74f4SBenjamin Herrenschmidt int psize; 24978bde53eSBenjamin Herrenschmidt 250f1fa74f4SBenjamin Herrenschmidt /* Check what page size we are using */ 251f1fa74f4SBenjamin Herrenschmidt psize = get_slice_psize(vma->vm_mm, address); 2528b3d6663SArnd Bergmann 253f1fa74f4SBenjamin Herrenschmidt /* Some sanity checking */ 254f1fa74f4SBenjamin Herrenschmidt BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K)); 255f1fa74f4SBenjamin Herrenschmidt 256f1fa74f4SBenjamin Herrenschmidt /* Wow, 64K, cool, we need to align the address though */ 257f1fa74f4SBenjamin Herrenschmidt if (csa->use_big_pages) { 258f1fa74f4SBenjamin Herrenschmidt BUG_ON(vma->vm_start & 0xffff); 259f1fa74f4SBenjamin Herrenschmidt address &= ~0xfffful; 260f1fa74f4SBenjamin Herrenschmidt } 261f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 262f1fa74f4SBenjamin Herrenschmidt 263f1fa74f4SBenjamin Herrenschmidt offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); 264128b8546SMasato Noguchi if (offset >= LS_SIZE) 265128b8546SMasato Noguchi return NOPFN_SIGBUS; 266128b8546SMasato Noguchi 267f1fa74f4SBenjamin Herrenschmidt pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n", 268f1fa74f4SBenjamin Herrenschmidt addr0, address, offset); 269f1fa74f4SBenjamin Herrenschmidt 270c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 271c9101bdbSChristoph Hellwig return NOPFN_REFAULT; 2728b3d6663SArnd Bergmann 273ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 274ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 275932f535dSArnd Bergmann & ~_PAGE_NO_CACHE); 27678bde53eSBenjamin Herrenschmidt pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); 277ac91cb8dSArnd Bergmann } else { 278ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 279932f535dSArnd Bergmann | _PAGE_NO_CACHE); 28078bde53eSBenjamin Herrenschmidt pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; 281ac91cb8dSArnd Bergmann } 28278bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, pfn); 28378bde53eSBenjamin Herrenschmidt 2848b3d6663SArnd Bergmann spu_release(ctx); 2858b3d6663SArnd Bergmann 28678bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 2878b3d6663SArnd Bergmann } 2888b3d6663SArnd Bergmann 28978bde53eSBenjamin Herrenschmidt 2908b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = { 29178bde53eSBenjamin Herrenschmidt .nopfn = spufs_mem_mmap_nopfn, 2928b3d6663SArnd Bergmann }; 2938b3d6663SArnd Bergmann 294f1fa74f4SBenjamin Herrenschmidt static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 29567207b96SArnd Bergmann { 296f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 297f1fa74f4SBenjamin Herrenschmidt struct spu_context *ctx = file->private_data; 298f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 299f1fa74f4SBenjamin Herrenschmidt 300f1fa74f4SBenjamin Herrenschmidt /* Sanity check VMA alignment */ 301f1fa74f4SBenjamin Herrenschmidt if (csa->use_big_pages) { 302f1fa74f4SBenjamin Herrenschmidt pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx," 303f1fa74f4SBenjamin Herrenschmidt " pgoff=0x%lx\n", vma->vm_start, vma->vm_end, 304f1fa74f4SBenjamin Herrenschmidt vma->vm_pgoff); 305f1fa74f4SBenjamin Herrenschmidt if (vma->vm_start & 0xffff) 306f1fa74f4SBenjamin Herrenschmidt return -EINVAL; 307f1fa74f4SBenjamin Herrenschmidt if (vma->vm_pgoff & 0xf) 308f1fa74f4SBenjamin Herrenschmidt return -EINVAL; 309f1fa74f4SBenjamin Herrenschmidt } 310f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 311f1fa74f4SBenjamin Herrenschmidt 3128b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 3138b3d6663SArnd Bergmann return -EINVAL; 31467207b96SArnd Bergmann 31578bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 31667207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 31767207b96SArnd Bergmann | _PAGE_NO_CACHE); 3188b3d6663SArnd Bergmann 3198b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 32067207b96SArnd Bergmann return 0; 32167207b96SArnd Bergmann } 32267207b96SArnd Bergmann 323f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 3241238819aSSebastian Siewior static unsigned long spufs_get_unmapped_area(struct file *file, 3251238819aSSebastian Siewior unsigned long addr, unsigned long len, unsigned long pgoff, 326f1fa74f4SBenjamin Herrenschmidt unsigned long flags) 327f1fa74f4SBenjamin Herrenschmidt { 328f1fa74f4SBenjamin Herrenschmidt struct spu_context *ctx = file->private_data; 329f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 330f1fa74f4SBenjamin Herrenschmidt 331f1fa74f4SBenjamin Herrenschmidt /* If not using big pages, fallback to normal MM g_u_a */ 332f1fa74f4SBenjamin Herrenschmidt if (!csa->use_big_pages) 333f1fa74f4SBenjamin Herrenschmidt return current->mm->get_unmapped_area(file, addr, len, 334f1fa74f4SBenjamin Herrenschmidt pgoff, flags); 335f1fa74f4SBenjamin Herrenschmidt 336f1fa74f4SBenjamin Herrenschmidt /* Else, try to obtain a 64K pages slice */ 337f1fa74f4SBenjamin Herrenschmidt return slice_get_unmapped_area(addr, len, flags, 338f1fa74f4SBenjamin Herrenschmidt MMU_PAGE_64K, 1, 0); 339f1fa74f4SBenjamin Herrenschmidt } 340f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 341f1fa74f4SBenjamin Herrenschmidt 3425dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = { 34367207b96SArnd Bergmann .open = spufs_mem_open, 344ce92987bSChristoph Hellwig .release = spufs_mem_release, 34567207b96SArnd Bergmann .read = spufs_mem_read, 34667207b96SArnd Bergmann .write = spufs_mem_write, 3478b3d6663SArnd Bergmann .llseek = generic_file_llseek, 34867207b96SArnd Bergmann .mmap = spufs_mem_mmap, 349f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 350f1fa74f4SBenjamin Herrenschmidt .get_unmapped_area = spufs_get_unmapped_area, 351f1fa74f4SBenjamin Herrenschmidt #endif 3528b3d6663SArnd Bergmann }; 3538b3d6663SArnd Bergmann 35478bde53eSBenjamin Herrenschmidt static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, 3556df10a82SMark Nutter unsigned long address, 35678bde53eSBenjamin Herrenschmidt unsigned long ps_offs, 35727d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 3586df10a82SMark Nutter { 3596df10a82SMark Nutter struct spu_context *ctx = vma->vm_file->private_data; 36078bde53eSBenjamin Herrenschmidt unsigned long area, offset = address - vma->vm_start; 361eebead5bSChristoph Hellwig int ret = 0; 3626df10a82SMark Nutter 363038200cfSChristoph Hellwig spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx); 364038200cfSChristoph Hellwig 3656df10a82SMark Nutter offset += vma->vm_pgoff << PAGE_SHIFT; 36627d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 36778bde53eSBenjamin Herrenschmidt return NOPFN_SIGBUS; 3686df10a82SMark Nutter 36933bfd7a7SArnd Bergmann /* 370d5883137SJeremy Kerr * Because we release the mmap_sem, the context may be destroyed while 371d5883137SJeremy Kerr * we're in spu_wait. Grab an extra reference so it isn't destroyed 372d5883137SJeremy Kerr * in the meantime. 373d5883137SJeremy Kerr */ 374d5883137SJeremy Kerr get_spu_context(ctx); 375d5883137SJeremy Kerr 376d5883137SJeremy Kerr /* 37733bfd7a7SArnd Bergmann * We have to wait for context to be loaded before we have 37833bfd7a7SArnd Bergmann * pages to hand out to the user, but we don't want to wait 37933bfd7a7SArnd Bergmann * with the mmap_sem held. 38033bfd7a7SArnd Bergmann * It is possible to drop the mmap_sem here, but then we need 38133bfd7a7SArnd Bergmann * to return NOPFN_REFAULT because the mappings may have 38233bfd7a7SArnd Bergmann * hanged. 38378bde53eSBenjamin Herrenschmidt */ 384c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 385d5883137SJeremy Kerr goto refault; 386c9101bdbSChristoph Hellwig 38733bfd7a7SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 38833bfd7a7SArnd Bergmann up_read(¤t->mm->mmap_sem); 389038200cfSChristoph Hellwig spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx); 390eebead5bSChristoph Hellwig ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 391038200cfSChristoph Hellwig spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu); 39233bfd7a7SArnd Bergmann down_read(¤t->mm->mmap_sem); 393c9101bdbSChristoph Hellwig } else { 3946df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 39578bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); 396038200cfSChristoph Hellwig spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu); 397c9101bdbSChristoph Hellwig } 39833bfd7a7SArnd Bergmann 399eebead5bSChristoph Hellwig if (!ret) 4006df10a82SMark Nutter spu_release(ctx); 401d5883137SJeremy Kerr 402d5883137SJeremy Kerr refault: 403d5883137SJeremy Kerr put_spu_context(ctx); 40478bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 4056df10a82SMark Nutter } 4066df10a82SMark Nutter 40727d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 40878bde53eSBenjamin Herrenschmidt static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, 40978bde53eSBenjamin Herrenschmidt unsigned long address) 4106df10a82SMark Nutter { 41178bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x4000, 0x1000); 4126df10a82SMark Nutter } 4136df10a82SMark Nutter 4146df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = { 41578bde53eSBenjamin Herrenschmidt .nopfn = spufs_cntl_mmap_nopfn, 4166df10a82SMark Nutter }; 4176df10a82SMark Nutter 4186df10a82SMark Nutter /* 4196df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 4206df10a82SMark Nutter */ 4216df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 4226df10a82SMark Nutter { 4236df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 4246df10a82SMark Nutter return -EINVAL; 4256df10a82SMark Nutter 42678bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 4276df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 42823cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 4296df10a82SMark Nutter 4306df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 4316df10a82SMark Nutter return 0; 4326df10a82SMark Nutter } 43327d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 43427d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 43527d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 4366df10a82SMark Nutter 437197b1a82SChristoph Hellwig static int spufs_cntl_get(void *data, u64 *val) 438e1dbff2bSArnd Bergmann { 439e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 440c9101bdbSChristoph Hellwig int ret; 441e1dbff2bSArnd Bergmann 442c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 443c9101bdbSChristoph Hellwig if (ret) 444c9101bdbSChristoph Hellwig return ret; 445197b1a82SChristoph Hellwig *val = ctx->ops->status_read(ctx); 446e1dbff2bSArnd Bergmann spu_release(ctx); 447e1dbff2bSArnd Bergmann 448197b1a82SChristoph Hellwig return 0; 449e1dbff2bSArnd Bergmann } 450e1dbff2bSArnd Bergmann 451197b1a82SChristoph Hellwig static int spufs_cntl_set(void *data, u64 val) 452e1dbff2bSArnd Bergmann { 453e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 454c9101bdbSChristoph Hellwig int ret; 455e1dbff2bSArnd Bergmann 456c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 457c9101bdbSChristoph Hellwig if (ret) 458c9101bdbSChristoph Hellwig return ret; 459e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 460e1dbff2bSArnd Bergmann spu_release(ctx); 461197b1a82SChristoph Hellwig 462197b1a82SChristoph Hellwig return 0; 463e1dbff2bSArnd Bergmann } 464e1dbff2bSArnd Bergmann 4656df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 4666df10a82SMark Nutter { 4676df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 4686df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 4696df10a82SMark Nutter 47047d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 4716df10a82SMark Nutter file->private_data = ctx; 47243c2bbd9SChristoph Hellwig if (!i->i_openers++) 4736df10a82SMark Nutter ctx->cntl = inode->i_mapping; 47447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 4758b88b099SChristoph Hellwig return simple_attr_open(inode, file, spufs_cntl_get, 476e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 4776df10a82SMark Nutter } 4786df10a82SMark Nutter 47943c2bbd9SChristoph Hellwig static int 48043c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file) 48143c2bbd9SChristoph Hellwig { 48243c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 48343c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 48443c2bbd9SChristoph Hellwig 48574bedc4dSChristoph Hellwig simple_attr_release(inode, file); 48643c2bbd9SChristoph Hellwig 48747d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 48843c2bbd9SChristoph Hellwig if (!--i->i_openers) 48943c2bbd9SChristoph Hellwig ctx->cntl = NULL; 49047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 49143c2bbd9SChristoph Hellwig return 0; 49243c2bbd9SChristoph Hellwig } 49343c2bbd9SChristoph Hellwig 4945dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = { 4956df10a82SMark Nutter .open = spufs_cntl_open, 49643c2bbd9SChristoph Hellwig .release = spufs_cntl_release, 4978b88b099SChristoph Hellwig .read = simple_attr_read, 4988b88b099SChristoph Hellwig .write = simple_attr_write, 4996df10a82SMark Nutter .mmap = spufs_cntl_mmap, 5006df10a82SMark Nutter }; 5016df10a82SMark Nutter 5028b3d6663SArnd Bergmann static int 5038b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 5048b3d6663SArnd Bergmann { 5058b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 5068b3d6663SArnd Bergmann file->private_data = i->i_ctx; 5078b3d6663SArnd Bergmann return 0; 5088b3d6663SArnd Bergmann } 5098b3d6663SArnd Bergmann 5108b3d6663SArnd Bergmann static ssize_t 511bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer, 512bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 513bf1ab978SDwayne Grant McConnell { 514bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 515bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 516bf1ab978SDwayne Grant McConnell lscsa->gprs, sizeof lscsa->gprs); 517bf1ab978SDwayne Grant McConnell } 518bf1ab978SDwayne Grant McConnell 519bf1ab978SDwayne Grant McConnell static ssize_t 5208b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 5218b3d6663SArnd Bergmann size_t size, loff_t *pos) 5228b3d6663SArnd Bergmann { 5238b3d6663SArnd Bergmann int ret; 524bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5258b3d6663SArnd Bergmann 526c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 527c9101bdbSChristoph Hellwig if (ret) 528c9101bdbSChristoph Hellwig return ret; 529bf1ab978SDwayne Grant McConnell ret = __spufs_regs_read(ctx, buffer, size, pos); 53027b1ea09SChristoph Hellwig spu_release_saved(ctx); 5318b3d6663SArnd Bergmann return ret; 5328b3d6663SArnd Bergmann } 5338b3d6663SArnd Bergmann 5348b3d6663SArnd Bergmann static ssize_t 5358b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 5368b3d6663SArnd Bergmann size_t size, loff_t *pos) 5378b3d6663SArnd Bergmann { 5388b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5398b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5408b3d6663SArnd Bergmann int ret; 5418b3d6663SArnd Bergmann 5428b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 5438b3d6663SArnd Bergmann if (size <= 0) 5448b3d6663SArnd Bergmann return -EFBIG; 5458b3d6663SArnd Bergmann *pos += size; 5468b3d6663SArnd Bergmann 547c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 548c9101bdbSChristoph Hellwig if (ret) 549c9101bdbSChristoph Hellwig return ret; 5508b3d6663SArnd Bergmann 5518b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 5528b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 5538b3d6663SArnd Bergmann 55427b1ea09SChristoph Hellwig spu_release_saved(ctx); 5558b3d6663SArnd Bergmann return ret; 5568b3d6663SArnd Bergmann } 5578b3d6663SArnd Bergmann 5585dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = { 5598b3d6663SArnd Bergmann .open = spufs_regs_open, 5608b3d6663SArnd Bergmann .read = spufs_regs_read, 5618b3d6663SArnd Bergmann .write = spufs_regs_write, 5628b3d6663SArnd Bergmann .llseek = generic_file_llseek, 5638b3d6663SArnd Bergmann }; 5648b3d6663SArnd Bergmann 5658b3d6663SArnd Bergmann static ssize_t 566bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, 567bf1ab978SDwayne Grant McConnell size_t size, loff_t * pos) 568bf1ab978SDwayne Grant McConnell { 569bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 570bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 571bf1ab978SDwayne Grant McConnell &lscsa->fpcr, sizeof(lscsa->fpcr)); 572bf1ab978SDwayne Grant McConnell } 573bf1ab978SDwayne Grant McConnell 574bf1ab978SDwayne Grant McConnell static ssize_t 5758b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 5768b3d6663SArnd Bergmann size_t size, loff_t * pos) 5778b3d6663SArnd Bergmann { 5788b3d6663SArnd Bergmann int ret; 579bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5808b3d6663SArnd Bergmann 581c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 582c9101bdbSChristoph Hellwig if (ret) 583c9101bdbSChristoph Hellwig return ret; 584bf1ab978SDwayne Grant McConnell ret = __spufs_fpcr_read(ctx, buffer, size, pos); 58527b1ea09SChristoph Hellwig spu_release_saved(ctx); 5868b3d6663SArnd Bergmann return ret; 5878b3d6663SArnd Bergmann } 5888b3d6663SArnd Bergmann 5898b3d6663SArnd Bergmann static ssize_t 5908b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 5918b3d6663SArnd Bergmann size_t size, loff_t * pos) 5928b3d6663SArnd Bergmann { 5938b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5948b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5958b3d6663SArnd Bergmann int ret; 5968b3d6663SArnd Bergmann 5978b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 5988b3d6663SArnd Bergmann if (size <= 0) 5998b3d6663SArnd Bergmann return -EFBIG; 600c9101bdbSChristoph Hellwig 601c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 602c9101bdbSChristoph Hellwig if (ret) 603c9101bdbSChristoph Hellwig return ret; 604c9101bdbSChristoph Hellwig 6058b3d6663SArnd Bergmann *pos += size; 6068b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 6078b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 6088b3d6663SArnd Bergmann 60927b1ea09SChristoph Hellwig spu_release_saved(ctx); 6108b3d6663SArnd Bergmann return ret; 6118b3d6663SArnd Bergmann } 6128b3d6663SArnd Bergmann 6135dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = { 6148b3d6663SArnd Bergmann .open = spufs_regs_open, 6158b3d6663SArnd Bergmann .read = spufs_fpcr_read, 6168b3d6663SArnd Bergmann .write = spufs_fpcr_write, 61767207b96SArnd Bergmann .llseek = generic_file_llseek, 61867207b96SArnd Bergmann }; 61967207b96SArnd Bergmann 62067207b96SArnd Bergmann /* generic open function for all pipe-like files */ 62167207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 62267207b96SArnd Bergmann { 62367207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 62467207b96SArnd Bergmann file->private_data = i->i_ctx; 62567207b96SArnd Bergmann 62667207b96SArnd Bergmann return nonseekable_open(inode, file); 62767207b96SArnd Bergmann } 62867207b96SArnd Bergmann 629cdcc89bbSArnd Bergmann /* 630cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 631cdcc89bbSArnd Bergmann * one of the conditions becomes true: 632cdcc89bbSArnd Bergmann * 633cdcc89bbSArnd Bergmann * - no more data available in the mailbox 634cdcc89bbSArnd Bergmann * - end of the user provided buffer 635cdcc89bbSArnd Bergmann * - end of the mapped area 636cdcc89bbSArnd Bergmann */ 63767207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 63867207b96SArnd Bergmann size_t len, loff_t *pos) 63967207b96SArnd Bergmann { 6408b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 641cdcc89bbSArnd Bergmann u32 mbox_data, __user *udata; 642cdcc89bbSArnd Bergmann ssize_t count; 64367207b96SArnd Bergmann 64467207b96SArnd Bergmann if (len < 4) 64567207b96SArnd Bergmann return -EINVAL; 64667207b96SArnd Bergmann 647cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 64867207b96SArnd Bergmann return -EFAULT; 64967207b96SArnd Bergmann 650cdcc89bbSArnd Bergmann udata = (void __user *)buf; 651cdcc89bbSArnd Bergmann 652c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 653c9101bdbSChristoph Hellwig if (count) 654c9101bdbSChristoph Hellwig return count; 655c9101bdbSChristoph Hellwig 656274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 657cdcc89bbSArnd Bergmann int ret; 658cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 659cdcc89bbSArnd Bergmann if (ret == 0) 660cdcc89bbSArnd Bergmann break; 661cdcc89bbSArnd Bergmann 662cdcc89bbSArnd Bergmann /* 663cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 664cdcc89bbSArnd Bergmann * but still need to return the data we have 665cdcc89bbSArnd Bergmann * read successfully so far. 666cdcc89bbSArnd Bergmann */ 667cdcc89bbSArnd Bergmann ret = __put_user(mbox_data, udata); 668cdcc89bbSArnd Bergmann if (ret) { 669cdcc89bbSArnd Bergmann if (!count) 670cdcc89bbSArnd Bergmann count = -EFAULT; 671cdcc89bbSArnd Bergmann break; 672cdcc89bbSArnd Bergmann } 673cdcc89bbSArnd Bergmann } 674cdcc89bbSArnd Bergmann spu_release(ctx); 675cdcc89bbSArnd Bergmann 676cdcc89bbSArnd Bergmann if (!count) 677cdcc89bbSArnd Bergmann count = -EAGAIN; 678cdcc89bbSArnd Bergmann 679cdcc89bbSArnd Bergmann return count; 68067207b96SArnd Bergmann } 68167207b96SArnd Bergmann 6825dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = { 68367207b96SArnd Bergmann .open = spufs_pipe_open, 68467207b96SArnd Bergmann .read = spufs_mbox_read, 68567207b96SArnd Bergmann }; 68667207b96SArnd Bergmann 68767207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 68867207b96SArnd Bergmann size_t len, loff_t *pos) 68967207b96SArnd Bergmann { 6908b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 691c9101bdbSChristoph Hellwig ssize_t ret; 69267207b96SArnd Bergmann u32 mbox_stat; 69367207b96SArnd Bergmann 69467207b96SArnd Bergmann if (len < 4) 69567207b96SArnd Bergmann return -EINVAL; 69667207b96SArnd Bergmann 697c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 698c9101bdbSChristoph Hellwig if (ret) 699c9101bdbSChristoph Hellwig return ret; 7008b3d6663SArnd Bergmann 7018b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 7028b3d6663SArnd Bergmann 7038b3d6663SArnd Bergmann spu_release(ctx); 70467207b96SArnd Bergmann 70567207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 70667207b96SArnd Bergmann return -EFAULT; 70767207b96SArnd Bergmann 70867207b96SArnd Bergmann return 4; 70967207b96SArnd Bergmann } 71067207b96SArnd Bergmann 7115dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = { 71267207b96SArnd Bergmann .open = spufs_pipe_open, 71367207b96SArnd Bergmann .read = spufs_mbox_stat_read, 71467207b96SArnd Bergmann }; 71567207b96SArnd Bergmann 71667207b96SArnd Bergmann /* low-level ibox access function */ 7178b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 71867207b96SArnd Bergmann { 7198b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 72067207b96SArnd Bergmann } 72167207b96SArnd Bergmann 72267207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 72367207b96SArnd Bergmann { 7248b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 7258b3d6663SArnd Bergmann 7268b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 7278b3d6663SArnd Bergmann } 7288b3d6663SArnd Bergmann 7298b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 7308b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 7318b3d6663SArnd Bergmann { 7328b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 7338b3d6663SArnd Bergmann 734e65c2f6fSLuke Browning if (!ctx) 735e65c2f6fSLuke Browning return; 736e65c2f6fSLuke Browning 7378b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 7388b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 73967207b96SArnd Bergmann } 74067207b96SArnd Bergmann 741cdcc89bbSArnd Bergmann /* 742cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 743cdcc89bbSArnd Bergmann * one of the conditions becomes true: 744cdcc89bbSArnd Bergmann * 745cdcc89bbSArnd Bergmann * - no more data available in the mailbox 746cdcc89bbSArnd Bergmann * - end of the user provided buffer 747cdcc89bbSArnd Bergmann * - end of the mapped area 748cdcc89bbSArnd Bergmann * 749cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 750cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 751cdcc89bbSArnd Bergmann * read something. 752cdcc89bbSArnd Bergmann */ 75367207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 75467207b96SArnd Bergmann size_t len, loff_t *pos) 75567207b96SArnd Bergmann { 7568b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 757cdcc89bbSArnd Bergmann u32 ibox_data, __user *udata; 758cdcc89bbSArnd Bergmann ssize_t count; 75967207b96SArnd Bergmann 76067207b96SArnd Bergmann if (len < 4) 76167207b96SArnd Bergmann return -EINVAL; 76267207b96SArnd Bergmann 763cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 764cdcc89bbSArnd Bergmann return -EFAULT; 765cdcc89bbSArnd Bergmann 766cdcc89bbSArnd Bergmann udata = (void __user *)buf; 767cdcc89bbSArnd Bergmann 768c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 769c9101bdbSChristoph Hellwig if (count) 770eebead5bSChristoph Hellwig goto out; 77167207b96SArnd Bergmann 772cdcc89bbSArnd Bergmann /* wait only for the first element */ 773cdcc89bbSArnd Bergmann count = 0; 77467207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 775eebead5bSChristoph Hellwig if (!spu_ibox_read(ctx, &ibox_data)) { 776cdcc89bbSArnd Bergmann count = -EAGAIN; 777eebead5bSChristoph Hellwig goto out_unlock; 778eebead5bSChristoph Hellwig } 77967207b96SArnd Bergmann } else { 780cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 781cdcc89bbSArnd Bergmann if (count) 782cdcc89bbSArnd Bergmann goto out; 783eebead5bSChristoph Hellwig } 784cdcc89bbSArnd Bergmann 785cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 786cdcc89bbSArnd Bergmann count = __put_user(ibox_data, udata); 787cdcc89bbSArnd Bergmann if (count) 788eebead5bSChristoph Hellwig goto out_unlock; 789cdcc89bbSArnd Bergmann 790cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 791cdcc89bbSArnd Bergmann int ret; 792cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 793cdcc89bbSArnd Bergmann if (ret == 0) 794cdcc89bbSArnd Bergmann break; 795cdcc89bbSArnd Bergmann /* 796cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 797cdcc89bbSArnd Bergmann * but still need to return the data we have 798cdcc89bbSArnd Bergmann * read successfully so far. 799cdcc89bbSArnd Bergmann */ 800cdcc89bbSArnd Bergmann ret = __put_user(ibox_data, udata); 801cdcc89bbSArnd Bergmann if (ret) 802cdcc89bbSArnd Bergmann break; 80367207b96SArnd Bergmann } 80467207b96SArnd Bergmann 805eebead5bSChristoph Hellwig out_unlock: 8068b3d6663SArnd Bergmann spu_release(ctx); 807eebead5bSChristoph Hellwig out: 808cdcc89bbSArnd Bergmann return count; 80967207b96SArnd Bergmann } 81067207b96SArnd Bergmann 81167207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 81267207b96SArnd Bergmann { 8138b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 81467207b96SArnd Bergmann unsigned int mask; 81567207b96SArnd Bergmann 8168b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 81767207b96SArnd Bergmann 818c9101bdbSChristoph Hellwig /* 819c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 820c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 821c9101bdbSChristoph Hellwig */ 822c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 8233a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 8243a843d7cSArnd Bergmann spu_release(ctx); 82567207b96SArnd Bergmann 82667207b96SArnd Bergmann return mask; 82767207b96SArnd Bergmann } 82867207b96SArnd Bergmann 8295dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = { 83067207b96SArnd Bergmann .open = spufs_pipe_open, 83167207b96SArnd Bergmann .read = spufs_ibox_read, 83267207b96SArnd Bergmann .poll = spufs_ibox_poll, 83367207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 83467207b96SArnd Bergmann }; 83567207b96SArnd Bergmann 83667207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 83767207b96SArnd Bergmann size_t len, loff_t *pos) 83867207b96SArnd Bergmann { 8398b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 840c9101bdbSChristoph Hellwig ssize_t ret; 84167207b96SArnd Bergmann u32 ibox_stat; 84267207b96SArnd Bergmann 84367207b96SArnd Bergmann if (len < 4) 84467207b96SArnd Bergmann return -EINVAL; 84567207b96SArnd Bergmann 846c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 847c9101bdbSChristoph Hellwig if (ret) 848c9101bdbSChristoph Hellwig return ret; 8498b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 8508b3d6663SArnd Bergmann spu_release(ctx); 85167207b96SArnd Bergmann 85267207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 85367207b96SArnd Bergmann return -EFAULT; 85467207b96SArnd Bergmann 85567207b96SArnd Bergmann return 4; 85667207b96SArnd Bergmann } 85767207b96SArnd Bergmann 8585dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = { 85967207b96SArnd Bergmann .open = spufs_pipe_open, 86067207b96SArnd Bergmann .read = spufs_ibox_stat_read, 86167207b96SArnd Bergmann }; 86267207b96SArnd Bergmann 86367207b96SArnd Bergmann /* low-level mailbox write */ 8648b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 86567207b96SArnd Bergmann { 8668b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 86767207b96SArnd Bergmann } 86867207b96SArnd Bergmann 86967207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 87067207b96SArnd Bergmann { 8718b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 8728b3d6663SArnd Bergmann int ret; 8738b3d6663SArnd Bergmann 8748b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 8758b3d6663SArnd Bergmann 8768b3d6663SArnd Bergmann return ret; 8778b3d6663SArnd Bergmann } 8788b3d6663SArnd Bergmann 8798b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 8808b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 8818b3d6663SArnd Bergmann { 8828b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 8838b3d6663SArnd Bergmann 884e65c2f6fSLuke Browning if (!ctx) 885e65c2f6fSLuke Browning return; 886e65c2f6fSLuke Browning 8878b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 8888b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 88967207b96SArnd Bergmann } 89067207b96SArnd Bergmann 891cdcc89bbSArnd Bergmann /* 892cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 893cdcc89bbSArnd Bergmann * one of the conditions becomes true: 894cdcc89bbSArnd Bergmann * 895cdcc89bbSArnd Bergmann * - the mailbox is full 896cdcc89bbSArnd Bergmann * - end of the user provided buffer 897cdcc89bbSArnd Bergmann * - end of the mapped area 898cdcc89bbSArnd Bergmann * 899cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 900cdcc89bbSArnd Bergmann * space is availabyl, but return when we have been able to 901cdcc89bbSArnd Bergmann * write something. 902cdcc89bbSArnd Bergmann */ 90367207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 90467207b96SArnd Bergmann size_t len, loff_t *pos) 90567207b96SArnd Bergmann { 9068b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 907cdcc89bbSArnd Bergmann u32 wbox_data, __user *udata; 908cdcc89bbSArnd Bergmann ssize_t count; 90967207b96SArnd Bergmann 91067207b96SArnd Bergmann if (len < 4) 91167207b96SArnd Bergmann return -EINVAL; 91267207b96SArnd Bergmann 913cdcc89bbSArnd Bergmann udata = (void __user *)buf; 914cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_READ, buf, len)) 915cdcc89bbSArnd Bergmann return -EFAULT; 916cdcc89bbSArnd Bergmann 917cdcc89bbSArnd Bergmann if (__get_user(wbox_data, udata)) 91867207b96SArnd Bergmann return -EFAULT; 91967207b96SArnd Bergmann 920c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 921c9101bdbSChristoph Hellwig if (count) 922eebead5bSChristoph Hellwig goto out; 9238b3d6663SArnd Bergmann 924cdcc89bbSArnd Bergmann /* 925cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 926cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 927cdcc89bbSArnd Bergmann */ 928cdcc89bbSArnd Bergmann count = 0; 92967207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 930eebead5bSChristoph Hellwig if (!spu_wbox_write(ctx, wbox_data)) { 931cdcc89bbSArnd Bergmann count = -EAGAIN; 932eebead5bSChristoph Hellwig goto out_unlock; 933eebead5bSChristoph Hellwig } 93467207b96SArnd Bergmann } else { 935cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 936cdcc89bbSArnd Bergmann if (count) 937cdcc89bbSArnd Bergmann goto out; 938eebead5bSChristoph Hellwig } 939eebead5bSChristoph Hellwig 9408b3d6663SArnd Bergmann 94196de0e25SJan Engelhardt /* write as much as possible */ 942cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 943cdcc89bbSArnd Bergmann int ret; 944cdcc89bbSArnd Bergmann ret = __get_user(wbox_data, udata); 945cdcc89bbSArnd Bergmann if (ret) 946cdcc89bbSArnd Bergmann break; 947cdcc89bbSArnd Bergmann 948cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 949cdcc89bbSArnd Bergmann if (ret == 0) 950cdcc89bbSArnd Bergmann break; 951cdcc89bbSArnd Bergmann } 952cdcc89bbSArnd Bergmann 953eebead5bSChristoph Hellwig out_unlock: 954cdcc89bbSArnd Bergmann spu_release(ctx); 955eebead5bSChristoph Hellwig out: 956cdcc89bbSArnd Bergmann return count; 95767207b96SArnd Bergmann } 95867207b96SArnd Bergmann 95967207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 96067207b96SArnd Bergmann { 9618b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 96267207b96SArnd Bergmann unsigned int mask; 96367207b96SArnd Bergmann 9648b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 96567207b96SArnd Bergmann 966c9101bdbSChristoph Hellwig /* 967c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 968c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 969c9101bdbSChristoph Hellwig */ 970c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 9713a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 9723a843d7cSArnd Bergmann spu_release(ctx); 97367207b96SArnd Bergmann 97467207b96SArnd Bergmann return mask; 97567207b96SArnd Bergmann } 97667207b96SArnd Bergmann 9775dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = { 97867207b96SArnd Bergmann .open = spufs_pipe_open, 97967207b96SArnd Bergmann .write = spufs_wbox_write, 98067207b96SArnd Bergmann .poll = spufs_wbox_poll, 98167207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 98267207b96SArnd Bergmann }; 98367207b96SArnd Bergmann 98467207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 98567207b96SArnd Bergmann size_t len, loff_t *pos) 98667207b96SArnd Bergmann { 9878b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 988c9101bdbSChristoph Hellwig ssize_t ret; 98967207b96SArnd Bergmann u32 wbox_stat; 99067207b96SArnd Bergmann 99167207b96SArnd Bergmann if (len < 4) 99267207b96SArnd Bergmann return -EINVAL; 99367207b96SArnd Bergmann 994c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 995c9101bdbSChristoph Hellwig if (ret) 996c9101bdbSChristoph Hellwig return ret; 9978b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 9988b3d6663SArnd Bergmann spu_release(ctx); 99967207b96SArnd Bergmann 100067207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 100167207b96SArnd Bergmann return -EFAULT; 100267207b96SArnd Bergmann 100367207b96SArnd Bergmann return 4; 100467207b96SArnd Bergmann } 100567207b96SArnd Bergmann 10065dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = { 100767207b96SArnd Bergmann .open = spufs_pipe_open, 100867207b96SArnd Bergmann .read = spufs_wbox_stat_read, 100967207b96SArnd Bergmann }; 101067207b96SArnd Bergmann 10116df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 10126df10a82SMark Nutter { 10136df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 10146df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 101543c2bbd9SChristoph Hellwig 101647d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 10176df10a82SMark Nutter file->private_data = ctx; 101843c2bbd9SChristoph Hellwig if (!i->i_openers++) 10196df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 102047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 10216df10a82SMark Nutter return nonseekable_open(inode, file); 10226df10a82SMark Nutter } 10236df10a82SMark Nutter 102443c2bbd9SChristoph Hellwig static int 102543c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file) 102643c2bbd9SChristoph Hellwig { 102743c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 102843c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 102943c2bbd9SChristoph Hellwig 103047d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 103143c2bbd9SChristoph Hellwig if (!--i->i_openers) 103243c2bbd9SChristoph Hellwig ctx->signal1 = NULL; 103347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 103443c2bbd9SChristoph Hellwig return 0; 103543c2bbd9SChristoph Hellwig } 103643c2bbd9SChristoph Hellwig 1037bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 103867207b96SArnd Bergmann size_t len, loff_t *pos) 103967207b96SArnd Bergmann { 104017f88cebSDwayne Grant McConnell int ret = 0; 104167207b96SArnd Bergmann u32 data; 104267207b96SArnd Bergmann 104367207b96SArnd Bergmann if (len < 4) 104467207b96SArnd Bergmann return -EINVAL; 104567207b96SArnd Bergmann 104617f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[3]) { 104717f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[3]; 104817f88cebSDwayne Grant McConnell ret = 4; 104917f88cebSDwayne Grant McConnell } 10508b3d6663SArnd Bergmann 105117f88cebSDwayne Grant McConnell if (!ret) 105217f88cebSDwayne Grant McConnell goto out; 105317f88cebSDwayne Grant McConnell 105467207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 105567207b96SArnd Bergmann return -EFAULT; 105667207b96SArnd Bergmann 105717f88cebSDwayne Grant McConnell out: 105817f88cebSDwayne Grant McConnell return ret; 105967207b96SArnd Bergmann } 106067207b96SArnd Bergmann 1061bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 1062bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1063bf1ab978SDwayne Grant McConnell { 1064bf1ab978SDwayne Grant McConnell int ret; 1065bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1066bf1ab978SDwayne Grant McConnell 1067c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1068c9101bdbSChristoph Hellwig if (ret) 1069c9101bdbSChristoph Hellwig return ret; 1070bf1ab978SDwayne Grant McConnell ret = __spufs_signal1_read(ctx, buf, len, pos); 107127b1ea09SChristoph Hellwig spu_release_saved(ctx); 1072bf1ab978SDwayne Grant McConnell 1073bf1ab978SDwayne Grant McConnell return ret; 1074bf1ab978SDwayne Grant McConnell } 1075bf1ab978SDwayne Grant McConnell 107667207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 107767207b96SArnd Bergmann size_t len, loff_t *pos) 107867207b96SArnd Bergmann { 107967207b96SArnd Bergmann struct spu_context *ctx; 1080c9101bdbSChristoph Hellwig ssize_t ret; 108167207b96SArnd Bergmann u32 data; 108267207b96SArnd Bergmann 108367207b96SArnd Bergmann ctx = file->private_data; 108467207b96SArnd Bergmann 108567207b96SArnd Bergmann if (len < 4) 108667207b96SArnd Bergmann return -EINVAL; 108767207b96SArnd Bergmann 108867207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 108967207b96SArnd Bergmann return -EFAULT; 109067207b96SArnd Bergmann 1091c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1092c9101bdbSChristoph Hellwig if (ret) 1093c9101bdbSChristoph Hellwig return ret; 10948b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 10958b3d6663SArnd Bergmann spu_release(ctx); 109667207b96SArnd Bergmann 109767207b96SArnd Bergmann return 4; 109867207b96SArnd Bergmann } 109967207b96SArnd Bergmann 110078bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma, 110178bde53eSBenjamin Herrenschmidt unsigned long address) 11026df10a82SMark Nutter { 110327d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 110478bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x14000, 0x1000); 110527d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 110627d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 110727d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 110827d5bf2aSBenjamin Herrenschmidt */ 110978bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 111027d5bf2aSBenjamin Herrenschmidt #else 111127d5bf2aSBenjamin Herrenschmidt #error unsupported page size 111227d5bf2aSBenjamin Herrenschmidt #endif 11136df10a82SMark Nutter } 11146df10a82SMark Nutter 11156df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = { 111678bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal1_mmap_nopfn, 11176df10a82SMark Nutter }; 11186df10a82SMark Nutter 11196df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 11206df10a82SMark Nutter { 11216df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 11226df10a82SMark Nutter return -EINVAL; 11236df10a82SMark Nutter 112478bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 11256df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 112623cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 11276df10a82SMark Nutter 11286df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 11296df10a82SMark Nutter return 0; 11306df10a82SMark Nutter } 11316df10a82SMark Nutter 11325dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = { 11336df10a82SMark Nutter .open = spufs_signal1_open, 113443c2bbd9SChristoph Hellwig .release = spufs_signal1_release, 113567207b96SArnd Bergmann .read = spufs_signal1_read, 113667207b96SArnd Bergmann .write = spufs_signal1_write, 11376df10a82SMark Nutter .mmap = spufs_signal1_mmap, 113867207b96SArnd Bergmann }; 113967207b96SArnd Bergmann 1140d054b36fSJeremy Kerr static const struct file_operations spufs_signal1_nosched_fops = { 1141d054b36fSJeremy Kerr .open = spufs_signal1_open, 1142d054b36fSJeremy Kerr .release = spufs_signal1_release, 1143d054b36fSJeremy Kerr .write = spufs_signal1_write, 1144d054b36fSJeremy Kerr .mmap = spufs_signal1_mmap, 1145d054b36fSJeremy Kerr }; 1146d054b36fSJeremy Kerr 11476df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 11486df10a82SMark Nutter { 11496df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 11506df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 115143c2bbd9SChristoph Hellwig 115247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 11536df10a82SMark Nutter file->private_data = ctx; 115443c2bbd9SChristoph Hellwig if (!i->i_openers++) 11556df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 115647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 11576df10a82SMark Nutter return nonseekable_open(inode, file); 11586df10a82SMark Nutter } 11596df10a82SMark Nutter 116043c2bbd9SChristoph Hellwig static int 116143c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file) 116243c2bbd9SChristoph Hellwig { 116343c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 116443c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 116543c2bbd9SChristoph Hellwig 116647d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 116743c2bbd9SChristoph Hellwig if (!--i->i_openers) 116843c2bbd9SChristoph Hellwig ctx->signal2 = NULL; 116947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 117043c2bbd9SChristoph Hellwig return 0; 117143c2bbd9SChristoph Hellwig } 117243c2bbd9SChristoph Hellwig 1173bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 117467207b96SArnd Bergmann size_t len, loff_t *pos) 117567207b96SArnd Bergmann { 117617f88cebSDwayne Grant McConnell int ret = 0; 117767207b96SArnd Bergmann u32 data; 117867207b96SArnd Bergmann 117967207b96SArnd Bergmann if (len < 4) 118067207b96SArnd Bergmann return -EINVAL; 118167207b96SArnd Bergmann 118217f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[4]) { 118317f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[4]; 118417f88cebSDwayne Grant McConnell ret = 4; 118517f88cebSDwayne Grant McConnell } 11868b3d6663SArnd Bergmann 118717f88cebSDwayne Grant McConnell if (!ret) 118817f88cebSDwayne Grant McConnell goto out; 118917f88cebSDwayne Grant McConnell 119067207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 119167207b96SArnd Bergmann return -EFAULT; 119267207b96SArnd Bergmann 119317f88cebSDwayne Grant McConnell out: 1194bf1ab978SDwayne Grant McConnell return ret; 1195bf1ab978SDwayne Grant McConnell } 1196bf1ab978SDwayne Grant McConnell 1197bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 1198bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1199bf1ab978SDwayne Grant McConnell { 1200bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1201bf1ab978SDwayne Grant McConnell int ret; 1202bf1ab978SDwayne Grant McConnell 1203c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1204c9101bdbSChristoph Hellwig if (ret) 1205c9101bdbSChristoph Hellwig return ret; 1206bf1ab978SDwayne Grant McConnell ret = __spufs_signal2_read(ctx, buf, len, pos); 120727b1ea09SChristoph Hellwig spu_release_saved(ctx); 1208bf1ab978SDwayne Grant McConnell 1209bf1ab978SDwayne Grant McConnell return ret; 121067207b96SArnd Bergmann } 121167207b96SArnd Bergmann 121267207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 121367207b96SArnd Bergmann size_t len, loff_t *pos) 121467207b96SArnd Bergmann { 121567207b96SArnd Bergmann struct spu_context *ctx; 1216c9101bdbSChristoph Hellwig ssize_t ret; 121767207b96SArnd Bergmann u32 data; 121867207b96SArnd Bergmann 121967207b96SArnd Bergmann ctx = file->private_data; 122067207b96SArnd Bergmann 122167207b96SArnd Bergmann if (len < 4) 122267207b96SArnd Bergmann return -EINVAL; 122367207b96SArnd Bergmann 122467207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 122567207b96SArnd Bergmann return -EFAULT; 122667207b96SArnd Bergmann 1227c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1228c9101bdbSChristoph Hellwig if (ret) 1229c9101bdbSChristoph Hellwig return ret; 12308b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 12318b3d6663SArnd Bergmann spu_release(ctx); 123267207b96SArnd Bergmann 123367207b96SArnd Bergmann return 4; 123467207b96SArnd Bergmann } 123567207b96SArnd Bergmann 123627d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 123778bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma, 123878bde53eSBenjamin Herrenschmidt unsigned long address) 12396df10a82SMark Nutter { 124027d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 124178bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000); 124227d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 124327d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 124427d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 124527d5bf2aSBenjamin Herrenschmidt */ 124678bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 124727d5bf2aSBenjamin Herrenschmidt #else 124827d5bf2aSBenjamin Herrenschmidt #error unsupported page size 124927d5bf2aSBenjamin Herrenschmidt #endif 12506df10a82SMark Nutter } 12516df10a82SMark Nutter 12526df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = { 125378bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal2_mmap_nopfn, 12546df10a82SMark Nutter }; 12556df10a82SMark Nutter 12566df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 12576df10a82SMark Nutter { 12586df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 12596df10a82SMark Nutter return -EINVAL; 12606df10a82SMark Nutter 126178bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 12626df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 126323cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 12646df10a82SMark Nutter 12656df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 12666df10a82SMark Nutter return 0; 12676df10a82SMark Nutter } 126827d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 126927d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 127027d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 12716df10a82SMark Nutter 12725dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = { 12736df10a82SMark Nutter .open = spufs_signal2_open, 127443c2bbd9SChristoph Hellwig .release = spufs_signal2_release, 127567207b96SArnd Bergmann .read = spufs_signal2_read, 127667207b96SArnd Bergmann .write = spufs_signal2_write, 12776df10a82SMark Nutter .mmap = spufs_signal2_mmap, 127867207b96SArnd Bergmann }; 127967207b96SArnd Bergmann 1280d054b36fSJeremy Kerr static const struct file_operations spufs_signal2_nosched_fops = { 1281d054b36fSJeremy Kerr .open = spufs_signal2_open, 1282d054b36fSJeremy Kerr .release = spufs_signal2_release, 1283d054b36fSJeremy Kerr .write = spufs_signal2_write, 1284d054b36fSJeremy Kerr .mmap = spufs_signal2_mmap, 1285d054b36fSJeremy Kerr }; 1286d054b36fSJeremy Kerr 1287104f0cc2SMichael Ellerman /* 1288104f0cc2SMichael Ellerman * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the 1289104f0cc2SMichael Ellerman * work of acquiring (or not) the SPU context before calling through 1290104f0cc2SMichael Ellerman * to the actual get routine. The set routine is called directly. 1291104f0cc2SMichael Ellerman */ 1292104f0cc2SMichael Ellerman #define SPU_ATTR_NOACQUIRE 0 1293104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE 1 1294104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE_SAVED 2 1295104f0cc2SMichael Ellerman 1296104f0cc2SMichael Ellerman #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ 1297197b1a82SChristoph Hellwig static int __##__get(void *data, u64 *val) \ 1298104f0cc2SMichael Ellerman { \ 1299104f0cc2SMichael Ellerman struct spu_context *ctx = data; \ 1300c9101bdbSChristoph Hellwig int ret = 0; \ 1301104f0cc2SMichael Ellerman \ 1302104f0cc2SMichael Ellerman if (__acquire == SPU_ATTR_ACQUIRE) { \ 1303c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); \ 1304c9101bdbSChristoph Hellwig if (ret) \ 1305c9101bdbSChristoph Hellwig return ret; \ 1306197b1a82SChristoph Hellwig *val = __get(ctx); \ 1307104f0cc2SMichael Ellerman spu_release(ctx); \ 1308104f0cc2SMichael Ellerman } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ 1309c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); \ 1310c9101bdbSChristoph Hellwig if (ret) \ 1311c9101bdbSChristoph Hellwig return ret; \ 1312197b1a82SChristoph Hellwig *val = __get(ctx); \ 1313104f0cc2SMichael Ellerman spu_release_saved(ctx); \ 1314104f0cc2SMichael Ellerman } else \ 1315197b1a82SChristoph Hellwig *val = __get(ctx); \ 1316104f0cc2SMichael Ellerman \ 1317197b1a82SChristoph Hellwig return 0; \ 1318104f0cc2SMichael Ellerman } \ 1319197b1a82SChristoph Hellwig DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); 1320104f0cc2SMichael Ellerman 1321197b1a82SChristoph Hellwig static int spufs_signal1_type_set(void *data, u64 val) 132267207b96SArnd Bergmann { 132367207b96SArnd Bergmann struct spu_context *ctx = data; 1324c9101bdbSChristoph Hellwig int ret; 132567207b96SArnd Bergmann 1326c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1327c9101bdbSChristoph Hellwig if (ret) 1328c9101bdbSChristoph Hellwig return ret; 13298b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 13308b3d6663SArnd Bergmann spu_release(ctx); 1331197b1a82SChristoph Hellwig 1332197b1a82SChristoph Hellwig return 0; 133367207b96SArnd Bergmann } 133467207b96SArnd Bergmann 1335104f0cc2SMichael Ellerman static u64 spufs_signal1_type_get(struct spu_context *ctx) 1336bf1ab978SDwayne Grant McConnell { 1337bf1ab978SDwayne Grant McConnell return ctx->ops->signal1_type_get(ctx); 1338bf1ab978SDwayne Grant McConnell } 1339104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 1340104f0cc2SMichael Ellerman spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); 1341bf1ab978SDwayne Grant McConnell 134267207b96SArnd Bergmann 1343197b1a82SChristoph Hellwig static int spufs_signal2_type_set(void *data, u64 val) 134467207b96SArnd Bergmann { 134567207b96SArnd Bergmann struct spu_context *ctx = data; 1346c9101bdbSChristoph Hellwig int ret; 134767207b96SArnd Bergmann 1348c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1349c9101bdbSChristoph Hellwig if (ret) 1350c9101bdbSChristoph Hellwig return ret; 13518b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 13528b3d6663SArnd Bergmann spu_release(ctx); 1353197b1a82SChristoph Hellwig 1354197b1a82SChristoph Hellwig return 0; 135567207b96SArnd Bergmann } 135667207b96SArnd Bergmann 1357104f0cc2SMichael Ellerman static u64 spufs_signal2_type_get(struct spu_context *ctx) 1358bf1ab978SDwayne Grant McConnell { 1359bf1ab978SDwayne Grant McConnell return ctx->ops->signal2_type_get(ctx); 1360bf1ab978SDwayne Grant McConnell } 1361104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 1362104f0cc2SMichael Ellerman spufs_signal2_type_set, "%llu", SPU_ATTR_ACQUIRE); 136367207b96SArnd Bergmann 136427d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 136578bde53eSBenjamin Herrenschmidt static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, 136678bde53eSBenjamin Herrenschmidt unsigned long address) 1367d9379c4bSarnd@arndb.de { 136878bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x1000); 1369d9379c4bSarnd@arndb.de } 1370d9379c4bSarnd@arndb.de 1371d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = { 137278bde53eSBenjamin Herrenschmidt .nopfn = spufs_mss_mmap_nopfn, 1373d9379c4bSarnd@arndb.de }; 1374d9379c4bSarnd@arndb.de 1375d9379c4bSarnd@arndb.de /* 1376d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 1377d9379c4bSarnd@arndb.de */ 1378d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 1379d9379c4bSarnd@arndb.de { 1380d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 1381d9379c4bSarnd@arndb.de return -EINVAL; 1382d9379c4bSarnd@arndb.de 138378bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 1384d9379c4bSarnd@arndb.de vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 138523cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 1386d9379c4bSarnd@arndb.de 1387d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 1388d9379c4bSarnd@arndb.de return 0; 1389d9379c4bSarnd@arndb.de } 139027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 139127d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 139227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1393d9379c4bSarnd@arndb.de 1394d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 1395d9379c4bSarnd@arndb.de { 1396d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 139717e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 1398d9379c4bSarnd@arndb.de 1399d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 140043c2bbd9SChristoph Hellwig 140147d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 140243c2bbd9SChristoph Hellwig if (!i->i_openers++) 140317e0e270SBenjamin Herrenschmidt ctx->mss = inode->i_mapping; 140447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1405d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 1406d9379c4bSarnd@arndb.de } 1407d9379c4bSarnd@arndb.de 140843c2bbd9SChristoph Hellwig static int 140943c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file) 141043c2bbd9SChristoph Hellwig { 141143c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 141243c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 141343c2bbd9SChristoph Hellwig 141447d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 141543c2bbd9SChristoph Hellwig if (!--i->i_openers) 141643c2bbd9SChristoph Hellwig ctx->mss = NULL; 141747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 141843c2bbd9SChristoph Hellwig return 0; 141943c2bbd9SChristoph Hellwig } 142043c2bbd9SChristoph Hellwig 14215dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = { 1422d9379c4bSarnd@arndb.de .open = spufs_mss_open, 142343c2bbd9SChristoph Hellwig .release = spufs_mss_release, 1424d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 142527d5bf2aSBenjamin Herrenschmidt }; 142627d5bf2aSBenjamin Herrenschmidt 142778bde53eSBenjamin Herrenschmidt static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma, 142878bde53eSBenjamin Herrenschmidt unsigned long address) 142927d5bf2aSBenjamin Herrenschmidt { 143078bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x20000); 143127d5bf2aSBenjamin Herrenschmidt } 143227d5bf2aSBenjamin Herrenschmidt 143327d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = { 143478bde53eSBenjamin Herrenschmidt .nopfn = spufs_psmap_mmap_nopfn, 143527d5bf2aSBenjamin Herrenschmidt }; 143627d5bf2aSBenjamin Herrenschmidt 143727d5bf2aSBenjamin Herrenschmidt /* 143827d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 143927d5bf2aSBenjamin Herrenschmidt */ 144027d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 144127d5bf2aSBenjamin Herrenschmidt { 144227d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 144327d5bf2aSBenjamin Herrenschmidt return -EINVAL; 144427d5bf2aSBenjamin Herrenschmidt 144578bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 144627d5bf2aSBenjamin Herrenschmidt vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 144727d5bf2aSBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 144827d5bf2aSBenjamin Herrenschmidt 144927d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 145027d5bf2aSBenjamin Herrenschmidt return 0; 145127d5bf2aSBenjamin Herrenschmidt } 145227d5bf2aSBenjamin Herrenschmidt 145327d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 145427d5bf2aSBenjamin Herrenschmidt { 145527d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 145617e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 145727d5bf2aSBenjamin Herrenschmidt 145847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 145927d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 146043c2bbd9SChristoph Hellwig if (!i->i_openers++) 146117e0e270SBenjamin Herrenschmidt ctx->psmap = inode->i_mapping; 146247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 146327d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 146427d5bf2aSBenjamin Herrenschmidt } 146527d5bf2aSBenjamin Herrenschmidt 146643c2bbd9SChristoph Hellwig static int 146743c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file) 146843c2bbd9SChristoph Hellwig { 146943c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 147043c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 147143c2bbd9SChristoph Hellwig 147247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 147343c2bbd9SChristoph Hellwig if (!--i->i_openers) 147443c2bbd9SChristoph Hellwig ctx->psmap = NULL; 147547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 147643c2bbd9SChristoph Hellwig return 0; 147743c2bbd9SChristoph Hellwig } 147843c2bbd9SChristoph Hellwig 14795dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = { 148027d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 148143c2bbd9SChristoph Hellwig .release = spufs_psmap_release, 148227d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1483d9379c4bSarnd@arndb.de }; 1484d9379c4bSarnd@arndb.de 1485d9379c4bSarnd@arndb.de 148627d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 148778bde53eSBenjamin Herrenschmidt static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma, 148878bde53eSBenjamin Herrenschmidt unsigned long address) 14896df10a82SMark Nutter { 149078bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x3000, 0x1000); 14916df10a82SMark Nutter } 14926df10a82SMark Nutter 14936df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = { 149478bde53eSBenjamin Herrenschmidt .nopfn = spufs_mfc_mmap_nopfn, 14956df10a82SMark Nutter }; 14966df10a82SMark Nutter 14976df10a82SMark Nutter /* 14986df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 14996df10a82SMark Nutter */ 15006df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 15016df10a82SMark Nutter { 15026df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 15036df10a82SMark Nutter return -EINVAL; 15046df10a82SMark Nutter 150578bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 15066df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 150723cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 15086df10a82SMark Nutter 15096df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 15106df10a82SMark Nutter return 0; 15116df10a82SMark Nutter } 151227d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 151327d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 151427d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1515a33a7d73SArnd Bergmann 1516a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1517a33a7d73SArnd Bergmann { 1518a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1519a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1520a33a7d73SArnd Bergmann 1521a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1522a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1523a33a7d73SArnd Bergmann return -EINVAL; 1524a33a7d73SArnd Bergmann 1525a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1526a33a7d73SArnd Bergmann return -EBUSY; 1527a33a7d73SArnd Bergmann 152847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1529a33a7d73SArnd Bergmann file->private_data = ctx; 153043c2bbd9SChristoph Hellwig if (!i->i_openers++) 153117e0e270SBenjamin Herrenschmidt ctx->mfc = inode->i_mapping; 153247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1533a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1534a33a7d73SArnd Bergmann } 1535a33a7d73SArnd Bergmann 153643c2bbd9SChristoph Hellwig static int 153743c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file) 153843c2bbd9SChristoph Hellwig { 153943c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 154043c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 154143c2bbd9SChristoph Hellwig 154247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 154343c2bbd9SChristoph Hellwig if (!--i->i_openers) 154443c2bbd9SChristoph Hellwig ctx->mfc = NULL; 154547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 154643c2bbd9SChristoph Hellwig return 0; 154743c2bbd9SChristoph Hellwig } 154843c2bbd9SChristoph Hellwig 1549a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1550a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1551a33a7d73SArnd Bergmann { 1552a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1553a33a7d73SArnd Bergmann 1554e65c2f6fSLuke Browning if (!ctx) 1555e65c2f6fSLuke Browning return; 1556e65c2f6fSLuke Browning 1557a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1558a33a7d73SArnd Bergmann 1559*e48b1b45SHarvey Harrison pr_debug("%s %s\n", __func__, spu->name); 1560a33a7d73SArnd Bergmann if (ctx->mfc_fasync) { 1561a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1562a33a7d73SArnd Bergmann unsigned int mask; 1563a33a7d73SArnd Bergmann 1564a33a7d73SArnd Bergmann /* no need for spu_acquire in interrupt context */ 1565a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1566a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1567a33a7d73SArnd Bergmann 1568a33a7d73SArnd Bergmann mask = 0; 1569a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1570a33a7d73SArnd Bergmann mask |= POLLOUT; 1571a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1572a33a7d73SArnd Bergmann mask |= POLLIN; 1573a33a7d73SArnd Bergmann 1574a33a7d73SArnd Bergmann kill_fasync(&ctx->mfc_fasync, SIGIO, mask); 1575a33a7d73SArnd Bergmann } 1576a33a7d73SArnd Bergmann } 1577a33a7d73SArnd Bergmann 1578a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1579a33a7d73SArnd Bergmann { 1580a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1581a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1582a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1583a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1584a33a7d73SArnd Bergmann if (*status) 1585a33a7d73SArnd Bergmann return 1; 1586a33a7d73SArnd Bergmann 1587a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1588a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1589a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1590a33a7d73SArnd Bergmann return 0; 1591a33a7d73SArnd Bergmann } 1592a33a7d73SArnd Bergmann 1593a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1594a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1595a33a7d73SArnd Bergmann { 1596a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1597a33a7d73SArnd Bergmann int ret = -EINVAL; 1598a33a7d73SArnd Bergmann u32 status; 1599a33a7d73SArnd Bergmann 1600a33a7d73SArnd Bergmann if (size != 4) 1601a33a7d73SArnd Bergmann goto out; 1602a33a7d73SArnd Bergmann 1603c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1604c9101bdbSChristoph Hellwig if (ret) 1605c9101bdbSChristoph Hellwig return ret; 1606c9101bdbSChristoph Hellwig 1607c9101bdbSChristoph Hellwig ret = -EINVAL; 1608a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1609a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1610a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1611a33a7d73SArnd Bergmann ret = -EAGAIN; 1612a33a7d73SArnd Bergmann else 1613c9101bdbSChristoph Hellwig /* XXX(hch): shouldn't we clear ret here? */ 1614a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1615a33a7d73SArnd Bergmann } else { 1616a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1617a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1618a33a7d73SArnd Bergmann if (ret) 1619a33a7d73SArnd Bergmann goto out; 1620eebead5bSChristoph Hellwig } 1621eebead5bSChristoph Hellwig spu_release(ctx); 1622a33a7d73SArnd Bergmann 1623a33a7d73SArnd Bergmann ret = 4; 1624a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1625a33a7d73SArnd Bergmann ret = -EFAULT; 1626a33a7d73SArnd Bergmann 1627a33a7d73SArnd Bergmann out: 1628a33a7d73SArnd Bergmann return ret; 1629a33a7d73SArnd Bergmann } 1630a33a7d73SArnd Bergmann 1631a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1632a33a7d73SArnd Bergmann { 1633a33a7d73SArnd Bergmann pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, 1634a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1635a33a7d73SArnd Bergmann 1636a33a7d73SArnd Bergmann switch (cmd->cmd) { 1637a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1638a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1639a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1640a33a7d73SArnd Bergmann case MFC_GET_CMD: 1641a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1642a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1643a33a7d73SArnd Bergmann break; 1644a33a7d73SArnd Bergmann default: 1645a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1646a33a7d73SArnd Bergmann return -EIO; 1647a33a7d73SArnd Bergmann } 1648a33a7d73SArnd Bergmann 1649a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 1650a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment, ea %lx lsa %x\n", 1651a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1652a33a7d73SArnd Bergmann return -EIO; 1653a33a7d73SArnd Bergmann } 1654a33a7d73SArnd Bergmann 1655a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1656a33a7d73SArnd Bergmann case 1: 1657a33a7d73SArnd Bergmann break; 1658a33a7d73SArnd Bergmann case 2: 1659a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1660a33a7d73SArnd Bergmann goto error; 1661a33a7d73SArnd Bergmann break; 1662a33a7d73SArnd Bergmann case 4: 1663a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1664a33a7d73SArnd Bergmann goto error; 1665a33a7d73SArnd Bergmann break; 1666a33a7d73SArnd Bergmann case 8: 1667a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1668a33a7d73SArnd Bergmann goto error; 1669a33a7d73SArnd Bergmann break; 1670a33a7d73SArnd Bergmann case 0: 1671a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1672a33a7d73SArnd Bergmann goto error; 1673a33a7d73SArnd Bergmann break; 1674a33a7d73SArnd Bergmann error: 1675a33a7d73SArnd Bergmann default: 1676a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1677a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1678a33a7d73SArnd Bergmann return -EIO; 1679a33a7d73SArnd Bergmann } 1680a33a7d73SArnd Bergmann 1681a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1682a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1683a33a7d73SArnd Bergmann return -EIO; 1684a33a7d73SArnd Bergmann } 1685a33a7d73SArnd Bergmann 1686a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1687a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1688a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1689a33a7d73SArnd Bergmann return -EIO; 1690a33a7d73SArnd Bergmann } 1691a33a7d73SArnd Bergmann 1692a33a7d73SArnd Bergmann if (cmd->class) { 1693a33a7d73SArnd Bergmann /* not supported in this version */ 1694a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1695a33a7d73SArnd Bergmann return -EIO; 1696a33a7d73SArnd Bergmann } 1697a33a7d73SArnd Bergmann 1698a33a7d73SArnd Bergmann return 0; 1699a33a7d73SArnd Bergmann } 1700a33a7d73SArnd Bergmann 1701a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1702a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1703a33a7d73SArnd Bergmann int *error) 1704a33a7d73SArnd Bergmann { 1705a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1706a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1707a33a7d73SArnd Bergmann /* wait for any tag group to complete 1708a33a7d73SArnd Bergmann so we have space for the new command */ 1709a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1710a33a7d73SArnd Bergmann /* try again, because the queue might be 1711a33a7d73SArnd Bergmann empty again */ 1712a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1713a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1714a33a7d73SArnd Bergmann return 0; 1715a33a7d73SArnd Bergmann } 1716a33a7d73SArnd Bergmann return 1; 1717a33a7d73SArnd Bergmann } 1718a33a7d73SArnd Bergmann 1719a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1720a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1721a33a7d73SArnd Bergmann { 1722a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1723a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1724a33a7d73SArnd Bergmann int ret = -EINVAL; 1725a33a7d73SArnd Bergmann 1726a33a7d73SArnd Bergmann if (size != sizeof cmd) 1727a33a7d73SArnd Bergmann goto out; 1728a33a7d73SArnd Bergmann 1729a33a7d73SArnd Bergmann ret = -EFAULT; 1730a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1731a33a7d73SArnd Bergmann goto out; 1732a33a7d73SArnd Bergmann 1733a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1734a33a7d73SArnd Bergmann if (ret) 1735a33a7d73SArnd Bergmann goto out; 1736a33a7d73SArnd Bergmann 1737c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1738c9101bdbSChristoph Hellwig if (ret) 1739c9101bdbSChristoph Hellwig goto out; 1740c9101bdbSChristoph Hellwig 174133bfd7a7SArnd Bergmann ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 1742577f8f10SAkinobu Mita if (ret) 1743577f8f10SAkinobu Mita goto out; 1744577f8f10SAkinobu Mita 1745a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1746a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1747a33a7d73SArnd Bergmann } else { 1748a33a7d73SArnd Bergmann int status; 1749a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1750a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1751eebead5bSChristoph Hellwig if (ret) 1752eebead5bSChristoph Hellwig goto out; 1753a33a7d73SArnd Bergmann if (status) 1754a33a7d73SArnd Bergmann ret = status; 1755a33a7d73SArnd Bergmann } 1756a33a7d73SArnd Bergmann 1757a33a7d73SArnd Bergmann if (ret) 1758933b0e35SKazunori Asayama goto out_unlock; 1759a33a7d73SArnd Bergmann 1760a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 17613692dc66SMasato Noguchi ret = size; 1762a33a7d73SArnd Bergmann 1763933b0e35SKazunori Asayama out_unlock: 1764933b0e35SKazunori Asayama spu_release(ctx); 1765a33a7d73SArnd Bergmann out: 1766a33a7d73SArnd Bergmann return ret; 1767a33a7d73SArnd Bergmann } 1768a33a7d73SArnd Bergmann 1769a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) 1770a33a7d73SArnd Bergmann { 1771a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1772a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1773a33a7d73SArnd Bergmann unsigned int mask; 1774a33a7d73SArnd Bergmann 1775933b0e35SKazunori Asayama poll_wait(file, &ctx->mfc_wq, wait); 1776933b0e35SKazunori Asayama 1777c9101bdbSChristoph Hellwig /* 1778c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 1779c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 1780c9101bdbSChristoph Hellwig */ 1781c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 1782a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1783a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1784a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1785a33a7d73SArnd Bergmann spu_release(ctx); 1786a33a7d73SArnd Bergmann 1787a33a7d73SArnd Bergmann mask = 0; 1788a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1789a33a7d73SArnd Bergmann mask |= POLLOUT | POLLWRNORM; 1790a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1791a33a7d73SArnd Bergmann mask |= POLLIN | POLLRDNORM; 1792a33a7d73SArnd Bergmann 1793*e48b1b45SHarvey Harrison pr_debug("%s: free %d tagstatus %d tagwait %d\n", __func__, 1794a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1795a33a7d73SArnd Bergmann 1796a33a7d73SArnd Bergmann return mask; 1797a33a7d73SArnd Bergmann } 1798a33a7d73SArnd Bergmann 179973b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1800a33a7d73SArnd Bergmann { 1801a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1802a33a7d73SArnd Bergmann int ret; 1803a33a7d73SArnd Bergmann 1804c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1805c9101bdbSChristoph Hellwig if (ret) 1806eebead5bSChristoph Hellwig goto out; 1807a33a7d73SArnd Bergmann #if 0 1808a33a7d73SArnd Bergmann /* this currently hangs */ 1809a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1810a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1811a33a7d73SArnd Bergmann if (ret) 1812a33a7d73SArnd Bergmann goto out; 1813a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1814a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1815eebead5bSChristoph Hellwig if (ret) 1816eebead5bSChristoph Hellwig goto out; 1817a33a7d73SArnd Bergmann #else 1818a33a7d73SArnd Bergmann ret = 0; 1819a33a7d73SArnd Bergmann #endif 1820a33a7d73SArnd Bergmann spu_release(ctx); 1821eebead5bSChristoph Hellwig out: 1822a33a7d73SArnd Bergmann return ret; 1823a33a7d73SArnd Bergmann } 1824a33a7d73SArnd Bergmann 1825a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, 1826a33a7d73SArnd Bergmann int datasync) 1827a33a7d73SArnd Bergmann { 182873b6af8aSAl Viro return spufs_mfc_flush(file, NULL); 1829a33a7d73SArnd Bergmann } 1830a33a7d73SArnd Bergmann 1831a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on) 1832a33a7d73SArnd Bergmann { 1833a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1834a33a7d73SArnd Bergmann 1835a33a7d73SArnd Bergmann return fasync_helper(fd, file, on, &ctx->mfc_fasync); 1836a33a7d73SArnd Bergmann } 1837a33a7d73SArnd Bergmann 18385dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = { 1839a33a7d73SArnd Bergmann .open = spufs_mfc_open, 184043c2bbd9SChristoph Hellwig .release = spufs_mfc_release, 1841a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1842a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1843a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1844a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1845a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 1846a33a7d73SArnd Bergmann .fasync = spufs_mfc_fasync, 18476df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1848a33a7d73SArnd Bergmann }; 1849a33a7d73SArnd Bergmann 1850197b1a82SChristoph Hellwig static int spufs_npc_set(void *data, u64 val) 185167207b96SArnd Bergmann { 185267207b96SArnd Bergmann struct spu_context *ctx = data; 1853c9101bdbSChristoph Hellwig int ret; 1854c9101bdbSChristoph Hellwig 1855c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1856c9101bdbSChristoph Hellwig if (ret) 1857c9101bdbSChristoph Hellwig return ret; 18588b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 18598b3d6663SArnd Bergmann spu_release(ctx); 1860197b1a82SChristoph Hellwig 1861197b1a82SChristoph Hellwig return 0; 186267207b96SArnd Bergmann } 186367207b96SArnd Bergmann 1864104f0cc2SMichael Ellerman static u64 spufs_npc_get(struct spu_context *ctx) 186578810ff6SMichael Ellerman { 186678810ff6SMichael Ellerman return ctx->ops->npc_read(ctx); 186778810ff6SMichael Ellerman } 1868104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 1869104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE); 187067207b96SArnd Bergmann 1871197b1a82SChristoph Hellwig static int spufs_decr_set(void *data, u64 val) 18728b3d6663SArnd Bergmann { 18738b3d6663SArnd Bergmann struct spu_context *ctx = data; 18748b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1875c9101bdbSChristoph Hellwig int ret; 1876c9101bdbSChristoph Hellwig 1877c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1878c9101bdbSChristoph Hellwig if (ret) 1879c9101bdbSChristoph Hellwig return ret; 18808b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 188127b1ea09SChristoph Hellwig spu_release_saved(ctx); 1882197b1a82SChristoph Hellwig 1883197b1a82SChristoph Hellwig return 0; 18848b3d6663SArnd Bergmann } 18858b3d6663SArnd Bergmann 1886104f0cc2SMichael Ellerman static u64 spufs_decr_get(struct spu_context *ctx) 18878b3d6663SArnd Bergmann { 18888b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1889bf1ab978SDwayne Grant McConnell return lscsa->decr.slot[0]; 1890bf1ab978SDwayne Grant McConnell } 1891104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 1892104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); 18938b3d6663SArnd Bergmann 1894197b1a82SChristoph Hellwig static int spufs_decr_status_set(void *data, u64 val) 18958b3d6663SArnd Bergmann { 18968b3d6663SArnd Bergmann struct spu_context *ctx = data; 1897c9101bdbSChristoph Hellwig int ret; 1898c9101bdbSChristoph Hellwig 1899c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1900c9101bdbSChristoph Hellwig if (ret) 1901c9101bdbSChristoph Hellwig return ret; 1902d40a01d4SMasato Noguchi if (val) 1903d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 1904d40a01d4SMasato Noguchi else 1905d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 190627b1ea09SChristoph Hellwig spu_release_saved(ctx); 1907197b1a82SChristoph Hellwig 1908197b1a82SChristoph Hellwig return 0; 19098b3d6663SArnd Bergmann } 19108b3d6663SArnd Bergmann 1911104f0cc2SMichael Ellerman static u64 spufs_decr_status_get(struct spu_context *ctx) 19128b3d6663SArnd Bergmann { 1913d40a01d4SMasato Noguchi if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 1914d40a01d4SMasato Noguchi return SPU_DECR_STATUS_RUNNING; 1915d40a01d4SMasato Noguchi else 1916d40a01d4SMasato Noguchi return 0; 1917bf1ab978SDwayne Grant McConnell } 1918104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 1919104f0cc2SMichael Ellerman spufs_decr_status_set, "0x%llx\n", 1920104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 19218b3d6663SArnd Bergmann 1922197b1a82SChristoph Hellwig static int spufs_event_mask_set(void *data, u64 val) 19238b3d6663SArnd Bergmann { 19248b3d6663SArnd Bergmann struct spu_context *ctx = data; 19258b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1926c9101bdbSChristoph Hellwig int ret; 1927c9101bdbSChristoph Hellwig 1928c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1929c9101bdbSChristoph Hellwig if (ret) 1930c9101bdbSChristoph Hellwig return ret; 19318b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 193227b1ea09SChristoph Hellwig spu_release_saved(ctx); 1933197b1a82SChristoph Hellwig 1934197b1a82SChristoph Hellwig return 0; 19358b3d6663SArnd Bergmann } 19368b3d6663SArnd Bergmann 1937104f0cc2SMichael Ellerman static u64 spufs_event_mask_get(struct spu_context *ctx) 19388b3d6663SArnd Bergmann { 19398b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1940bf1ab978SDwayne Grant McConnell return lscsa->event_mask.slot[0]; 1941bf1ab978SDwayne Grant McConnell } 1942bf1ab978SDwayne Grant McConnell 1943104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 1944104f0cc2SMichael Ellerman spufs_event_mask_set, "0x%llx\n", 1945104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 19468b3d6663SArnd Bergmann 1947104f0cc2SMichael Ellerman static u64 spufs_event_status_get(struct spu_context *ctx) 1948b9e3bd77SDwayne Grant McConnell { 1949b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1950b9e3bd77SDwayne Grant McConnell u64 stat; 1951b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1952b9e3bd77SDwayne Grant McConnell if (stat) 1953bf1ab978SDwayne Grant McConnell return state->spu_chnldata_RW[0]; 1954bf1ab978SDwayne Grant McConnell return 0; 1955bf1ab978SDwayne Grant McConnell } 1956104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1957104f0cc2SMichael Ellerman NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 1958b9e3bd77SDwayne Grant McConnell 1959197b1a82SChristoph Hellwig static int spufs_srr0_set(void *data, u64 val) 19608b3d6663SArnd Bergmann { 19618b3d6663SArnd Bergmann struct spu_context *ctx = data; 19628b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1963c9101bdbSChristoph Hellwig int ret; 1964c9101bdbSChristoph Hellwig 1965c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1966c9101bdbSChristoph Hellwig if (ret) 1967c9101bdbSChristoph Hellwig return ret; 19688b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 196927b1ea09SChristoph Hellwig spu_release_saved(ctx); 1970197b1a82SChristoph Hellwig 1971197b1a82SChristoph Hellwig return 0; 19728b3d6663SArnd Bergmann } 19738b3d6663SArnd Bergmann 1974104f0cc2SMichael Ellerman static u64 spufs_srr0_get(struct spu_context *ctx) 19758b3d6663SArnd Bergmann { 19768b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1977104f0cc2SMichael Ellerman return lscsa->srr0.slot[0]; 19788b3d6663SArnd Bergmann } 1979104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 1980104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 19818b3d6663SArnd Bergmann 1982104f0cc2SMichael Ellerman static u64 spufs_id_get(struct spu_context *ctx) 19837b1a7014Sarnd@arndb.de { 19847b1a7014Sarnd@arndb.de u64 num; 19857b1a7014Sarnd@arndb.de 19867b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 19877b1a7014Sarnd@arndb.de num = ctx->spu->number; 19887b1a7014Sarnd@arndb.de else 19897b1a7014Sarnd@arndb.de num = (unsigned int)-1; 19907b1a7014Sarnd@arndb.de 19917b1a7014Sarnd@arndb.de return num; 19927b1a7014Sarnd@arndb.de } 1993104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", 1994104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE) 19957b1a7014Sarnd@arndb.de 1996104f0cc2SMichael Ellerman static u64 spufs_object_id_get(struct spu_context *ctx) 1997bf1ab978SDwayne Grant McConnell { 1998bf1ab978SDwayne Grant McConnell /* FIXME: Should there really be no locking here? */ 1999104f0cc2SMichael Ellerman return ctx->object_id; 2000bf1ab978SDwayne Grant McConnell } 2001bf1ab978SDwayne Grant McConnell 2002197b1a82SChristoph Hellwig static int spufs_object_id_set(void *data, u64 id) 200386767277SArnd Bergmann { 200486767277SArnd Bergmann struct spu_context *ctx = data; 200586767277SArnd Bergmann ctx->object_id = id; 2006197b1a82SChristoph Hellwig 2007197b1a82SChristoph Hellwig return 0; 200886767277SArnd Bergmann } 200986767277SArnd Bergmann 2010104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 2011104f0cc2SMichael Ellerman spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); 201286767277SArnd Bergmann 2013104f0cc2SMichael Ellerman static u64 spufs_lslr_get(struct spu_context *ctx) 2014bf1ab978SDwayne Grant McConnell { 2015bf1ab978SDwayne Grant McConnell return ctx->csa.priv2.spu_lslr_RW; 2016bf1ab978SDwayne Grant McConnell } 2017104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", 2018104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 2019b9e3bd77SDwayne Grant McConnell 2020b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 2021b9e3bd77SDwayne Grant McConnell { 2022b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 2023b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 2024b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 2025b9e3bd77SDwayne Grant McConnell return 0; 2026b9e3bd77SDwayne Grant McConnell } 2027b9e3bd77SDwayne Grant McConnell 2028cbe709c1SBenjamin Herrenschmidt static int spufs_caps_show(struct seq_file *s, void *private) 2029cbe709c1SBenjamin Herrenschmidt { 2030cbe709c1SBenjamin Herrenschmidt struct spu_context *ctx = s->private; 2031cbe709c1SBenjamin Herrenschmidt 2032cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_NOSCHED)) 2033cbe709c1SBenjamin Herrenschmidt seq_puts(s, "sched\n"); 2034cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_ISOLATE)) 2035cbe709c1SBenjamin Herrenschmidt seq_puts(s, "step\n"); 2036cbe709c1SBenjamin Herrenschmidt return 0; 2037cbe709c1SBenjamin Herrenschmidt } 2038cbe709c1SBenjamin Herrenschmidt 2039cbe709c1SBenjamin Herrenschmidt static int spufs_caps_open(struct inode *inode, struct file *file) 2040cbe709c1SBenjamin Herrenschmidt { 2041cbe709c1SBenjamin Herrenschmidt return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); 2042cbe709c1SBenjamin Herrenschmidt } 2043cbe709c1SBenjamin Herrenschmidt 2044cbe709c1SBenjamin Herrenschmidt static const struct file_operations spufs_caps_fops = { 2045cbe709c1SBenjamin Herrenschmidt .open = spufs_caps_open, 2046cbe709c1SBenjamin Herrenschmidt .read = seq_read, 2047cbe709c1SBenjamin Herrenschmidt .llseek = seq_lseek, 2048cbe709c1SBenjamin Herrenschmidt .release = single_release, 2049cbe709c1SBenjamin Herrenschmidt }; 2050cbe709c1SBenjamin Herrenschmidt 2051bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, 2052bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2053bf1ab978SDwayne Grant McConnell { 2054bf1ab978SDwayne Grant McConnell u32 data; 2055bf1ab978SDwayne Grant McConnell 2056cbea9238SJeremy Kerr /* EOF if there's no entry in the mbox */ 2057cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0x0000ff)) 2058cbea9238SJeremy Kerr return 0; 2059cbea9238SJeremy Kerr 2060bf1ab978SDwayne Grant McConnell data = ctx->csa.prob.pu_mb_R; 2061bf1ab978SDwayne Grant McConnell 2062bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2063bf1ab978SDwayne Grant McConnell } 2064bf1ab978SDwayne Grant McConnell 206569a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 206669a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 206769a2f00cSDwayne Grant McConnell { 2068bf1ab978SDwayne Grant McConnell int ret; 206969a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 207069a2f00cSDwayne Grant McConnell 207169a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 207269a2f00cSDwayne Grant McConnell return -EFAULT; 207369a2f00cSDwayne Grant McConnell 2074c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2075c9101bdbSChristoph Hellwig if (ret) 2076c9101bdbSChristoph Hellwig return ret; 207769a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2078bf1ab978SDwayne Grant McConnell ret = __spufs_mbox_info_read(ctx, buf, len, pos); 207969a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 208027b1ea09SChristoph Hellwig spu_release_saved(ctx); 208169a2f00cSDwayne Grant McConnell 2082bf1ab978SDwayne Grant McConnell return ret; 208369a2f00cSDwayne Grant McConnell } 208469a2f00cSDwayne Grant McConnell 20855dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = { 208669a2f00cSDwayne Grant McConnell .open = spufs_info_open, 208769a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 208869a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 208969a2f00cSDwayne Grant McConnell }; 209069a2f00cSDwayne Grant McConnell 2091bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, 2092bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2093bf1ab978SDwayne Grant McConnell { 2094bf1ab978SDwayne Grant McConnell u32 data; 2095bf1ab978SDwayne Grant McConnell 2096cbea9238SJeremy Kerr /* EOF if there's no entry in the ibox */ 2097cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) 2098cbea9238SJeremy Kerr return 0; 2099cbea9238SJeremy Kerr 2100bf1ab978SDwayne Grant McConnell data = ctx->csa.priv2.puint_mb_R; 2101bf1ab978SDwayne Grant McConnell 2102bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2103bf1ab978SDwayne Grant McConnell } 2104bf1ab978SDwayne Grant McConnell 210569a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 210669a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 210769a2f00cSDwayne Grant McConnell { 210869a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2109bf1ab978SDwayne Grant McConnell int ret; 211069a2f00cSDwayne Grant McConnell 211169a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 211269a2f00cSDwayne Grant McConnell return -EFAULT; 211369a2f00cSDwayne Grant McConnell 2114c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2115c9101bdbSChristoph Hellwig if (ret) 2116c9101bdbSChristoph Hellwig return ret; 211769a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2118bf1ab978SDwayne Grant McConnell ret = __spufs_ibox_info_read(ctx, buf, len, pos); 211969a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 212027b1ea09SChristoph Hellwig spu_release_saved(ctx); 212169a2f00cSDwayne Grant McConnell 2122bf1ab978SDwayne Grant McConnell return ret; 212369a2f00cSDwayne Grant McConnell } 212469a2f00cSDwayne Grant McConnell 21255dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = { 212669a2f00cSDwayne Grant McConnell .open = spufs_info_open, 212769a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 212869a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 212969a2f00cSDwayne Grant McConnell }; 213069a2f00cSDwayne Grant McConnell 2131bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, 2132bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2133bf1ab978SDwayne Grant McConnell { 2134bf1ab978SDwayne Grant McConnell int i, cnt; 2135bf1ab978SDwayne Grant McConnell u32 data[4]; 2136bf1ab978SDwayne Grant McConnell u32 wbox_stat; 2137bf1ab978SDwayne Grant McConnell 2138bf1ab978SDwayne Grant McConnell wbox_stat = ctx->csa.prob.mb_stat_R; 2139bf1ab978SDwayne Grant McConnell cnt = 4 - ((wbox_stat & 0x00ff00) >> 8); 2140bf1ab978SDwayne Grant McConnell for (i = 0; i < cnt; i++) { 2141bf1ab978SDwayne Grant McConnell data[i] = ctx->csa.spu_mailbox_data[i]; 2142bf1ab978SDwayne Grant McConnell } 2143bf1ab978SDwayne Grant McConnell 2144bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, 2145bf1ab978SDwayne Grant McConnell cnt * sizeof(u32)); 2146bf1ab978SDwayne Grant McConnell } 2147bf1ab978SDwayne Grant McConnell 214869a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 214969a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 215069a2f00cSDwayne Grant McConnell { 215169a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2152bf1ab978SDwayne Grant McConnell int ret; 215369a2f00cSDwayne Grant McConnell 215469a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 215569a2f00cSDwayne Grant McConnell return -EFAULT; 215669a2f00cSDwayne Grant McConnell 2157c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2158c9101bdbSChristoph Hellwig if (ret) 2159c9101bdbSChristoph Hellwig return ret; 216069a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2161bf1ab978SDwayne Grant McConnell ret = __spufs_wbox_info_read(ctx, buf, len, pos); 216269a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 216327b1ea09SChristoph Hellwig spu_release_saved(ctx); 216469a2f00cSDwayne Grant McConnell 2165bf1ab978SDwayne Grant McConnell return ret; 216669a2f00cSDwayne Grant McConnell } 216769a2f00cSDwayne Grant McConnell 21685dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = { 216969a2f00cSDwayne Grant McConnell .open = spufs_info_open, 217069a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 217169a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 217269a2f00cSDwayne Grant McConnell }; 217369a2f00cSDwayne Grant McConnell 2174bf1ab978SDwayne Grant McConnell static ssize_t __spufs_dma_info_read(struct spu_context *ctx, 2175bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2176b9e3bd77SDwayne Grant McConnell { 2177b9e3bd77SDwayne Grant McConnell struct spu_dma_info info; 2178b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *spuqp; 2179b9e3bd77SDwayne Grant McConnell int i; 2180b9e3bd77SDwayne Grant McConnell 2181b9e3bd77SDwayne Grant McConnell info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 2182b9e3bd77SDwayne Grant McConnell info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 2183b9e3bd77SDwayne Grant McConnell info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; 2184b9e3bd77SDwayne Grant McConnell info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 2185b9e3bd77SDwayne Grant McConnell info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 2186b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 2187b9e3bd77SDwayne Grant McConnell qp = &info.dma_info_command_data[i]; 2188b9e3bd77SDwayne Grant McConnell spuqp = &ctx->csa.priv2.spuq[i]; 2189b9e3bd77SDwayne Grant McConnell 2190b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 2191b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 2192b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 2193b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 2194b9e3bd77SDwayne Grant McConnell } 2195b9e3bd77SDwayne Grant McConnell 2196b9e3bd77SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2197b9e3bd77SDwayne Grant McConnell sizeof info); 2198b9e3bd77SDwayne Grant McConnell } 2199b9e3bd77SDwayne Grant McConnell 2200bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 2201bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2202bf1ab978SDwayne Grant McConnell { 2203bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2204bf1ab978SDwayne Grant McConnell int ret; 2205bf1ab978SDwayne Grant McConnell 2206bf1ab978SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2207bf1ab978SDwayne Grant McConnell return -EFAULT; 2208bf1ab978SDwayne Grant McConnell 2209c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2210c9101bdbSChristoph Hellwig if (ret) 2211c9101bdbSChristoph Hellwig return ret; 2212bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2213bf1ab978SDwayne Grant McConnell ret = __spufs_dma_info_read(ctx, buf, len, pos); 2214bf1ab978SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 221527b1ea09SChristoph Hellwig spu_release_saved(ctx); 2216bf1ab978SDwayne Grant McConnell 2217bf1ab978SDwayne Grant McConnell return ret; 2218bf1ab978SDwayne Grant McConnell } 2219bf1ab978SDwayne Grant McConnell 22205dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = { 2221b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2222b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 2223b9e3bd77SDwayne Grant McConnell }; 2224b9e3bd77SDwayne Grant McConnell 2225bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, 2226bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2227b9e3bd77SDwayne Grant McConnell { 2228b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 2229b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *puqp; 2230bf1ab978SDwayne Grant McConnell int ret = sizeof info; 2231b9e3bd77SDwayne Grant McConnell int i; 2232b9e3bd77SDwayne Grant McConnell 2233b9e3bd77SDwayne Grant McConnell if (len < ret) 2234b9e3bd77SDwayne Grant McConnell return -EINVAL; 2235b9e3bd77SDwayne Grant McConnell 2236b9e3bd77SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2237b9e3bd77SDwayne Grant McConnell return -EFAULT; 2238b9e3bd77SDwayne Grant McConnell 2239b9e3bd77SDwayne Grant McConnell info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 2240b9e3bd77SDwayne Grant McConnell info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 2241b9e3bd77SDwayne Grant McConnell info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 2242b9e3bd77SDwayne Grant McConnell for (i = 0; i < 8; i++) { 2243b9e3bd77SDwayne Grant McConnell qp = &info.proxydma_info_command_data[i]; 2244b9e3bd77SDwayne Grant McConnell puqp = &ctx->csa.priv2.puq[i]; 2245b9e3bd77SDwayne Grant McConnell 2246b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 2247b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 2248b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 2249b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 2250b9e3bd77SDwayne Grant McConnell } 2251bf1ab978SDwayne Grant McConnell 2252bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2253bf1ab978SDwayne Grant McConnell sizeof info); 2254bf1ab978SDwayne Grant McConnell } 2255bf1ab978SDwayne Grant McConnell 2256bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 2257bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2258bf1ab978SDwayne Grant McConnell { 2259bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2260bf1ab978SDwayne Grant McConnell int ret; 2261bf1ab978SDwayne Grant McConnell 2262c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2263c9101bdbSChristoph Hellwig if (ret) 2264c9101bdbSChristoph Hellwig return ret; 2265bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2266bf1ab978SDwayne Grant McConnell ret = __spufs_proxydma_info_read(ctx, buf, len, pos); 2267b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 226827b1ea09SChristoph Hellwig spu_release_saved(ctx); 2269b9e3bd77SDwayne Grant McConnell 2270b9e3bd77SDwayne Grant McConnell return ret; 2271b9e3bd77SDwayne Grant McConnell } 2272b9e3bd77SDwayne Grant McConnell 22735dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = { 2274b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2275b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 2276b9e3bd77SDwayne Grant McConnell }; 2277b9e3bd77SDwayne Grant McConnell 2278476273adSChristoph Hellwig static int spufs_show_tid(struct seq_file *s, void *private) 2279476273adSChristoph Hellwig { 2280476273adSChristoph Hellwig struct spu_context *ctx = s->private; 2281476273adSChristoph Hellwig 2282476273adSChristoph Hellwig seq_printf(s, "%d\n", ctx->tid); 2283476273adSChristoph Hellwig return 0; 2284476273adSChristoph Hellwig } 2285476273adSChristoph Hellwig 2286476273adSChristoph Hellwig static int spufs_tid_open(struct inode *inode, struct file *file) 2287476273adSChristoph Hellwig { 2288476273adSChristoph Hellwig return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); 2289476273adSChristoph Hellwig } 2290476273adSChristoph Hellwig 2291476273adSChristoph Hellwig static const struct file_operations spufs_tid_fops = { 2292476273adSChristoph Hellwig .open = spufs_tid_open, 2293476273adSChristoph Hellwig .read = seq_read, 2294476273adSChristoph Hellwig .llseek = seq_lseek, 2295476273adSChristoph Hellwig .release = single_release, 2296476273adSChristoph Hellwig }; 2297476273adSChristoph Hellwig 2298e9f8a0b6SChristoph Hellwig static const char *ctx_state_names[] = { 2299e9f8a0b6SChristoph Hellwig "user", "system", "iowait", "loaded" 2300e9f8a0b6SChristoph Hellwig }; 2301e9f8a0b6SChristoph Hellwig 2302e9f8a0b6SChristoph Hellwig static unsigned long long spufs_acct_time(struct spu_context *ctx, 230327ec41d3SAndre Detsch enum spu_utilization_state state) 2304e9f8a0b6SChristoph Hellwig { 230527ec41d3SAndre Detsch struct timespec ts; 230627ec41d3SAndre Detsch unsigned long long time = ctx->stats.times[state]; 2307e9f8a0b6SChristoph Hellwig 230827ec41d3SAndre Detsch /* 230927ec41d3SAndre Detsch * In general, utilization statistics are updated by the controlling 231027ec41d3SAndre Detsch * thread as the spu context moves through various well defined 231127ec41d3SAndre Detsch * state transitions, but if the context is lazily loaded its 231227ec41d3SAndre Detsch * utilization statistics are not updated as the controlling thread 231327ec41d3SAndre Detsch * is not tightly coupled with the execution of the spu context. We 231427ec41d3SAndre Detsch * calculate and apply the time delta from the last recorded state 231527ec41d3SAndre Detsch * of the spu context. 231627ec41d3SAndre Detsch */ 231727ec41d3SAndre Detsch if (ctx->spu && ctx->stats.util_state == state) { 231827ec41d3SAndre Detsch ktime_get_ts(&ts); 231927ec41d3SAndre Detsch time += timespec_to_ns(&ts) - ctx->stats.tstamp; 232027ec41d3SAndre Detsch } 2321e9f8a0b6SChristoph Hellwig 232227ec41d3SAndre Detsch return time / NSEC_PER_MSEC; 2323e9f8a0b6SChristoph Hellwig } 2324e9f8a0b6SChristoph Hellwig 2325e9f8a0b6SChristoph Hellwig static unsigned long long spufs_slb_flts(struct spu_context *ctx) 2326e9f8a0b6SChristoph Hellwig { 2327e9f8a0b6SChristoph Hellwig unsigned long long slb_flts = ctx->stats.slb_flt; 2328e9f8a0b6SChristoph Hellwig 2329e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2330e9f8a0b6SChristoph Hellwig slb_flts += (ctx->spu->stats.slb_flt - 2331e9f8a0b6SChristoph Hellwig ctx->stats.slb_flt_base); 2332e9f8a0b6SChristoph Hellwig } 2333e9f8a0b6SChristoph Hellwig 2334e9f8a0b6SChristoph Hellwig return slb_flts; 2335e9f8a0b6SChristoph Hellwig } 2336e9f8a0b6SChristoph Hellwig 2337e9f8a0b6SChristoph Hellwig static unsigned long long spufs_class2_intrs(struct spu_context *ctx) 2338e9f8a0b6SChristoph Hellwig { 2339e9f8a0b6SChristoph Hellwig unsigned long long class2_intrs = ctx->stats.class2_intr; 2340e9f8a0b6SChristoph Hellwig 2341e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2342e9f8a0b6SChristoph Hellwig class2_intrs += (ctx->spu->stats.class2_intr - 2343e9f8a0b6SChristoph Hellwig ctx->stats.class2_intr_base); 2344e9f8a0b6SChristoph Hellwig } 2345e9f8a0b6SChristoph Hellwig 2346e9f8a0b6SChristoph Hellwig return class2_intrs; 2347e9f8a0b6SChristoph Hellwig } 2348e9f8a0b6SChristoph Hellwig 2349e9f8a0b6SChristoph Hellwig 2350e9f8a0b6SChristoph Hellwig static int spufs_show_stat(struct seq_file *s, void *private) 2351e9f8a0b6SChristoph Hellwig { 2352e9f8a0b6SChristoph Hellwig struct spu_context *ctx = s->private; 2353c9101bdbSChristoph Hellwig int ret; 2354e9f8a0b6SChristoph Hellwig 2355c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 2356c9101bdbSChristoph Hellwig if (ret) 2357c9101bdbSChristoph Hellwig return ret; 2358c9101bdbSChristoph Hellwig 2359e9f8a0b6SChristoph Hellwig seq_printf(s, "%s %llu %llu %llu %llu " 2360e9f8a0b6SChristoph Hellwig "%llu %llu %llu %llu %llu %llu %llu %llu\n", 236127ec41d3SAndre Detsch ctx_state_names[ctx->stats.util_state], 236227ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_USER), 236327ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 236427ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 236527ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 2366e9f8a0b6SChristoph Hellwig ctx->stats.vol_ctx_switch, 2367e9f8a0b6SChristoph Hellwig ctx->stats.invol_ctx_switch, 2368e9f8a0b6SChristoph Hellwig spufs_slb_flts(ctx), 2369e9f8a0b6SChristoph Hellwig ctx->stats.hash_flt, 2370e9f8a0b6SChristoph Hellwig ctx->stats.min_flt, 2371e9f8a0b6SChristoph Hellwig ctx->stats.maj_flt, 2372e9f8a0b6SChristoph Hellwig spufs_class2_intrs(ctx), 2373e9f8a0b6SChristoph Hellwig ctx->stats.libassist); 2374e9f8a0b6SChristoph Hellwig spu_release(ctx); 2375e9f8a0b6SChristoph Hellwig return 0; 2376e9f8a0b6SChristoph Hellwig } 2377e9f8a0b6SChristoph Hellwig 2378e9f8a0b6SChristoph Hellwig static int spufs_stat_open(struct inode *inode, struct file *file) 2379e9f8a0b6SChristoph Hellwig { 2380e9f8a0b6SChristoph Hellwig return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); 2381e9f8a0b6SChristoph Hellwig } 2382e9f8a0b6SChristoph Hellwig 2383e9f8a0b6SChristoph Hellwig static const struct file_operations spufs_stat_fops = { 2384e9f8a0b6SChristoph Hellwig .open = spufs_stat_open, 2385e9f8a0b6SChristoph Hellwig .read = seq_read, 2386e9f8a0b6SChristoph Hellwig .llseek = seq_lseek, 2387e9f8a0b6SChristoph Hellwig .release = single_release, 2388e9f8a0b6SChristoph Hellwig }; 2389e9f8a0b6SChristoph Hellwig 2390e9f8a0b6SChristoph Hellwig 239167207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 2392cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 239367207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 23948b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 239567207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 239667207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 239767207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 239867207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 239967207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 240067207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2401603c4612SJeremy Kerr { "signal1", &spufs_signal1_fops, 0666, }, 2402603c4612SJeremy Kerr { "signal2", &spufs_signal2_fops, 0666, }, 240367207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 240467207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 24056df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 24068b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 2407b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 2408b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 2409b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 2410b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 2411b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 24128b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 24138b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 24148b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 2415b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 241627d5bf2aSBenjamin Herrenschmidt { "psmap", &spufs_psmap_fops, 0666, }, 241786767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 241886767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 241969a2f00cSDwayne Grant McConnell { "mbox_info", &spufs_mbox_info_fops, 0444, }, 242069a2f00cSDwayne Grant McConnell { "ibox_info", &spufs_ibox_info_fops, 0444, }, 242169a2f00cSDwayne Grant McConnell { "wbox_info", &spufs_wbox_info_fops, 0444, }, 2422b9e3bd77SDwayne Grant McConnell { "dma_info", &spufs_dma_info_fops, 0444, }, 2423b9e3bd77SDwayne Grant McConnell { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, 2424476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2425e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 242667207b96SArnd Bergmann {}, 242767207b96SArnd Bergmann }; 24285737edd1SMark Nutter 24295737edd1SMark Nutter struct tree_descr spufs_dir_nosched_contents[] = { 2430cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 24315737edd1SMark Nutter { "mem", &spufs_mem_fops, 0666, }, 24325737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 24335737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 24345737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 24355737edd1SMark Nutter { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 24365737edd1SMark Nutter { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 24375737edd1SMark Nutter { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2438d054b36fSJeremy Kerr { "signal1", &spufs_signal1_nosched_fops, 0222, }, 2439d054b36fSJeremy Kerr { "signal2", &spufs_signal2_nosched_fops, 0222, }, 24405737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 24415737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 24425737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 24435737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 24445737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 24455737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 24465737edd1SMark Nutter { "psmap", &spufs_psmap_fops, 0666, }, 24475737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 24485737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 2449476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2450e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 24515737edd1SMark Nutter {}, 24525737edd1SMark Nutter }; 2453bf1ab978SDwayne Grant McConnell 2454bf1ab978SDwayne Grant McConnell struct spufs_coredump_reader spufs_coredump_read[] = { 24554fca9c42SMichael Ellerman { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, 24564fca9c42SMichael Ellerman { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, 2457104f0cc2SMichael Ellerman { "lslr", NULL, spufs_lslr_get, 19 }, 2458104f0cc2SMichael Ellerman { "decr", NULL, spufs_decr_get, 19 }, 2459104f0cc2SMichael Ellerman { "decr_status", NULL, spufs_decr_status_get, 19 }, 24604fca9c42SMichael Ellerman { "mem", __spufs_mem_read, NULL, LS_SIZE, }, 24614fca9c42SMichael Ellerman { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, 2462104f0cc2SMichael Ellerman { "signal1_type", NULL, spufs_signal1_type_get, 19 }, 24634fca9c42SMichael Ellerman { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, 2464104f0cc2SMichael Ellerman { "signal2_type", NULL, spufs_signal2_type_get, 19 }, 2465104f0cc2SMichael Ellerman { "event_mask", NULL, spufs_event_mask_get, 19 }, 2466104f0cc2SMichael Ellerman { "event_status", NULL, spufs_event_status_get, 19 }, 24674fca9c42SMichael Ellerman { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, 24684fca9c42SMichael Ellerman { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, 24694fca9c42SMichael Ellerman { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, 24704fca9c42SMichael Ellerman { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, 24714fca9c42SMichael Ellerman { "proxydma_info", __spufs_proxydma_info_read, 24724fca9c42SMichael Ellerman NULL, sizeof(struct spu_proxydma_info)}, 2473104f0cc2SMichael Ellerman { "object-id", NULL, spufs_object_id_get, 19 }, 2474104f0cc2SMichael Ellerman { "npc", NULL, spufs_npc_get, 19 }, 2475936d5bf1SMichael Ellerman { NULL }, 2476bf1ab978SDwayne Grant McConnell }; 2477