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> 3267207b96SArnd Bergmann 3367207b96SArnd Bergmann #include <asm/io.h> 3467207b96SArnd Bergmann #include <asm/semaphore.h> 3567207b96SArnd Bergmann #include <asm/spu.h> 36b9e3bd77SDwayne Grant McConnell #include <asm/spu_info.h> 3767207b96SArnd Bergmann #include <asm/uaccess.h> 3867207b96SArnd Bergmann 3967207b96SArnd Bergmann #include "spufs.h" 4067207b96SArnd Bergmann 4127d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 4227d5bf2aSBenjamin Herrenschmidt 43197b1a82SChristoph Hellwig /* Simple attribute files */ 44197b1a82SChristoph Hellwig struct spufs_attr { 45197b1a82SChristoph Hellwig int (*get)(void *, u64 *); 46197b1a82SChristoph Hellwig int (*set)(void *, u64); 47197b1a82SChristoph Hellwig char get_buf[24]; /* enough to store a u64 and "\n\0" */ 48197b1a82SChristoph Hellwig char set_buf[24]; 49197b1a82SChristoph Hellwig void *data; 50197b1a82SChristoph Hellwig const char *fmt; /* format for read operation */ 51197b1a82SChristoph Hellwig struct mutex mutex; /* protects access to these buffers */ 52197b1a82SChristoph Hellwig }; 53197b1a82SChristoph Hellwig 54197b1a82SChristoph Hellwig static int spufs_attr_open(struct inode *inode, struct file *file, 55197b1a82SChristoph Hellwig int (*get)(void *, u64 *), int (*set)(void *, u64), 56197b1a82SChristoph Hellwig const char *fmt) 57197b1a82SChristoph Hellwig { 58197b1a82SChristoph Hellwig struct spufs_attr *attr; 59197b1a82SChristoph Hellwig 60197b1a82SChristoph Hellwig attr = kmalloc(sizeof(*attr), GFP_KERNEL); 61197b1a82SChristoph Hellwig if (!attr) 62197b1a82SChristoph Hellwig return -ENOMEM; 63197b1a82SChristoph Hellwig 64197b1a82SChristoph Hellwig attr->get = get; 65197b1a82SChristoph Hellwig attr->set = set; 66197b1a82SChristoph Hellwig attr->data = inode->i_private; 67197b1a82SChristoph Hellwig attr->fmt = fmt; 68197b1a82SChristoph Hellwig mutex_init(&attr->mutex); 69197b1a82SChristoph Hellwig file->private_data = attr; 70197b1a82SChristoph Hellwig 71197b1a82SChristoph Hellwig return nonseekable_open(inode, file); 72197b1a82SChristoph Hellwig } 73197b1a82SChristoph Hellwig 74197b1a82SChristoph Hellwig static int spufs_attr_release(struct inode *inode, struct file *file) 75197b1a82SChristoph Hellwig { 76197b1a82SChristoph Hellwig kfree(file->private_data); 77197b1a82SChristoph Hellwig return 0; 78197b1a82SChristoph Hellwig } 79197b1a82SChristoph Hellwig 80197b1a82SChristoph Hellwig static ssize_t spufs_attr_read(struct file *file, char __user *buf, 81197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 82197b1a82SChristoph Hellwig { 83197b1a82SChristoph Hellwig struct spufs_attr *attr; 84197b1a82SChristoph Hellwig size_t size; 85197b1a82SChristoph Hellwig ssize_t ret; 86197b1a82SChristoph Hellwig 87197b1a82SChristoph Hellwig attr = file->private_data; 88197b1a82SChristoph Hellwig if (!attr->get) 89197b1a82SChristoph Hellwig return -EACCES; 90197b1a82SChristoph Hellwig 91197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 92197b1a82SChristoph Hellwig if (ret) 93197b1a82SChristoph Hellwig return ret; 94197b1a82SChristoph Hellwig 95197b1a82SChristoph Hellwig if (*ppos) { /* continued read */ 96197b1a82SChristoph Hellwig size = strlen(attr->get_buf); 97197b1a82SChristoph Hellwig } else { /* first read */ 98197b1a82SChristoph Hellwig u64 val; 99197b1a82SChristoph Hellwig ret = attr->get(attr->data, &val); 100197b1a82SChristoph Hellwig if (ret) 101197b1a82SChristoph Hellwig goto out; 102197b1a82SChristoph Hellwig 103197b1a82SChristoph Hellwig size = scnprintf(attr->get_buf, sizeof(attr->get_buf), 104197b1a82SChristoph Hellwig attr->fmt, (unsigned long long)val); 105197b1a82SChristoph Hellwig } 106197b1a82SChristoph Hellwig 107197b1a82SChristoph Hellwig ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); 108197b1a82SChristoph Hellwig out: 109197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 110197b1a82SChristoph Hellwig return ret; 111197b1a82SChristoph Hellwig } 112197b1a82SChristoph Hellwig 113197b1a82SChristoph Hellwig static ssize_t spufs_attr_write(struct file *file, const char __user *buf, 114197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 115197b1a82SChristoph Hellwig { 116197b1a82SChristoph Hellwig struct spufs_attr *attr; 117197b1a82SChristoph Hellwig u64 val; 118197b1a82SChristoph Hellwig size_t size; 119197b1a82SChristoph Hellwig ssize_t ret; 120197b1a82SChristoph Hellwig 121197b1a82SChristoph Hellwig attr = file->private_data; 122197b1a82SChristoph Hellwig if (!attr->set) 123197b1a82SChristoph Hellwig return -EACCES; 124197b1a82SChristoph Hellwig 125197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 126197b1a82SChristoph Hellwig if (ret) 127197b1a82SChristoph Hellwig return ret; 128197b1a82SChristoph Hellwig 129197b1a82SChristoph Hellwig ret = -EFAULT; 130197b1a82SChristoph Hellwig size = min(sizeof(attr->set_buf) - 1, len); 131197b1a82SChristoph Hellwig if (copy_from_user(attr->set_buf, buf, size)) 132197b1a82SChristoph Hellwig goto out; 133197b1a82SChristoph Hellwig 134197b1a82SChristoph Hellwig ret = len; /* claim we got the whole input */ 135197b1a82SChristoph Hellwig attr->set_buf[size] = '\0'; 136197b1a82SChristoph Hellwig val = simple_strtol(attr->set_buf, NULL, 0); 137197b1a82SChristoph Hellwig attr->set(attr->data, val); 138197b1a82SChristoph Hellwig out: 139197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 140197b1a82SChristoph Hellwig return ret; 141197b1a82SChristoph Hellwig } 142197b1a82SChristoph Hellwig 143197b1a82SChristoph Hellwig #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ 144197b1a82SChristoph Hellwig static int __fops ## _open(struct inode *inode, struct file *file) \ 145197b1a82SChristoph Hellwig { \ 146197b1a82SChristoph Hellwig __simple_attr_check_format(__fmt, 0ull); \ 147197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, __get, __set, __fmt); \ 148197b1a82SChristoph Hellwig } \ 149197b1a82SChristoph Hellwig static struct file_operations __fops = { \ 150197b1a82SChristoph Hellwig .owner = THIS_MODULE, \ 151197b1a82SChristoph Hellwig .open = __fops ## _open, \ 152197b1a82SChristoph Hellwig .release = spufs_attr_release, \ 153197b1a82SChristoph Hellwig .read = spufs_attr_read, \ 154197b1a82SChristoph Hellwig .write = spufs_attr_write, \ 155197b1a82SChristoph Hellwig }; 156197b1a82SChristoph Hellwig 157cbe709c1SBenjamin Herrenschmidt 15867207b96SArnd Bergmann static int 15967207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 16067207b96SArnd Bergmann { 16167207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1626df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 16343c2bbd9SChristoph Hellwig 16447d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1656df10a82SMark Nutter file->private_data = ctx; 16643c2bbd9SChristoph Hellwig if (!i->i_openers++) 1676df10a82SMark Nutter ctx->local_store = inode->i_mapping; 16847d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 16943c2bbd9SChristoph Hellwig return 0; 17043c2bbd9SChristoph Hellwig } 17143c2bbd9SChristoph Hellwig 17243c2bbd9SChristoph Hellwig static int 17343c2bbd9SChristoph Hellwig spufs_mem_release(struct inode *inode, struct file *file) 17443c2bbd9SChristoph Hellwig { 17543c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 17643c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 17743c2bbd9SChristoph Hellwig 17847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 17943c2bbd9SChristoph Hellwig if (!--i->i_openers) 18043c2bbd9SChristoph Hellwig ctx->local_store = NULL; 18147d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 18267207b96SArnd Bergmann return 0; 18367207b96SArnd Bergmann } 18467207b96SArnd Bergmann 18567207b96SArnd Bergmann static ssize_t 186bf1ab978SDwayne Grant McConnell __spufs_mem_read(struct spu_context *ctx, char __user *buffer, 187bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 188bf1ab978SDwayne Grant McConnell { 189bf1ab978SDwayne Grant McConnell char *local_store = ctx->ops->get_ls(ctx); 190bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, local_store, 191bf1ab978SDwayne Grant McConnell LS_SIZE); 192bf1ab978SDwayne Grant McConnell } 193bf1ab978SDwayne Grant McConnell 194bf1ab978SDwayne Grant McConnell static ssize_t 19567207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 19667207b96SArnd Bergmann size_t size, loff_t *pos) 19767207b96SArnd Bergmann { 198bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 199aa0ed2bdSArnd Bergmann ssize_t ret; 20067207b96SArnd Bergmann 201c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 202c9101bdbSChristoph Hellwig if (ret) 203c9101bdbSChristoph Hellwig return ret; 204bf1ab978SDwayne Grant McConnell ret = __spufs_mem_read(ctx, buffer, size, pos); 2058b3d6663SArnd Bergmann spu_release(ctx); 206c9101bdbSChristoph Hellwig 20767207b96SArnd Bergmann return ret; 20867207b96SArnd Bergmann } 20967207b96SArnd Bergmann 21067207b96SArnd Bergmann static ssize_t 21167207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 212aa0ed2bdSArnd Bergmann size_t size, loff_t *ppos) 21367207b96SArnd Bergmann { 21467207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 2158b3d6663SArnd Bergmann char *local_store; 216aa0ed2bdSArnd Bergmann loff_t pos = *ppos; 2178b3d6663SArnd Bergmann int ret; 21867207b96SArnd Bergmann 219aa0ed2bdSArnd Bergmann if (pos < 0) 220aa0ed2bdSArnd Bergmann return -EINVAL; 221aa0ed2bdSArnd Bergmann if (pos > LS_SIZE) 22267207b96SArnd Bergmann return -EFBIG; 223aa0ed2bdSArnd Bergmann if (size > LS_SIZE - pos) 224aa0ed2bdSArnd Bergmann size = LS_SIZE - pos; 2258b3d6663SArnd Bergmann 226c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 227c9101bdbSChristoph Hellwig if (ret) 228c9101bdbSChristoph Hellwig return ret; 229c9101bdbSChristoph Hellwig 2308b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 231aa0ed2bdSArnd Bergmann ret = copy_from_user(local_store + pos, buffer, size); 2328b3d6663SArnd Bergmann spu_release(ctx); 233aa0ed2bdSArnd Bergmann 234aa0ed2bdSArnd Bergmann if (ret) 235aa0ed2bdSArnd Bergmann return -EFAULT; 236aa0ed2bdSArnd Bergmann *ppos = pos + size; 237aa0ed2bdSArnd Bergmann return size; 23867207b96SArnd Bergmann } 23967207b96SArnd Bergmann 24078bde53eSBenjamin Herrenschmidt static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, 24178bde53eSBenjamin Herrenschmidt unsigned long address) 2428b3d6663SArnd Bergmann { 2438b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 244f1fa74f4SBenjamin Herrenschmidt unsigned long pfn, offset, addr0 = address; 245f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 246f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 247f1fa74f4SBenjamin Herrenschmidt int psize; 24878bde53eSBenjamin Herrenschmidt 249f1fa74f4SBenjamin Herrenschmidt /* Check what page size we are using */ 250f1fa74f4SBenjamin Herrenschmidt psize = get_slice_psize(vma->vm_mm, address); 2518b3d6663SArnd Bergmann 252f1fa74f4SBenjamin Herrenschmidt /* Some sanity checking */ 253f1fa74f4SBenjamin Herrenschmidt BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K)); 254f1fa74f4SBenjamin Herrenschmidt 255f1fa74f4SBenjamin Herrenschmidt /* Wow, 64K, cool, we need to align the address though */ 256f1fa74f4SBenjamin Herrenschmidt if (csa->use_big_pages) { 257f1fa74f4SBenjamin Herrenschmidt BUG_ON(vma->vm_start & 0xffff); 258f1fa74f4SBenjamin Herrenschmidt address &= ~0xfffful; 259f1fa74f4SBenjamin Herrenschmidt } 260f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 261f1fa74f4SBenjamin Herrenschmidt 262f1fa74f4SBenjamin Herrenschmidt offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); 263128b8546SMasato Noguchi if (offset >= LS_SIZE) 264128b8546SMasato Noguchi return NOPFN_SIGBUS; 265128b8546SMasato Noguchi 266f1fa74f4SBenjamin Herrenschmidt pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n", 267f1fa74f4SBenjamin Herrenschmidt addr0, address, offset); 268f1fa74f4SBenjamin Herrenschmidt 269c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 270c9101bdbSChristoph Hellwig return NOPFN_REFAULT; 2718b3d6663SArnd Bergmann 272ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 273ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 274932f535dSArnd Bergmann & ~_PAGE_NO_CACHE); 27578bde53eSBenjamin Herrenschmidt pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); 276ac91cb8dSArnd Bergmann } else { 277ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 278932f535dSArnd Bergmann | _PAGE_NO_CACHE); 27978bde53eSBenjamin Herrenschmidt pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; 280ac91cb8dSArnd Bergmann } 28178bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, pfn); 28278bde53eSBenjamin Herrenschmidt 2838b3d6663SArnd Bergmann spu_release(ctx); 2848b3d6663SArnd Bergmann 28578bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 2868b3d6663SArnd Bergmann } 2878b3d6663SArnd Bergmann 28878bde53eSBenjamin Herrenschmidt 2898b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = { 29078bde53eSBenjamin Herrenschmidt .nopfn = spufs_mem_mmap_nopfn, 2918b3d6663SArnd Bergmann }; 2928b3d6663SArnd Bergmann 293f1fa74f4SBenjamin Herrenschmidt static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 29467207b96SArnd Bergmann { 295f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 296f1fa74f4SBenjamin Herrenschmidt struct spu_context *ctx = file->private_data; 297f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 298f1fa74f4SBenjamin Herrenschmidt 299f1fa74f4SBenjamin Herrenschmidt /* Sanity check VMA alignment */ 300f1fa74f4SBenjamin Herrenschmidt if (csa->use_big_pages) { 301f1fa74f4SBenjamin Herrenschmidt pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx," 302f1fa74f4SBenjamin Herrenschmidt " pgoff=0x%lx\n", vma->vm_start, vma->vm_end, 303f1fa74f4SBenjamin Herrenschmidt vma->vm_pgoff); 304f1fa74f4SBenjamin Herrenschmidt if (vma->vm_start & 0xffff) 305f1fa74f4SBenjamin Herrenschmidt return -EINVAL; 306f1fa74f4SBenjamin Herrenschmidt if (vma->vm_pgoff & 0xf) 307f1fa74f4SBenjamin Herrenschmidt return -EINVAL; 308f1fa74f4SBenjamin Herrenschmidt } 309f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 310f1fa74f4SBenjamin Herrenschmidt 3118b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 3128b3d6663SArnd Bergmann return -EINVAL; 31367207b96SArnd Bergmann 31478bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 31567207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 31667207b96SArnd Bergmann | _PAGE_NO_CACHE); 3178b3d6663SArnd Bergmann 3188b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 31967207b96SArnd Bergmann return 0; 32067207b96SArnd Bergmann } 32167207b96SArnd Bergmann 322f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 3231238819aSSebastian Siewior static unsigned long spufs_get_unmapped_area(struct file *file, 3241238819aSSebastian Siewior unsigned long addr, unsigned long len, unsigned long pgoff, 325f1fa74f4SBenjamin Herrenschmidt unsigned long flags) 326f1fa74f4SBenjamin Herrenschmidt { 327f1fa74f4SBenjamin Herrenschmidt struct spu_context *ctx = file->private_data; 328f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 329f1fa74f4SBenjamin Herrenschmidt 330f1fa74f4SBenjamin Herrenschmidt /* If not using big pages, fallback to normal MM g_u_a */ 331f1fa74f4SBenjamin Herrenschmidt if (!csa->use_big_pages) 332f1fa74f4SBenjamin Herrenschmidt return current->mm->get_unmapped_area(file, addr, len, 333f1fa74f4SBenjamin Herrenschmidt pgoff, flags); 334f1fa74f4SBenjamin Herrenschmidt 335f1fa74f4SBenjamin Herrenschmidt /* Else, try to obtain a 64K pages slice */ 336f1fa74f4SBenjamin Herrenschmidt return slice_get_unmapped_area(addr, len, flags, 337f1fa74f4SBenjamin Herrenschmidt MMU_PAGE_64K, 1, 0); 338f1fa74f4SBenjamin Herrenschmidt } 339f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 340f1fa74f4SBenjamin Herrenschmidt 3415dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = { 34267207b96SArnd Bergmann .open = spufs_mem_open, 343ce92987bSChristoph Hellwig .release = spufs_mem_release, 34467207b96SArnd Bergmann .read = spufs_mem_read, 34567207b96SArnd Bergmann .write = spufs_mem_write, 3468b3d6663SArnd Bergmann .llseek = generic_file_llseek, 34767207b96SArnd Bergmann .mmap = spufs_mem_mmap, 348f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 349f1fa74f4SBenjamin Herrenschmidt .get_unmapped_area = spufs_get_unmapped_area, 350f1fa74f4SBenjamin Herrenschmidt #endif 3518b3d6663SArnd Bergmann }; 3528b3d6663SArnd Bergmann 35378bde53eSBenjamin Herrenschmidt static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, 3546df10a82SMark Nutter unsigned long address, 35578bde53eSBenjamin Herrenschmidt unsigned long ps_offs, 35627d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 3576df10a82SMark Nutter { 3586df10a82SMark Nutter struct spu_context *ctx = vma->vm_file->private_data; 35978bde53eSBenjamin Herrenschmidt unsigned long area, offset = address - vma->vm_start; 3606df10a82SMark Nutter 3616df10a82SMark Nutter offset += vma->vm_pgoff << PAGE_SHIFT; 36227d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 36378bde53eSBenjamin Herrenschmidt return NOPFN_SIGBUS; 3646df10a82SMark Nutter 36533bfd7a7SArnd Bergmann /* 36633bfd7a7SArnd Bergmann * We have to wait for context to be loaded before we have 36733bfd7a7SArnd Bergmann * pages to hand out to the user, but we don't want to wait 36833bfd7a7SArnd Bergmann * with the mmap_sem held. 36933bfd7a7SArnd Bergmann * It is possible to drop the mmap_sem here, but then we need 37033bfd7a7SArnd Bergmann * to return NOPFN_REFAULT because the mappings may have 37133bfd7a7SArnd Bergmann * hanged. 37278bde53eSBenjamin Herrenschmidt */ 373c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 374c9101bdbSChristoph Hellwig return NOPFN_REFAULT; 375c9101bdbSChristoph Hellwig 37633bfd7a7SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 37733bfd7a7SArnd Bergmann up_read(¤t->mm->mmap_sem); 37833bfd7a7SArnd Bergmann spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 37933bfd7a7SArnd Bergmann down_read(¤t->mm->mmap_sem); 380c9101bdbSChristoph Hellwig } else { 3816df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 38278bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); 383c9101bdbSChristoph Hellwig } 38433bfd7a7SArnd Bergmann 3856df10a82SMark Nutter spu_release(ctx); 38678bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 3876df10a82SMark Nutter } 3886df10a82SMark Nutter 38927d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 39078bde53eSBenjamin Herrenschmidt static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, 39178bde53eSBenjamin Herrenschmidt unsigned long address) 3926df10a82SMark Nutter { 39378bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x4000, 0x1000); 3946df10a82SMark Nutter } 3956df10a82SMark Nutter 3966df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = { 39778bde53eSBenjamin Herrenschmidt .nopfn = spufs_cntl_mmap_nopfn, 3986df10a82SMark Nutter }; 3996df10a82SMark Nutter 4006df10a82SMark Nutter /* 4016df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 4026df10a82SMark Nutter */ 4036df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 4046df10a82SMark Nutter { 4056df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 4066df10a82SMark Nutter return -EINVAL; 4076df10a82SMark Nutter 40878bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 4096df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 41023cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 4116df10a82SMark Nutter 4126df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 4136df10a82SMark Nutter return 0; 4146df10a82SMark Nutter } 41527d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 41627d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 41727d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 4186df10a82SMark Nutter 419197b1a82SChristoph Hellwig static int spufs_cntl_get(void *data, u64 *val) 420e1dbff2bSArnd Bergmann { 421e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 422c9101bdbSChristoph Hellwig int ret; 423e1dbff2bSArnd Bergmann 424c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 425c9101bdbSChristoph Hellwig if (ret) 426c9101bdbSChristoph Hellwig return ret; 427197b1a82SChristoph Hellwig *val = ctx->ops->status_read(ctx); 428e1dbff2bSArnd Bergmann spu_release(ctx); 429e1dbff2bSArnd Bergmann 430197b1a82SChristoph Hellwig return 0; 431e1dbff2bSArnd Bergmann } 432e1dbff2bSArnd Bergmann 433197b1a82SChristoph Hellwig static int spufs_cntl_set(void *data, u64 val) 434e1dbff2bSArnd Bergmann { 435e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 436c9101bdbSChristoph Hellwig int ret; 437e1dbff2bSArnd Bergmann 438c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 439c9101bdbSChristoph Hellwig if (ret) 440c9101bdbSChristoph Hellwig return ret; 441e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 442e1dbff2bSArnd Bergmann spu_release(ctx); 443197b1a82SChristoph Hellwig 444197b1a82SChristoph Hellwig return 0; 445e1dbff2bSArnd Bergmann } 446e1dbff2bSArnd Bergmann 4476df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 4486df10a82SMark Nutter { 4496df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 4506df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 4516df10a82SMark Nutter 45247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 4536df10a82SMark Nutter file->private_data = ctx; 45443c2bbd9SChristoph Hellwig if (!i->i_openers++) 4556df10a82SMark Nutter ctx->cntl = inode->i_mapping; 45647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 457197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, spufs_cntl_get, 458e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 4596df10a82SMark Nutter } 4606df10a82SMark Nutter 46143c2bbd9SChristoph Hellwig static int 46243c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file) 46343c2bbd9SChristoph Hellwig { 46443c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 46543c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 46643c2bbd9SChristoph Hellwig 467197b1a82SChristoph Hellwig spufs_attr_release(inode, file); 46843c2bbd9SChristoph Hellwig 46947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 47043c2bbd9SChristoph Hellwig if (!--i->i_openers) 47143c2bbd9SChristoph Hellwig ctx->cntl = NULL; 47247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 47343c2bbd9SChristoph Hellwig return 0; 47443c2bbd9SChristoph Hellwig } 47543c2bbd9SChristoph Hellwig 4765dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = { 4776df10a82SMark Nutter .open = spufs_cntl_open, 47843c2bbd9SChristoph Hellwig .release = spufs_cntl_release, 479197b1a82SChristoph Hellwig .read = spufs_attr_read, 480197b1a82SChristoph Hellwig .write = spufs_attr_write, 4816df10a82SMark Nutter .mmap = spufs_cntl_mmap, 4826df10a82SMark Nutter }; 4836df10a82SMark Nutter 4848b3d6663SArnd Bergmann static int 4858b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 4868b3d6663SArnd Bergmann { 4878b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 4888b3d6663SArnd Bergmann file->private_data = i->i_ctx; 4898b3d6663SArnd Bergmann return 0; 4908b3d6663SArnd Bergmann } 4918b3d6663SArnd Bergmann 4928b3d6663SArnd Bergmann static ssize_t 493bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer, 494bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 495bf1ab978SDwayne Grant McConnell { 496bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 497bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 498bf1ab978SDwayne Grant McConnell lscsa->gprs, sizeof lscsa->gprs); 499bf1ab978SDwayne Grant McConnell } 500bf1ab978SDwayne Grant McConnell 501bf1ab978SDwayne Grant McConnell static ssize_t 5028b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 5038b3d6663SArnd Bergmann size_t size, loff_t *pos) 5048b3d6663SArnd Bergmann { 5058b3d6663SArnd Bergmann int ret; 506bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5078b3d6663SArnd Bergmann 508c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 509c9101bdbSChristoph Hellwig if (ret) 510c9101bdbSChristoph Hellwig return ret; 511bf1ab978SDwayne Grant McConnell ret = __spufs_regs_read(ctx, buffer, size, pos); 51227b1ea09SChristoph Hellwig spu_release_saved(ctx); 5138b3d6663SArnd Bergmann return ret; 5148b3d6663SArnd Bergmann } 5158b3d6663SArnd Bergmann 5168b3d6663SArnd Bergmann static ssize_t 5178b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 5188b3d6663SArnd Bergmann size_t size, loff_t *pos) 5198b3d6663SArnd Bergmann { 5208b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5218b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5228b3d6663SArnd Bergmann int ret; 5238b3d6663SArnd Bergmann 5248b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 5258b3d6663SArnd Bergmann if (size <= 0) 5268b3d6663SArnd Bergmann return -EFBIG; 5278b3d6663SArnd Bergmann *pos += size; 5288b3d6663SArnd Bergmann 529c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 530c9101bdbSChristoph Hellwig if (ret) 531c9101bdbSChristoph Hellwig return ret; 5328b3d6663SArnd Bergmann 5338b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 5348b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 5358b3d6663SArnd Bergmann 53627b1ea09SChristoph Hellwig spu_release_saved(ctx); 5378b3d6663SArnd Bergmann return ret; 5388b3d6663SArnd Bergmann } 5398b3d6663SArnd Bergmann 5405dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = { 5418b3d6663SArnd Bergmann .open = spufs_regs_open, 5428b3d6663SArnd Bergmann .read = spufs_regs_read, 5438b3d6663SArnd Bergmann .write = spufs_regs_write, 5448b3d6663SArnd Bergmann .llseek = generic_file_llseek, 5458b3d6663SArnd Bergmann }; 5468b3d6663SArnd Bergmann 5478b3d6663SArnd Bergmann static ssize_t 548bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, 549bf1ab978SDwayne Grant McConnell size_t size, loff_t * pos) 550bf1ab978SDwayne Grant McConnell { 551bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 552bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 553bf1ab978SDwayne Grant McConnell &lscsa->fpcr, sizeof(lscsa->fpcr)); 554bf1ab978SDwayne Grant McConnell } 555bf1ab978SDwayne Grant McConnell 556bf1ab978SDwayne Grant McConnell static ssize_t 5578b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 5588b3d6663SArnd Bergmann size_t size, loff_t * pos) 5598b3d6663SArnd Bergmann { 5608b3d6663SArnd Bergmann int ret; 561bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5628b3d6663SArnd Bergmann 563c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 564c9101bdbSChristoph Hellwig if (ret) 565c9101bdbSChristoph Hellwig return ret; 566bf1ab978SDwayne Grant McConnell ret = __spufs_fpcr_read(ctx, buffer, size, pos); 56727b1ea09SChristoph Hellwig spu_release_saved(ctx); 5688b3d6663SArnd Bergmann return ret; 5698b3d6663SArnd Bergmann } 5708b3d6663SArnd Bergmann 5718b3d6663SArnd Bergmann static ssize_t 5728b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 5738b3d6663SArnd Bergmann size_t size, loff_t * pos) 5748b3d6663SArnd Bergmann { 5758b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5768b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5778b3d6663SArnd Bergmann int ret; 5788b3d6663SArnd Bergmann 5798b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 5808b3d6663SArnd Bergmann if (size <= 0) 5818b3d6663SArnd Bergmann return -EFBIG; 582c9101bdbSChristoph Hellwig 583c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 584c9101bdbSChristoph Hellwig if (ret) 585c9101bdbSChristoph Hellwig return ret; 586c9101bdbSChristoph Hellwig 5878b3d6663SArnd Bergmann *pos += size; 5888b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 5898b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 5908b3d6663SArnd Bergmann 59127b1ea09SChristoph Hellwig spu_release_saved(ctx); 5928b3d6663SArnd Bergmann return ret; 5938b3d6663SArnd Bergmann } 5948b3d6663SArnd Bergmann 5955dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = { 5968b3d6663SArnd Bergmann .open = spufs_regs_open, 5978b3d6663SArnd Bergmann .read = spufs_fpcr_read, 5988b3d6663SArnd Bergmann .write = spufs_fpcr_write, 59967207b96SArnd Bergmann .llseek = generic_file_llseek, 60067207b96SArnd Bergmann }; 60167207b96SArnd Bergmann 60267207b96SArnd Bergmann /* generic open function for all pipe-like files */ 60367207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 60467207b96SArnd Bergmann { 60567207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 60667207b96SArnd Bergmann file->private_data = i->i_ctx; 60767207b96SArnd Bergmann 60867207b96SArnd Bergmann return nonseekable_open(inode, file); 60967207b96SArnd Bergmann } 61067207b96SArnd Bergmann 611cdcc89bbSArnd Bergmann /* 612cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 613cdcc89bbSArnd Bergmann * one of the conditions becomes true: 614cdcc89bbSArnd Bergmann * 615cdcc89bbSArnd Bergmann * - no more data available in the mailbox 616cdcc89bbSArnd Bergmann * - end of the user provided buffer 617cdcc89bbSArnd Bergmann * - end of the mapped area 618cdcc89bbSArnd Bergmann */ 61967207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 62067207b96SArnd Bergmann size_t len, loff_t *pos) 62167207b96SArnd Bergmann { 6228b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 623cdcc89bbSArnd Bergmann u32 mbox_data, __user *udata; 624cdcc89bbSArnd Bergmann ssize_t count; 62567207b96SArnd Bergmann 62667207b96SArnd Bergmann if (len < 4) 62767207b96SArnd Bergmann return -EINVAL; 62867207b96SArnd Bergmann 629cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 63067207b96SArnd Bergmann return -EFAULT; 63167207b96SArnd Bergmann 632cdcc89bbSArnd Bergmann udata = (void __user *)buf; 633cdcc89bbSArnd Bergmann 634c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 635c9101bdbSChristoph Hellwig if (count) 636c9101bdbSChristoph Hellwig return count; 637c9101bdbSChristoph Hellwig 638274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 639cdcc89bbSArnd Bergmann int ret; 640cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 641cdcc89bbSArnd Bergmann if (ret == 0) 642cdcc89bbSArnd Bergmann break; 643cdcc89bbSArnd Bergmann 644cdcc89bbSArnd Bergmann /* 645cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 646cdcc89bbSArnd Bergmann * but still need to return the data we have 647cdcc89bbSArnd Bergmann * read successfully so far. 648cdcc89bbSArnd Bergmann */ 649cdcc89bbSArnd Bergmann ret = __put_user(mbox_data, udata); 650cdcc89bbSArnd Bergmann if (ret) { 651cdcc89bbSArnd Bergmann if (!count) 652cdcc89bbSArnd Bergmann count = -EFAULT; 653cdcc89bbSArnd Bergmann break; 654cdcc89bbSArnd Bergmann } 655cdcc89bbSArnd Bergmann } 656cdcc89bbSArnd Bergmann spu_release(ctx); 657cdcc89bbSArnd Bergmann 658cdcc89bbSArnd Bergmann if (!count) 659cdcc89bbSArnd Bergmann count = -EAGAIN; 660cdcc89bbSArnd Bergmann 661cdcc89bbSArnd Bergmann return count; 66267207b96SArnd Bergmann } 66367207b96SArnd Bergmann 6645dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = { 66567207b96SArnd Bergmann .open = spufs_pipe_open, 66667207b96SArnd Bergmann .read = spufs_mbox_read, 66767207b96SArnd Bergmann }; 66867207b96SArnd Bergmann 66967207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 67067207b96SArnd Bergmann size_t len, loff_t *pos) 67167207b96SArnd Bergmann { 6728b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 673c9101bdbSChristoph Hellwig ssize_t ret; 67467207b96SArnd Bergmann u32 mbox_stat; 67567207b96SArnd Bergmann 67667207b96SArnd Bergmann if (len < 4) 67767207b96SArnd Bergmann return -EINVAL; 67867207b96SArnd Bergmann 679c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 680c9101bdbSChristoph Hellwig if (ret) 681c9101bdbSChristoph Hellwig return ret; 6828b3d6663SArnd Bergmann 6838b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 6848b3d6663SArnd Bergmann 6858b3d6663SArnd Bergmann spu_release(ctx); 68667207b96SArnd Bergmann 68767207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 68867207b96SArnd Bergmann return -EFAULT; 68967207b96SArnd Bergmann 69067207b96SArnd Bergmann return 4; 69167207b96SArnd Bergmann } 69267207b96SArnd Bergmann 6935dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = { 69467207b96SArnd Bergmann .open = spufs_pipe_open, 69567207b96SArnd Bergmann .read = spufs_mbox_stat_read, 69667207b96SArnd Bergmann }; 69767207b96SArnd Bergmann 69867207b96SArnd Bergmann /* low-level ibox access function */ 6998b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 70067207b96SArnd Bergmann { 7018b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 70267207b96SArnd Bergmann } 70367207b96SArnd Bergmann 70467207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 70567207b96SArnd Bergmann { 7068b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 7078b3d6663SArnd Bergmann 7088b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 7098b3d6663SArnd Bergmann } 7108b3d6663SArnd Bergmann 7118b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 7128b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 7138b3d6663SArnd Bergmann { 7148b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 7158b3d6663SArnd Bergmann 716e65c2f6fSLuke Browning if (!ctx) 717e65c2f6fSLuke Browning return; 718e65c2f6fSLuke Browning 7198b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 7208b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 72167207b96SArnd Bergmann } 72267207b96SArnd Bergmann 723cdcc89bbSArnd Bergmann /* 724cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 725cdcc89bbSArnd Bergmann * one of the conditions becomes true: 726cdcc89bbSArnd Bergmann * 727cdcc89bbSArnd Bergmann * - no more data available in the mailbox 728cdcc89bbSArnd Bergmann * - end of the user provided buffer 729cdcc89bbSArnd Bergmann * - end of the mapped area 730cdcc89bbSArnd Bergmann * 731cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 732cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 733cdcc89bbSArnd Bergmann * read something. 734cdcc89bbSArnd Bergmann */ 73567207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 73667207b96SArnd Bergmann size_t len, loff_t *pos) 73767207b96SArnd Bergmann { 7388b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 739cdcc89bbSArnd Bergmann u32 ibox_data, __user *udata; 740cdcc89bbSArnd Bergmann ssize_t count; 74167207b96SArnd Bergmann 74267207b96SArnd Bergmann if (len < 4) 74367207b96SArnd Bergmann return -EINVAL; 74467207b96SArnd Bergmann 745cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 746cdcc89bbSArnd Bergmann return -EFAULT; 747cdcc89bbSArnd Bergmann 748cdcc89bbSArnd Bergmann udata = (void __user *)buf; 749cdcc89bbSArnd Bergmann 750c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 751c9101bdbSChristoph Hellwig if (count) 752c9101bdbSChristoph Hellwig return count; 75367207b96SArnd Bergmann 754cdcc89bbSArnd Bergmann /* wait only for the first element */ 755cdcc89bbSArnd Bergmann count = 0; 75667207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 7578b3d6663SArnd Bergmann if (!spu_ibox_read(ctx, &ibox_data)) 758cdcc89bbSArnd Bergmann count = -EAGAIN; 75967207b96SArnd Bergmann } else { 760cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 761cdcc89bbSArnd Bergmann } 762cdcc89bbSArnd Bergmann if (count) 763cdcc89bbSArnd Bergmann goto out; 764cdcc89bbSArnd Bergmann 765cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 766cdcc89bbSArnd Bergmann count = __put_user(ibox_data, udata); 767cdcc89bbSArnd Bergmann if (count) 768cdcc89bbSArnd Bergmann goto out; 769cdcc89bbSArnd Bergmann 770cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 771cdcc89bbSArnd Bergmann int ret; 772cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 773cdcc89bbSArnd Bergmann if (ret == 0) 774cdcc89bbSArnd Bergmann break; 775cdcc89bbSArnd Bergmann /* 776cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 777cdcc89bbSArnd Bergmann * but still need to return the data we have 778cdcc89bbSArnd Bergmann * read successfully so far. 779cdcc89bbSArnd Bergmann */ 780cdcc89bbSArnd Bergmann ret = __put_user(ibox_data, udata); 781cdcc89bbSArnd Bergmann if (ret) 782cdcc89bbSArnd Bergmann break; 78367207b96SArnd Bergmann } 78467207b96SArnd Bergmann 785cdcc89bbSArnd Bergmann out: 7868b3d6663SArnd Bergmann spu_release(ctx); 7878b3d6663SArnd Bergmann 788cdcc89bbSArnd Bergmann return count; 78967207b96SArnd Bergmann } 79067207b96SArnd Bergmann 79167207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 79267207b96SArnd Bergmann { 7938b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 79467207b96SArnd Bergmann unsigned int mask; 79567207b96SArnd Bergmann 7968b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 79767207b96SArnd Bergmann 798c9101bdbSChristoph Hellwig /* 799c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 800c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 801c9101bdbSChristoph Hellwig */ 802c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 8033a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 8043a843d7cSArnd Bergmann spu_release(ctx); 80567207b96SArnd Bergmann 80667207b96SArnd Bergmann return mask; 80767207b96SArnd Bergmann } 80867207b96SArnd Bergmann 8095dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = { 81067207b96SArnd Bergmann .open = spufs_pipe_open, 81167207b96SArnd Bergmann .read = spufs_ibox_read, 81267207b96SArnd Bergmann .poll = spufs_ibox_poll, 81367207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 81467207b96SArnd Bergmann }; 81567207b96SArnd Bergmann 81667207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 81767207b96SArnd Bergmann size_t len, loff_t *pos) 81867207b96SArnd Bergmann { 8198b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 820c9101bdbSChristoph Hellwig ssize_t ret; 82167207b96SArnd Bergmann u32 ibox_stat; 82267207b96SArnd Bergmann 82367207b96SArnd Bergmann if (len < 4) 82467207b96SArnd Bergmann return -EINVAL; 82567207b96SArnd Bergmann 826c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 827c9101bdbSChristoph Hellwig if (ret) 828c9101bdbSChristoph Hellwig return ret; 8298b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 8308b3d6663SArnd Bergmann spu_release(ctx); 83167207b96SArnd Bergmann 83267207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 83367207b96SArnd Bergmann return -EFAULT; 83467207b96SArnd Bergmann 83567207b96SArnd Bergmann return 4; 83667207b96SArnd Bergmann } 83767207b96SArnd Bergmann 8385dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = { 83967207b96SArnd Bergmann .open = spufs_pipe_open, 84067207b96SArnd Bergmann .read = spufs_ibox_stat_read, 84167207b96SArnd Bergmann }; 84267207b96SArnd Bergmann 84367207b96SArnd Bergmann /* low-level mailbox write */ 8448b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 84567207b96SArnd Bergmann { 8468b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 84767207b96SArnd Bergmann } 84867207b96SArnd Bergmann 84967207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 85067207b96SArnd Bergmann { 8518b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 8528b3d6663SArnd Bergmann int ret; 8538b3d6663SArnd Bergmann 8548b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 8558b3d6663SArnd Bergmann 8568b3d6663SArnd Bergmann return ret; 8578b3d6663SArnd Bergmann } 8588b3d6663SArnd Bergmann 8598b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 8608b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 8618b3d6663SArnd Bergmann { 8628b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 8638b3d6663SArnd Bergmann 864e65c2f6fSLuke Browning if (!ctx) 865e65c2f6fSLuke Browning return; 866e65c2f6fSLuke Browning 8678b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 8688b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 86967207b96SArnd Bergmann } 87067207b96SArnd Bergmann 871cdcc89bbSArnd Bergmann /* 872cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 873cdcc89bbSArnd Bergmann * one of the conditions becomes true: 874cdcc89bbSArnd Bergmann * 875cdcc89bbSArnd Bergmann * - the mailbox is full 876cdcc89bbSArnd Bergmann * - end of the user provided buffer 877cdcc89bbSArnd Bergmann * - end of the mapped area 878cdcc89bbSArnd Bergmann * 879cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 880cdcc89bbSArnd Bergmann * space is availabyl, but return when we have been able to 881cdcc89bbSArnd Bergmann * write something. 882cdcc89bbSArnd Bergmann */ 88367207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 88467207b96SArnd Bergmann size_t len, loff_t *pos) 88567207b96SArnd Bergmann { 8868b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 887cdcc89bbSArnd Bergmann u32 wbox_data, __user *udata; 888cdcc89bbSArnd Bergmann ssize_t count; 88967207b96SArnd Bergmann 89067207b96SArnd Bergmann if (len < 4) 89167207b96SArnd Bergmann return -EINVAL; 89267207b96SArnd Bergmann 893cdcc89bbSArnd Bergmann udata = (void __user *)buf; 894cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_READ, buf, len)) 895cdcc89bbSArnd Bergmann return -EFAULT; 896cdcc89bbSArnd Bergmann 897cdcc89bbSArnd Bergmann if (__get_user(wbox_data, udata)) 89867207b96SArnd Bergmann return -EFAULT; 89967207b96SArnd Bergmann 900c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 901c9101bdbSChristoph Hellwig if (count) 902c9101bdbSChristoph Hellwig return count; 9038b3d6663SArnd Bergmann 904cdcc89bbSArnd Bergmann /* 905cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 906cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 907cdcc89bbSArnd Bergmann */ 908cdcc89bbSArnd Bergmann count = 0; 90967207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 9108b3d6663SArnd Bergmann if (!spu_wbox_write(ctx, wbox_data)) 911cdcc89bbSArnd Bergmann count = -EAGAIN; 91267207b96SArnd Bergmann } else { 913cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 91467207b96SArnd Bergmann } 91567207b96SArnd Bergmann 916cdcc89bbSArnd Bergmann if (count) 917cdcc89bbSArnd Bergmann goto out; 9188b3d6663SArnd Bergmann 91996de0e25SJan Engelhardt /* write as much as possible */ 920cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 921cdcc89bbSArnd Bergmann int ret; 922cdcc89bbSArnd Bergmann ret = __get_user(wbox_data, udata); 923cdcc89bbSArnd Bergmann if (ret) 924cdcc89bbSArnd Bergmann break; 925cdcc89bbSArnd Bergmann 926cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 927cdcc89bbSArnd Bergmann if (ret == 0) 928cdcc89bbSArnd Bergmann break; 929cdcc89bbSArnd Bergmann } 930cdcc89bbSArnd Bergmann 931cdcc89bbSArnd Bergmann out: 932cdcc89bbSArnd Bergmann spu_release(ctx); 933cdcc89bbSArnd Bergmann return count; 93467207b96SArnd Bergmann } 93567207b96SArnd Bergmann 93667207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 93767207b96SArnd Bergmann { 9388b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 93967207b96SArnd Bergmann unsigned int mask; 94067207b96SArnd Bergmann 9418b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 94267207b96SArnd Bergmann 943c9101bdbSChristoph Hellwig /* 944c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 945c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 946c9101bdbSChristoph Hellwig */ 947c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 9483a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 9493a843d7cSArnd Bergmann spu_release(ctx); 95067207b96SArnd Bergmann 95167207b96SArnd Bergmann return mask; 95267207b96SArnd Bergmann } 95367207b96SArnd Bergmann 9545dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = { 95567207b96SArnd Bergmann .open = spufs_pipe_open, 95667207b96SArnd Bergmann .write = spufs_wbox_write, 95767207b96SArnd Bergmann .poll = spufs_wbox_poll, 95867207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 95967207b96SArnd Bergmann }; 96067207b96SArnd Bergmann 96167207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 96267207b96SArnd Bergmann size_t len, loff_t *pos) 96367207b96SArnd Bergmann { 9648b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 965c9101bdbSChristoph Hellwig ssize_t ret; 96667207b96SArnd Bergmann u32 wbox_stat; 96767207b96SArnd Bergmann 96867207b96SArnd Bergmann if (len < 4) 96967207b96SArnd Bergmann return -EINVAL; 97067207b96SArnd Bergmann 971c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 972c9101bdbSChristoph Hellwig if (ret) 973c9101bdbSChristoph Hellwig return ret; 9748b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 9758b3d6663SArnd Bergmann spu_release(ctx); 97667207b96SArnd Bergmann 97767207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 97867207b96SArnd Bergmann return -EFAULT; 97967207b96SArnd Bergmann 98067207b96SArnd Bergmann return 4; 98167207b96SArnd Bergmann } 98267207b96SArnd Bergmann 9835dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = { 98467207b96SArnd Bergmann .open = spufs_pipe_open, 98567207b96SArnd Bergmann .read = spufs_wbox_stat_read, 98667207b96SArnd Bergmann }; 98767207b96SArnd Bergmann 9886df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 9896df10a82SMark Nutter { 9906df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 9916df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 99243c2bbd9SChristoph Hellwig 99347d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 9946df10a82SMark Nutter file->private_data = ctx; 99543c2bbd9SChristoph Hellwig if (!i->i_openers++) 9966df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 99747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 9986df10a82SMark Nutter return nonseekable_open(inode, file); 9996df10a82SMark Nutter } 10006df10a82SMark Nutter 100143c2bbd9SChristoph Hellwig static int 100243c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file) 100343c2bbd9SChristoph Hellwig { 100443c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 100543c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 100643c2bbd9SChristoph Hellwig 100747d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 100843c2bbd9SChristoph Hellwig if (!--i->i_openers) 100943c2bbd9SChristoph Hellwig ctx->signal1 = NULL; 101047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 101143c2bbd9SChristoph Hellwig return 0; 101243c2bbd9SChristoph Hellwig } 101343c2bbd9SChristoph Hellwig 1014bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 101567207b96SArnd Bergmann size_t len, loff_t *pos) 101667207b96SArnd Bergmann { 101717f88cebSDwayne Grant McConnell int ret = 0; 101867207b96SArnd Bergmann u32 data; 101967207b96SArnd Bergmann 102067207b96SArnd Bergmann if (len < 4) 102167207b96SArnd Bergmann return -EINVAL; 102267207b96SArnd Bergmann 102317f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[3]) { 102417f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[3]; 102517f88cebSDwayne Grant McConnell ret = 4; 102617f88cebSDwayne Grant McConnell } 10278b3d6663SArnd Bergmann 102817f88cebSDwayne Grant McConnell if (!ret) 102917f88cebSDwayne Grant McConnell goto out; 103017f88cebSDwayne Grant McConnell 103167207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 103267207b96SArnd Bergmann return -EFAULT; 103367207b96SArnd Bergmann 103417f88cebSDwayne Grant McConnell out: 103517f88cebSDwayne Grant McConnell return ret; 103667207b96SArnd Bergmann } 103767207b96SArnd Bergmann 1038bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 1039bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1040bf1ab978SDwayne Grant McConnell { 1041bf1ab978SDwayne Grant McConnell int ret; 1042bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1043bf1ab978SDwayne Grant McConnell 1044c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1045c9101bdbSChristoph Hellwig if (ret) 1046c9101bdbSChristoph Hellwig return ret; 1047bf1ab978SDwayne Grant McConnell ret = __spufs_signal1_read(ctx, buf, len, pos); 104827b1ea09SChristoph Hellwig spu_release_saved(ctx); 1049bf1ab978SDwayne Grant McConnell 1050bf1ab978SDwayne Grant McConnell return ret; 1051bf1ab978SDwayne Grant McConnell } 1052bf1ab978SDwayne Grant McConnell 105367207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 105467207b96SArnd Bergmann size_t len, loff_t *pos) 105567207b96SArnd Bergmann { 105667207b96SArnd Bergmann struct spu_context *ctx; 1057c9101bdbSChristoph Hellwig ssize_t ret; 105867207b96SArnd Bergmann u32 data; 105967207b96SArnd Bergmann 106067207b96SArnd Bergmann ctx = file->private_data; 106167207b96SArnd Bergmann 106267207b96SArnd Bergmann if (len < 4) 106367207b96SArnd Bergmann return -EINVAL; 106467207b96SArnd Bergmann 106567207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 106667207b96SArnd Bergmann return -EFAULT; 106767207b96SArnd Bergmann 1068c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1069c9101bdbSChristoph Hellwig if (ret) 1070c9101bdbSChristoph Hellwig return ret; 10718b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 10728b3d6663SArnd Bergmann spu_release(ctx); 107367207b96SArnd Bergmann 107467207b96SArnd Bergmann return 4; 107567207b96SArnd Bergmann } 107667207b96SArnd Bergmann 107778bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma, 107878bde53eSBenjamin Herrenschmidt unsigned long address) 10796df10a82SMark Nutter { 108027d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 108178bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x14000, 0x1000); 108227d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 108327d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 108427d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 108527d5bf2aSBenjamin Herrenschmidt */ 108678bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 108727d5bf2aSBenjamin Herrenschmidt #else 108827d5bf2aSBenjamin Herrenschmidt #error unsupported page size 108927d5bf2aSBenjamin Herrenschmidt #endif 10906df10a82SMark Nutter } 10916df10a82SMark Nutter 10926df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = { 109378bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal1_mmap_nopfn, 10946df10a82SMark Nutter }; 10956df10a82SMark Nutter 10966df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 10976df10a82SMark Nutter { 10986df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 10996df10a82SMark Nutter return -EINVAL; 11006df10a82SMark Nutter 110178bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 11026df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 110323cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 11046df10a82SMark Nutter 11056df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 11066df10a82SMark Nutter return 0; 11076df10a82SMark Nutter } 11086df10a82SMark Nutter 11095dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = { 11106df10a82SMark Nutter .open = spufs_signal1_open, 111143c2bbd9SChristoph Hellwig .release = spufs_signal1_release, 111267207b96SArnd Bergmann .read = spufs_signal1_read, 111367207b96SArnd Bergmann .write = spufs_signal1_write, 11146df10a82SMark Nutter .mmap = spufs_signal1_mmap, 111567207b96SArnd Bergmann }; 111667207b96SArnd Bergmann 1117d054b36fSJeremy Kerr static const struct file_operations spufs_signal1_nosched_fops = { 1118d054b36fSJeremy Kerr .open = spufs_signal1_open, 1119d054b36fSJeremy Kerr .release = spufs_signal1_release, 1120d054b36fSJeremy Kerr .write = spufs_signal1_write, 1121d054b36fSJeremy Kerr .mmap = spufs_signal1_mmap, 1122d054b36fSJeremy Kerr }; 1123d054b36fSJeremy Kerr 11246df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 11256df10a82SMark Nutter { 11266df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 11276df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 112843c2bbd9SChristoph Hellwig 112947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 11306df10a82SMark Nutter file->private_data = ctx; 113143c2bbd9SChristoph Hellwig if (!i->i_openers++) 11326df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 113347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 11346df10a82SMark Nutter return nonseekable_open(inode, file); 11356df10a82SMark Nutter } 11366df10a82SMark Nutter 113743c2bbd9SChristoph Hellwig static int 113843c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file) 113943c2bbd9SChristoph Hellwig { 114043c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 114143c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 114243c2bbd9SChristoph Hellwig 114347d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 114443c2bbd9SChristoph Hellwig if (!--i->i_openers) 114543c2bbd9SChristoph Hellwig ctx->signal2 = NULL; 114647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 114743c2bbd9SChristoph Hellwig return 0; 114843c2bbd9SChristoph Hellwig } 114943c2bbd9SChristoph Hellwig 1150bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 115167207b96SArnd Bergmann size_t len, loff_t *pos) 115267207b96SArnd Bergmann { 115317f88cebSDwayne Grant McConnell int ret = 0; 115467207b96SArnd Bergmann u32 data; 115567207b96SArnd Bergmann 115667207b96SArnd Bergmann if (len < 4) 115767207b96SArnd Bergmann return -EINVAL; 115867207b96SArnd Bergmann 115917f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[4]) { 116017f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[4]; 116117f88cebSDwayne Grant McConnell ret = 4; 116217f88cebSDwayne Grant McConnell } 11638b3d6663SArnd Bergmann 116417f88cebSDwayne Grant McConnell if (!ret) 116517f88cebSDwayne Grant McConnell goto out; 116617f88cebSDwayne Grant McConnell 116767207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 116867207b96SArnd Bergmann return -EFAULT; 116967207b96SArnd Bergmann 117017f88cebSDwayne Grant McConnell out: 1171bf1ab978SDwayne Grant McConnell return ret; 1172bf1ab978SDwayne Grant McConnell } 1173bf1ab978SDwayne Grant McConnell 1174bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 1175bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1176bf1ab978SDwayne Grant McConnell { 1177bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1178bf1ab978SDwayne Grant McConnell int ret; 1179bf1ab978SDwayne Grant McConnell 1180c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1181c9101bdbSChristoph Hellwig if (ret) 1182c9101bdbSChristoph Hellwig return ret; 1183bf1ab978SDwayne Grant McConnell ret = __spufs_signal2_read(ctx, buf, len, pos); 118427b1ea09SChristoph Hellwig spu_release_saved(ctx); 1185bf1ab978SDwayne Grant McConnell 1186bf1ab978SDwayne Grant McConnell return ret; 118767207b96SArnd Bergmann } 118867207b96SArnd Bergmann 118967207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 119067207b96SArnd Bergmann size_t len, loff_t *pos) 119167207b96SArnd Bergmann { 119267207b96SArnd Bergmann struct spu_context *ctx; 1193c9101bdbSChristoph Hellwig ssize_t ret; 119467207b96SArnd Bergmann u32 data; 119567207b96SArnd Bergmann 119667207b96SArnd Bergmann ctx = file->private_data; 119767207b96SArnd Bergmann 119867207b96SArnd Bergmann if (len < 4) 119967207b96SArnd Bergmann return -EINVAL; 120067207b96SArnd Bergmann 120167207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 120267207b96SArnd Bergmann return -EFAULT; 120367207b96SArnd Bergmann 1204c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1205c9101bdbSChristoph Hellwig if (ret) 1206c9101bdbSChristoph Hellwig return ret; 12078b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 12088b3d6663SArnd Bergmann spu_release(ctx); 120967207b96SArnd Bergmann 121067207b96SArnd Bergmann return 4; 121167207b96SArnd Bergmann } 121267207b96SArnd Bergmann 121327d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 121478bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma, 121578bde53eSBenjamin Herrenschmidt unsigned long address) 12166df10a82SMark Nutter { 121727d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 121878bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000); 121927d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 122027d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 122127d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 122227d5bf2aSBenjamin Herrenschmidt */ 122378bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 122427d5bf2aSBenjamin Herrenschmidt #else 122527d5bf2aSBenjamin Herrenschmidt #error unsupported page size 122627d5bf2aSBenjamin Herrenschmidt #endif 12276df10a82SMark Nutter } 12286df10a82SMark Nutter 12296df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = { 123078bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal2_mmap_nopfn, 12316df10a82SMark Nutter }; 12326df10a82SMark Nutter 12336df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 12346df10a82SMark Nutter { 12356df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 12366df10a82SMark Nutter return -EINVAL; 12376df10a82SMark Nutter 123878bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 12396df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 124023cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 12416df10a82SMark Nutter 12426df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 12436df10a82SMark Nutter return 0; 12446df10a82SMark Nutter } 124527d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 124627d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 124727d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 12486df10a82SMark Nutter 12495dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = { 12506df10a82SMark Nutter .open = spufs_signal2_open, 125143c2bbd9SChristoph Hellwig .release = spufs_signal2_release, 125267207b96SArnd Bergmann .read = spufs_signal2_read, 125367207b96SArnd Bergmann .write = spufs_signal2_write, 12546df10a82SMark Nutter .mmap = spufs_signal2_mmap, 125567207b96SArnd Bergmann }; 125667207b96SArnd Bergmann 1257d054b36fSJeremy Kerr static const struct file_operations spufs_signal2_nosched_fops = { 1258d054b36fSJeremy Kerr .open = spufs_signal2_open, 1259d054b36fSJeremy Kerr .release = spufs_signal2_release, 1260d054b36fSJeremy Kerr .write = spufs_signal2_write, 1261d054b36fSJeremy Kerr .mmap = spufs_signal2_mmap, 1262d054b36fSJeremy Kerr }; 1263d054b36fSJeremy Kerr 1264104f0cc2SMichael Ellerman /* 1265104f0cc2SMichael Ellerman * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the 1266104f0cc2SMichael Ellerman * work of acquiring (or not) the SPU context before calling through 1267104f0cc2SMichael Ellerman * to the actual get routine. The set routine is called directly. 1268104f0cc2SMichael Ellerman */ 1269104f0cc2SMichael Ellerman #define SPU_ATTR_NOACQUIRE 0 1270104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE 1 1271104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE_SAVED 2 1272104f0cc2SMichael Ellerman 1273104f0cc2SMichael Ellerman #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ 1274197b1a82SChristoph Hellwig static int __##__get(void *data, u64 *val) \ 1275104f0cc2SMichael Ellerman { \ 1276104f0cc2SMichael Ellerman struct spu_context *ctx = data; \ 1277c9101bdbSChristoph Hellwig int ret = 0; \ 1278104f0cc2SMichael Ellerman \ 1279104f0cc2SMichael Ellerman if (__acquire == SPU_ATTR_ACQUIRE) { \ 1280c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); \ 1281c9101bdbSChristoph Hellwig if (ret) \ 1282c9101bdbSChristoph Hellwig return ret; \ 1283197b1a82SChristoph Hellwig *val = __get(ctx); \ 1284104f0cc2SMichael Ellerman spu_release(ctx); \ 1285104f0cc2SMichael Ellerman } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ 1286c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); \ 1287c9101bdbSChristoph Hellwig if (ret) \ 1288c9101bdbSChristoph Hellwig return ret; \ 1289197b1a82SChristoph Hellwig *val = __get(ctx); \ 1290104f0cc2SMichael Ellerman spu_release_saved(ctx); \ 1291104f0cc2SMichael Ellerman } else \ 1292197b1a82SChristoph Hellwig *val = __get(ctx); \ 1293104f0cc2SMichael Ellerman \ 1294197b1a82SChristoph Hellwig return 0; \ 1295104f0cc2SMichael Ellerman } \ 1296197b1a82SChristoph Hellwig DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); 1297104f0cc2SMichael Ellerman 1298197b1a82SChristoph Hellwig static int spufs_signal1_type_set(void *data, u64 val) 129967207b96SArnd Bergmann { 130067207b96SArnd Bergmann struct spu_context *ctx = data; 1301c9101bdbSChristoph Hellwig int ret; 130267207b96SArnd Bergmann 1303c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1304c9101bdbSChristoph Hellwig if (ret) 1305c9101bdbSChristoph Hellwig return ret; 13068b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 13078b3d6663SArnd Bergmann spu_release(ctx); 1308197b1a82SChristoph Hellwig 1309197b1a82SChristoph Hellwig return 0; 131067207b96SArnd Bergmann } 131167207b96SArnd Bergmann 1312104f0cc2SMichael Ellerman static u64 spufs_signal1_type_get(struct spu_context *ctx) 1313bf1ab978SDwayne Grant McConnell { 1314bf1ab978SDwayne Grant McConnell return ctx->ops->signal1_type_get(ctx); 1315bf1ab978SDwayne Grant McConnell } 1316104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 1317104f0cc2SMichael Ellerman spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); 1318bf1ab978SDwayne Grant McConnell 131967207b96SArnd Bergmann 1320197b1a82SChristoph Hellwig static int spufs_signal2_type_set(void *data, u64 val) 132167207b96SArnd Bergmann { 132267207b96SArnd Bergmann struct spu_context *ctx = data; 1323c9101bdbSChristoph Hellwig int ret; 132467207b96SArnd Bergmann 1325c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1326c9101bdbSChristoph Hellwig if (ret) 1327c9101bdbSChristoph Hellwig return ret; 13288b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 13298b3d6663SArnd Bergmann spu_release(ctx); 1330197b1a82SChristoph Hellwig 1331197b1a82SChristoph Hellwig return 0; 133267207b96SArnd Bergmann } 133367207b96SArnd Bergmann 1334104f0cc2SMichael Ellerman static u64 spufs_signal2_type_get(struct spu_context *ctx) 1335bf1ab978SDwayne Grant McConnell { 1336bf1ab978SDwayne Grant McConnell return ctx->ops->signal2_type_get(ctx); 1337bf1ab978SDwayne Grant McConnell } 1338104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 1339104f0cc2SMichael Ellerman spufs_signal2_type_set, "%llu", SPU_ATTR_ACQUIRE); 134067207b96SArnd Bergmann 134127d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 134278bde53eSBenjamin Herrenschmidt static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, 134378bde53eSBenjamin Herrenschmidt unsigned long address) 1344d9379c4bSarnd@arndb.de { 134578bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x1000); 1346d9379c4bSarnd@arndb.de } 1347d9379c4bSarnd@arndb.de 1348d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = { 134978bde53eSBenjamin Herrenschmidt .nopfn = spufs_mss_mmap_nopfn, 1350d9379c4bSarnd@arndb.de }; 1351d9379c4bSarnd@arndb.de 1352d9379c4bSarnd@arndb.de /* 1353d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 1354d9379c4bSarnd@arndb.de */ 1355d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 1356d9379c4bSarnd@arndb.de { 1357d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 1358d9379c4bSarnd@arndb.de return -EINVAL; 1359d9379c4bSarnd@arndb.de 136078bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 1361d9379c4bSarnd@arndb.de vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 136223cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 1363d9379c4bSarnd@arndb.de 1364d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 1365d9379c4bSarnd@arndb.de return 0; 1366d9379c4bSarnd@arndb.de } 136727d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 136827d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 136927d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1370d9379c4bSarnd@arndb.de 1371d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 1372d9379c4bSarnd@arndb.de { 1373d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 137417e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 1375d9379c4bSarnd@arndb.de 1376d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 137743c2bbd9SChristoph Hellwig 137847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 137943c2bbd9SChristoph Hellwig if (!i->i_openers++) 138017e0e270SBenjamin Herrenschmidt ctx->mss = inode->i_mapping; 138147d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1382d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 1383d9379c4bSarnd@arndb.de } 1384d9379c4bSarnd@arndb.de 138543c2bbd9SChristoph Hellwig static int 138643c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file) 138743c2bbd9SChristoph Hellwig { 138843c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 138943c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 139043c2bbd9SChristoph Hellwig 139147d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 139243c2bbd9SChristoph Hellwig if (!--i->i_openers) 139343c2bbd9SChristoph Hellwig ctx->mss = NULL; 139447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 139543c2bbd9SChristoph Hellwig return 0; 139643c2bbd9SChristoph Hellwig } 139743c2bbd9SChristoph Hellwig 13985dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = { 1399d9379c4bSarnd@arndb.de .open = spufs_mss_open, 140043c2bbd9SChristoph Hellwig .release = spufs_mss_release, 1401d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 140227d5bf2aSBenjamin Herrenschmidt }; 140327d5bf2aSBenjamin Herrenschmidt 140478bde53eSBenjamin Herrenschmidt static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma, 140578bde53eSBenjamin Herrenschmidt unsigned long address) 140627d5bf2aSBenjamin Herrenschmidt { 140778bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x20000); 140827d5bf2aSBenjamin Herrenschmidt } 140927d5bf2aSBenjamin Herrenschmidt 141027d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = { 141178bde53eSBenjamin Herrenschmidt .nopfn = spufs_psmap_mmap_nopfn, 141227d5bf2aSBenjamin Herrenschmidt }; 141327d5bf2aSBenjamin Herrenschmidt 141427d5bf2aSBenjamin Herrenschmidt /* 141527d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 141627d5bf2aSBenjamin Herrenschmidt */ 141727d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 141827d5bf2aSBenjamin Herrenschmidt { 141927d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 142027d5bf2aSBenjamin Herrenschmidt return -EINVAL; 142127d5bf2aSBenjamin Herrenschmidt 142278bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 142327d5bf2aSBenjamin Herrenschmidt vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 142427d5bf2aSBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 142527d5bf2aSBenjamin Herrenschmidt 142627d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 142727d5bf2aSBenjamin Herrenschmidt return 0; 142827d5bf2aSBenjamin Herrenschmidt } 142927d5bf2aSBenjamin Herrenschmidt 143027d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 143127d5bf2aSBenjamin Herrenschmidt { 143227d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 143317e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 143427d5bf2aSBenjamin Herrenschmidt 143547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 143627d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 143743c2bbd9SChristoph Hellwig if (!i->i_openers++) 143817e0e270SBenjamin Herrenschmidt ctx->psmap = inode->i_mapping; 143947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 144027d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 144127d5bf2aSBenjamin Herrenschmidt } 144227d5bf2aSBenjamin Herrenschmidt 144343c2bbd9SChristoph Hellwig static int 144443c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file) 144543c2bbd9SChristoph Hellwig { 144643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 144743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 144843c2bbd9SChristoph Hellwig 144947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 145043c2bbd9SChristoph Hellwig if (!--i->i_openers) 145143c2bbd9SChristoph Hellwig ctx->psmap = NULL; 145247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 145343c2bbd9SChristoph Hellwig return 0; 145443c2bbd9SChristoph Hellwig } 145543c2bbd9SChristoph Hellwig 14565dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = { 145727d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 145843c2bbd9SChristoph Hellwig .release = spufs_psmap_release, 145927d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1460d9379c4bSarnd@arndb.de }; 1461d9379c4bSarnd@arndb.de 1462d9379c4bSarnd@arndb.de 146327d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 146478bde53eSBenjamin Herrenschmidt static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma, 146578bde53eSBenjamin Herrenschmidt unsigned long address) 14666df10a82SMark Nutter { 146778bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x3000, 0x1000); 14686df10a82SMark Nutter } 14696df10a82SMark Nutter 14706df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = { 147178bde53eSBenjamin Herrenschmidt .nopfn = spufs_mfc_mmap_nopfn, 14726df10a82SMark Nutter }; 14736df10a82SMark Nutter 14746df10a82SMark Nutter /* 14756df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 14766df10a82SMark Nutter */ 14776df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 14786df10a82SMark Nutter { 14796df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 14806df10a82SMark Nutter return -EINVAL; 14816df10a82SMark Nutter 148278bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 14836df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 148423cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 14856df10a82SMark Nutter 14866df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 14876df10a82SMark Nutter return 0; 14886df10a82SMark Nutter } 148927d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 149027d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 149127d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1492a33a7d73SArnd Bergmann 1493a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1494a33a7d73SArnd Bergmann { 1495a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1496a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1497a33a7d73SArnd Bergmann 1498a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1499a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1500a33a7d73SArnd Bergmann return -EINVAL; 1501a33a7d73SArnd Bergmann 1502a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1503a33a7d73SArnd Bergmann return -EBUSY; 1504a33a7d73SArnd Bergmann 150547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1506a33a7d73SArnd Bergmann file->private_data = ctx; 150743c2bbd9SChristoph Hellwig if (!i->i_openers++) 150817e0e270SBenjamin Herrenschmidt ctx->mfc = inode->i_mapping; 150947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1510a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1511a33a7d73SArnd Bergmann } 1512a33a7d73SArnd Bergmann 151343c2bbd9SChristoph Hellwig static int 151443c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file) 151543c2bbd9SChristoph Hellwig { 151643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 151743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 151843c2bbd9SChristoph Hellwig 151947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 152043c2bbd9SChristoph Hellwig if (!--i->i_openers) 152143c2bbd9SChristoph Hellwig ctx->mfc = NULL; 152247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 152343c2bbd9SChristoph Hellwig return 0; 152443c2bbd9SChristoph Hellwig } 152543c2bbd9SChristoph Hellwig 1526a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1527a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1528a33a7d73SArnd Bergmann { 1529a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1530a33a7d73SArnd Bergmann 1531e65c2f6fSLuke Browning if (!ctx) 1532e65c2f6fSLuke Browning return; 1533e65c2f6fSLuke Browning 1534a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1535a33a7d73SArnd Bergmann 1536a33a7d73SArnd Bergmann pr_debug("%s %s\n", __FUNCTION__, spu->name); 1537a33a7d73SArnd Bergmann if (ctx->mfc_fasync) { 1538a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1539a33a7d73SArnd Bergmann unsigned int mask; 1540a33a7d73SArnd Bergmann 1541a33a7d73SArnd Bergmann /* no need for spu_acquire in interrupt context */ 1542a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1543a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1544a33a7d73SArnd Bergmann 1545a33a7d73SArnd Bergmann mask = 0; 1546a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1547a33a7d73SArnd Bergmann mask |= POLLOUT; 1548a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1549a33a7d73SArnd Bergmann mask |= POLLIN; 1550a33a7d73SArnd Bergmann 1551a33a7d73SArnd Bergmann kill_fasync(&ctx->mfc_fasync, SIGIO, mask); 1552a33a7d73SArnd Bergmann } 1553a33a7d73SArnd Bergmann } 1554a33a7d73SArnd Bergmann 1555a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1556a33a7d73SArnd Bergmann { 1557a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1558a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1559a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1560a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1561a33a7d73SArnd Bergmann if (*status) 1562a33a7d73SArnd Bergmann return 1; 1563a33a7d73SArnd Bergmann 1564a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1565a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1566a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1567a33a7d73SArnd Bergmann return 0; 1568a33a7d73SArnd Bergmann } 1569a33a7d73SArnd Bergmann 1570a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1571a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1572a33a7d73SArnd Bergmann { 1573a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1574a33a7d73SArnd Bergmann int ret = -EINVAL; 1575a33a7d73SArnd Bergmann u32 status; 1576a33a7d73SArnd Bergmann 1577a33a7d73SArnd Bergmann if (size != 4) 1578a33a7d73SArnd Bergmann goto out; 1579a33a7d73SArnd Bergmann 1580c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1581c9101bdbSChristoph Hellwig if (ret) 1582c9101bdbSChristoph Hellwig return ret; 1583c9101bdbSChristoph Hellwig 1584c9101bdbSChristoph Hellwig ret = -EINVAL; 1585a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1586a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1587a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1588a33a7d73SArnd Bergmann ret = -EAGAIN; 1589a33a7d73SArnd Bergmann else 1590c9101bdbSChristoph Hellwig /* XXX(hch): shouldn't we clear ret here? */ 1591a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1592a33a7d73SArnd Bergmann } else { 1593a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1594a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1595a33a7d73SArnd Bergmann } 1596a33a7d73SArnd Bergmann spu_release(ctx); 1597a33a7d73SArnd Bergmann 1598a33a7d73SArnd Bergmann if (ret) 1599a33a7d73SArnd Bergmann goto out; 1600a33a7d73SArnd Bergmann 1601a33a7d73SArnd Bergmann ret = 4; 1602a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1603a33a7d73SArnd Bergmann ret = -EFAULT; 1604a33a7d73SArnd Bergmann 1605a33a7d73SArnd Bergmann out: 1606a33a7d73SArnd Bergmann return ret; 1607a33a7d73SArnd Bergmann } 1608a33a7d73SArnd Bergmann 1609a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1610a33a7d73SArnd Bergmann { 1611a33a7d73SArnd Bergmann pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, 1612a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1613a33a7d73SArnd Bergmann 1614a33a7d73SArnd Bergmann switch (cmd->cmd) { 1615a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1616a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1617a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1618a33a7d73SArnd Bergmann case MFC_GET_CMD: 1619a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1620a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1621a33a7d73SArnd Bergmann break; 1622a33a7d73SArnd Bergmann default: 1623a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1624a33a7d73SArnd Bergmann return -EIO; 1625a33a7d73SArnd Bergmann } 1626a33a7d73SArnd Bergmann 1627a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 1628a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment, ea %lx lsa %x\n", 1629a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1630a33a7d73SArnd Bergmann return -EIO; 1631a33a7d73SArnd Bergmann } 1632a33a7d73SArnd Bergmann 1633a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1634a33a7d73SArnd Bergmann case 1: 1635a33a7d73SArnd Bergmann break; 1636a33a7d73SArnd Bergmann case 2: 1637a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1638a33a7d73SArnd Bergmann goto error; 1639a33a7d73SArnd Bergmann break; 1640a33a7d73SArnd Bergmann case 4: 1641a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1642a33a7d73SArnd Bergmann goto error; 1643a33a7d73SArnd Bergmann break; 1644a33a7d73SArnd Bergmann case 8: 1645a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1646a33a7d73SArnd Bergmann goto error; 1647a33a7d73SArnd Bergmann break; 1648a33a7d73SArnd Bergmann case 0: 1649a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1650a33a7d73SArnd Bergmann goto error; 1651a33a7d73SArnd Bergmann break; 1652a33a7d73SArnd Bergmann error: 1653a33a7d73SArnd Bergmann default: 1654a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1655a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1656a33a7d73SArnd Bergmann return -EIO; 1657a33a7d73SArnd Bergmann } 1658a33a7d73SArnd Bergmann 1659a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1660a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1661a33a7d73SArnd Bergmann return -EIO; 1662a33a7d73SArnd Bergmann } 1663a33a7d73SArnd Bergmann 1664a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1665a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1666a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1667a33a7d73SArnd Bergmann return -EIO; 1668a33a7d73SArnd Bergmann } 1669a33a7d73SArnd Bergmann 1670a33a7d73SArnd Bergmann if (cmd->class) { 1671a33a7d73SArnd Bergmann /* not supported in this version */ 1672a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1673a33a7d73SArnd Bergmann return -EIO; 1674a33a7d73SArnd Bergmann } 1675a33a7d73SArnd Bergmann 1676a33a7d73SArnd Bergmann return 0; 1677a33a7d73SArnd Bergmann } 1678a33a7d73SArnd Bergmann 1679a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1680a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1681a33a7d73SArnd Bergmann int *error) 1682a33a7d73SArnd Bergmann { 1683a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1684a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1685a33a7d73SArnd Bergmann /* wait for any tag group to complete 1686a33a7d73SArnd Bergmann so we have space for the new command */ 1687a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1688a33a7d73SArnd Bergmann /* try again, because the queue might be 1689a33a7d73SArnd Bergmann empty again */ 1690a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1691a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1692a33a7d73SArnd Bergmann return 0; 1693a33a7d73SArnd Bergmann } 1694a33a7d73SArnd Bergmann return 1; 1695a33a7d73SArnd Bergmann } 1696a33a7d73SArnd Bergmann 1697a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1698a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1699a33a7d73SArnd Bergmann { 1700a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1701a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1702a33a7d73SArnd Bergmann int ret = -EINVAL; 1703a33a7d73SArnd Bergmann 1704a33a7d73SArnd Bergmann if (size != sizeof cmd) 1705a33a7d73SArnd Bergmann goto out; 1706a33a7d73SArnd Bergmann 1707a33a7d73SArnd Bergmann ret = -EFAULT; 1708a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1709a33a7d73SArnd Bergmann goto out; 1710a33a7d73SArnd Bergmann 1711a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1712a33a7d73SArnd Bergmann if (ret) 1713a33a7d73SArnd Bergmann goto out; 1714a33a7d73SArnd Bergmann 1715c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1716c9101bdbSChristoph Hellwig if (ret) 1717c9101bdbSChristoph Hellwig goto out; 1718c9101bdbSChristoph Hellwig 171933bfd7a7SArnd Bergmann ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 1720577f8f10SAkinobu Mita if (ret) 1721577f8f10SAkinobu Mita goto out; 1722577f8f10SAkinobu Mita 1723a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1724a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1725a33a7d73SArnd Bergmann } else { 1726a33a7d73SArnd Bergmann int status; 1727a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1728a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1729a33a7d73SArnd Bergmann if (status) 1730a33a7d73SArnd Bergmann ret = status; 1731a33a7d73SArnd Bergmann } 1732a33a7d73SArnd Bergmann 1733a33a7d73SArnd Bergmann if (ret) 1734933b0e35SKazunori Asayama goto out_unlock; 1735a33a7d73SArnd Bergmann 1736a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 17373692dc66SMasato Noguchi ret = size; 1738a33a7d73SArnd Bergmann 1739933b0e35SKazunori Asayama out_unlock: 1740933b0e35SKazunori Asayama spu_release(ctx); 1741a33a7d73SArnd Bergmann out: 1742a33a7d73SArnd Bergmann return ret; 1743a33a7d73SArnd Bergmann } 1744a33a7d73SArnd Bergmann 1745a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) 1746a33a7d73SArnd Bergmann { 1747a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1748a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1749a33a7d73SArnd Bergmann unsigned int mask; 1750a33a7d73SArnd Bergmann 1751933b0e35SKazunori Asayama poll_wait(file, &ctx->mfc_wq, wait); 1752933b0e35SKazunori Asayama 1753c9101bdbSChristoph Hellwig /* 1754c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 1755c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 1756c9101bdbSChristoph Hellwig */ 1757c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 1758a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1759a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1760a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1761a33a7d73SArnd Bergmann spu_release(ctx); 1762a33a7d73SArnd Bergmann 1763a33a7d73SArnd Bergmann mask = 0; 1764a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1765a33a7d73SArnd Bergmann mask |= POLLOUT | POLLWRNORM; 1766a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1767a33a7d73SArnd Bergmann mask |= POLLIN | POLLRDNORM; 1768a33a7d73SArnd Bergmann 1769a33a7d73SArnd Bergmann pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, 1770a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1771a33a7d73SArnd Bergmann 1772a33a7d73SArnd Bergmann return mask; 1773a33a7d73SArnd Bergmann } 1774a33a7d73SArnd Bergmann 177573b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1776a33a7d73SArnd Bergmann { 1777a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1778a33a7d73SArnd Bergmann int ret; 1779a33a7d73SArnd Bergmann 1780c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1781c9101bdbSChristoph Hellwig if (ret) 1782c9101bdbSChristoph Hellwig return ret; 1783a33a7d73SArnd Bergmann #if 0 1784a33a7d73SArnd Bergmann /* this currently hangs */ 1785a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1786a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1787a33a7d73SArnd Bergmann if (ret) 1788a33a7d73SArnd Bergmann goto out; 1789a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1790a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1791a33a7d73SArnd Bergmann out: 1792a33a7d73SArnd Bergmann #else 1793a33a7d73SArnd Bergmann ret = 0; 1794a33a7d73SArnd Bergmann #endif 1795a33a7d73SArnd Bergmann spu_release(ctx); 1796a33a7d73SArnd Bergmann 1797a33a7d73SArnd Bergmann return ret; 1798a33a7d73SArnd Bergmann } 1799a33a7d73SArnd Bergmann 1800a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, 1801a33a7d73SArnd Bergmann int datasync) 1802a33a7d73SArnd Bergmann { 180373b6af8aSAl Viro return spufs_mfc_flush(file, NULL); 1804a33a7d73SArnd Bergmann } 1805a33a7d73SArnd Bergmann 1806a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on) 1807a33a7d73SArnd Bergmann { 1808a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1809a33a7d73SArnd Bergmann 1810a33a7d73SArnd Bergmann return fasync_helper(fd, file, on, &ctx->mfc_fasync); 1811a33a7d73SArnd Bergmann } 1812a33a7d73SArnd Bergmann 18135dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = { 1814a33a7d73SArnd Bergmann .open = spufs_mfc_open, 181543c2bbd9SChristoph Hellwig .release = spufs_mfc_release, 1816a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1817a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1818a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1819a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1820a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 1821a33a7d73SArnd Bergmann .fasync = spufs_mfc_fasync, 18226df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1823a33a7d73SArnd Bergmann }; 1824a33a7d73SArnd Bergmann 1825197b1a82SChristoph Hellwig static int spufs_npc_set(void *data, u64 val) 182667207b96SArnd Bergmann { 182767207b96SArnd Bergmann struct spu_context *ctx = data; 1828c9101bdbSChristoph Hellwig int ret; 1829c9101bdbSChristoph Hellwig 1830c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1831c9101bdbSChristoph Hellwig if (ret) 1832c9101bdbSChristoph Hellwig return ret; 18338b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 18348b3d6663SArnd Bergmann spu_release(ctx); 1835197b1a82SChristoph Hellwig 1836197b1a82SChristoph Hellwig return 0; 183767207b96SArnd Bergmann } 183867207b96SArnd Bergmann 1839104f0cc2SMichael Ellerman static u64 spufs_npc_get(struct spu_context *ctx) 184078810ff6SMichael Ellerman { 184178810ff6SMichael Ellerman return ctx->ops->npc_read(ctx); 184278810ff6SMichael Ellerman } 1843104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 1844104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE); 184567207b96SArnd Bergmann 1846197b1a82SChristoph Hellwig static int spufs_decr_set(void *data, u64 val) 18478b3d6663SArnd Bergmann { 18488b3d6663SArnd Bergmann struct spu_context *ctx = data; 18498b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1850c9101bdbSChristoph Hellwig int ret; 1851c9101bdbSChristoph Hellwig 1852c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1853c9101bdbSChristoph Hellwig if (ret) 1854c9101bdbSChristoph Hellwig return ret; 18558b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 185627b1ea09SChristoph Hellwig spu_release_saved(ctx); 1857197b1a82SChristoph Hellwig 1858197b1a82SChristoph Hellwig return 0; 18598b3d6663SArnd Bergmann } 18608b3d6663SArnd Bergmann 1861104f0cc2SMichael Ellerman static u64 spufs_decr_get(struct spu_context *ctx) 18628b3d6663SArnd Bergmann { 18638b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1864bf1ab978SDwayne Grant McConnell return lscsa->decr.slot[0]; 1865bf1ab978SDwayne Grant McConnell } 1866104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 1867104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); 18688b3d6663SArnd Bergmann 1869197b1a82SChristoph Hellwig static int spufs_decr_status_set(void *data, u64 val) 18708b3d6663SArnd Bergmann { 18718b3d6663SArnd Bergmann struct spu_context *ctx = data; 1872c9101bdbSChristoph Hellwig int ret; 1873c9101bdbSChristoph Hellwig 1874c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1875c9101bdbSChristoph Hellwig if (ret) 1876c9101bdbSChristoph Hellwig return ret; 1877d40a01d4SMasato Noguchi if (val) 1878d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 1879d40a01d4SMasato Noguchi else 1880d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 188127b1ea09SChristoph Hellwig spu_release_saved(ctx); 1882197b1a82SChristoph Hellwig 1883197b1a82SChristoph Hellwig return 0; 18848b3d6663SArnd Bergmann } 18858b3d6663SArnd Bergmann 1886104f0cc2SMichael Ellerman static u64 spufs_decr_status_get(struct spu_context *ctx) 18878b3d6663SArnd Bergmann { 1888d40a01d4SMasato Noguchi if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 1889d40a01d4SMasato Noguchi return SPU_DECR_STATUS_RUNNING; 1890d40a01d4SMasato Noguchi else 1891d40a01d4SMasato Noguchi return 0; 1892bf1ab978SDwayne Grant McConnell } 1893104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 1894104f0cc2SMichael Ellerman spufs_decr_status_set, "0x%llx\n", 1895104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 18968b3d6663SArnd Bergmann 1897197b1a82SChristoph Hellwig static int spufs_event_mask_set(void *data, u64 val) 18988b3d6663SArnd Bergmann { 18998b3d6663SArnd Bergmann struct spu_context *ctx = data; 19008b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1901c9101bdbSChristoph Hellwig int ret; 1902c9101bdbSChristoph Hellwig 1903c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1904c9101bdbSChristoph Hellwig if (ret) 1905c9101bdbSChristoph Hellwig return ret; 19068b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 190727b1ea09SChristoph Hellwig spu_release_saved(ctx); 1908197b1a82SChristoph Hellwig 1909197b1a82SChristoph Hellwig return 0; 19108b3d6663SArnd Bergmann } 19118b3d6663SArnd Bergmann 1912104f0cc2SMichael Ellerman static u64 spufs_event_mask_get(struct spu_context *ctx) 19138b3d6663SArnd Bergmann { 19148b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1915bf1ab978SDwayne Grant McConnell return lscsa->event_mask.slot[0]; 1916bf1ab978SDwayne Grant McConnell } 1917bf1ab978SDwayne Grant McConnell 1918104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 1919104f0cc2SMichael Ellerman spufs_event_mask_set, "0x%llx\n", 1920104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 19218b3d6663SArnd Bergmann 1922104f0cc2SMichael Ellerman static u64 spufs_event_status_get(struct spu_context *ctx) 1923b9e3bd77SDwayne Grant McConnell { 1924b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1925b9e3bd77SDwayne Grant McConnell u64 stat; 1926b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1927b9e3bd77SDwayne Grant McConnell if (stat) 1928bf1ab978SDwayne Grant McConnell return state->spu_chnldata_RW[0]; 1929bf1ab978SDwayne Grant McConnell return 0; 1930bf1ab978SDwayne Grant McConnell } 1931104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1932104f0cc2SMichael Ellerman NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 1933b9e3bd77SDwayne Grant McConnell 1934197b1a82SChristoph Hellwig static int spufs_srr0_set(void *data, u64 val) 19358b3d6663SArnd Bergmann { 19368b3d6663SArnd Bergmann struct spu_context *ctx = data; 19378b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1938c9101bdbSChristoph Hellwig int ret; 1939c9101bdbSChristoph Hellwig 1940c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1941c9101bdbSChristoph Hellwig if (ret) 1942c9101bdbSChristoph Hellwig return ret; 19438b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 194427b1ea09SChristoph Hellwig spu_release_saved(ctx); 1945197b1a82SChristoph Hellwig 1946197b1a82SChristoph Hellwig return 0; 19478b3d6663SArnd Bergmann } 19488b3d6663SArnd Bergmann 1949104f0cc2SMichael Ellerman static u64 spufs_srr0_get(struct spu_context *ctx) 19508b3d6663SArnd Bergmann { 19518b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1952104f0cc2SMichael Ellerman return lscsa->srr0.slot[0]; 19538b3d6663SArnd Bergmann } 1954104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 1955104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 19568b3d6663SArnd Bergmann 1957104f0cc2SMichael Ellerman static u64 spufs_id_get(struct spu_context *ctx) 19587b1a7014Sarnd@arndb.de { 19597b1a7014Sarnd@arndb.de u64 num; 19607b1a7014Sarnd@arndb.de 19617b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 19627b1a7014Sarnd@arndb.de num = ctx->spu->number; 19637b1a7014Sarnd@arndb.de else 19647b1a7014Sarnd@arndb.de num = (unsigned int)-1; 19657b1a7014Sarnd@arndb.de 19667b1a7014Sarnd@arndb.de return num; 19677b1a7014Sarnd@arndb.de } 1968104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", 1969104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE) 19707b1a7014Sarnd@arndb.de 1971104f0cc2SMichael Ellerman static u64 spufs_object_id_get(struct spu_context *ctx) 1972bf1ab978SDwayne Grant McConnell { 1973bf1ab978SDwayne Grant McConnell /* FIXME: Should there really be no locking here? */ 1974104f0cc2SMichael Ellerman return ctx->object_id; 1975bf1ab978SDwayne Grant McConnell } 1976bf1ab978SDwayne Grant McConnell 1977197b1a82SChristoph Hellwig static int spufs_object_id_set(void *data, u64 id) 197886767277SArnd Bergmann { 197986767277SArnd Bergmann struct spu_context *ctx = data; 198086767277SArnd Bergmann ctx->object_id = id; 1981197b1a82SChristoph Hellwig 1982197b1a82SChristoph Hellwig return 0; 198386767277SArnd Bergmann } 198486767277SArnd Bergmann 1985104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 1986104f0cc2SMichael Ellerman spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); 198786767277SArnd Bergmann 1988104f0cc2SMichael Ellerman static u64 spufs_lslr_get(struct spu_context *ctx) 1989bf1ab978SDwayne Grant McConnell { 1990bf1ab978SDwayne Grant McConnell return ctx->csa.priv2.spu_lslr_RW; 1991bf1ab978SDwayne Grant McConnell } 1992104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", 1993104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 1994b9e3bd77SDwayne Grant McConnell 1995b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 1996b9e3bd77SDwayne Grant McConnell { 1997b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 1998b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 1999b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 2000b9e3bd77SDwayne Grant McConnell return 0; 2001b9e3bd77SDwayne Grant McConnell } 2002b9e3bd77SDwayne Grant McConnell 2003cbe709c1SBenjamin Herrenschmidt static int spufs_caps_show(struct seq_file *s, void *private) 2004cbe709c1SBenjamin Herrenschmidt { 2005cbe709c1SBenjamin Herrenschmidt struct spu_context *ctx = s->private; 2006cbe709c1SBenjamin Herrenschmidt 2007cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_NOSCHED)) 2008cbe709c1SBenjamin Herrenschmidt seq_puts(s, "sched\n"); 2009cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_ISOLATE)) 2010cbe709c1SBenjamin Herrenschmidt seq_puts(s, "step\n"); 2011cbe709c1SBenjamin Herrenschmidt return 0; 2012cbe709c1SBenjamin Herrenschmidt } 2013cbe709c1SBenjamin Herrenschmidt 2014cbe709c1SBenjamin Herrenschmidt static int spufs_caps_open(struct inode *inode, struct file *file) 2015cbe709c1SBenjamin Herrenschmidt { 2016cbe709c1SBenjamin Herrenschmidt return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); 2017cbe709c1SBenjamin Herrenschmidt } 2018cbe709c1SBenjamin Herrenschmidt 2019cbe709c1SBenjamin Herrenschmidt static const struct file_operations spufs_caps_fops = { 2020cbe709c1SBenjamin Herrenschmidt .open = spufs_caps_open, 2021cbe709c1SBenjamin Herrenschmidt .read = seq_read, 2022cbe709c1SBenjamin Herrenschmidt .llseek = seq_lseek, 2023cbe709c1SBenjamin Herrenschmidt .release = single_release, 2024cbe709c1SBenjamin Herrenschmidt }; 2025cbe709c1SBenjamin Herrenschmidt 2026bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, 2027bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2028bf1ab978SDwayne Grant McConnell { 2029bf1ab978SDwayne Grant McConnell u32 mbox_stat; 2030bf1ab978SDwayne Grant McConnell u32 data; 2031bf1ab978SDwayne Grant McConnell 2032bf1ab978SDwayne Grant McConnell mbox_stat = ctx->csa.prob.mb_stat_R; 2033bf1ab978SDwayne Grant McConnell if (mbox_stat & 0x0000ff) { 2034bf1ab978SDwayne Grant McConnell data = ctx->csa.prob.pu_mb_R; 2035bf1ab978SDwayne Grant McConnell } 2036bf1ab978SDwayne Grant McConnell 2037bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2038bf1ab978SDwayne Grant McConnell } 2039bf1ab978SDwayne Grant McConnell 204069a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 204169a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 204269a2f00cSDwayne Grant McConnell { 2043bf1ab978SDwayne Grant McConnell int ret; 204469a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 204569a2f00cSDwayne Grant McConnell 204669a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 204769a2f00cSDwayne Grant McConnell return -EFAULT; 204869a2f00cSDwayne Grant McConnell 2049c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2050c9101bdbSChristoph Hellwig if (ret) 2051c9101bdbSChristoph Hellwig return ret; 205269a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2053bf1ab978SDwayne Grant McConnell ret = __spufs_mbox_info_read(ctx, buf, len, pos); 205469a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 205527b1ea09SChristoph Hellwig spu_release_saved(ctx); 205669a2f00cSDwayne Grant McConnell 2057bf1ab978SDwayne Grant McConnell return ret; 205869a2f00cSDwayne Grant McConnell } 205969a2f00cSDwayne Grant McConnell 20605dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = { 206169a2f00cSDwayne Grant McConnell .open = spufs_info_open, 206269a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 206369a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 206469a2f00cSDwayne Grant McConnell }; 206569a2f00cSDwayne Grant McConnell 2066bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, 2067bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2068bf1ab978SDwayne Grant McConnell { 2069bf1ab978SDwayne Grant McConnell u32 ibox_stat; 2070bf1ab978SDwayne Grant McConnell u32 data; 2071bf1ab978SDwayne Grant McConnell 2072bf1ab978SDwayne Grant McConnell ibox_stat = ctx->csa.prob.mb_stat_R; 2073bf1ab978SDwayne Grant McConnell if (ibox_stat & 0xff0000) { 2074bf1ab978SDwayne Grant McConnell data = ctx->csa.priv2.puint_mb_R; 2075bf1ab978SDwayne Grant McConnell } 2076bf1ab978SDwayne Grant McConnell 2077bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2078bf1ab978SDwayne Grant McConnell } 2079bf1ab978SDwayne Grant McConnell 208069a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 208169a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 208269a2f00cSDwayne Grant McConnell { 208369a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2084bf1ab978SDwayne Grant McConnell int ret; 208569a2f00cSDwayne Grant McConnell 208669a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 208769a2f00cSDwayne Grant McConnell return -EFAULT; 208869a2f00cSDwayne Grant McConnell 2089c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2090c9101bdbSChristoph Hellwig if (ret) 2091c9101bdbSChristoph Hellwig return ret; 209269a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2093bf1ab978SDwayne Grant McConnell ret = __spufs_ibox_info_read(ctx, buf, len, pos); 209469a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 209527b1ea09SChristoph Hellwig spu_release_saved(ctx); 209669a2f00cSDwayne Grant McConnell 2097bf1ab978SDwayne Grant McConnell return ret; 209869a2f00cSDwayne Grant McConnell } 209969a2f00cSDwayne Grant McConnell 21005dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = { 210169a2f00cSDwayne Grant McConnell .open = spufs_info_open, 210269a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 210369a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 210469a2f00cSDwayne Grant McConnell }; 210569a2f00cSDwayne Grant McConnell 2106bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, 2107bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2108bf1ab978SDwayne Grant McConnell { 2109bf1ab978SDwayne Grant McConnell int i, cnt; 2110bf1ab978SDwayne Grant McConnell u32 data[4]; 2111bf1ab978SDwayne Grant McConnell u32 wbox_stat; 2112bf1ab978SDwayne Grant McConnell 2113bf1ab978SDwayne Grant McConnell wbox_stat = ctx->csa.prob.mb_stat_R; 2114bf1ab978SDwayne Grant McConnell cnt = 4 - ((wbox_stat & 0x00ff00) >> 8); 2115bf1ab978SDwayne Grant McConnell for (i = 0; i < cnt; i++) { 2116bf1ab978SDwayne Grant McConnell data[i] = ctx->csa.spu_mailbox_data[i]; 2117bf1ab978SDwayne Grant McConnell } 2118bf1ab978SDwayne Grant McConnell 2119bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, 2120bf1ab978SDwayne Grant McConnell cnt * sizeof(u32)); 2121bf1ab978SDwayne Grant McConnell } 2122bf1ab978SDwayne Grant McConnell 212369a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 212469a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 212569a2f00cSDwayne Grant McConnell { 212669a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2127bf1ab978SDwayne Grant McConnell int ret; 212869a2f00cSDwayne Grant McConnell 212969a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 213069a2f00cSDwayne Grant McConnell return -EFAULT; 213169a2f00cSDwayne Grant McConnell 2132c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2133c9101bdbSChristoph Hellwig if (ret) 2134c9101bdbSChristoph Hellwig return ret; 213569a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2136bf1ab978SDwayne Grant McConnell ret = __spufs_wbox_info_read(ctx, buf, len, pos); 213769a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 213827b1ea09SChristoph Hellwig spu_release_saved(ctx); 213969a2f00cSDwayne Grant McConnell 2140bf1ab978SDwayne Grant McConnell return ret; 214169a2f00cSDwayne Grant McConnell } 214269a2f00cSDwayne Grant McConnell 21435dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = { 214469a2f00cSDwayne Grant McConnell .open = spufs_info_open, 214569a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 214669a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 214769a2f00cSDwayne Grant McConnell }; 214869a2f00cSDwayne Grant McConnell 2149bf1ab978SDwayne Grant McConnell static ssize_t __spufs_dma_info_read(struct spu_context *ctx, 2150bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2151b9e3bd77SDwayne Grant McConnell { 2152b9e3bd77SDwayne Grant McConnell struct spu_dma_info info; 2153b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *spuqp; 2154b9e3bd77SDwayne Grant McConnell int i; 2155b9e3bd77SDwayne Grant McConnell 2156b9e3bd77SDwayne Grant McConnell info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 2157b9e3bd77SDwayne Grant McConnell info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 2158b9e3bd77SDwayne Grant McConnell info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; 2159b9e3bd77SDwayne Grant McConnell info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 2160b9e3bd77SDwayne Grant McConnell info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 2161b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 2162b9e3bd77SDwayne Grant McConnell qp = &info.dma_info_command_data[i]; 2163b9e3bd77SDwayne Grant McConnell spuqp = &ctx->csa.priv2.spuq[i]; 2164b9e3bd77SDwayne Grant McConnell 2165b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 2166b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 2167b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 2168b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 2169b9e3bd77SDwayne Grant McConnell } 2170b9e3bd77SDwayne Grant McConnell 2171b9e3bd77SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2172b9e3bd77SDwayne Grant McConnell sizeof info); 2173b9e3bd77SDwayne Grant McConnell } 2174b9e3bd77SDwayne Grant McConnell 2175bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 2176bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2177bf1ab978SDwayne Grant McConnell { 2178bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2179bf1ab978SDwayne Grant McConnell int ret; 2180bf1ab978SDwayne Grant McConnell 2181bf1ab978SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2182bf1ab978SDwayne Grant McConnell return -EFAULT; 2183bf1ab978SDwayne Grant McConnell 2184c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2185c9101bdbSChristoph Hellwig if (ret) 2186c9101bdbSChristoph Hellwig return ret; 2187bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2188bf1ab978SDwayne Grant McConnell ret = __spufs_dma_info_read(ctx, buf, len, pos); 2189bf1ab978SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 219027b1ea09SChristoph Hellwig spu_release_saved(ctx); 2191bf1ab978SDwayne Grant McConnell 2192bf1ab978SDwayne Grant McConnell return ret; 2193bf1ab978SDwayne Grant McConnell } 2194bf1ab978SDwayne Grant McConnell 21955dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = { 2196b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2197b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 2198b9e3bd77SDwayne Grant McConnell }; 2199b9e3bd77SDwayne Grant McConnell 2200bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, 2201bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2202b9e3bd77SDwayne Grant McConnell { 2203b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 2204b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *puqp; 2205bf1ab978SDwayne Grant McConnell int ret = sizeof info; 2206b9e3bd77SDwayne Grant McConnell int i; 2207b9e3bd77SDwayne Grant McConnell 2208b9e3bd77SDwayne Grant McConnell if (len < ret) 2209b9e3bd77SDwayne Grant McConnell return -EINVAL; 2210b9e3bd77SDwayne Grant McConnell 2211b9e3bd77SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2212b9e3bd77SDwayne Grant McConnell return -EFAULT; 2213b9e3bd77SDwayne Grant McConnell 2214b9e3bd77SDwayne Grant McConnell info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 2215b9e3bd77SDwayne Grant McConnell info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 2216b9e3bd77SDwayne Grant McConnell info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 2217b9e3bd77SDwayne Grant McConnell for (i = 0; i < 8; i++) { 2218b9e3bd77SDwayne Grant McConnell qp = &info.proxydma_info_command_data[i]; 2219b9e3bd77SDwayne Grant McConnell puqp = &ctx->csa.priv2.puq[i]; 2220b9e3bd77SDwayne Grant McConnell 2221b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 2222b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 2223b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 2224b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 2225b9e3bd77SDwayne Grant McConnell } 2226bf1ab978SDwayne Grant McConnell 2227bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2228bf1ab978SDwayne Grant McConnell sizeof info); 2229bf1ab978SDwayne Grant McConnell } 2230bf1ab978SDwayne Grant McConnell 2231bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 2232bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2233bf1ab978SDwayne Grant McConnell { 2234bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2235bf1ab978SDwayne Grant McConnell int ret; 2236bf1ab978SDwayne Grant McConnell 2237c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2238c9101bdbSChristoph Hellwig if (ret) 2239c9101bdbSChristoph Hellwig return ret; 2240bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2241bf1ab978SDwayne Grant McConnell ret = __spufs_proxydma_info_read(ctx, buf, len, pos); 2242b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 224327b1ea09SChristoph Hellwig spu_release_saved(ctx); 2244b9e3bd77SDwayne Grant McConnell 2245b9e3bd77SDwayne Grant McConnell return ret; 2246b9e3bd77SDwayne Grant McConnell } 2247b9e3bd77SDwayne Grant McConnell 22485dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = { 2249b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2250b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 2251b9e3bd77SDwayne Grant McConnell }; 2252b9e3bd77SDwayne Grant McConnell 2253476273adSChristoph Hellwig static int spufs_show_tid(struct seq_file *s, void *private) 2254476273adSChristoph Hellwig { 2255476273adSChristoph Hellwig struct spu_context *ctx = s->private; 2256476273adSChristoph Hellwig 2257476273adSChristoph Hellwig seq_printf(s, "%d\n", ctx->tid); 2258476273adSChristoph Hellwig return 0; 2259476273adSChristoph Hellwig } 2260476273adSChristoph Hellwig 2261476273adSChristoph Hellwig static int spufs_tid_open(struct inode *inode, struct file *file) 2262476273adSChristoph Hellwig { 2263476273adSChristoph Hellwig return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); 2264476273adSChristoph Hellwig } 2265476273adSChristoph Hellwig 2266476273adSChristoph Hellwig static const struct file_operations spufs_tid_fops = { 2267476273adSChristoph Hellwig .open = spufs_tid_open, 2268476273adSChristoph Hellwig .read = seq_read, 2269476273adSChristoph Hellwig .llseek = seq_lseek, 2270476273adSChristoph Hellwig .release = single_release, 2271476273adSChristoph Hellwig }; 2272476273adSChristoph Hellwig 2273e9f8a0b6SChristoph Hellwig static const char *ctx_state_names[] = { 2274e9f8a0b6SChristoph Hellwig "user", "system", "iowait", "loaded" 2275e9f8a0b6SChristoph Hellwig }; 2276e9f8a0b6SChristoph Hellwig 2277e9f8a0b6SChristoph Hellwig static unsigned long long spufs_acct_time(struct spu_context *ctx, 227827ec41d3SAndre Detsch enum spu_utilization_state state) 2279e9f8a0b6SChristoph Hellwig { 228027ec41d3SAndre Detsch struct timespec ts; 228127ec41d3SAndre Detsch unsigned long long time = ctx->stats.times[state]; 2282e9f8a0b6SChristoph Hellwig 228327ec41d3SAndre Detsch /* 228427ec41d3SAndre Detsch * In general, utilization statistics are updated by the controlling 228527ec41d3SAndre Detsch * thread as the spu context moves through various well defined 228627ec41d3SAndre Detsch * state transitions, but if the context is lazily loaded its 228727ec41d3SAndre Detsch * utilization statistics are not updated as the controlling thread 228827ec41d3SAndre Detsch * is not tightly coupled with the execution of the spu context. We 228927ec41d3SAndre Detsch * calculate and apply the time delta from the last recorded state 229027ec41d3SAndre Detsch * of the spu context. 229127ec41d3SAndre Detsch */ 229227ec41d3SAndre Detsch if (ctx->spu && ctx->stats.util_state == state) { 229327ec41d3SAndre Detsch ktime_get_ts(&ts); 229427ec41d3SAndre Detsch time += timespec_to_ns(&ts) - ctx->stats.tstamp; 229527ec41d3SAndre Detsch } 2296e9f8a0b6SChristoph Hellwig 229727ec41d3SAndre Detsch return time / NSEC_PER_MSEC; 2298e9f8a0b6SChristoph Hellwig } 2299e9f8a0b6SChristoph Hellwig 2300e9f8a0b6SChristoph Hellwig static unsigned long long spufs_slb_flts(struct spu_context *ctx) 2301e9f8a0b6SChristoph Hellwig { 2302e9f8a0b6SChristoph Hellwig unsigned long long slb_flts = ctx->stats.slb_flt; 2303e9f8a0b6SChristoph Hellwig 2304e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2305e9f8a0b6SChristoph Hellwig slb_flts += (ctx->spu->stats.slb_flt - 2306e9f8a0b6SChristoph Hellwig ctx->stats.slb_flt_base); 2307e9f8a0b6SChristoph Hellwig } 2308e9f8a0b6SChristoph Hellwig 2309e9f8a0b6SChristoph Hellwig return slb_flts; 2310e9f8a0b6SChristoph Hellwig } 2311e9f8a0b6SChristoph Hellwig 2312e9f8a0b6SChristoph Hellwig static unsigned long long spufs_class2_intrs(struct spu_context *ctx) 2313e9f8a0b6SChristoph Hellwig { 2314e9f8a0b6SChristoph Hellwig unsigned long long class2_intrs = ctx->stats.class2_intr; 2315e9f8a0b6SChristoph Hellwig 2316e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2317e9f8a0b6SChristoph Hellwig class2_intrs += (ctx->spu->stats.class2_intr - 2318e9f8a0b6SChristoph Hellwig ctx->stats.class2_intr_base); 2319e9f8a0b6SChristoph Hellwig } 2320e9f8a0b6SChristoph Hellwig 2321e9f8a0b6SChristoph Hellwig return class2_intrs; 2322e9f8a0b6SChristoph Hellwig } 2323e9f8a0b6SChristoph Hellwig 2324e9f8a0b6SChristoph Hellwig 2325e9f8a0b6SChristoph Hellwig static int spufs_show_stat(struct seq_file *s, void *private) 2326e9f8a0b6SChristoph Hellwig { 2327e9f8a0b6SChristoph Hellwig struct spu_context *ctx = s->private; 2328c9101bdbSChristoph Hellwig int ret; 2329e9f8a0b6SChristoph Hellwig 2330c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 2331c9101bdbSChristoph Hellwig if (ret) 2332c9101bdbSChristoph Hellwig return ret; 2333c9101bdbSChristoph Hellwig 2334e9f8a0b6SChristoph Hellwig seq_printf(s, "%s %llu %llu %llu %llu " 2335e9f8a0b6SChristoph Hellwig "%llu %llu %llu %llu %llu %llu %llu %llu\n", 233627ec41d3SAndre Detsch ctx_state_names[ctx->stats.util_state], 233727ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_USER), 233827ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 233927ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 234027ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 2341e9f8a0b6SChristoph Hellwig ctx->stats.vol_ctx_switch, 2342e9f8a0b6SChristoph Hellwig ctx->stats.invol_ctx_switch, 2343e9f8a0b6SChristoph Hellwig spufs_slb_flts(ctx), 2344e9f8a0b6SChristoph Hellwig ctx->stats.hash_flt, 2345e9f8a0b6SChristoph Hellwig ctx->stats.min_flt, 2346e9f8a0b6SChristoph Hellwig ctx->stats.maj_flt, 2347e9f8a0b6SChristoph Hellwig spufs_class2_intrs(ctx), 2348e9f8a0b6SChristoph Hellwig ctx->stats.libassist); 2349e9f8a0b6SChristoph Hellwig spu_release(ctx); 2350e9f8a0b6SChristoph Hellwig return 0; 2351e9f8a0b6SChristoph Hellwig } 2352e9f8a0b6SChristoph Hellwig 2353e9f8a0b6SChristoph Hellwig static int spufs_stat_open(struct inode *inode, struct file *file) 2354e9f8a0b6SChristoph Hellwig { 2355e9f8a0b6SChristoph Hellwig return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); 2356e9f8a0b6SChristoph Hellwig } 2357e9f8a0b6SChristoph Hellwig 2358e9f8a0b6SChristoph Hellwig static const struct file_operations spufs_stat_fops = { 2359e9f8a0b6SChristoph Hellwig .open = spufs_stat_open, 2360e9f8a0b6SChristoph Hellwig .read = seq_read, 2361e9f8a0b6SChristoph Hellwig .llseek = seq_lseek, 2362e9f8a0b6SChristoph Hellwig .release = single_release, 2363e9f8a0b6SChristoph Hellwig }; 2364e9f8a0b6SChristoph Hellwig 2365e9f8a0b6SChristoph Hellwig 236667207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 2367cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 236867207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 23698b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 237067207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 237167207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 237267207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 237367207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 237467207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 237567207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2376603c4612SJeremy Kerr { "signal1", &spufs_signal1_fops, 0666, }, 2377603c4612SJeremy Kerr { "signal2", &spufs_signal2_fops, 0666, }, 237867207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 237967207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 23806df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 23818b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 2382b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 2383b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 2384b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 2385b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 2386b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 23878b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 23888b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 23898b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 2390b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 239127d5bf2aSBenjamin Herrenschmidt { "psmap", &spufs_psmap_fops, 0666, }, 239286767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 239386767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 239469a2f00cSDwayne Grant McConnell { "mbox_info", &spufs_mbox_info_fops, 0444, }, 239569a2f00cSDwayne Grant McConnell { "ibox_info", &spufs_ibox_info_fops, 0444, }, 239669a2f00cSDwayne Grant McConnell { "wbox_info", &spufs_wbox_info_fops, 0444, }, 2397b9e3bd77SDwayne Grant McConnell { "dma_info", &spufs_dma_info_fops, 0444, }, 2398b9e3bd77SDwayne Grant McConnell { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, 2399476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2400e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 240167207b96SArnd Bergmann {}, 240267207b96SArnd Bergmann }; 24035737edd1SMark Nutter 24045737edd1SMark Nutter struct tree_descr spufs_dir_nosched_contents[] = { 2405cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 24065737edd1SMark Nutter { "mem", &spufs_mem_fops, 0666, }, 24075737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 24085737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 24095737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 24105737edd1SMark Nutter { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 24115737edd1SMark Nutter { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 24125737edd1SMark Nutter { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2413d054b36fSJeremy Kerr { "signal1", &spufs_signal1_nosched_fops, 0222, }, 2414d054b36fSJeremy Kerr { "signal2", &spufs_signal2_nosched_fops, 0222, }, 24155737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 24165737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 24175737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 24185737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 24195737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 24205737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 24215737edd1SMark Nutter { "psmap", &spufs_psmap_fops, 0666, }, 24225737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 24235737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 2424476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2425e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 24265737edd1SMark Nutter {}, 24275737edd1SMark Nutter }; 2428bf1ab978SDwayne Grant McConnell 2429bf1ab978SDwayne Grant McConnell struct spufs_coredump_reader spufs_coredump_read[] = { 24304fca9c42SMichael Ellerman { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, 24314fca9c42SMichael Ellerman { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, 2432104f0cc2SMichael Ellerman { "lslr", NULL, spufs_lslr_get, 19 }, 2433104f0cc2SMichael Ellerman { "decr", NULL, spufs_decr_get, 19 }, 2434104f0cc2SMichael Ellerman { "decr_status", NULL, spufs_decr_status_get, 19 }, 24354fca9c42SMichael Ellerman { "mem", __spufs_mem_read, NULL, LS_SIZE, }, 24364fca9c42SMichael Ellerman { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, 2437104f0cc2SMichael Ellerman { "signal1_type", NULL, spufs_signal1_type_get, 19 }, 24384fca9c42SMichael Ellerman { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, 2439104f0cc2SMichael Ellerman { "signal2_type", NULL, spufs_signal2_type_get, 19 }, 2440104f0cc2SMichael Ellerman { "event_mask", NULL, spufs_event_mask_get, 19 }, 2441104f0cc2SMichael Ellerman { "event_status", NULL, spufs_event_status_get, 19 }, 24424fca9c42SMichael Ellerman { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, 24434fca9c42SMichael Ellerman { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, 24444fca9c42SMichael Ellerman { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, 24454fca9c42SMichael Ellerman { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, 24464fca9c42SMichael Ellerman { "proxydma_info", __spufs_proxydma_info_read, 24474fca9c42SMichael Ellerman NULL, sizeof(struct spu_proxydma_info)}, 2448104f0cc2SMichael Ellerman { "object-id", NULL, spufs_object_id_get, 19 }, 2449104f0cc2SMichael Ellerman { "npc", NULL, spufs_npc_get, 19 }, 2450936d5bf1SMichael Ellerman { NULL }, 2451bf1ab978SDwayne Grant McConnell }; 2452