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 /* 37033bfd7a7SArnd Bergmann * We have to wait for context to be loaded before we have 37133bfd7a7SArnd Bergmann * pages to hand out to the user, but we don't want to wait 37233bfd7a7SArnd Bergmann * with the mmap_sem held. 37333bfd7a7SArnd Bergmann * It is possible to drop the mmap_sem here, but then we need 37433bfd7a7SArnd Bergmann * to return NOPFN_REFAULT because the mappings may have 37533bfd7a7SArnd Bergmann * hanged. 37678bde53eSBenjamin Herrenschmidt */ 377c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 378c9101bdbSChristoph Hellwig return NOPFN_REFAULT; 379c9101bdbSChristoph Hellwig 38033bfd7a7SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 38133bfd7a7SArnd Bergmann up_read(¤t->mm->mmap_sem); 382038200cfSChristoph Hellwig spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx); 383eebead5bSChristoph Hellwig ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 384038200cfSChristoph Hellwig spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu); 38533bfd7a7SArnd Bergmann down_read(¤t->mm->mmap_sem); 386c9101bdbSChristoph Hellwig } else { 3876df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 38878bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); 389038200cfSChristoph Hellwig spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu); 390c9101bdbSChristoph Hellwig } 39133bfd7a7SArnd Bergmann 392eebead5bSChristoph Hellwig if (!ret) 3936df10a82SMark Nutter spu_release(ctx); 39478bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 3956df10a82SMark Nutter } 3966df10a82SMark Nutter 39727d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 39878bde53eSBenjamin Herrenschmidt static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, 39978bde53eSBenjamin Herrenschmidt unsigned long address) 4006df10a82SMark Nutter { 40178bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x4000, 0x1000); 4026df10a82SMark Nutter } 4036df10a82SMark Nutter 4046df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = { 40578bde53eSBenjamin Herrenschmidt .nopfn = spufs_cntl_mmap_nopfn, 4066df10a82SMark Nutter }; 4076df10a82SMark Nutter 4086df10a82SMark Nutter /* 4096df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 4106df10a82SMark Nutter */ 4116df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 4126df10a82SMark Nutter { 4136df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 4146df10a82SMark Nutter return -EINVAL; 4156df10a82SMark Nutter 41678bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 4176df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 41823cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 4196df10a82SMark Nutter 4206df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 4216df10a82SMark Nutter return 0; 4226df10a82SMark Nutter } 42327d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 42427d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 42527d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 4266df10a82SMark Nutter 427197b1a82SChristoph Hellwig static int spufs_cntl_get(void *data, u64 *val) 428e1dbff2bSArnd Bergmann { 429e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 430c9101bdbSChristoph Hellwig int ret; 431e1dbff2bSArnd Bergmann 432c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 433c9101bdbSChristoph Hellwig if (ret) 434c9101bdbSChristoph Hellwig return ret; 435197b1a82SChristoph Hellwig *val = ctx->ops->status_read(ctx); 436e1dbff2bSArnd Bergmann spu_release(ctx); 437e1dbff2bSArnd Bergmann 438197b1a82SChristoph Hellwig return 0; 439e1dbff2bSArnd Bergmann } 440e1dbff2bSArnd Bergmann 441197b1a82SChristoph Hellwig static int spufs_cntl_set(void *data, u64 val) 442e1dbff2bSArnd Bergmann { 443e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 444c9101bdbSChristoph Hellwig int ret; 445e1dbff2bSArnd Bergmann 446c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 447c9101bdbSChristoph Hellwig if (ret) 448c9101bdbSChristoph Hellwig return ret; 449e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 450e1dbff2bSArnd Bergmann spu_release(ctx); 451197b1a82SChristoph Hellwig 452197b1a82SChristoph Hellwig return 0; 453e1dbff2bSArnd Bergmann } 454e1dbff2bSArnd Bergmann 4556df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 4566df10a82SMark Nutter { 4576df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 4586df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 4596df10a82SMark Nutter 46047d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 4616df10a82SMark Nutter file->private_data = ctx; 46243c2bbd9SChristoph Hellwig if (!i->i_openers++) 4636df10a82SMark Nutter ctx->cntl = inode->i_mapping; 46447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 465197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, spufs_cntl_get, 466e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 4676df10a82SMark Nutter } 4686df10a82SMark Nutter 46943c2bbd9SChristoph Hellwig static int 47043c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file) 47143c2bbd9SChristoph Hellwig { 47243c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 47343c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 47443c2bbd9SChristoph Hellwig 475197b1a82SChristoph Hellwig spufs_attr_release(inode, file); 47643c2bbd9SChristoph Hellwig 47747d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 47843c2bbd9SChristoph Hellwig if (!--i->i_openers) 47943c2bbd9SChristoph Hellwig ctx->cntl = NULL; 48047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 48143c2bbd9SChristoph Hellwig return 0; 48243c2bbd9SChristoph Hellwig } 48343c2bbd9SChristoph Hellwig 4845dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = { 4856df10a82SMark Nutter .open = spufs_cntl_open, 48643c2bbd9SChristoph Hellwig .release = spufs_cntl_release, 487197b1a82SChristoph Hellwig .read = spufs_attr_read, 488197b1a82SChristoph Hellwig .write = spufs_attr_write, 4896df10a82SMark Nutter .mmap = spufs_cntl_mmap, 4906df10a82SMark Nutter }; 4916df10a82SMark Nutter 4928b3d6663SArnd Bergmann static int 4938b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 4948b3d6663SArnd Bergmann { 4958b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 4968b3d6663SArnd Bergmann file->private_data = i->i_ctx; 4978b3d6663SArnd Bergmann return 0; 4988b3d6663SArnd Bergmann } 4998b3d6663SArnd Bergmann 5008b3d6663SArnd Bergmann static ssize_t 501bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer, 502bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 503bf1ab978SDwayne Grant McConnell { 504bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 505bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 506bf1ab978SDwayne Grant McConnell lscsa->gprs, sizeof lscsa->gprs); 507bf1ab978SDwayne Grant McConnell } 508bf1ab978SDwayne Grant McConnell 509bf1ab978SDwayne Grant McConnell static ssize_t 5108b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 5118b3d6663SArnd Bergmann size_t size, loff_t *pos) 5128b3d6663SArnd Bergmann { 5138b3d6663SArnd Bergmann int ret; 514bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5158b3d6663SArnd Bergmann 516c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 517c9101bdbSChristoph Hellwig if (ret) 518c9101bdbSChristoph Hellwig return ret; 519bf1ab978SDwayne Grant McConnell ret = __spufs_regs_read(ctx, buffer, size, pos); 52027b1ea09SChristoph Hellwig spu_release_saved(ctx); 5218b3d6663SArnd Bergmann return ret; 5228b3d6663SArnd Bergmann } 5238b3d6663SArnd Bergmann 5248b3d6663SArnd Bergmann static ssize_t 5258b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 5268b3d6663SArnd Bergmann size_t size, loff_t *pos) 5278b3d6663SArnd Bergmann { 5288b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5298b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5308b3d6663SArnd Bergmann int ret; 5318b3d6663SArnd Bergmann 5328b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 5338b3d6663SArnd Bergmann if (size <= 0) 5348b3d6663SArnd Bergmann return -EFBIG; 5358b3d6663SArnd Bergmann *pos += size; 5368b3d6663SArnd Bergmann 537c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 538c9101bdbSChristoph Hellwig if (ret) 539c9101bdbSChristoph Hellwig return ret; 5408b3d6663SArnd Bergmann 5418b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 5428b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 5438b3d6663SArnd Bergmann 54427b1ea09SChristoph Hellwig spu_release_saved(ctx); 5458b3d6663SArnd Bergmann return ret; 5468b3d6663SArnd Bergmann } 5478b3d6663SArnd Bergmann 5485dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = { 5498b3d6663SArnd Bergmann .open = spufs_regs_open, 5508b3d6663SArnd Bergmann .read = spufs_regs_read, 5518b3d6663SArnd Bergmann .write = spufs_regs_write, 5528b3d6663SArnd Bergmann .llseek = generic_file_llseek, 5538b3d6663SArnd Bergmann }; 5548b3d6663SArnd Bergmann 5558b3d6663SArnd Bergmann static ssize_t 556bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, 557bf1ab978SDwayne Grant McConnell size_t size, loff_t * pos) 558bf1ab978SDwayne Grant McConnell { 559bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 560bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 561bf1ab978SDwayne Grant McConnell &lscsa->fpcr, sizeof(lscsa->fpcr)); 562bf1ab978SDwayne Grant McConnell } 563bf1ab978SDwayne Grant McConnell 564bf1ab978SDwayne Grant McConnell static ssize_t 5658b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 5668b3d6663SArnd Bergmann size_t size, loff_t * pos) 5678b3d6663SArnd Bergmann { 5688b3d6663SArnd Bergmann int ret; 569bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5708b3d6663SArnd Bergmann 571c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 572c9101bdbSChristoph Hellwig if (ret) 573c9101bdbSChristoph Hellwig return ret; 574bf1ab978SDwayne Grant McConnell ret = __spufs_fpcr_read(ctx, buffer, size, pos); 57527b1ea09SChristoph Hellwig spu_release_saved(ctx); 5768b3d6663SArnd Bergmann return ret; 5778b3d6663SArnd Bergmann } 5788b3d6663SArnd Bergmann 5798b3d6663SArnd Bergmann static ssize_t 5808b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 5818b3d6663SArnd Bergmann size_t size, loff_t * pos) 5828b3d6663SArnd Bergmann { 5838b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5848b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5858b3d6663SArnd Bergmann int ret; 5868b3d6663SArnd Bergmann 5878b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 5888b3d6663SArnd Bergmann if (size <= 0) 5898b3d6663SArnd Bergmann return -EFBIG; 590c9101bdbSChristoph Hellwig 591c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 592c9101bdbSChristoph Hellwig if (ret) 593c9101bdbSChristoph Hellwig return ret; 594c9101bdbSChristoph Hellwig 5958b3d6663SArnd Bergmann *pos += size; 5968b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 5978b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 5988b3d6663SArnd Bergmann 59927b1ea09SChristoph Hellwig spu_release_saved(ctx); 6008b3d6663SArnd Bergmann return ret; 6018b3d6663SArnd Bergmann } 6028b3d6663SArnd Bergmann 6035dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = { 6048b3d6663SArnd Bergmann .open = spufs_regs_open, 6058b3d6663SArnd Bergmann .read = spufs_fpcr_read, 6068b3d6663SArnd Bergmann .write = spufs_fpcr_write, 60767207b96SArnd Bergmann .llseek = generic_file_llseek, 60867207b96SArnd Bergmann }; 60967207b96SArnd Bergmann 61067207b96SArnd Bergmann /* generic open function for all pipe-like files */ 61167207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 61267207b96SArnd Bergmann { 61367207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 61467207b96SArnd Bergmann file->private_data = i->i_ctx; 61567207b96SArnd Bergmann 61667207b96SArnd Bergmann return nonseekable_open(inode, file); 61767207b96SArnd Bergmann } 61867207b96SArnd Bergmann 619cdcc89bbSArnd Bergmann /* 620cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 621cdcc89bbSArnd Bergmann * one of the conditions becomes true: 622cdcc89bbSArnd Bergmann * 623cdcc89bbSArnd Bergmann * - no more data available in the mailbox 624cdcc89bbSArnd Bergmann * - end of the user provided buffer 625cdcc89bbSArnd Bergmann * - end of the mapped area 626cdcc89bbSArnd Bergmann */ 62767207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 62867207b96SArnd Bergmann size_t len, loff_t *pos) 62967207b96SArnd Bergmann { 6308b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 631cdcc89bbSArnd Bergmann u32 mbox_data, __user *udata; 632cdcc89bbSArnd Bergmann ssize_t count; 63367207b96SArnd Bergmann 63467207b96SArnd Bergmann if (len < 4) 63567207b96SArnd Bergmann return -EINVAL; 63667207b96SArnd Bergmann 637cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 63867207b96SArnd Bergmann return -EFAULT; 63967207b96SArnd Bergmann 640cdcc89bbSArnd Bergmann udata = (void __user *)buf; 641cdcc89bbSArnd Bergmann 642c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 643c9101bdbSChristoph Hellwig if (count) 644c9101bdbSChristoph Hellwig return count; 645c9101bdbSChristoph Hellwig 646274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 647cdcc89bbSArnd Bergmann int ret; 648cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 649cdcc89bbSArnd Bergmann if (ret == 0) 650cdcc89bbSArnd Bergmann break; 651cdcc89bbSArnd Bergmann 652cdcc89bbSArnd Bergmann /* 653cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 654cdcc89bbSArnd Bergmann * but still need to return the data we have 655cdcc89bbSArnd Bergmann * read successfully so far. 656cdcc89bbSArnd Bergmann */ 657cdcc89bbSArnd Bergmann ret = __put_user(mbox_data, udata); 658cdcc89bbSArnd Bergmann if (ret) { 659cdcc89bbSArnd Bergmann if (!count) 660cdcc89bbSArnd Bergmann count = -EFAULT; 661cdcc89bbSArnd Bergmann break; 662cdcc89bbSArnd Bergmann } 663cdcc89bbSArnd Bergmann } 664cdcc89bbSArnd Bergmann spu_release(ctx); 665cdcc89bbSArnd Bergmann 666cdcc89bbSArnd Bergmann if (!count) 667cdcc89bbSArnd Bergmann count = -EAGAIN; 668cdcc89bbSArnd Bergmann 669cdcc89bbSArnd Bergmann return count; 67067207b96SArnd Bergmann } 67167207b96SArnd Bergmann 6725dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = { 67367207b96SArnd Bergmann .open = spufs_pipe_open, 67467207b96SArnd Bergmann .read = spufs_mbox_read, 67567207b96SArnd Bergmann }; 67667207b96SArnd Bergmann 67767207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 67867207b96SArnd Bergmann size_t len, loff_t *pos) 67967207b96SArnd Bergmann { 6808b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 681c9101bdbSChristoph Hellwig ssize_t ret; 68267207b96SArnd Bergmann u32 mbox_stat; 68367207b96SArnd Bergmann 68467207b96SArnd Bergmann if (len < 4) 68567207b96SArnd Bergmann return -EINVAL; 68667207b96SArnd Bergmann 687c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 688c9101bdbSChristoph Hellwig if (ret) 689c9101bdbSChristoph Hellwig return ret; 6908b3d6663SArnd Bergmann 6918b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 6928b3d6663SArnd Bergmann 6938b3d6663SArnd Bergmann spu_release(ctx); 69467207b96SArnd Bergmann 69567207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 69667207b96SArnd Bergmann return -EFAULT; 69767207b96SArnd Bergmann 69867207b96SArnd Bergmann return 4; 69967207b96SArnd Bergmann } 70067207b96SArnd Bergmann 7015dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = { 70267207b96SArnd Bergmann .open = spufs_pipe_open, 70367207b96SArnd Bergmann .read = spufs_mbox_stat_read, 70467207b96SArnd Bergmann }; 70567207b96SArnd Bergmann 70667207b96SArnd Bergmann /* low-level ibox access function */ 7078b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 70867207b96SArnd Bergmann { 7098b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 71067207b96SArnd Bergmann } 71167207b96SArnd Bergmann 71267207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 71367207b96SArnd Bergmann { 7148b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 7158b3d6663SArnd Bergmann 7168b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 7178b3d6663SArnd Bergmann } 7188b3d6663SArnd Bergmann 7198b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 7208b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 7218b3d6663SArnd Bergmann { 7228b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 7238b3d6663SArnd Bergmann 724e65c2f6fSLuke Browning if (!ctx) 725e65c2f6fSLuke Browning return; 726e65c2f6fSLuke Browning 7278b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 7288b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 72967207b96SArnd Bergmann } 73067207b96SArnd Bergmann 731cdcc89bbSArnd Bergmann /* 732cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 733cdcc89bbSArnd Bergmann * one of the conditions becomes true: 734cdcc89bbSArnd Bergmann * 735cdcc89bbSArnd Bergmann * - no more data available in the mailbox 736cdcc89bbSArnd Bergmann * - end of the user provided buffer 737cdcc89bbSArnd Bergmann * - end of the mapped area 738cdcc89bbSArnd Bergmann * 739cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 740cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 741cdcc89bbSArnd Bergmann * read something. 742cdcc89bbSArnd Bergmann */ 74367207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 74467207b96SArnd Bergmann size_t len, loff_t *pos) 74567207b96SArnd Bergmann { 7468b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 747cdcc89bbSArnd Bergmann u32 ibox_data, __user *udata; 748cdcc89bbSArnd Bergmann ssize_t count; 74967207b96SArnd Bergmann 75067207b96SArnd Bergmann if (len < 4) 75167207b96SArnd Bergmann return -EINVAL; 75267207b96SArnd Bergmann 753cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 754cdcc89bbSArnd Bergmann return -EFAULT; 755cdcc89bbSArnd Bergmann 756cdcc89bbSArnd Bergmann udata = (void __user *)buf; 757cdcc89bbSArnd Bergmann 758c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 759c9101bdbSChristoph Hellwig if (count) 760eebead5bSChristoph Hellwig goto out; 76167207b96SArnd Bergmann 762cdcc89bbSArnd Bergmann /* wait only for the first element */ 763cdcc89bbSArnd Bergmann count = 0; 76467207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 765eebead5bSChristoph Hellwig if (!spu_ibox_read(ctx, &ibox_data)) { 766cdcc89bbSArnd Bergmann count = -EAGAIN; 767eebead5bSChristoph Hellwig goto out_unlock; 768eebead5bSChristoph Hellwig } 76967207b96SArnd Bergmann } else { 770cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 771cdcc89bbSArnd Bergmann if (count) 772cdcc89bbSArnd Bergmann goto out; 773eebead5bSChristoph Hellwig } 774cdcc89bbSArnd Bergmann 775cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 776cdcc89bbSArnd Bergmann count = __put_user(ibox_data, udata); 777cdcc89bbSArnd Bergmann if (count) 778eebead5bSChristoph Hellwig goto out_unlock; 779cdcc89bbSArnd Bergmann 780cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 781cdcc89bbSArnd Bergmann int ret; 782cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 783cdcc89bbSArnd Bergmann if (ret == 0) 784cdcc89bbSArnd Bergmann break; 785cdcc89bbSArnd Bergmann /* 786cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 787cdcc89bbSArnd Bergmann * but still need to return the data we have 788cdcc89bbSArnd Bergmann * read successfully so far. 789cdcc89bbSArnd Bergmann */ 790cdcc89bbSArnd Bergmann ret = __put_user(ibox_data, udata); 791cdcc89bbSArnd Bergmann if (ret) 792cdcc89bbSArnd Bergmann break; 79367207b96SArnd Bergmann } 79467207b96SArnd Bergmann 795eebead5bSChristoph Hellwig out_unlock: 7968b3d6663SArnd Bergmann spu_release(ctx); 797eebead5bSChristoph Hellwig out: 798cdcc89bbSArnd Bergmann return count; 79967207b96SArnd Bergmann } 80067207b96SArnd Bergmann 80167207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 80267207b96SArnd Bergmann { 8038b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 80467207b96SArnd Bergmann unsigned int mask; 80567207b96SArnd Bergmann 8068b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 80767207b96SArnd Bergmann 808c9101bdbSChristoph Hellwig /* 809c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 810c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 811c9101bdbSChristoph Hellwig */ 812c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 8133a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 8143a843d7cSArnd Bergmann spu_release(ctx); 81567207b96SArnd Bergmann 81667207b96SArnd Bergmann return mask; 81767207b96SArnd Bergmann } 81867207b96SArnd Bergmann 8195dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = { 82067207b96SArnd Bergmann .open = spufs_pipe_open, 82167207b96SArnd Bergmann .read = spufs_ibox_read, 82267207b96SArnd Bergmann .poll = spufs_ibox_poll, 82367207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 82467207b96SArnd Bergmann }; 82567207b96SArnd Bergmann 82667207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 82767207b96SArnd Bergmann size_t len, loff_t *pos) 82867207b96SArnd Bergmann { 8298b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 830c9101bdbSChristoph Hellwig ssize_t ret; 83167207b96SArnd Bergmann u32 ibox_stat; 83267207b96SArnd Bergmann 83367207b96SArnd Bergmann if (len < 4) 83467207b96SArnd Bergmann return -EINVAL; 83567207b96SArnd Bergmann 836c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 837c9101bdbSChristoph Hellwig if (ret) 838c9101bdbSChristoph Hellwig return ret; 8398b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 8408b3d6663SArnd Bergmann spu_release(ctx); 84167207b96SArnd Bergmann 84267207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 84367207b96SArnd Bergmann return -EFAULT; 84467207b96SArnd Bergmann 84567207b96SArnd Bergmann return 4; 84667207b96SArnd Bergmann } 84767207b96SArnd Bergmann 8485dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = { 84967207b96SArnd Bergmann .open = spufs_pipe_open, 85067207b96SArnd Bergmann .read = spufs_ibox_stat_read, 85167207b96SArnd Bergmann }; 85267207b96SArnd Bergmann 85367207b96SArnd Bergmann /* low-level mailbox write */ 8548b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 85567207b96SArnd Bergmann { 8568b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 85767207b96SArnd Bergmann } 85867207b96SArnd Bergmann 85967207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 86067207b96SArnd Bergmann { 8618b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 8628b3d6663SArnd Bergmann int ret; 8638b3d6663SArnd Bergmann 8648b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 8658b3d6663SArnd Bergmann 8668b3d6663SArnd Bergmann return ret; 8678b3d6663SArnd Bergmann } 8688b3d6663SArnd Bergmann 8698b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 8708b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 8718b3d6663SArnd Bergmann { 8728b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 8738b3d6663SArnd Bergmann 874e65c2f6fSLuke Browning if (!ctx) 875e65c2f6fSLuke Browning return; 876e65c2f6fSLuke Browning 8778b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 8788b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 87967207b96SArnd Bergmann } 88067207b96SArnd Bergmann 881cdcc89bbSArnd Bergmann /* 882cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 883cdcc89bbSArnd Bergmann * one of the conditions becomes true: 884cdcc89bbSArnd Bergmann * 885cdcc89bbSArnd Bergmann * - the mailbox is full 886cdcc89bbSArnd Bergmann * - end of the user provided buffer 887cdcc89bbSArnd Bergmann * - end of the mapped area 888cdcc89bbSArnd Bergmann * 889cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 890cdcc89bbSArnd Bergmann * space is availabyl, but return when we have been able to 891cdcc89bbSArnd Bergmann * write something. 892cdcc89bbSArnd Bergmann */ 89367207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 89467207b96SArnd Bergmann size_t len, loff_t *pos) 89567207b96SArnd Bergmann { 8968b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 897cdcc89bbSArnd Bergmann u32 wbox_data, __user *udata; 898cdcc89bbSArnd Bergmann ssize_t count; 89967207b96SArnd Bergmann 90067207b96SArnd Bergmann if (len < 4) 90167207b96SArnd Bergmann return -EINVAL; 90267207b96SArnd Bergmann 903cdcc89bbSArnd Bergmann udata = (void __user *)buf; 904cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_READ, buf, len)) 905cdcc89bbSArnd Bergmann return -EFAULT; 906cdcc89bbSArnd Bergmann 907cdcc89bbSArnd Bergmann if (__get_user(wbox_data, udata)) 90867207b96SArnd Bergmann return -EFAULT; 90967207b96SArnd Bergmann 910c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 911c9101bdbSChristoph Hellwig if (count) 912eebead5bSChristoph Hellwig goto out; 9138b3d6663SArnd Bergmann 914cdcc89bbSArnd Bergmann /* 915cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 916cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 917cdcc89bbSArnd Bergmann */ 918cdcc89bbSArnd Bergmann count = 0; 91967207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 920eebead5bSChristoph Hellwig if (!spu_wbox_write(ctx, wbox_data)) { 921cdcc89bbSArnd Bergmann count = -EAGAIN; 922eebead5bSChristoph Hellwig goto out_unlock; 923eebead5bSChristoph Hellwig } 92467207b96SArnd Bergmann } else { 925cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 926cdcc89bbSArnd Bergmann if (count) 927cdcc89bbSArnd Bergmann goto out; 928eebead5bSChristoph Hellwig } 929eebead5bSChristoph Hellwig 9308b3d6663SArnd Bergmann 93196de0e25SJan Engelhardt /* write as much as possible */ 932cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 933cdcc89bbSArnd Bergmann int ret; 934cdcc89bbSArnd Bergmann ret = __get_user(wbox_data, udata); 935cdcc89bbSArnd Bergmann if (ret) 936cdcc89bbSArnd Bergmann break; 937cdcc89bbSArnd Bergmann 938cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 939cdcc89bbSArnd Bergmann if (ret == 0) 940cdcc89bbSArnd Bergmann break; 941cdcc89bbSArnd Bergmann } 942cdcc89bbSArnd Bergmann 943eebead5bSChristoph Hellwig out_unlock: 944cdcc89bbSArnd Bergmann spu_release(ctx); 945eebead5bSChristoph Hellwig out: 946cdcc89bbSArnd Bergmann return count; 94767207b96SArnd Bergmann } 94867207b96SArnd Bergmann 94967207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 95067207b96SArnd Bergmann { 9518b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 95267207b96SArnd Bergmann unsigned int mask; 95367207b96SArnd Bergmann 9548b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 95567207b96SArnd Bergmann 956c9101bdbSChristoph Hellwig /* 957c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 958c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 959c9101bdbSChristoph Hellwig */ 960c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 9613a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 9623a843d7cSArnd Bergmann spu_release(ctx); 96367207b96SArnd Bergmann 96467207b96SArnd Bergmann return mask; 96567207b96SArnd Bergmann } 96667207b96SArnd Bergmann 9675dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = { 96867207b96SArnd Bergmann .open = spufs_pipe_open, 96967207b96SArnd Bergmann .write = spufs_wbox_write, 97067207b96SArnd Bergmann .poll = spufs_wbox_poll, 97167207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 97267207b96SArnd Bergmann }; 97367207b96SArnd Bergmann 97467207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 97567207b96SArnd Bergmann size_t len, loff_t *pos) 97667207b96SArnd Bergmann { 9778b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 978c9101bdbSChristoph Hellwig ssize_t ret; 97967207b96SArnd Bergmann u32 wbox_stat; 98067207b96SArnd Bergmann 98167207b96SArnd Bergmann if (len < 4) 98267207b96SArnd Bergmann return -EINVAL; 98367207b96SArnd Bergmann 984c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 985c9101bdbSChristoph Hellwig if (ret) 986c9101bdbSChristoph Hellwig return ret; 9878b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 9888b3d6663SArnd Bergmann spu_release(ctx); 98967207b96SArnd Bergmann 99067207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 99167207b96SArnd Bergmann return -EFAULT; 99267207b96SArnd Bergmann 99367207b96SArnd Bergmann return 4; 99467207b96SArnd Bergmann } 99567207b96SArnd Bergmann 9965dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = { 99767207b96SArnd Bergmann .open = spufs_pipe_open, 99867207b96SArnd Bergmann .read = spufs_wbox_stat_read, 99967207b96SArnd Bergmann }; 100067207b96SArnd Bergmann 10016df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 10026df10a82SMark Nutter { 10036df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 10046df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 100543c2bbd9SChristoph Hellwig 100647d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 10076df10a82SMark Nutter file->private_data = ctx; 100843c2bbd9SChristoph Hellwig if (!i->i_openers++) 10096df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 101047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 10116df10a82SMark Nutter return nonseekable_open(inode, file); 10126df10a82SMark Nutter } 10136df10a82SMark Nutter 101443c2bbd9SChristoph Hellwig static int 101543c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file) 101643c2bbd9SChristoph Hellwig { 101743c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 101843c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 101943c2bbd9SChristoph Hellwig 102047d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 102143c2bbd9SChristoph Hellwig if (!--i->i_openers) 102243c2bbd9SChristoph Hellwig ctx->signal1 = NULL; 102347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 102443c2bbd9SChristoph Hellwig return 0; 102543c2bbd9SChristoph Hellwig } 102643c2bbd9SChristoph Hellwig 1027bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 102867207b96SArnd Bergmann size_t len, loff_t *pos) 102967207b96SArnd Bergmann { 103017f88cebSDwayne Grant McConnell int ret = 0; 103167207b96SArnd Bergmann u32 data; 103267207b96SArnd Bergmann 103367207b96SArnd Bergmann if (len < 4) 103467207b96SArnd Bergmann return -EINVAL; 103567207b96SArnd Bergmann 103617f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[3]) { 103717f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[3]; 103817f88cebSDwayne Grant McConnell ret = 4; 103917f88cebSDwayne Grant McConnell } 10408b3d6663SArnd Bergmann 104117f88cebSDwayne Grant McConnell if (!ret) 104217f88cebSDwayne Grant McConnell goto out; 104317f88cebSDwayne Grant McConnell 104467207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 104567207b96SArnd Bergmann return -EFAULT; 104667207b96SArnd Bergmann 104717f88cebSDwayne Grant McConnell out: 104817f88cebSDwayne Grant McConnell return ret; 104967207b96SArnd Bergmann } 105067207b96SArnd Bergmann 1051bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 1052bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1053bf1ab978SDwayne Grant McConnell { 1054bf1ab978SDwayne Grant McConnell int ret; 1055bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1056bf1ab978SDwayne Grant McConnell 1057c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1058c9101bdbSChristoph Hellwig if (ret) 1059c9101bdbSChristoph Hellwig return ret; 1060bf1ab978SDwayne Grant McConnell ret = __spufs_signal1_read(ctx, buf, len, pos); 106127b1ea09SChristoph Hellwig spu_release_saved(ctx); 1062bf1ab978SDwayne Grant McConnell 1063bf1ab978SDwayne Grant McConnell return ret; 1064bf1ab978SDwayne Grant McConnell } 1065bf1ab978SDwayne Grant McConnell 106667207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 106767207b96SArnd Bergmann size_t len, loff_t *pos) 106867207b96SArnd Bergmann { 106967207b96SArnd Bergmann struct spu_context *ctx; 1070c9101bdbSChristoph Hellwig ssize_t ret; 107167207b96SArnd Bergmann u32 data; 107267207b96SArnd Bergmann 107367207b96SArnd Bergmann ctx = file->private_data; 107467207b96SArnd Bergmann 107567207b96SArnd Bergmann if (len < 4) 107667207b96SArnd Bergmann return -EINVAL; 107767207b96SArnd Bergmann 107867207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 107967207b96SArnd Bergmann return -EFAULT; 108067207b96SArnd Bergmann 1081c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1082c9101bdbSChristoph Hellwig if (ret) 1083c9101bdbSChristoph Hellwig return ret; 10848b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 10858b3d6663SArnd Bergmann spu_release(ctx); 108667207b96SArnd Bergmann 108767207b96SArnd Bergmann return 4; 108867207b96SArnd Bergmann } 108967207b96SArnd Bergmann 109078bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma, 109178bde53eSBenjamin Herrenschmidt unsigned long address) 10926df10a82SMark Nutter { 109327d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 109478bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x14000, 0x1000); 109527d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 109627d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 109727d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 109827d5bf2aSBenjamin Herrenschmidt */ 109978bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 110027d5bf2aSBenjamin Herrenschmidt #else 110127d5bf2aSBenjamin Herrenschmidt #error unsupported page size 110227d5bf2aSBenjamin Herrenschmidt #endif 11036df10a82SMark Nutter } 11046df10a82SMark Nutter 11056df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = { 110678bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal1_mmap_nopfn, 11076df10a82SMark Nutter }; 11086df10a82SMark Nutter 11096df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 11106df10a82SMark Nutter { 11116df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 11126df10a82SMark Nutter return -EINVAL; 11136df10a82SMark Nutter 111478bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 11156df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 111623cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 11176df10a82SMark Nutter 11186df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 11196df10a82SMark Nutter return 0; 11206df10a82SMark Nutter } 11216df10a82SMark Nutter 11225dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = { 11236df10a82SMark Nutter .open = spufs_signal1_open, 112443c2bbd9SChristoph Hellwig .release = spufs_signal1_release, 112567207b96SArnd Bergmann .read = spufs_signal1_read, 112667207b96SArnd Bergmann .write = spufs_signal1_write, 11276df10a82SMark Nutter .mmap = spufs_signal1_mmap, 112867207b96SArnd Bergmann }; 112967207b96SArnd Bergmann 1130d054b36fSJeremy Kerr static const struct file_operations spufs_signal1_nosched_fops = { 1131d054b36fSJeremy Kerr .open = spufs_signal1_open, 1132d054b36fSJeremy Kerr .release = spufs_signal1_release, 1133d054b36fSJeremy Kerr .write = spufs_signal1_write, 1134d054b36fSJeremy Kerr .mmap = spufs_signal1_mmap, 1135d054b36fSJeremy Kerr }; 1136d054b36fSJeremy Kerr 11376df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 11386df10a82SMark Nutter { 11396df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 11406df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 114143c2bbd9SChristoph Hellwig 114247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 11436df10a82SMark Nutter file->private_data = ctx; 114443c2bbd9SChristoph Hellwig if (!i->i_openers++) 11456df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 114647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 11476df10a82SMark Nutter return nonseekable_open(inode, file); 11486df10a82SMark Nutter } 11496df10a82SMark Nutter 115043c2bbd9SChristoph Hellwig static int 115143c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file) 115243c2bbd9SChristoph Hellwig { 115343c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 115443c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 115543c2bbd9SChristoph Hellwig 115647d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 115743c2bbd9SChristoph Hellwig if (!--i->i_openers) 115843c2bbd9SChristoph Hellwig ctx->signal2 = NULL; 115947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 116043c2bbd9SChristoph Hellwig return 0; 116143c2bbd9SChristoph Hellwig } 116243c2bbd9SChristoph Hellwig 1163bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 116467207b96SArnd Bergmann size_t len, loff_t *pos) 116567207b96SArnd Bergmann { 116617f88cebSDwayne Grant McConnell int ret = 0; 116767207b96SArnd Bergmann u32 data; 116867207b96SArnd Bergmann 116967207b96SArnd Bergmann if (len < 4) 117067207b96SArnd Bergmann return -EINVAL; 117167207b96SArnd Bergmann 117217f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[4]) { 117317f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[4]; 117417f88cebSDwayne Grant McConnell ret = 4; 117517f88cebSDwayne Grant McConnell } 11768b3d6663SArnd Bergmann 117717f88cebSDwayne Grant McConnell if (!ret) 117817f88cebSDwayne Grant McConnell goto out; 117917f88cebSDwayne Grant McConnell 118067207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 118167207b96SArnd Bergmann return -EFAULT; 118267207b96SArnd Bergmann 118317f88cebSDwayne Grant McConnell out: 1184bf1ab978SDwayne Grant McConnell return ret; 1185bf1ab978SDwayne Grant McConnell } 1186bf1ab978SDwayne Grant McConnell 1187bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 1188bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1189bf1ab978SDwayne Grant McConnell { 1190bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1191bf1ab978SDwayne Grant McConnell int ret; 1192bf1ab978SDwayne Grant McConnell 1193c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1194c9101bdbSChristoph Hellwig if (ret) 1195c9101bdbSChristoph Hellwig return ret; 1196bf1ab978SDwayne Grant McConnell ret = __spufs_signal2_read(ctx, buf, len, pos); 119727b1ea09SChristoph Hellwig spu_release_saved(ctx); 1198bf1ab978SDwayne Grant McConnell 1199bf1ab978SDwayne Grant McConnell return ret; 120067207b96SArnd Bergmann } 120167207b96SArnd Bergmann 120267207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 120367207b96SArnd Bergmann size_t len, loff_t *pos) 120467207b96SArnd Bergmann { 120567207b96SArnd Bergmann struct spu_context *ctx; 1206c9101bdbSChristoph Hellwig ssize_t ret; 120767207b96SArnd Bergmann u32 data; 120867207b96SArnd Bergmann 120967207b96SArnd Bergmann ctx = file->private_data; 121067207b96SArnd Bergmann 121167207b96SArnd Bergmann if (len < 4) 121267207b96SArnd Bergmann return -EINVAL; 121367207b96SArnd Bergmann 121467207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 121567207b96SArnd Bergmann return -EFAULT; 121667207b96SArnd Bergmann 1217c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1218c9101bdbSChristoph Hellwig if (ret) 1219c9101bdbSChristoph Hellwig return ret; 12208b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 12218b3d6663SArnd Bergmann spu_release(ctx); 122267207b96SArnd Bergmann 122367207b96SArnd Bergmann return 4; 122467207b96SArnd Bergmann } 122567207b96SArnd Bergmann 122627d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 122778bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma, 122878bde53eSBenjamin Herrenschmidt unsigned long address) 12296df10a82SMark Nutter { 123027d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 123178bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000); 123227d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 123327d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 123427d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 123527d5bf2aSBenjamin Herrenschmidt */ 123678bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 123727d5bf2aSBenjamin Herrenschmidt #else 123827d5bf2aSBenjamin Herrenschmidt #error unsupported page size 123927d5bf2aSBenjamin Herrenschmidt #endif 12406df10a82SMark Nutter } 12416df10a82SMark Nutter 12426df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = { 124378bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal2_mmap_nopfn, 12446df10a82SMark Nutter }; 12456df10a82SMark Nutter 12466df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 12476df10a82SMark Nutter { 12486df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 12496df10a82SMark Nutter return -EINVAL; 12506df10a82SMark Nutter 125178bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 12526df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 125323cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 12546df10a82SMark Nutter 12556df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 12566df10a82SMark Nutter return 0; 12576df10a82SMark Nutter } 125827d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 125927d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 126027d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 12616df10a82SMark Nutter 12625dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = { 12636df10a82SMark Nutter .open = spufs_signal2_open, 126443c2bbd9SChristoph Hellwig .release = spufs_signal2_release, 126567207b96SArnd Bergmann .read = spufs_signal2_read, 126667207b96SArnd Bergmann .write = spufs_signal2_write, 12676df10a82SMark Nutter .mmap = spufs_signal2_mmap, 126867207b96SArnd Bergmann }; 126967207b96SArnd Bergmann 1270d054b36fSJeremy Kerr static const struct file_operations spufs_signal2_nosched_fops = { 1271d054b36fSJeremy Kerr .open = spufs_signal2_open, 1272d054b36fSJeremy Kerr .release = spufs_signal2_release, 1273d054b36fSJeremy Kerr .write = spufs_signal2_write, 1274d054b36fSJeremy Kerr .mmap = spufs_signal2_mmap, 1275d054b36fSJeremy Kerr }; 1276d054b36fSJeremy Kerr 1277104f0cc2SMichael Ellerman /* 1278104f0cc2SMichael Ellerman * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the 1279104f0cc2SMichael Ellerman * work of acquiring (or not) the SPU context before calling through 1280104f0cc2SMichael Ellerman * to the actual get routine. The set routine is called directly. 1281104f0cc2SMichael Ellerman */ 1282104f0cc2SMichael Ellerman #define SPU_ATTR_NOACQUIRE 0 1283104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE 1 1284104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE_SAVED 2 1285104f0cc2SMichael Ellerman 1286104f0cc2SMichael Ellerman #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ 1287197b1a82SChristoph Hellwig static int __##__get(void *data, u64 *val) \ 1288104f0cc2SMichael Ellerman { \ 1289104f0cc2SMichael Ellerman struct spu_context *ctx = data; \ 1290c9101bdbSChristoph Hellwig int ret = 0; \ 1291104f0cc2SMichael Ellerman \ 1292104f0cc2SMichael Ellerman if (__acquire == SPU_ATTR_ACQUIRE) { \ 1293c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); \ 1294c9101bdbSChristoph Hellwig if (ret) \ 1295c9101bdbSChristoph Hellwig return ret; \ 1296197b1a82SChristoph Hellwig *val = __get(ctx); \ 1297104f0cc2SMichael Ellerman spu_release(ctx); \ 1298104f0cc2SMichael Ellerman } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ 1299c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); \ 1300c9101bdbSChristoph Hellwig if (ret) \ 1301c9101bdbSChristoph Hellwig return ret; \ 1302197b1a82SChristoph Hellwig *val = __get(ctx); \ 1303104f0cc2SMichael Ellerman spu_release_saved(ctx); \ 1304104f0cc2SMichael Ellerman } else \ 1305197b1a82SChristoph Hellwig *val = __get(ctx); \ 1306104f0cc2SMichael Ellerman \ 1307197b1a82SChristoph Hellwig return 0; \ 1308104f0cc2SMichael Ellerman } \ 1309197b1a82SChristoph Hellwig DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); 1310104f0cc2SMichael Ellerman 1311197b1a82SChristoph Hellwig static int spufs_signal1_type_set(void *data, u64 val) 131267207b96SArnd Bergmann { 131367207b96SArnd Bergmann struct spu_context *ctx = data; 1314c9101bdbSChristoph Hellwig int ret; 131567207b96SArnd Bergmann 1316c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1317c9101bdbSChristoph Hellwig if (ret) 1318c9101bdbSChristoph Hellwig return ret; 13198b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 13208b3d6663SArnd Bergmann spu_release(ctx); 1321197b1a82SChristoph Hellwig 1322197b1a82SChristoph Hellwig return 0; 132367207b96SArnd Bergmann } 132467207b96SArnd Bergmann 1325104f0cc2SMichael Ellerman static u64 spufs_signal1_type_get(struct spu_context *ctx) 1326bf1ab978SDwayne Grant McConnell { 1327bf1ab978SDwayne Grant McConnell return ctx->ops->signal1_type_get(ctx); 1328bf1ab978SDwayne Grant McConnell } 1329104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 1330104f0cc2SMichael Ellerman spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); 1331bf1ab978SDwayne Grant McConnell 133267207b96SArnd Bergmann 1333197b1a82SChristoph Hellwig static int spufs_signal2_type_set(void *data, u64 val) 133467207b96SArnd Bergmann { 133567207b96SArnd Bergmann struct spu_context *ctx = data; 1336c9101bdbSChristoph Hellwig int ret; 133767207b96SArnd Bergmann 1338c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1339c9101bdbSChristoph Hellwig if (ret) 1340c9101bdbSChristoph Hellwig return ret; 13418b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 13428b3d6663SArnd Bergmann spu_release(ctx); 1343197b1a82SChristoph Hellwig 1344197b1a82SChristoph Hellwig return 0; 134567207b96SArnd Bergmann } 134667207b96SArnd Bergmann 1347104f0cc2SMichael Ellerman static u64 spufs_signal2_type_get(struct spu_context *ctx) 1348bf1ab978SDwayne Grant McConnell { 1349bf1ab978SDwayne Grant McConnell return ctx->ops->signal2_type_get(ctx); 1350bf1ab978SDwayne Grant McConnell } 1351104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 1352104f0cc2SMichael Ellerman spufs_signal2_type_set, "%llu", SPU_ATTR_ACQUIRE); 135367207b96SArnd Bergmann 135427d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 135578bde53eSBenjamin Herrenschmidt static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, 135678bde53eSBenjamin Herrenschmidt unsigned long address) 1357d9379c4bSarnd@arndb.de { 135878bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x1000); 1359d9379c4bSarnd@arndb.de } 1360d9379c4bSarnd@arndb.de 1361d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = { 136278bde53eSBenjamin Herrenschmidt .nopfn = spufs_mss_mmap_nopfn, 1363d9379c4bSarnd@arndb.de }; 1364d9379c4bSarnd@arndb.de 1365d9379c4bSarnd@arndb.de /* 1366d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 1367d9379c4bSarnd@arndb.de */ 1368d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 1369d9379c4bSarnd@arndb.de { 1370d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 1371d9379c4bSarnd@arndb.de return -EINVAL; 1372d9379c4bSarnd@arndb.de 137378bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 1374d9379c4bSarnd@arndb.de vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 137523cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 1376d9379c4bSarnd@arndb.de 1377d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 1378d9379c4bSarnd@arndb.de return 0; 1379d9379c4bSarnd@arndb.de } 138027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 138127d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 138227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1383d9379c4bSarnd@arndb.de 1384d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 1385d9379c4bSarnd@arndb.de { 1386d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 138717e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 1388d9379c4bSarnd@arndb.de 1389d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 139043c2bbd9SChristoph Hellwig 139147d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 139243c2bbd9SChristoph Hellwig if (!i->i_openers++) 139317e0e270SBenjamin Herrenschmidt ctx->mss = inode->i_mapping; 139447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1395d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 1396d9379c4bSarnd@arndb.de } 1397d9379c4bSarnd@arndb.de 139843c2bbd9SChristoph Hellwig static int 139943c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file) 140043c2bbd9SChristoph Hellwig { 140143c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 140243c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 140343c2bbd9SChristoph Hellwig 140447d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 140543c2bbd9SChristoph Hellwig if (!--i->i_openers) 140643c2bbd9SChristoph Hellwig ctx->mss = NULL; 140747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 140843c2bbd9SChristoph Hellwig return 0; 140943c2bbd9SChristoph Hellwig } 141043c2bbd9SChristoph Hellwig 14115dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = { 1412d9379c4bSarnd@arndb.de .open = spufs_mss_open, 141343c2bbd9SChristoph Hellwig .release = spufs_mss_release, 1414d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 141527d5bf2aSBenjamin Herrenschmidt }; 141627d5bf2aSBenjamin Herrenschmidt 141778bde53eSBenjamin Herrenschmidt static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma, 141878bde53eSBenjamin Herrenschmidt unsigned long address) 141927d5bf2aSBenjamin Herrenschmidt { 142078bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x20000); 142127d5bf2aSBenjamin Herrenschmidt } 142227d5bf2aSBenjamin Herrenschmidt 142327d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = { 142478bde53eSBenjamin Herrenschmidt .nopfn = spufs_psmap_mmap_nopfn, 142527d5bf2aSBenjamin Herrenschmidt }; 142627d5bf2aSBenjamin Herrenschmidt 142727d5bf2aSBenjamin Herrenschmidt /* 142827d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 142927d5bf2aSBenjamin Herrenschmidt */ 143027d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 143127d5bf2aSBenjamin Herrenschmidt { 143227d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 143327d5bf2aSBenjamin Herrenschmidt return -EINVAL; 143427d5bf2aSBenjamin Herrenschmidt 143578bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 143627d5bf2aSBenjamin Herrenschmidt vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 143727d5bf2aSBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 143827d5bf2aSBenjamin Herrenschmidt 143927d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 144027d5bf2aSBenjamin Herrenschmidt return 0; 144127d5bf2aSBenjamin Herrenschmidt } 144227d5bf2aSBenjamin Herrenschmidt 144327d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 144427d5bf2aSBenjamin Herrenschmidt { 144527d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 144617e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 144727d5bf2aSBenjamin Herrenschmidt 144847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 144927d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 145043c2bbd9SChristoph Hellwig if (!i->i_openers++) 145117e0e270SBenjamin Herrenschmidt ctx->psmap = inode->i_mapping; 145247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 145327d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 145427d5bf2aSBenjamin Herrenschmidt } 145527d5bf2aSBenjamin Herrenschmidt 145643c2bbd9SChristoph Hellwig static int 145743c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file) 145843c2bbd9SChristoph Hellwig { 145943c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 146043c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 146143c2bbd9SChristoph Hellwig 146247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 146343c2bbd9SChristoph Hellwig if (!--i->i_openers) 146443c2bbd9SChristoph Hellwig ctx->psmap = NULL; 146547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 146643c2bbd9SChristoph Hellwig return 0; 146743c2bbd9SChristoph Hellwig } 146843c2bbd9SChristoph Hellwig 14695dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = { 147027d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 147143c2bbd9SChristoph Hellwig .release = spufs_psmap_release, 147227d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1473d9379c4bSarnd@arndb.de }; 1474d9379c4bSarnd@arndb.de 1475d9379c4bSarnd@arndb.de 147627d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 147778bde53eSBenjamin Herrenschmidt static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma, 147878bde53eSBenjamin Herrenschmidt unsigned long address) 14796df10a82SMark Nutter { 148078bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x3000, 0x1000); 14816df10a82SMark Nutter } 14826df10a82SMark Nutter 14836df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = { 148478bde53eSBenjamin Herrenschmidt .nopfn = spufs_mfc_mmap_nopfn, 14856df10a82SMark Nutter }; 14866df10a82SMark Nutter 14876df10a82SMark Nutter /* 14886df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 14896df10a82SMark Nutter */ 14906df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 14916df10a82SMark Nutter { 14926df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 14936df10a82SMark Nutter return -EINVAL; 14946df10a82SMark Nutter 149578bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 14966df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 149723cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 14986df10a82SMark Nutter 14996df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 15006df10a82SMark Nutter return 0; 15016df10a82SMark Nutter } 150227d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 150327d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 150427d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1505a33a7d73SArnd Bergmann 1506a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1507a33a7d73SArnd Bergmann { 1508a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1509a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1510a33a7d73SArnd Bergmann 1511a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1512a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1513a33a7d73SArnd Bergmann return -EINVAL; 1514a33a7d73SArnd Bergmann 1515a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1516a33a7d73SArnd Bergmann return -EBUSY; 1517a33a7d73SArnd Bergmann 151847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1519a33a7d73SArnd Bergmann file->private_data = ctx; 152043c2bbd9SChristoph Hellwig if (!i->i_openers++) 152117e0e270SBenjamin Herrenschmidt ctx->mfc = inode->i_mapping; 152247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1523a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1524a33a7d73SArnd Bergmann } 1525a33a7d73SArnd Bergmann 152643c2bbd9SChristoph Hellwig static int 152743c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file) 152843c2bbd9SChristoph Hellwig { 152943c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 153043c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 153143c2bbd9SChristoph Hellwig 153247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 153343c2bbd9SChristoph Hellwig if (!--i->i_openers) 153443c2bbd9SChristoph Hellwig ctx->mfc = NULL; 153547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 153643c2bbd9SChristoph Hellwig return 0; 153743c2bbd9SChristoph Hellwig } 153843c2bbd9SChristoph Hellwig 1539a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1540a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1541a33a7d73SArnd Bergmann { 1542a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1543a33a7d73SArnd Bergmann 1544e65c2f6fSLuke Browning if (!ctx) 1545e65c2f6fSLuke Browning return; 1546e65c2f6fSLuke Browning 1547a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1548a33a7d73SArnd Bergmann 1549a33a7d73SArnd Bergmann pr_debug("%s %s\n", __FUNCTION__, spu->name); 1550a33a7d73SArnd Bergmann if (ctx->mfc_fasync) { 1551a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1552a33a7d73SArnd Bergmann unsigned int mask; 1553a33a7d73SArnd Bergmann 1554a33a7d73SArnd Bergmann /* no need for spu_acquire in interrupt context */ 1555a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1556a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1557a33a7d73SArnd Bergmann 1558a33a7d73SArnd Bergmann mask = 0; 1559a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1560a33a7d73SArnd Bergmann mask |= POLLOUT; 1561a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1562a33a7d73SArnd Bergmann mask |= POLLIN; 1563a33a7d73SArnd Bergmann 1564a33a7d73SArnd Bergmann kill_fasync(&ctx->mfc_fasync, SIGIO, mask); 1565a33a7d73SArnd Bergmann } 1566a33a7d73SArnd Bergmann } 1567a33a7d73SArnd Bergmann 1568a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1569a33a7d73SArnd Bergmann { 1570a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1571a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1572a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1573a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1574a33a7d73SArnd Bergmann if (*status) 1575a33a7d73SArnd Bergmann return 1; 1576a33a7d73SArnd Bergmann 1577a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1578a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1579a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1580a33a7d73SArnd Bergmann return 0; 1581a33a7d73SArnd Bergmann } 1582a33a7d73SArnd Bergmann 1583a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1584a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1585a33a7d73SArnd Bergmann { 1586a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1587a33a7d73SArnd Bergmann int ret = -EINVAL; 1588a33a7d73SArnd Bergmann u32 status; 1589a33a7d73SArnd Bergmann 1590a33a7d73SArnd Bergmann if (size != 4) 1591a33a7d73SArnd Bergmann goto out; 1592a33a7d73SArnd Bergmann 1593c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1594c9101bdbSChristoph Hellwig if (ret) 1595c9101bdbSChristoph Hellwig return ret; 1596c9101bdbSChristoph Hellwig 1597c9101bdbSChristoph Hellwig ret = -EINVAL; 1598a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1599a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1600a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1601a33a7d73SArnd Bergmann ret = -EAGAIN; 1602a33a7d73SArnd Bergmann else 1603c9101bdbSChristoph Hellwig /* XXX(hch): shouldn't we clear ret here? */ 1604a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1605a33a7d73SArnd Bergmann } else { 1606a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1607a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1608a33a7d73SArnd Bergmann if (ret) 1609a33a7d73SArnd Bergmann goto out; 1610eebead5bSChristoph Hellwig } 1611eebead5bSChristoph Hellwig spu_release(ctx); 1612a33a7d73SArnd Bergmann 1613a33a7d73SArnd Bergmann ret = 4; 1614a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1615a33a7d73SArnd Bergmann ret = -EFAULT; 1616a33a7d73SArnd Bergmann 1617a33a7d73SArnd Bergmann out: 1618a33a7d73SArnd Bergmann return ret; 1619a33a7d73SArnd Bergmann } 1620a33a7d73SArnd Bergmann 1621a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1622a33a7d73SArnd Bergmann { 1623a33a7d73SArnd Bergmann pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, 1624a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1625a33a7d73SArnd Bergmann 1626a33a7d73SArnd Bergmann switch (cmd->cmd) { 1627a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1628a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1629a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1630a33a7d73SArnd Bergmann case MFC_GET_CMD: 1631a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1632a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1633a33a7d73SArnd Bergmann break; 1634a33a7d73SArnd Bergmann default: 1635a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1636a33a7d73SArnd Bergmann return -EIO; 1637a33a7d73SArnd Bergmann } 1638a33a7d73SArnd Bergmann 1639a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 1640a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment, ea %lx lsa %x\n", 1641a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1642a33a7d73SArnd Bergmann return -EIO; 1643a33a7d73SArnd Bergmann } 1644a33a7d73SArnd Bergmann 1645a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1646a33a7d73SArnd Bergmann case 1: 1647a33a7d73SArnd Bergmann break; 1648a33a7d73SArnd Bergmann case 2: 1649a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1650a33a7d73SArnd Bergmann goto error; 1651a33a7d73SArnd Bergmann break; 1652a33a7d73SArnd Bergmann case 4: 1653a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1654a33a7d73SArnd Bergmann goto error; 1655a33a7d73SArnd Bergmann break; 1656a33a7d73SArnd Bergmann case 8: 1657a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1658a33a7d73SArnd Bergmann goto error; 1659a33a7d73SArnd Bergmann break; 1660a33a7d73SArnd Bergmann case 0: 1661a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1662a33a7d73SArnd Bergmann goto error; 1663a33a7d73SArnd Bergmann break; 1664a33a7d73SArnd Bergmann error: 1665a33a7d73SArnd Bergmann default: 1666a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1667a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1668a33a7d73SArnd Bergmann return -EIO; 1669a33a7d73SArnd Bergmann } 1670a33a7d73SArnd Bergmann 1671a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1672a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1673a33a7d73SArnd Bergmann return -EIO; 1674a33a7d73SArnd Bergmann } 1675a33a7d73SArnd Bergmann 1676a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1677a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1678a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1679a33a7d73SArnd Bergmann return -EIO; 1680a33a7d73SArnd Bergmann } 1681a33a7d73SArnd Bergmann 1682a33a7d73SArnd Bergmann if (cmd->class) { 1683a33a7d73SArnd Bergmann /* not supported in this version */ 1684a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1685a33a7d73SArnd Bergmann return -EIO; 1686a33a7d73SArnd Bergmann } 1687a33a7d73SArnd Bergmann 1688a33a7d73SArnd Bergmann return 0; 1689a33a7d73SArnd Bergmann } 1690a33a7d73SArnd Bergmann 1691a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1692a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1693a33a7d73SArnd Bergmann int *error) 1694a33a7d73SArnd Bergmann { 1695a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1696a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1697a33a7d73SArnd Bergmann /* wait for any tag group to complete 1698a33a7d73SArnd Bergmann so we have space for the new command */ 1699a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1700a33a7d73SArnd Bergmann /* try again, because the queue might be 1701a33a7d73SArnd Bergmann empty again */ 1702a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1703a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1704a33a7d73SArnd Bergmann return 0; 1705a33a7d73SArnd Bergmann } 1706a33a7d73SArnd Bergmann return 1; 1707a33a7d73SArnd Bergmann } 1708a33a7d73SArnd Bergmann 1709a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1710a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1711a33a7d73SArnd Bergmann { 1712a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1713a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1714a33a7d73SArnd Bergmann int ret = -EINVAL; 1715a33a7d73SArnd Bergmann 1716a33a7d73SArnd Bergmann if (size != sizeof cmd) 1717a33a7d73SArnd Bergmann goto out; 1718a33a7d73SArnd Bergmann 1719a33a7d73SArnd Bergmann ret = -EFAULT; 1720a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1721a33a7d73SArnd Bergmann goto out; 1722a33a7d73SArnd Bergmann 1723a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1724a33a7d73SArnd Bergmann if (ret) 1725a33a7d73SArnd Bergmann goto out; 1726a33a7d73SArnd Bergmann 1727c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1728c9101bdbSChristoph Hellwig if (ret) 1729c9101bdbSChristoph Hellwig goto out; 1730c9101bdbSChristoph Hellwig 173133bfd7a7SArnd Bergmann ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 1732577f8f10SAkinobu Mita if (ret) 1733577f8f10SAkinobu Mita goto out; 1734577f8f10SAkinobu Mita 1735a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1736a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1737a33a7d73SArnd Bergmann } else { 1738a33a7d73SArnd Bergmann int status; 1739a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1740a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1741eebead5bSChristoph Hellwig if (ret) 1742eebead5bSChristoph Hellwig goto out; 1743a33a7d73SArnd Bergmann if (status) 1744a33a7d73SArnd Bergmann ret = status; 1745a33a7d73SArnd Bergmann } 1746a33a7d73SArnd Bergmann 1747a33a7d73SArnd Bergmann if (ret) 1748933b0e35SKazunori Asayama goto out_unlock; 1749a33a7d73SArnd Bergmann 1750a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 17513692dc66SMasato Noguchi ret = size; 1752a33a7d73SArnd Bergmann 1753933b0e35SKazunori Asayama out_unlock: 1754933b0e35SKazunori Asayama spu_release(ctx); 1755a33a7d73SArnd Bergmann out: 1756a33a7d73SArnd Bergmann return ret; 1757a33a7d73SArnd Bergmann } 1758a33a7d73SArnd Bergmann 1759a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) 1760a33a7d73SArnd Bergmann { 1761a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1762a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1763a33a7d73SArnd Bergmann unsigned int mask; 1764a33a7d73SArnd Bergmann 1765933b0e35SKazunori Asayama poll_wait(file, &ctx->mfc_wq, wait); 1766933b0e35SKazunori Asayama 1767c9101bdbSChristoph Hellwig /* 1768c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 1769c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 1770c9101bdbSChristoph Hellwig */ 1771c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 1772a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1773a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1774a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1775a33a7d73SArnd Bergmann spu_release(ctx); 1776a33a7d73SArnd Bergmann 1777a33a7d73SArnd Bergmann mask = 0; 1778a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1779a33a7d73SArnd Bergmann mask |= POLLOUT | POLLWRNORM; 1780a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1781a33a7d73SArnd Bergmann mask |= POLLIN | POLLRDNORM; 1782a33a7d73SArnd Bergmann 1783a33a7d73SArnd Bergmann pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, 1784a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1785a33a7d73SArnd Bergmann 1786a33a7d73SArnd Bergmann return mask; 1787a33a7d73SArnd Bergmann } 1788a33a7d73SArnd Bergmann 178973b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1790a33a7d73SArnd Bergmann { 1791a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1792a33a7d73SArnd Bergmann int ret; 1793a33a7d73SArnd Bergmann 1794c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1795c9101bdbSChristoph Hellwig if (ret) 1796eebead5bSChristoph Hellwig goto out; 1797a33a7d73SArnd Bergmann #if 0 1798a33a7d73SArnd Bergmann /* this currently hangs */ 1799a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1800a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1801a33a7d73SArnd Bergmann if (ret) 1802a33a7d73SArnd Bergmann goto out; 1803a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1804a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1805eebead5bSChristoph Hellwig if (ret) 1806eebead5bSChristoph Hellwig goto out; 1807a33a7d73SArnd Bergmann #else 1808a33a7d73SArnd Bergmann ret = 0; 1809a33a7d73SArnd Bergmann #endif 1810a33a7d73SArnd Bergmann spu_release(ctx); 1811eebead5bSChristoph Hellwig out: 1812a33a7d73SArnd Bergmann return ret; 1813a33a7d73SArnd Bergmann } 1814a33a7d73SArnd Bergmann 1815a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, 1816a33a7d73SArnd Bergmann int datasync) 1817a33a7d73SArnd Bergmann { 181873b6af8aSAl Viro return spufs_mfc_flush(file, NULL); 1819a33a7d73SArnd Bergmann } 1820a33a7d73SArnd Bergmann 1821a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on) 1822a33a7d73SArnd Bergmann { 1823a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1824a33a7d73SArnd Bergmann 1825a33a7d73SArnd Bergmann return fasync_helper(fd, file, on, &ctx->mfc_fasync); 1826a33a7d73SArnd Bergmann } 1827a33a7d73SArnd Bergmann 18285dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = { 1829a33a7d73SArnd Bergmann .open = spufs_mfc_open, 183043c2bbd9SChristoph Hellwig .release = spufs_mfc_release, 1831a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1832a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1833a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1834a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1835a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 1836a33a7d73SArnd Bergmann .fasync = spufs_mfc_fasync, 18376df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1838a33a7d73SArnd Bergmann }; 1839a33a7d73SArnd Bergmann 1840197b1a82SChristoph Hellwig static int spufs_npc_set(void *data, u64 val) 184167207b96SArnd Bergmann { 184267207b96SArnd Bergmann struct spu_context *ctx = data; 1843c9101bdbSChristoph Hellwig int ret; 1844c9101bdbSChristoph Hellwig 1845c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1846c9101bdbSChristoph Hellwig if (ret) 1847c9101bdbSChristoph Hellwig return ret; 18488b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 18498b3d6663SArnd Bergmann spu_release(ctx); 1850197b1a82SChristoph Hellwig 1851197b1a82SChristoph Hellwig return 0; 185267207b96SArnd Bergmann } 185367207b96SArnd Bergmann 1854104f0cc2SMichael Ellerman static u64 spufs_npc_get(struct spu_context *ctx) 185578810ff6SMichael Ellerman { 185678810ff6SMichael Ellerman return ctx->ops->npc_read(ctx); 185778810ff6SMichael Ellerman } 1858104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 1859104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE); 186067207b96SArnd Bergmann 1861197b1a82SChristoph Hellwig static int spufs_decr_set(void *data, u64 val) 18628b3d6663SArnd Bergmann { 18638b3d6663SArnd Bergmann struct spu_context *ctx = data; 18648b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1865c9101bdbSChristoph Hellwig int ret; 1866c9101bdbSChristoph Hellwig 1867c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1868c9101bdbSChristoph Hellwig if (ret) 1869c9101bdbSChristoph Hellwig return ret; 18708b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 187127b1ea09SChristoph Hellwig spu_release_saved(ctx); 1872197b1a82SChristoph Hellwig 1873197b1a82SChristoph Hellwig return 0; 18748b3d6663SArnd Bergmann } 18758b3d6663SArnd Bergmann 1876104f0cc2SMichael Ellerman static u64 spufs_decr_get(struct spu_context *ctx) 18778b3d6663SArnd Bergmann { 18788b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1879bf1ab978SDwayne Grant McConnell return lscsa->decr.slot[0]; 1880bf1ab978SDwayne Grant McConnell } 1881104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 1882104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); 18838b3d6663SArnd Bergmann 1884197b1a82SChristoph Hellwig static int spufs_decr_status_set(void *data, u64 val) 18858b3d6663SArnd Bergmann { 18868b3d6663SArnd Bergmann struct spu_context *ctx = data; 1887c9101bdbSChristoph Hellwig int ret; 1888c9101bdbSChristoph Hellwig 1889c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1890c9101bdbSChristoph Hellwig if (ret) 1891c9101bdbSChristoph Hellwig return ret; 1892d40a01d4SMasato Noguchi if (val) 1893d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 1894d40a01d4SMasato Noguchi else 1895d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 189627b1ea09SChristoph Hellwig spu_release_saved(ctx); 1897197b1a82SChristoph Hellwig 1898197b1a82SChristoph Hellwig return 0; 18998b3d6663SArnd Bergmann } 19008b3d6663SArnd Bergmann 1901104f0cc2SMichael Ellerman static u64 spufs_decr_status_get(struct spu_context *ctx) 19028b3d6663SArnd Bergmann { 1903d40a01d4SMasato Noguchi if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 1904d40a01d4SMasato Noguchi return SPU_DECR_STATUS_RUNNING; 1905d40a01d4SMasato Noguchi else 1906d40a01d4SMasato Noguchi return 0; 1907bf1ab978SDwayne Grant McConnell } 1908104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 1909104f0cc2SMichael Ellerman spufs_decr_status_set, "0x%llx\n", 1910104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 19118b3d6663SArnd Bergmann 1912197b1a82SChristoph Hellwig static int spufs_event_mask_set(void *data, u64 val) 19138b3d6663SArnd Bergmann { 19148b3d6663SArnd Bergmann struct spu_context *ctx = data; 19158b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1916c9101bdbSChristoph Hellwig int ret; 1917c9101bdbSChristoph Hellwig 1918c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1919c9101bdbSChristoph Hellwig if (ret) 1920c9101bdbSChristoph Hellwig return ret; 19218b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 192227b1ea09SChristoph Hellwig spu_release_saved(ctx); 1923197b1a82SChristoph Hellwig 1924197b1a82SChristoph Hellwig return 0; 19258b3d6663SArnd Bergmann } 19268b3d6663SArnd Bergmann 1927104f0cc2SMichael Ellerman static u64 spufs_event_mask_get(struct spu_context *ctx) 19288b3d6663SArnd Bergmann { 19298b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1930bf1ab978SDwayne Grant McConnell return lscsa->event_mask.slot[0]; 1931bf1ab978SDwayne Grant McConnell } 1932bf1ab978SDwayne Grant McConnell 1933104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 1934104f0cc2SMichael Ellerman spufs_event_mask_set, "0x%llx\n", 1935104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 19368b3d6663SArnd Bergmann 1937104f0cc2SMichael Ellerman static u64 spufs_event_status_get(struct spu_context *ctx) 1938b9e3bd77SDwayne Grant McConnell { 1939b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1940b9e3bd77SDwayne Grant McConnell u64 stat; 1941b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1942b9e3bd77SDwayne Grant McConnell if (stat) 1943bf1ab978SDwayne Grant McConnell return state->spu_chnldata_RW[0]; 1944bf1ab978SDwayne Grant McConnell return 0; 1945bf1ab978SDwayne Grant McConnell } 1946104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1947104f0cc2SMichael Ellerman NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 1948b9e3bd77SDwayne Grant McConnell 1949197b1a82SChristoph Hellwig static int spufs_srr0_set(void *data, u64 val) 19508b3d6663SArnd Bergmann { 19518b3d6663SArnd Bergmann struct spu_context *ctx = data; 19528b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1953c9101bdbSChristoph Hellwig int ret; 1954c9101bdbSChristoph Hellwig 1955c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1956c9101bdbSChristoph Hellwig if (ret) 1957c9101bdbSChristoph Hellwig return ret; 19588b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 195927b1ea09SChristoph Hellwig spu_release_saved(ctx); 1960197b1a82SChristoph Hellwig 1961197b1a82SChristoph Hellwig return 0; 19628b3d6663SArnd Bergmann } 19638b3d6663SArnd Bergmann 1964104f0cc2SMichael Ellerman static u64 spufs_srr0_get(struct spu_context *ctx) 19658b3d6663SArnd Bergmann { 19668b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1967104f0cc2SMichael Ellerman return lscsa->srr0.slot[0]; 19688b3d6663SArnd Bergmann } 1969104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 1970104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 19718b3d6663SArnd Bergmann 1972104f0cc2SMichael Ellerman static u64 spufs_id_get(struct spu_context *ctx) 19737b1a7014Sarnd@arndb.de { 19747b1a7014Sarnd@arndb.de u64 num; 19757b1a7014Sarnd@arndb.de 19767b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 19777b1a7014Sarnd@arndb.de num = ctx->spu->number; 19787b1a7014Sarnd@arndb.de else 19797b1a7014Sarnd@arndb.de num = (unsigned int)-1; 19807b1a7014Sarnd@arndb.de 19817b1a7014Sarnd@arndb.de return num; 19827b1a7014Sarnd@arndb.de } 1983104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", 1984104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE) 19857b1a7014Sarnd@arndb.de 1986104f0cc2SMichael Ellerman static u64 spufs_object_id_get(struct spu_context *ctx) 1987bf1ab978SDwayne Grant McConnell { 1988bf1ab978SDwayne Grant McConnell /* FIXME: Should there really be no locking here? */ 1989104f0cc2SMichael Ellerman return ctx->object_id; 1990bf1ab978SDwayne Grant McConnell } 1991bf1ab978SDwayne Grant McConnell 1992197b1a82SChristoph Hellwig static int spufs_object_id_set(void *data, u64 id) 199386767277SArnd Bergmann { 199486767277SArnd Bergmann struct spu_context *ctx = data; 199586767277SArnd Bergmann ctx->object_id = id; 1996197b1a82SChristoph Hellwig 1997197b1a82SChristoph Hellwig return 0; 199886767277SArnd Bergmann } 199986767277SArnd Bergmann 2000104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 2001104f0cc2SMichael Ellerman spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); 200286767277SArnd Bergmann 2003104f0cc2SMichael Ellerman static u64 spufs_lslr_get(struct spu_context *ctx) 2004bf1ab978SDwayne Grant McConnell { 2005bf1ab978SDwayne Grant McConnell return ctx->csa.priv2.spu_lslr_RW; 2006bf1ab978SDwayne Grant McConnell } 2007104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", 2008104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 2009b9e3bd77SDwayne Grant McConnell 2010b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 2011b9e3bd77SDwayne Grant McConnell { 2012b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 2013b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 2014b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 2015b9e3bd77SDwayne Grant McConnell return 0; 2016b9e3bd77SDwayne Grant McConnell } 2017b9e3bd77SDwayne Grant McConnell 2018cbe709c1SBenjamin Herrenschmidt static int spufs_caps_show(struct seq_file *s, void *private) 2019cbe709c1SBenjamin Herrenschmidt { 2020cbe709c1SBenjamin Herrenschmidt struct spu_context *ctx = s->private; 2021cbe709c1SBenjamin Herrenschmidt 2022cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_NOSCHED)) 2023cbe709c1SBenjamin Herrenschmidt seq_puts(s, "sched\n"); 2024cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_ISOLATE)) 2025cbe709c1SBenjamin Herrenschmidt seq_puts(s, "step\n"); 2026cbe709c1SBenjamin Herrenschmidt return 0; 2027cbe709c1SBenjamin Herrenschmidt } 2028cbe709c1SBenjamin Herrenschmidt 2029cbe709c1SBenjamin Herrenschmidt static int spufs_caps_open(struct inode *inode, struct file *file) 2030cbe709c1SBenjamin Herrenschmidt { 2031cbe709c1SBenjamin Herrenschmidt return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); 2032cbe709c1SBenjamin Herrenschmidt } 2033cbe709c1SBenjamin Herrenschmidt 2034cbe709c1SBenjamin Herrenschmidt static const struct file_operations spufs_caps_fops = { 2035cbe709c1SBenjamin Herrenschmidt .open = spufs_caps_open, 2036cbe709c1SBenjamin Herrenschmidt .read = seq_read, 2037cbe709c1SBenjamin Herrenschmidt .llseek = seq_lseek, 2038cbe709c1SBenjamin Herrenschmidt .release = single_release, 2039cbe709c1SBenjamin Herrenschmidt }; 2040cbe709c1SBenjamin Herrenschmidt 2041bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, 2042bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2043bf1ab978SDwayne Grant McConnell { 2044bf1ab978SDwayne Grant McConnell u32 data; 2045bf1ab978SDwayne Grant McConnell 2046cbea9238SJeremy Kerr /* EOF if there's no entry in the mbox */ 2047cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0x0000ff)) 2048cbea9238SJeremy Kerr return 0; 2049cbea9238SJeremy Kerr 2050bf1ab978SDwayne Grant McConnell data = ctx->csa.prob.pu_mb_R; 2051bf1ab978SDwayne Grant McConnell 2052bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2053bf1ab978SDwayne Grant McConnell } 2054bf1ab978SDwayne Grant McConnell 205569a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 205669a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 205769a2f00cSDwayne Grant McConnell { 2058bf1ab978SDwayne Grant McConnell int ret; 205969a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 206069a2f00cSDwayne Grant McConnell 206169a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 206269a2f00cSDwayne Grant McConnell return -EFAULT; 206369a2f00cSDwayne Grant McConnell 2064c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2065c9101bdbSChristoph Hellwig if (ret) 2066c9101bdbSChristoph Hellwig return ret; 206769a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2068bf1ab978SDwayne Grant McConnell ret = __spufs_mbox_info_read(ctx, buf, len, pos); 206969a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 207027b1ea09SChristoph Hellwig spu_release_saved(ctx); 207169a2f00cSDwayne Grant McConnell 2072bf1ab978SDwayne Grant McConnell return ret; 207369a2f00cSDwayne Grant McConnell } 207469a2f00cSDwayne Grant McConnell 20755dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = { 207669a2f00cSDwayne Grant McConnell .open = spufs_info_open, 207769a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 207869a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 207969a2f00cSDwayne Grant McConnell }; 208069a2f00cSDwayne Grant McConnell 2081bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, 2082bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2083bf1ab978SDwayne Grant McConnell { 2084bf1ab978SDwayne Grant McConnell u32 data; 2085bf1ab978SDwayne Grant McConnell 2086cbea9238SJeremy Kerr /* EOF if there's no entry in the ibox */ 2087cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) 2088cbea9238SJeremy Kerr return 0; 2089cbea9238SJeremy Kerr 2090bf1ab978SDwayne Grant McConnell data = ctx->csa.priv2.puint_mb_R; 2091bf1ab978SDwayne Grant McConnell 2092bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2093bf1ab978SDwayne Grant McConnell } 2094bf1ab978SDwayne Grant McConnell 209569a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 209669a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 209769a2f00cSDwayne Grant McConnell { 209869a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2099bf1ab978SDwayne Grant McConnell int ret; 210069a2f00cSDwayne Grant McConnell 210169a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 210269a2f00cSDwayne Grant McConnell return -EFAULT; 210369a2f00cSDwayne Grant McConnell 2104c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2105c9101bdbSChristoph Hellwig if (ret) 2106c9101bdbSChristoph Hellwig return ret; 210769a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2108bf1ab978SDwayne Grant McConnell ret = __spufs_ibox_info_read(ctx, buf, len, pos); 210969a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 211027b1ea09SChristoph Hellwig spu_release_saved(ctx); 211169a2f00cSDwayne Grant McConnell 2112bf1ab978SDwayne Grant McConnell return ret; 211369a2f00cSDwayne Grant McConnell } 211469a2f00cSDwayne Grant McConnell 21155dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = { 211669a2f00cSDwayne Grant McConnell .open = spufs_info_open, 211769a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 211869a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 211969a2f00cSDwayne Grant McConnell }; 212069a2f00cSDwayne Grant McConnell 2121bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, 2122bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2123bf1ab978SDwayne Grant McConnell { 2124bf1ab978SDwayne Grant McConnell int i, cnt; 2125bf1ab978SDwayne Grant McConnell u32 data[4]; 2126bf1ab978SDwayne Grant McConnell u32 wbox_stat; 2127bf1ab978SDwayne Grant McConnell 2128bf1ab978SDwayne Grant McConnell wbox_stat = ctx->csa.prob.mb_stat_R; 2129bf1ab978SDwayne Grant McConnell cnt = 4 - ((wbox_stat & 0x00ff00) >> 8); 2130bf1ab978SDwayne Grant McConnell for (i = 0; i < cnt; i++) { 2131bf1ab978SDwayne Grant McConnell data[i] = ctx->csa.spu_mailbox_data[i]; 2132bf1ab978SDwayne Grant McConnell } 2133bf1ab978SDwayne Grant McConnell 2134bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, 2135bf1ab978SDwayne Grant McConnell cnt * sizeof(u32)); 2136bf1ab978SDwayne Grant McConnell } 2137bf1ab978SDwayne Grant McConnell 213869a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 213969a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 214069a2f00cSDwayne Grant McConnell { 214169a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2142bf1ab978SDwayne Grant McConnell int ret; 214369a2f00cSDwayne Grant McConnell 214469a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 214569a2f00cSDwayne Grant McConnell return -EFAULT; 214669a2f00cSDwayne Grant McConnell 2147c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2148c9101bdbSChristoph Hellwig if (ret) 2149c9101bdbSChristoph Hellwig return ret; 215069a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2151bf1ab978SDwayne Grant McConnell ret = __spufs_wbox_info_read(ctx, buf, len, pos); 215269a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 215327b1ea09SChristoph Hellwig spu_release_saved(ctx); 215469a2f00cSDwayne Grant McConnell 2155bf1ab978SDwayne Grant McConnell return ret; 215669a2f00cSDwayne Grant McConnell } 215769a2f00cSDwayne Grant McConnell 21585dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = { 215969a2f00cSDwayne Grant McConnell .open = spufs_info_open, 216069a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 216169a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 216269a2f00cSDwayne Grant McConnell }; 216369a2f00cSDwayne Grant McConnell 2164bf1ab978SDwayne Grant McConnell static ssize_t __spufs_dma_info_read(struct spu_context *ctx, 2165bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2166b9e3bd77SDwayne Grant McConnell { 2167b9e3bd77SDwayne Grant McConnell struct spu_dma_info info; 2168b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *spuqp; 2169b9e3bd77SDwayne Grant McConnell int i; 2170b9e3bd77SDwayne Grant McConnell 2171b9e3bd77SDwayne Grant McConnell info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 2172b9e3bd77SDwayne Grant McConnell info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 2173b9e3bd77SDwayne Grant McConnell info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; 2174b9e3bd77SDwayne Grant McConnell info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 2175b9e3bd77SDwayne Grant McConnell info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 2176b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 2177b9e3bd77SDwayne Grant McConnell qp = &info.dma_info_command_data[i]; 2178b9e3bd77SDwayne Grant McConnell spuqp = &ctx->csa.priv2.spuq[i]; 2179b9e3bd77SDwayne Grant McConnell 2180b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 2181b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 2182b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 2183b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 2184b9e3bd77SDwayne Grant McConnell } 2185b9e3bd77SDwayne Grant McConnell 2186b9e3bd77SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2187b9e3bd77SDwayne Grant McConnell sizeof info); 2188b9e3bd77SDwayne Grant McConnell } 2189b9e3bd77SDwayne Grant McConnell 2190bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 2191bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2192bf1ab978SDwayne Grant McConnell { 2193bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2194bf1ab978SDwayne Grant McConnell int ret; 2195bf1ab978SDwayne Grant McConnell 2196bf1ab978SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2197bf1ab978SDwayne Grant McConnell return -EFAULT; 2198bf1ab978SDwayne Grant McConnell 2199c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2200c9101bdbSChristoph Hellwig if (ret) 2201c9101bdbSChristoph Hellwig return ret; 2202bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2203bf1ab978SDwayne Grant McConnell ret = __spufs_dma_info_read(ctx, buf, len, pos); 2204bf1ab978SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 220527b1ea09SChristoph Hellwig spu_release_saved(ctx); 2206bf1ab978SDwayne Grant McConnell 2207bf1ab978SDwayne Grant McConnell return ret; 2208bf1ab978SDwayne Grant McConnell } 2209bf1ab978SDwayne Grant McConnell 22105dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = { 2211b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2212b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 2213b9e3bd77SDwayne Grant McConnell }; 2214b9e3bd77SDwayne Grant McConnell 2215bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, 2216bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2217b9e3bd77SDwayne Grant McConnell { 2218b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 2219b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *puqp; 2220bf1ab978SDwayne Grant McConnell int ret = sizeof info; 2221b9e3bd77SDwayne Grant McConnell int i; 2222b9e3bd77SDwayne Grant McConnell 2223b9e3bd77SDwayne Grant McConnell if (len < ret) 2224b9e3bd77SDwayne Grant McConnell return -EINVAL; 2225b9e3bd77SDwayne Grant McConnell 2226b9e3bd77SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2227b9e3bd77SDwayne Grant McConnell return -EFAULT; 2228b9e3bd77SDwayne Grant McConnell 2229b9e3bd77SDwayne Grant McConnell info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 2230b9e3bd77SDwayne Grant McConnell info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 2231b9e3bd77SDwayne Grant McConnell info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 2232b9e3bd77SDwayne Grant McConnell for (i = 0; i < 8; i++) { 2233b9e3bd77SDwayne Grant McConnell qp = &info.proxydma_info_command_data[i]; 2234b9e3bd77SDwayne Grant McConnell puqp = &ctx->csa.priv2.puq[i]; 2235b9e3bd77SDwayne Grant McConnell 2236b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 2237b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 2238b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 2239b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 2240b9e3bd77SDwayne Grant McConnell } 2241bf1ab978SDwayne Grant McConnell 2242bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2243bf1ab978SDwayne Grant McConnell sizeof info); 2244bf1ab978SDwayne Grant McConnell } 2245bf1ab978SDwayne Grant McConnell 2246bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 2247bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2248bf1ab978SDwayne Grant McConnell { 2249bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2250bf1ab978SDwayne Grant McConnell int ret; 2251bf1ab978SDwayne Grant McConnell 2252c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2253c9101bdbSChristoph Hellwig if (ret) 2254c9101bdbSChristoph Hellwig return ret; 2255bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2256bf1ab978SDwayne Grant McConnell ret = __spufs_proxydma_info_read(ctx, buf, len, pos); 2257b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 225827b1ea09SChristoph Hellwig spu_release_saved(ctx); 2259b9e3bd77SDwayne Grant McConnell 2260b9e3bd77SDwayne Grant McConnell return ret; 2261b9e3bd77SDwayne Grant McConnell } 2262b9e3bd77SDwayne Grant McConnell 22635dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = { 2264b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2265b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 2266b9e3bd77SDwayne Grant McConnell }; 2267b9e3bd77SDwayne Grant McConnell 2268476273adSChristoph Hellwig static int spufs_show_tid(struct seq_file *s, void *private) 2269476273adSChristoph Hellwig { 2270476273adSChristoph Hellwig struct spu_context *ctx = s->private; 2271476273adSChristoph Hellwig 2272476273adSChristoph Hellwig seq_printf(s, "%d\n", ctx->tid); 2273476273adSChristoph Hellwig return 0; 2274476273adSChristoph Hellwig } 2275476273adSChristoph Hellwig 2276476273adSChristoph Hellwig static int spufs_tid_open(struct inode *inode, struct file *file) 2277476273adSChristoph Hellwig { 2278476273adSChristoph Hellwig return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); 2279476273adSChristoph Hellwig } 2280476273adSChristoph Hellwig 2281476273adSChristoph Hellwig static const struct file_operations spufs_tid_fops = { 2282476273adSChristoph Hellwig .open = spufs_tid_open, 2283476273adSChristoph Hellwig .read = seq_read, 2284476273adSChristoph Hellwig .llseek = seq_lseek, 2285476273adSChristoph Hellwig .release = single_release, 2286476273adSChristoph Hellwig }; 2287476273adSChristoph Hellwig 2288e9f8a0b6SChristoph Hellwig static const char *ctx_state_names[] = { 2289e9f8a0b6SChristoph Hellwig "user", "system", "iowait", "loaded" 2290e9f8a0b6SChristoph Hellwig }; 2291e9f8a0b6SChristoph Hellwig 2292e9f8a0b6SChristoph Hellwig static unsigned long long spufs_acct_time(struct spu_context *ctx, 229327ec41d3SAndre Detsch enum spu_utilization_state state) 2294e9f8a0b6SChristoph Hellwig { 229527ec41d3SAndre Detsch struct timespec ts; 229627ec41d3SAndre Detsch unsigned long long time = ctx->stats.times[state]; 2297e9f8a0b6SChristoph Hellwig 229827ec41d3SAndre Detsch /* 229927ec41d3SAndre Detsch * In general, utilization statistics are updated by the controlling 230027ec41d3SAndre Detsch * thread as the spu context moves through various well defined 230127ec41d3SAndre Detsch * state transitions, but if the context is lazily loaded its 230227ec41d3SAndre Detsch * utilization statistics are not updated as the controlling thread 230327ec41d3SAndre Detsch * is not tightly coupled with the execution of the spu context. We 230427ec41d3SAndre Detsch * calculate and apply the time delta from the last recorded state 230527ec41d3SAndre Detsch * of the spu context. 230627ec41d3SAndre Detsch */ 230727ec41d3SAndre Detsch if (ctx->spu && ctx->stats.util_state == state) { 230827ec41d3SAndre Detsch ktime_get_ts(&ts); 230927ec41d3SAndre Detsch time += timespec_to_ns(&ts) - ctx->stats.tstamp; 231027ec41d3SAndre Detsch } 2311e9f8a0b6SChristoph Hellwig 231227ec41d3SAndre Detsch return time / NSEC_PER_MSEC; 2313e9f8a0b6SChristoph Hellwig } 2314e9f8a0b6SChristoph Hellwig 2315e9f8a0b6SChristoph Hellwig static unsigned long long spufs_slb_flts(struct spu_context *ctx) 2316e9f8a0b6SChristoph Hellwig { 2317e9f8a0b6SChristoph Hellwig unsigned long long slb_flts = ctx->stats.slb_flt; 2318e9f8a0b6SChristoph Hellwig 2319e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2320e9f8a0b6SChristoph Hellwig slb_flts += (ctx->spu->stats.slb_flt - 2321e9f8a0b6SChristoph Hellwig ctx->stats.slb_flt_base); 2322e9f8a0b6SChristoph Hellwig } 2323e9f8a0b6SChristoph Hellwig 2324e9f8a0b6SChristoph Hellwig return slb_flts; 2325e9f8a0b6SChristoph Hellwig } 2326e9f8a0b6SChristoph Hellwig 2327e9f8a0b6SChristoph Hellwig static unsigned long long spufs_class2_intrs(struct spu_context *ctx) 2328e9f8a0b6SChristoph Hellwig { 2329e9f8a0b6SChristoph Hellwig unsigned long long class2_intrs = ctx->stats.class2_intr; 2330e9f8a0b6SChristoph Hellwig 2331e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2332e9f8a0b6SChristoph Hellwig class2_intrs += (ctx->spu->stats.class2_intr - 2333e9f8a0b6SChristoph Hellwig ctx->stats.class2_intr_base); 2334e9f8a0b6SChristoph Hellwig } 2335e9f8a0b6SChristoph Hellwig 2336e9f8a0b6SChristoph Hellwig return class2_intrs; 2337e9f8a0b6SChristoph Hellwig } 2338e9f8a0b6SChristoph Hellwig 2339e9f8a0b6SChristoph Hellwig 2340e9f8a0b6SChristoph Hellwig static int spufs_show_stat(struct seq_file *s, void *private) 2341e9f8a0b6SChristoph Hellwig { 2342e9f8a0b6SChristoph Hellwig struct spu_context *ctx = s->private; 2343c9101bdbSChristoph Hellwig int ret; 2344e9f8a0b6SChristoph Hellwig 2345c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 2346c9101bdbSChristoph Hellwig if (ret) 2347c9101bdbSChristoph Hellwig return ret; 2348c9101bdbSChristoph Hellwig 2349e9f8a0b6SChristoph Hellwig seq_printf(s, "%s %llu %llu %llu %llu " 2350e9f8a0b6SChristoph Hellwig "%llu %llu %llu %llu %llu %llu %llu %llu\n", 235127ec41d3SAndre Detsch ctx_state_names[ctx->stats.util_state], 235227ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_USER), 235327ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 235427ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 235527ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 2356e9f8a0b6SChristoph Hellwig ctx->stats.vol_ctx_switch, 2357e9f8a0b6SChristoph Hellwig ctx->stats.invol_ctx_switch, 2358e9f8a0b6SChristoph Hellwig spufs_slb_flts(ctx), 2359e9f8a0b6SChristoph Hellwig ctx->stats.hash_flt, 2360e9f8a0b6SChristoph Hellwig ctx->stats.min_flt, 2361e9f8a0b6SChristoph Hellwig ctx->stats.maj_flt, 2362e9f8a0b6SChristoph Hellwig spufs_class2_intrs(ctx), 2363e9f8a0b6SChristoph Hellwig ctx->stats.libassist); 2364e9f8a0b6SChristoph Hellwig spu_release(ctx); 2365e9f8a0b6SChristoph Hellwig return 0; 2366e9f8a0b6SChristoph Hellwig } 2367e9f8a0b6SChristoph Hellwig 2368e9f8a0b6SChristoph Hellwig static int spufs_stat_open(struct inode *inode, struct file *file) 2369e9f8a0b6SChristoph Hellwig { 2370e9f8a0b6SChristoph Hellwig return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); 2371e9f8a0b6SChristoph Hellwig } 2372e9f8a0b6SChristoph Hellwig 2373e9f8a0b6SChristoph Hellwig static const struct file_operations spufs_stat_fops = { 2374e9f8a0b6SChristoph Hellwig .open = spufs_stat_open, 2375e9f8a0b6SChristoph Hellwig .read = seq_read, 2376e9f8a0b6SChristoph Hellwig .llseek = seq_lseek, 2377e9f8a0b6SChristoph Hellwig .release = single_release, 2378e9f8a0b6SChristoph Hellwig }; 2379e9f8a0b6SChristoph Hellwig 2380e9f8a0b6SChristoph Hellwig 238167207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 2382cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 238367207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 23848b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 238567207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 238667207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 238767207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 238867207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 238967207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 239067207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2391603c4612SJeremy Kerr { "signal1", &spufs_signal1_fops, 0666, }, 2392603c4612SJeremy Kerr { "signal2", &spufs_signal2_fops, 0666, }, 239367207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 239467207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 23956df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 23968b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 2397b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 2398b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 2399b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 2400b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 2401b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 24028b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 24038b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 24048b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 2405b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 240627d5bf2aSBenjamin Herrenschmidt { "psmap", &spufs_psmap_fops, 0666, }, 240786767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 240886767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 240969a2f00cSDwayne Grant McConnell { "mbox_info", &spufs_mbox_info_fops, 0444, }, 241069a2f00cSDwayne Grant McConnell { "ibox_info", &spufs_ibox_info_fops, 0444, }, 241169a2f00cSDwayne Grant McConnell { "wbox_info", &spufs_wbox_info_fops, 0444, }, 2412b9e3bd77SDwayne Grant McConnell { "dma_info", &spufs_dma_info_fops, 0444, }, 2413b9e3bd77SDwayne Grant McConnell { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, 2414476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2415e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 241667207b96SArnd Bergmann {}, 241767207b96SArnd Bergmann }; 24185737edd1SMark Nutter 24195737edd1SMark Nutter struct tree_descr spufs_dir_nosched_contents[] = { 2420cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 24215737edd1SMark Nutter { "mem", &spufs_mem_fops, 0666, }, 24225737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 24235737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 24245737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 24255737edd1SMark Nutter { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 24265737edd1SMark Nutter { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 24275737edd1SMark Nutter { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2428d054b36fSJeremy Kerr { "signal1", &spufs_signal1_nosched_fops, 0222, }, 2429d054b36fSJeremy Kerr { "signal2", &spufs_signal2_nosched_fops, 0222, }, 24305737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 24315737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 24325737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 24335737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 24345737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 24355737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 24365737edd1SMark Nutter { "psmap", &spufs_psmap_fops, 0666, }, 24375737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 24385737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 2439476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2440e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 24415737edd1SMark Nutter {}, 24425737edd1SMark Nutter }; 2443bf1ab978SDwayne Grant McConnell 2444bf1ab978SDwayne Grant McConnell struct spufs_coredump_reader spufs_coredump_read[] = { 24454fca9c42SMichael Ellerman { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, 24464fca9c42SMichael Ellerman { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, 2447104f0cc2SMichael Ellerman { "lslr", NULL, spufs_lslr_get, 19 }, 2448104f0cc2SMichael Ellerman { "decr", NULL, spufs_decr_get, 19 }, 2449104f0cc2SMichael Ellerman { "decr_status", NULL, spufs_decr_status_get, 19 }, 24504fca9c42SMichael Ellerman { "mem", __spufs_mem_read, NULL, LS_SIZE, }, 24514fca9c42SMichael Ellerman { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, 2452104f0cc2SMichael Ellerman { "signal1_type", NULL, spufs_signal1_type_get, 19 }, 24534fca9c42SMichael Ellerman { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, 2454104f0cc2SMichael Ellerman { "signal2_type", NULL, spufs_signal2_type_get, 19 }, 2455104f0cc2SMichael Ellerman { "event_mask", NULL, spufs_event_mask_get, 19 }, 2456104f0cc2SMichael Ellerman { "event_status", NULL, spufs_event_status_get, 19 }, 24574fca9c42SMichael Ellerman { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, 24584fca9c42SMichael Ellerman { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, 24594fca9c42SMichael Ellerman { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, 24604fca9c42SMichael Ellerman { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, 24614fca9c42SMichael Ellerman { "proxydma_info", __spufs_proxydma_info_read, 24624fca9c42SMichael Ellerman NULL, sizeof(struct spu_proxydma_info)}, 2463104f0cc2SMichael Ellerman { "object-id", NULL, spufs_object_id_get, 19 }, 2464104f0cc2SMichael Ellerman { "npc", NULL, spufs_npc_get, 19 }, 2465936d5bf1SMichael Ellerman { NULL }, 2466bf1ab978SDwayne Grant McConnell }; 2467