167207b96SArnd Bergmann /* 267207b96SArnd Bergmann * SPU file system -- file contents 367207b96SArnd Bergmann * 467207b96SArnd Bergmann * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 567207b96SArnd Bergmann * 667207b96SArnd Bergmann * Author: Arnd Bergmann <arndb@de.ibm.com> 767207b96SArnd Bergmann * 867207b96SArnd Bergmann * This program is free software; you can redistribute it and/or modify 967207b96SArnd Bergmann * it under the terms of the GNU General Public License as published by 1067207b96SArnd Bergmann * the Free Software Foundation; either version 2, or (at your option) 1167207b96SArnd Bergmann * any later version. 1267207b96SArnd Bergmann * 1367207b96SArnd Bergmann * This program is distributed in the hope that it will be useful, 1467207b96SArnd Bergmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 1567207b96SArnd Bergmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1667207b96SArnd Bergmann * GNU General Public License for more details. 1767207b96SArnd Bergmann * 1867207b96SArnd Bergmann * You should have received a copy of the GNU General Public License 1967207b96SArnd Bergmann * along with this program; if not, write to the Free Software 2067207b96SArnd Bergmann * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2167207b96SArnd Bergmann */ 2267207b96SArnd Bergmann 23a33a7d73SArnd Bergmann #undef DEBUG 24a33a7d73SArnd Bergmann 2567207b96SArnd Bergmann #include <linux/fs.h> 2667207b96SArnd Bergmann #include <linux/ioctl.h> 2767207b96SArnd Bergmann #include <linux/module.h> 28d88cfffaSArnd Bergmann #include <linux/pagemap.h> 2967207b96SArnd Bergmann #include <linux/poll.h> 305110459fSArnd Bergmann #include <linux/ptrace.h> 31cbe709c1SBenjamin Herrenschmidt #include <linux/seq_file.h> 32038200cfSChristoph Hellwig #include <linux/marker.h> 3367207b96SArnd Bergmann 3467207b96SArnd Bergmann #include <asm/io.h> 3567207b96SArnd Bergmann #include <asm/semaphore.h> 3667207b96SArnd Bergmann #include <asm/spu.h> 37b9e3bd77SDwayne Grant McConnell #include <asm/spu_info.h> 3867207b96SArnd Bergmann #include <asm/uaccess.h> 3967207b96SArnd Bergmann 4067207b96SArnd Bergmann #include "spufs.h" 4167207b96SArnd Bergmann 4227d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 4327d5bf2aSBenjamin Herrenschmidt 44197b1a82SChristoph Hellwig /* Simple attribute files */ 45197b1a82SChristoph Hellwig struct spufs_attr { 46197b1a82SChristoph Hellwig int (*get)(void *, u64 *); 47197b1a82SChristoph Hellwig int (*set)(void *, u64); 48197b1a82SChristoph Hellwig char get_buf[24]; /* enough to store a u64 and "\n\0" */ 49197b1a82SChristoph Hellwig char set_buf[24]; 50197b1a82SChristoph Hellwig void *data; 51197b1a82SChristoph Hellwig const char *fmt; /* format for read operation */ 52197b1a82SChristoph Hellwig struct mutex mutex; /* protects access to these buffers */ 53197b1a82SChristoph Hellwig }; 54197b1a82SChristoph Hellwig 55197b1a82SChristoph Hellwig static int spufs_attr_open(struct inode *inode, struct file *file, 56197b1a82SChristoph Hellwig int (*get)(void *, u64 *), int (*set)(void *, u64), 57197b1a82SChristoph Hellwig const char *fmt) 58197b1a82SChristoph Hellwig { 59197b1a82SChristoph Hellwig struct spufs_attr *attr; 60197b1a82SChristoph Hellwig 61197b1a82SChristoph Hellwig attr = kmalloc(sizeof(*attr), GFP_KERNEL); 62197b1a82SChristoph Hellwig if (!attr) 63197b1a82SChristoph Hellwig return -ENOMEM; 64197b1a82SChristoph Hellwig 65197b1a82SChristoph Hellwig attr->get = get; 66197b1a82SChristoph Hellwig attr->set = set; 67197b1a82SChristoph Hellwig attr->data = inode->i_private; 68197b1a82SChristoph Hellwig attr->fmt = fmt; 69197b1a82SChristoph Hellwig mutex_init(&attr->mutex); 70197b1a82SChristoph Hellwig file->private_data = attr; 71197b1a82SChristoph Hellwig 72197b1a82SChristoph Hellwig return nonseekable_open(inode, file); 73197b1a82SChristoph Hellwig } 74197b1a82SChristoph Hellwig 75197b1a82SChristoph Hellwig static int spufs_attr_release(struct inode *inode, struct file *file) 76197b1a82SChristoph Hellwig { 77197b1a82SChristoph Hellwig kfree(file->private_data); 78197b1a82SChristoph Hellwig return 0; 79197b1a82SChristoph Hellwig } 80197b1a82SChristoph Hellwig 81197b1a82SChristoph Hellwig static ssize_t spufs_attr_read(struct file *file, char __user *buf, 82197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 83197b1a82SChristoph Hellwig { 84197b1a82SChristoph Hellwig struct spufs_attr *attr; 85197b1a82SChristoph Hellwig size_t size; 86197b1a82SChristoph Hellwig ssize_t ret; 87197b1a82SChristoph Hellwig 88197b1a82SChristoph Hellwig attr = file->private_data; 89197b1a82SChristoph Hellwig if (!attr->get) 90197b1a82SChristoph Hellwig return -EACCES; 91197b1a82SChristoph Hellwig 92197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 93197b1a82SChristoph Hellwig if (ret) 94197b1a82SChristoph Hellwig return ret; 95197b1a82SChristoph Hellwig 96197b1a82SChristoph Hellwig if (*ppos) { /* continued read */ 97197b1a82SChristoph Hellwig size = strlen(attr->get_buf); 98197b1a82SChristoph Hellwig } else { /* first read */ 99197b1a82SChristoph Hellwig u64 val; 100197b1a82SChristoph Hellwig ret = attr->get(attr->data, &val); 101197b1a82SChristoph Hellwig if (ret) 102197b1a82SChristoph Hellwig goto out; 103197b1a82SChristoph Hellwig 104197b1a82SChristoph Hellwig size = scnprintf(attr->get_buf, sizeof(attr->get_buf), 105197b1a82SChristoph Hellwig attr->fmt, (unsigned long long)val); 106197b1a82SChristoph Hellwig } 107197b1a82SChristoph Hellwig 108197b1a82SChristoph Hellwig ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); 109197b1a82SChristoph Hellwig out: 110197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 111197b1a82SChristoph Hellwig return ret; 112197b1a82SChristoph Hellwig } 113197b1a82SChristoph Hellwig 114197b1a82SChristoph Hellwig static ssize_t spufs_attr_write(struct file *file, const char __user *buf, 115197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 116197b1a82SChristoph Hellwig { 117197b1a82SChristoph Hellwig struct spufs_attr *attr; 118197b1a82SChristoph Hellwig u64 val; 119197b1a82SChristoph Hellwig size_t size; 120197b1a82SChristoph Hellwig ssize_t ret; 121197b1a82SChristoph Hellwig 122197b1a82SChristoph Hellwig attr = file->private_data; 123197b1a82SChristoph Hellwig if (!attr->set) 124197b1a82SChristoph Hellwig return -EACCES; 125197b1a82SChristoph Hellwig 126197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 127197b1a82SChristoph Hellwig if (ret) 128197b1a82SChristoph Hellwig return ret; 129197b1a82SChristoph Hellwig 130197b1a82SChristoph Hellwig ret = -EFAULT; 131197b1a82SChristoph Hellwig size = min(sizeof(attr->set_buf) - 1, len); 132197b1a82SChristoph Hellwig if (copy_from_user(attr->set_buf, buf, size)) 133197b1a82SChristoph Hellwig goto out; 134197b1a82SChristoph Hellwig 135197b1a82SChristoph Hellwig ret = len; /* claim we got the whole input */ 136197b1a82SChristoph Hellwig attr->set_buf[size] = '\0'; 137197b1a82SChristoph Hellwig val = simple_strtol(attr->set_buf, NULL, 0); 138197b1a82SChristoph Hellwig attr->set(attr->data, val); 139197b1a82SChristoph Hellwig out: 140197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 141197b1a82SChristoph Hellwig return ret; 142197b1a82SChristoph Hellwig } 143197b1a82SChristoph Hellwig 144197b1a82SChristoph Hellwig #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ 145197b1a82SChristoph Hellwig static int __fops ## _open(struct inode *inode, struct file *file) \ 146197b1a82SChristoph Hellwig { \ 147197b1a82SChristoph Hellwig __simple_attr_check_format(__fmt, 0ull); \ 148197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, __get, __set, __fmt); \ 149197b1a82SChristoph Hellwig } \ 150197b1a82SChristoph Hellwig static struct file_operations __fops = { \ 151197b1a82SChristoph Hellwig .owner = THIS_MODULE, \ 152197b1a82SChristoph Hellwig .open = __fops ## _open, \ 153197b1a82SChristoph Hellwig .release = spufs_attr_release, \ 154197b1a82SChristoph Hellwig .read = spufs_attr_read, \ 155197b1a82SChristoph Hellwig .write = spufs_attr_write, \ 156197b1a82SChristoph Hellwig }; 157197b1a82SChristoph Hellwig 158cbe709c1SBenjamin Herrenschmidt 15967207b96SArnd Bergmann static int 16067207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 16167207b96SArnd Bergmann { 16267207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1636df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 16443c2bbd9SChristoph Hellwig 16547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1666df10a82SMark Nutter file->private_data = ctx; 16743c2bbd9SChristoph Hellwig if (!i->i_openers++) 1686df10a82SMark Nutter ctx->local_store = inode->i_mapping; 16947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 17043c2bbd9SChristoph Hellwig return 0; 17143c2bbd9SChristoph Hellwig } 17243c2bbd9SChristoph Hellwig 17343c2bbd9SChristoph Hellwig static int 17443c2bbd9SChristoph Hellwig spufs_mem_release(struct inode *inode, struct file *file) 17543c2bbd9SChristoph Hellwig { 17643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 17743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 17843c2bbd9SChristoph Hellwig 17947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 18043c2bbd9SChristoph Hellwig if (!--i->i_openers) 18143c2bbd9SChristoph Hellwig ctx->local_store = NULL; 18247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 18367207b96SArnd Bergmann return 0; 18467207b96SArnd Bergmann } 18567207b96SArnd Bergmann 18667207b96SArnd Bergmann static ssize_t 187bf1ab978SDwayne Grant McConnell __spufs_mem_read(struct spu_context *ctx, char __user *buffer, 188bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 189bf1ab978SDwayne Grant McConnell { 190bf1ab978SDwayne Grant McConnell char *local_store = ctx->ops->get_ls(ctx); 191bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, local_store, 192bf1ab978SDwayne Grant McConnell LS_SIZE); 193bf1ab978SDwayne Grant McConnell } 194bf1ab978SDwayne Grant McConnell 195bf1ab978SDwayne Grant McConnell static ssize_t 19667207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 19767207b96SArnd Bergmann size_t size, loff_t *pos) 19867207b96SArnd Bergmann { 199bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 200aa0ed2bdSArnd Bergmann ssize_t ret; 20167207b96SArnd Bergmann 202c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 203c9101bdbSChristoph Hellwig if (ret) 204c9101bdbSChristoph Hellwig return ret; 205bf1ab978SDwayne Grant McConnell ret = __spufs_mem_read(ctx, buffer, size, pos); 2068b3d6663SArnd Bergmann spu_release(ctx); 207c9101bdbSChristoph Hellwig 20867207b96SArnd Bergmann return ret; 20967207b96SArnd Bergmann } 21067207b96SArnd Bergmann 21167207b96SArnd Bergmann static ssize_t 21267207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 213aa0ed2bdSArnd Bergmann size_t size, loff_t *ppos) 21467207b96SArnd Bergmann { 21567207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 2168b3d6663SArnd Bergmann char *local_store; 217aa0ed2bdSArnd Bergmann loff_t pos = *ppos; 2188b3d6663SArnd Bergmann int ret; 21967207b96SArnd Bergmann 220aa0ed2bdSArnd Bergmann if (pos < 0) 221aa0ed2bdSArnd Bergmann return -EINVAL; 222aa0ed2bdSArnd Bergmann if (pos > LS_SIZE) 22367207b96SArnd Bergmann return -EFBIG; 224aa0ed2bdSArnd Bergmann if (size > LS_SIZE - pos) 225aa0ed2bdSArnd Bergmann size = LS_SIZE - pos; 2268b3d6663SArnd Bergmann 227c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 228c9101bdbSChristoph Hellwig if (ret) 229c9101bdbSChristoph Hellwig return ret; 230c9101bdbSChristoph Hellwig 2318b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 232aa0ed2bdSArnd Bergmann ret = copy_from_user(local_store + pos, buffer, size); 2338b3d6663SArnd Bergmann spu_release(ctx); 234aa0ed2bdSArnd Bergmann 235aa0ed2bdSArnd Bergmann if (ret) 236aa0ed2bdSArnd Bergmann return -EFAULT; 237aa0ed2bdSArnd Bergmann *ppos = pos + size; 238aa0ed2bdSArnd Bergmann return size; 23967207b96SArnd Bergmann } 24067207b96SArnd Bergmann 24178bde53eSBenjamin Herrenschmidt static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, 24278bde53eSBenjamin Herrenschmidt unsigned long address) 2438b3d6663SArnd Bergmann { 2448b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 245f1fa74f4SBenjamin Herrenschmidt unsigned long pfn, offset, addr0 = address; 246f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 247f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 248f1fa74f4SBenjamin Herrenschmidt int psize; 24978bde53eSBenjamin Herrenschmidt 250f1fa74f4SBenjamin Herrenschmidt /* Check what page size we are using */ 251f1fa74f4SBenjamin Herrenschmidt psize = get_slice_psize(vma->vm_mm, address); 2528b3d6663SArnd Bergmann 253f1fa74f4SBenjamin Herrenschmidt /* Some sanity checking */ 254f1fa74f4SBenjamin Herrenschmidt BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K)); 255f1fa74f4SBenjamin Herrenschmidt 256f1fa74f4SBenjamin Herrenschmidt /* Wow, 64K, cool, we need to align the address though */ 257f1fa74f4SBenjamin Herrenschmidt if (csa->use_big_pages) { 258f1fa74f4SBenjamin Herrenschmidt BUG_ON(vma->vm_start & 0xffff); 259f1fa74f4SBenjamin Herrenschmidt address &= ~0xfffful; 260f1fa74f4SBenjamin Herrenschmidt } 261f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 262f1fa74f4SBenjamin Herrenschmidt 263f1fa74f4SBenjamin Herrenschmidt offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); 264128b8546SMasato Noguchi if (offset >= LS_SIZE) 265128b8546SMasato Noguchi return NOPFN_SIGBUS; 266128b8546SMasato Noguchi 267f1fa74f4SBenjamin Herrenschmidt pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n", 268f1fa74f4SBenjamin Herrenschmidt addr0, address, offset); 269f1fa74f4SBenjamin Herrenschmidt 270c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 271c9101bdbSChristoph Hellwig return NOPFN_REFAULT; 2728b3d6663SArnd Bergmann 273ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 274ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 275932f535dSArnd Bergmann & ~_PAGE_NO_CACHE); 27678bde53eSBenjamin Herrenschmidt pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); 277ac91cb8dSArnd Bergmann } else { 278ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 279932f535dSArnd Bergmann | _PAGE_NO_CACHE); 28078bde53eSBenjamin Herrenschmidt pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; 281ac91cb8dSArnd Bergmann } 28278bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, pfn); 28378bde53eSBenjamin Herrenschmidt 2848b3d6663SArnd Bergmann spu_release(ctx); 2858b3d6663SArnd Bergmann 28678bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 2878b3d6663SArnd Bergmann } 2888b3d6663SArnd Bergmann 28978bde53eSBenjamin Herrenschmidt 2908b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = { 29178bde53eSBenjamin Herrenschmidt .nopfn = spufs_mem_mmap_nopfn, 2928b3d6663SArnd Bergmann }; 2938b3d6663SArnd Bergmann 294f1fa74f4SBenjamin Herrenschmidt static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 29567207b96SArnd Bergmann { 296f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 297f1fa74f4SBenjamin Herrenschmidt struct spu_context *ctx = file->private_data; 298f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 299f1fa74f4SBenjamin Herrenschmidt 300f1fa74f4SBenjamin Herrenschmidt /* Sanity check VMA alignment */ 301f1fa74f4SBenjamin Herrenschmidt if (csa->use_big_pages) { 302f1fa74f4SBenjamin Herrenschmidt pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx," 303f1fa74f4SBenjamin Herrenschmidt " pgoff=0x%lx\n", vma->vm_start, vma->vm_end, 304f1fa74f4SBenjamin Herrenschmidt vma->vm_pgoff); 305f1fa74f4SBenjamin Herrenschmidt if (vma->vm_start & 0xffff) 306f1fa74f4SBenjamin Herrenschmidt return -EINVAL; 307f1fa74f4SBenjamin Herrenschmidt if (vma->vm_pgoff & 0xf) 308f1fa74f4SBenjamin Herrenschmidt return -EINVAL; 309f1fa74f4SBenjamin Herrenschmidt } 310f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 311f1fa74f4SBenjamin Herrenschmidt 3128b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 3138b3d6663SArnd Bergmann return -EINVAL; 31467207b96SArnd Bergmann 31578bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 31667207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 31767207b96SArnd Bergmann | _PAGE_NO_CACHE); 3188b3d6663SArnd Bergmann 3198b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 32067207b96SArnd Bergmann return 0; 32167207b96SArnd Bergmann } 32267207b96SArnd Bergmann 323f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 3241238819aSSebastian Siewior static unsigned long spufs_get_unmapped_area(struct file *file, 3251238819aSSebastian Siewior unsigned long addr, unsigned long len, unsigned long pgoff, 326f1fa74f4SBenjamin Herrenschmidt unsigned long flags) 327f1fa74f4SBenjamin Herrenschmidt { 328f1fa74f4SBenjamin Herrenschmidt struct spu_context *ctx = file->private_data; 329f1fa74f4SBenjamin Herrenschmidt struct spu_state *csa = &ctx->csa; 330f1fa74f4SBenjamin Herrenschmidt 331f1fa74f4SBenjamin Herrenschmidt /* If not using big pages, fallback to normal MM g_u_a */ 332f1fa74f4SBenjamin Herrenschmidt if (!csa->use_big_pages) 333f1fa74f4SBenjamin Herrenschmidt return current->mm->get_unmapped_area(file, addr, len, 334f1fa74f4SBenjamin Herrenschmidt pgoff, flags); 335f1fa74f4SBenjamin Herrenschmidt 336f1fa74f4SBenjamin Herrenschmidt /* Else, try to obtain a 64K pages slice */ 337f1fa74f4SBenjamin Herrenschmidt return slice_get_unmapped_area(addr, len, flags, 338f1fa74f4SBenjamin Herrenschmidt MMU_PAGE_64K, 1, 0); 339f1fa74f4SBenjamin Herrenschmidt } 340f1fa74f4SBenjamin Herrenschmidt #endif /* CONFIG_SPU_FS_64K_LS */ 341f1fa74f4SBenjamin Herrenschmidt 3425dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = { 34367207b96SArnd Bergmann .open = spufs_mem_open, 344ce92987bSChristoph Hellwig .release = spufs_mem_release, 34567207b96SArnd Bergmann .read = spufs_mem_read, 34667207b96SArnd Bergmann .write = spufs_mem_write, 3478b3d6663SArnd Bergmann .llseek = generic_file_llseek, 34867207b96SArnd Bergmann .mmap = spufs_mem_mmap, 349f1fa74f4SBenjamin Herrenschmidt #ifdef CONFIG_SPU_FS_64K_LS 350f1fa74f4SBenjamin Herrenschmidt .get_unmapped_area = spufs_get_unmapped_area, 351f1fa74f4SBenjamin Herrenschmidt #endif 3528b3d6663SArnd Bergmann }; 3538b3d6663SArnd Bergmann 35478bde53eSBenjamin Herrenschmidt static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, 3556df10a82SMark Nutter unsigned long address, 35678bde53eSBenjamin Herrenschmidt unsigned long ps_offs, 35727d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 3586df10a82SMark Nutter { 3596df10a82SMark Nutter struct spu_context *ctx = vma->vm_file->private_data; 36078bde53eSBenjamin Herrenschmidt unsigned long area, offset = address - vma->vm_start; 3616df10a82SMark Nutter 362038200cfSChristoph Hellwig spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx); 363038200cfSChristoph Hellwig 3646df10a82SMark Nutter offset += vma->vm_pgoff << PAGE_SHIFT; 36527d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 36678bde53eSBenjamin Herrenschmidt return NOPFN_SIGBUS; 3676df10a82SMark Nutter 36833bfd7a7SArnd Bergmann /* 36933bfd7a7SArnd Bergmann * We have to wait for context to be loaded before we have 37033bfd7a7SArnd Bergmann * pages to hand out to the user, but we don't want to wait 37133bfd7a7SArnd Bergmann * with the mmap_sem held. 37233bfd7a7SArnd Bergmann * It is possible to drop the mmap_sem here, but then we need 37333bfd7a7SArnd Bergmann * to return NOPFN_REFAULT because the mappings may have 37433bfd7a7SArnd Bergmann * hanged. 37578bde53eSBenjamin Herrenschmidt */ 376c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 377c9101bdbSChristoph Hellwig return NOPFN_REFAULT; 378c9101bdbSChristoph Hellwig 37933bfd7a7SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 38033bfd7a7SArnd Bergmann up_read(¤t->mm->mmap_sem); 381038200cfSChristoph Hellwig spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx); 38233bfd7a7SArnd Bergmann spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 383038200cfSChristoph Hellwig spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu); 38433bfd7a7SArnd Bergmann down_read(¤t->mm->mmap_sem); 385c9101bdbSChristoph Hellwig } else { 3866df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 38778bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); 388038200cfSChristoph Hellwig spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu); 389c9101bdbSChristoph Hellwig } 39033bfd7a7SArnd Bergmann 3916df10a82SMark Nutter spu_release(ctx); 39278bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 3936df10a82SMark Nutter } 3946df10a82SMark Nutter 39527d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 39678bde53eSBenjamin Herrenschmidt static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, 39778bde53eSBenjamin Herrenschmidt unsigned long address) 3986df10a82SMark Nutter { 39978bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x4000, 0x1000); 4006df10a82SMark Nutter } 4016df10a82SMark Nutter 4026df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = { 40378bde53eSBenjamin Herrenschmidt .nopfn = spufs_cntl_mmap_nopfn, 4046df10a82SMark Nutter }; 4056df10a82SMark Nutter 4066df10a82SMark Nutter /* 4076df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 4086df10a82SMark Nutter */ 4096df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 4106df10a82SMark Nutter { 4116df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 4126df10a82SMark Nutter return -EINVAL; 4136df10a82SMark Nutter 41478bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 4156df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 41623cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 4176df10a82SMark Nutter 4186df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 4196df10a82SMark Nutter return 0; 4206df10a82SMark Nutter } 42127d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 42227d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 42327d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 4246df10a82SMark Nutter 425197b1a82SChristoph Hellwig static int spufs_cntl_get(void *data, u64 *val) 426e1dbff2bSArnd Bergmann { 427e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 428c9101bdbSChristoph Hellwig int ret; 429e1dbff2bSArnd Bergmann 430c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 431c9101bdbSChristoph Hellwig if (ret) 432c9101bdbSChristoph Hellwig return ret; 433197b1a82SChristoph Hellwig *val = ctx->ops->status_read(ctx); 434e1dbff2bSArnd Bergmann spu_release(ctx); 435e1dbff2bSArnd Bergmann 436197b1a82SChristoph Hellwig return 0; 437e1dbff2bSArnd Bergmann } 438e1dbff2bSArnd Bergmann 439197b1a82SChristoph Hellwig static int spufs_cntl_set(void *data, u64 val) 440e1dbff2bSArnd Bergmann { 441e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 442c9101bdbSChristoph Hellwig int ret; 443e1dbff2bSArnd Bergmann 444c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 445c9101bdbSChristoph Hellwig if (ret) 446c9101bdbSChristoph Hellwig return ret; 447e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 448e1dbff2bSArnd Bergmann spu_release(ctx); 449197b1a82SChristoph Hellwig 450197b1a82SChristoph Hellwig return 0; 451e1dbff2bSArnd Bergmann } 452e1dbff2bSArnd Bergmann 4536df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 4546df10a82SMark Nutter { 4556df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 4566df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 4576df10a82SMark Nutter 45847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 4596df10a82SMark Nutter file->private_data = ctx; 46043c2bbd9SChristoph Hellwig if (!i->i_openers++) 4616df10a82SMark Nutter ctx->cntl = inode->i_mapping; 46247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 463197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, spufs_cntl_get, 464e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 4656df10a82SMark Nutter } 4666df10a82SMark Nutter 46743c2bbd9SChristoph Hellwig static int 46843c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file) 46943c2bbd9SChristoph Hellwig { 47043c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 47143c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 47243c2bbd9SChristoph Hellwig 473197b1a82SChristoph Hellwig spufs_attr_release(inode, file); 47443c2bbd9SChristoph Hellwig 47547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 47643c2bbd9SChristoph Hellwig if (!--i->i_openers) 47743c2bbd9SChristoph Hellwig ctx->cntl = NULL; 47847d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 47943c2bbd9SChristoph Hellwig return 0; 48043c2bbd9SChristoph Hellwig } 48143c2bbd9SChristoph Hellwig 4825dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = { 4836df10a82SMark Nutter .open = spufs_cntl_open, 48443c2bbd9SChristoph Hellwig .release = spufs_cntl_release, 485197b1a82SChristoph Hellwig .read = spufs_attr_read, 486197b1a82SChristoph Hellwig .write = spufs_attr_write, 4876df10a82SMark Nutter .mmap = spufs_cntl_mmap, 4886df10a82SMark Nutter }; 4896df10a82SMark Nutter 4908b3d6663SArnd Bergmann static int 4918b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 4928b3d6663SArnd Bergmann { 4938b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 4948b3d6663SArnd Bergmann file->private_data = i->i_ctx; 4958b3d6663SArnd Bergmann return 0; 4968b3d6663SArnd Bergmann } 4978b3d6663SArnd Bergmann 4988b3d6663SArnd Bergmann static ssize_t 499bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer, 500bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 501bf1ab978SDwayne Grant McConnell { 502bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 503bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 504bf1ab978SDwayne Grant McConnell lscsa->gprs, sizeof lscsa->gprs); 505bf1ab978SDwayne Grant McConnell } 506bf1ab978SDwayne Grant McConnell 507bf1ab978SDwayne Grant McConnell static ssize_t 5088b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 5098b3d6663SArnd Bergmann size_t size, loff_t *pos) 5108b3d6663SArnd Bergmann { 5118b3d6663SArnd Bergmann int ret; 512bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5138b3d6663SArnd Bergmann 514c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 515c9101bdbSChristoph Hellwig if (ret) 516c9101bdbSChristoph Hellwig return ret; 517bf1ab978SDwayne Grant McConnell ret = __spufs_regs_read(ctx, buffer, size, pos); 51827b1ea09SChristoph Hellwig spu_release_saved(ctx); 5198b3d6663SArnd Bergmann return ret; 5208b3d6663SArnd Bergmann } 5218b3d6663SArnd Bergmann 5228b3d6663SArnd Bergmann static ssize_t 5238b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 5248b3d6663SArnd Bergmann size_t size, loff_t *pos) 5258b3d6663SArnd Bergmann { 5268b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5278b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5288b3d6663SArnd Bergmann int ret; 5298b3d6663SArnd Bergmann 5308b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 5318b3d6663SArnd Bergmann if (size <= 0) 5328b3d6663SArnd Bergmann return -EFBIG; 5338b3d6663SArnd Bergmann *pos += size; 5348b3d6663SArnd Bergmann 535c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 536c9101bdbSChristoph Hellwig if (ret) 537c9101bdbSChristoph Hellwig return ret; 5388b3d6663SArnd Bergmann 5398b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 5408b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 5418b3d6663SArnd Bergmann 54227b1ea09SChristoph Hellwig spu_release_saved(ctx); 5438b3d6663SArnd Bergmann return ret; 5448b3d6663SArnd Bergmann } 5458b3d6663SArnd Bergmann 5465dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = { 5478b3d6663SArnd Bergmann .open = spufs_regs_open, 5488b3d6663SArnd Bergmann .read = spufs_regs_read, 5498b3d6663SArnd Bergmann .write = spufs_regs_write, 5508b3d6663SArnd Bergmann .llseek = generic_file_llseek, 5518b3d6663SArnd Bergmann }; 5528b3d6663SArnd Bergmann 5538b3d6663SArnd Bergmann static ssize_t 554bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, 555bf1ab978SDwayne Grant McConnell size_t size, loff_t * pos) 556bf1ab978SDwayne Grant McConnell { 557bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 558bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 559bf1ab978SDwayne Grant McConnell &lscsa->fpcr, sizeof(lscsa->fpcr)); 560bf1ab978SDwayne Grant McConnell } 561bf1ab978SDwayne Grant McConnell 562bf1ab978SDwayne Grant McConnell static ssize_t 5638b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 5648b3d6663SArnd Bergmann size_t size, loff_t * pos) 5658b3d6663SArnd Bergmann { 5668b3d6663SArnd Bergmann int ret; 567bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5688b3d6663SArnd Bergmann 569c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 570c9101bdbSChristoph Hellwig if (ret) 571c9101bdbSChristoph Hellwig return ret; 572bf1ab978SDwayne Grant McConnell ret = __spufs_fpcr_read(ctx, buffer, size, pos); 57327b1ea09SChristoph Hellwig spu_release_saved(ctx); 5748b3d6663SArnd Bergmann return ret; 5758b3d6663SArnd Bergmann } 5768b3d6663SArnd Bergmann 5778b3d6663SArnd Bergmann static ssize_t 5788b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 5798b3d6663SArnd Bergmann size_t size, loff_t * pos) 5808b3d6663SArnd Bergmann { 5818b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5828b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5838b3d6663SArnd Bergmann int ret; 5848b3d6663SArnd Bergmann 5858b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 5868b3d6663SArnd Bergmann if (size <= 0) 5878b3d6663SArnd Bergmann return -EFBIG; 588c9101bdbSChristoph Hellwig 589c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 590c9101bdbSChristoph Hellwig if (ret) 591c9101bdbSChristoph Hellwig return ret; 592c9101bdbSChristoph Hellwig 5938b3d6663SArnd Bergmann *pos += size; 5948b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 5958b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 5968b3d6663SArnd Bergmann 59727b1ea09SChristoph Hellwig spu_release_saved(ctx); 5988b3d6663SArnd Bergmann return ret; 5998b3d6663SArnd Bergmann } 6008b3d6663SArnd Bergmann 6015dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = { 6028b3d6663SArnd Bergmann .open = spufs_regs_open, 6038b3d6663SArnd Bergmann .read = spufs_fpcr_read, 6048b3d6663SArnd Bergmann .write = spufs_fpcr_write, 60567207b96SArnd Bergmann .llseek = generic_file_llseek, 60667207b96SArnd Bergmann }; 60767207b96SArnd Bergmann 60867207b96SArnd Bergmann /* generic open function for all pipe-like files */ 60967207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 61067207b96SArnd Bergmann { 61167207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 61267207b96SArnd Bergmann file->private_data = i->i_ctx; 61367207b96SArnd Bergmann 61467207b96SArnd Bergmann return nonseekable_open(inode, file); 61567207b96SArnd Bergmann } 61667207b96SArnd Bergmann 617cdcc89bbSArnd Bergmann /* 618cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 619cdcc89bbSArnd Bergmann * one of the conditions becomes true: 620cdcc89bbSArnd Bergmann * 621cdcc89bbSArnd Bergmann * - no more data available in the mailbox 622cdcc89bbSArnd Bergmann * - end of the user provided buffer 623cdcc89bbSArnd Bergmann * - end of the mapped area 624cdcc89bbSArnd Bergmann */ 62567207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 62667207b96SArnd Bergmann size_t len, loff_t *pos) 62767207b96SArnd Bergmann { 6288b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 629cdcc89bbSArnd Bergmann u32 mbox_data, __user *udata; 630cdcc89bbSArnd Bergmann ssize_t count; 63167207b96SArnd Bergmann 63267207b96SArnd Bergmann if (len < 4) 63367207b96SArnd Bergmann return -EINVAL; 63467207b96SArnd Bergmann 635cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 63667207b96SArnd Bergmann return -EFAULT; 63767207b96SArnd Bergmann 638cdcc89bbSArnd Bergmann udata = (void __user *)buf; 639cdcc89bbSArnd Bergmann 640c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 641c9101bdbSChristoph Hellwig if (count) 642c9101bdbSChristoph Hellwig return count; 643c9101bdbSChristoph Hellwig 644274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 645cdcc89bbSArnd Bergmann int ret; 646cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 647cdcc89bbSArnd Bergmann if (ret == 0) 648cdcc89bbSArnd Bergmann break; 649cdcc89bbSArnd Bergmann 650cdcc89bbSArnd Bergmann /* 651cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 652cdcc89bbSArnd Bergmann * but still need to return the data we have 653cdcc89bbSArnd Bergmann * read successfully so far. 654cdcc89bbSArnd Bergmann */ 655cdcc89bbSArnd Bergmann ret = __put_user(mbox_data, udata); 656cdcc89bbSArnd Bergmann if (ret) { 657cdcc89bbSArnd Bergmann if (!count) 658cdcc89bbSArnd Bergmann count = -EFAULT; 659cdcc89bbSArnd Bergmann break; 660cdcc89bbSArnd Bergmann } 661cdcc89bbSArnd Bergmann } 662cdcc89bbSArnd Bergmann spu_release(ctx); 663cdcc89bbSArnd Bergmann 664cdcc89bbSArnd Bergmann if (!count) 665cdcc89bbSArnd Bergmann count = -EAGAIN; 666cdcc89bbSArnd Bergmann 667cdcc89bbSArnd Bergmann return count; 66867207b96SArnd Bergmann } 66967207b96SArnd Bergmann 6705dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = { 67167207b96SArnd Bergmann .open = spufs_pipe_open, 67267207b96SArnd Bergmann .read = spufs_mbox_read, 67367207b96SArnd Bergmann }; 67467207b96SArnd Bergmann 67567207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 67667207b96SArnd Bergmann size_t len, loff_t *pos) 67767207b96SArnd Bergmann { 6788b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 679c9101bdbSChristoph Hellwig ssize_t ret; 68067207b96SArnd Bergmann u32 mbox_stat; 68167207b96SArnd Bergmann 68267207b96SArnd Bergmann if (len < 4) 68367207b96SArnd Bergmann return -EINVAL; 68467207b96SArnd Bergmann 685c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 686c9101bdbSChristoph Hellwig if (ret) 687c9101bdbSChristoph Hellwig return ret; 6888b3d6663SArnd Bergmann 6898b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 6908b3d6663SArnd Bergmann 6918b3d6663SArnd Bergmann spu_release(ctx); 69267207b96SArnd Bergmann 69367207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 69467207b96SArnd Bergmann return -EFAULT; 69567207b96SArnd Bergmann 69667207b96SArnd Bergmann return 4; 69767207b96SArnd Bergmann } 69867207b96SArnd Bergmann 6995dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = { 70067207b96SArnd Bergmann .open = spufs_pipe_open, 70167207b96SArnd Bergmann .read = spufs_mbox_stat_read, 70267207b96SArnd Bergmann }; 70367207b96SArnd Bergmann 70467207b96SArnd Bergmann /* low-level ibox access function */ 7058b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 70667207b96SArnd Bergmann { 7078b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 70867207b96SArnd Bergmann } 70967207b96SArnd Bergmann 71067207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 71167207b96SArnd Bergmann { 7128b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 7138b3d6663SArnd Bergmann 7148b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 7158b3d6663SArnd Bergmann } 7168b3d6663SArnd Bergmann 7178b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 7188b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 7198b3d6663SArnd Bergmann { 7208b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 7218b3d6663SArnd Bergmann 722e65c2f6fSLuke Browning if (!ctx) 723e65c2f6fSLuke Browning return; 724e65c2f6fSLuke Browning 7258b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 7268b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 72767207b96SArnd Bergmann } 72867207b96SArnd Bergmann 729cdcc89bbSArnd Bergmann /* 730cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 731cdcc89bbSArnd Bergmann * one of the conditions becomes true: 732cdcc89bbSArnd Bergmann * 733cdcc89bbSArnd Bergmann * - no more data available in the mailbox 734cdcc89bbSArnd Bergmann * - end of the user provided buffer 735cdcc89bbSArnd Bergmann * - end of the mapped area 736cdcc89bbSArnd Bergmann * 737cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 738cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 739cdcc89bbSArnd Bergmann * read something. 740cdcc89bbSArnd Bergmann */ 74167207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 74267207b96SArnd Bergmann size_t len, loff_t *pos) 74367207b96SArnd Bergmann { 7448b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 745cdcc89bbSArnd Bergmann u32 ibox_data, __user *udata; 746cdcc89bbSArnd Bergmann ssize_t count; 74767207b96SArnd Bergmann 74867207b96SArnd Bergmann if (len < 4) 74967207b96SArnd Bergmann return -EINVAL; 75067207b96SArnd Bergmann 751cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 752cdcc89bbSArnd Bergmann return -EFAULT; 753cdcc89bbSArnd Bergmann 754cdcc89bbSArnd Bergmann udata = (void __user *)buf; 755cdcc89bbSArnd Bergmann 756c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 757c9101bdbSChristoph Hellwig if (count) 758c9101bdbSChristoph Hellwig return count; 75967207b96SArnd Bergmann 760cdcc89bbSArnd Bergmann /* wait only for the first element */ 761cdcc89bbSArnd Bergmann count = 0; 76267207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 7638b3d6663SArnd Bergmann if (!spu_ibox_read(ctx, &ibox_data)) 764cdcc89bbSArnd Bergmann count = -EAGAIN; 76567207b96SArnd Bergmann } else { 766cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 767cdcc89bbSArnd Bergmann } 768cdcc89bbSArnd Bergmann if (count) 769cdcc89bbSArnd Bergmann goto out; 770cdcc89bbSArnd Bergmann 771cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 772cdcc89bbSArnd Bergmann count = __put_user(ibox_data, udata); 773cdcc89bbSArnd Bergmann if (count) 774cdcc89bbSArnd Bergmann goto out; 775cdcc89bbSArnd Bergmann 776cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 777cdcc89bbSArnd Bergmann int ret; 778cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 779cdcc89bbSArnd Bergmann if (ret == 0) 780cdcc89bbSArnd Bergmann break; 781cdcc89bbSArnd Bergmann /* 782cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 783cdcc89bbSArnd Bergmann * but still need to return the data we have 784cdcc89bbSArnd Bergmann * read successfully so far. 785cdcc89bbSArnd Bergmann */ 786cdcc89bbSArnd Bergmann ret = __put_user(ibox_data, udata); 787cdcc89bbSArnd Bergmann if (ret) 788cdcc89bbSArnd Bergmann break; 78967207b96SArnd Bergmann } 79067207b96SArnd Bergmann 791cdcc89bbSArnd Bergmann out: 7928b3d6663SArnd Bergmann spu_release(ctx); 7938b3d6663SArnd Bergmann 794cdcc89bbSArnd Bergmann return count; 79567207b96SArnd Bergmann } 79667207b96SArnd Bergmann 79767207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 79867207b96SArnd Bergmann { 7998b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 80067207b96SArnd Bergmann unsigned int mask; 80167207b96SArnd Bergmann 8028b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 80367207b96SArnd Bergmann 804c9101bdbSChristoph Hellwig /* 805c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 806c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 807c9101bdbSChristoph Hellwig */ 808c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 8093a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 8103a843d7cSArnd Bergmann spu_release(ctx); 81167207b96SArnd Bergmann 81267207b96SArnd Bergmann return mask; 81367207b96SArnd Bergmann } 81467207b96SArnd Bergmann 8155dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = { 81667207b96SArnd Bergmann .open = spufs_pipe_open, 81767207b96SArnd Bergmann .read = spufs_ibox_read, 81867207b96SArnd Bergmann .poll = spufs_ibox_poll, 81967207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 82067207b96SArnd Bergmann }; 82167207b96SArnd Bergmann 82267207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 82367207b96SArnd Bergmann size_t len, loff_t *pos) 82467207b96SArnd Bergmann { 8258b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 826c9101bdbSChristoph Hellwig ssize_t ret; 82767207b96SArnd Bergmann u32 ibox_stat; 82867207b96SArnd Bergmann 82967207b96SArnd Bergmann if (len < 4) 83067207b96SArnd Bergmann return -EINVAL; 83167207b96SArnd Bergmann 832c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 833c9101bdbSChristoph Hellwig if (ret) 834c9101bdbSChristoph Hellwig return ret; 8358b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 8368b3d6663SArnd Bergmann spu_release(ctx); 83767207b96SArnd Bergmann 83867207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 83967207b96SArnd Bergmann return -EFAULT; 84067207b96SArnd Bergmann 84167207b96SArnd Bergmann return 4; 84267207b96SArnd Bergmann } 84367207b96SArnd Bergmann 8445dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = { 84567207b96SArnd Bergmann .open = spufs_pipe_open, 84667207b96SArnd Bergmann .read = spufs_ibox_stat_read, 84767207b96SArnd Bergmann }; 84867207b96SArnd Bergmann 84967207b96SArnd Bergmann /* low-level mailbox write */ 8508b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 85167207b96SArnd Bergmann { 8528b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 85367207b96SArnd Bergmann } 85467207b96SArnd Bergmann 85567207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 85667207b96SArnd Bergmann { 8578b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 8588b3d6663SArnd Bergmann int ret; 8598b3d6663SArnd Bergmann 8608b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 8618b3d6663SArnd Bergmann 8628b3d6663SArnd Bergmann return ret; 8638b3d6663SArnd Bergmann } 8648b3d6663SArnd Bergmann 8658b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 8668b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 8678b3d6663SArnd Bergmann { 8688b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 8698b3d6663SArnd Bergmann 870e65c2f6fSLuke Browning if (!ctx) 871e65c2f6fSLuke Browning return; 872e65c2f6fSLuke Browning 8738b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 8748b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 87567207b96SArnd Bergmann } 87667207b96SArnd Bergmann 877cdcc89bbSArnd Bergmann /* 878cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 879cdcc89bbSArnd Bergmann * one of the conditions becomes true: 880cdcc89bbSArnd Bergmann * 881cdcc89bbSArnd Bergmann * - the mailbox is full 882cdcc89bbSArnd Bergmann * - end of the user provided buffer 883cdcc89bbSArnd Bergmann * - end of the mapped area 884cdcc89bbSArnd Bergmann * 885cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 886cdcc89bbSArnd Bergmann * space is availabyl, but return when we have been able to 887cdcc89bbSArnd Bergmann * write something. 888cdcc89bbSArnd Bergmann */ 88967207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 89067207b96SArnd Bergmann size_t len, loff_t *pos) 89167207b96SArnd Bergmann { 8928b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 893cdcc89bbSArnd Bergmann u32 wbox_data, __user *udata; 894cdcc89bbSArnd Bergmann ssize_t count; 89567207b96SArnd Bergmann 89667207b96SArnd Bergmann if (len < 4) 89767207b96SArnd Bergmann return -EINVAL; 89867207b96SArnd Bergmann 899cdcc89bbSArnd Bergmann udata = (void __user *)buf; 900cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_READ, buf, len)) 901cdcc89bbSArnd Bergmann return -EFAULT; 902cdcc89bbSArnd Bergmann 903cdcc89bbSArnd Bergmann if (__get_user(wbox_data, udata)) 90467207b96SArnd Bergmann return -EFAULT; 90567207b96SArnd Bergmann 906c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 907c9101bdbSChristoph Hellwig if (count) 908c9101bdbSChristoph Hellwig return count; 9098b3d6663SArnd Bergmann 910cdcc89bbSArnd Bergmann /* 911cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 912cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 913cdcc89bbSArnd Bergmann */ 914cdcc89bbSArnd Bergmann count = 0; 91567207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 9168b3d6663SArnd Bergmann if (!spu_wbox_write(ctx, wbox_data)) 917cdcc89bbSArnd Bergmann count = -EAGAIN; 91867207b96SArnd Bergmann } else { 919cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 92067207b96SArnd Bergmann } 92167207b96SArnd Bergmann 922cdcc89bbSArnd Bergmann if (count) 923cdcc89bbSArnd Bergmann goto out; 9248b3d6663SArnd Bergmann 92596de0e25SJan Engelhardt /* write as much as possible */ 926cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 927cdcc89bbSArnd Bergmann int ret; 928cdcc89bbSArnd Bergmann ret = __get_user(wbox_data, udata); 929cdcc89bbSArnd Bergmann if (ret) 930cdcc89bbSArnd Bergmann break; 931cdcc89bbSArnd Bergmann 932cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 933cdcc89bbSArnd Bergmann if (ret == 0) 934cdcc89bbSArnd Bergmann break; 935cdcc89bbSArnd Bergmann } 936cdcc89bbSArnd Bergmann 937cdcc89bbSArnd Bergmann out: 938cdcc89bbSArnd Bergmann spu_release(ctx); 939cdcc89bbSArnd Bergmann return count; 94067207b96SArnd Bergmann } 94167207b96SArnd Bergmann 94267207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 94367207b96SArnd Bergmann { 9448b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 94567207b96SArnd Bergmann unsigned int mask; 94667207b96SArnd Bergmann 9478b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 94867207b96SArnd Bergmann 949c9101bdbSChristoph Hellwig /* 950c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 951c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 952c9101bdbSChristoph Hellwig */ 953c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 9543a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 9553a843d7cSArnd Bergmann spu_release(ctx); 95667207b96SArnd Bergmann 95767207b96SArnd Bergmann return mask; 95867207b96SArnd Bergmann } 95967207b96SArnd Bergmann 9605dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = { 96167207b96SArnd Bergmann .open = spufs_pipe_open, 96267207b96SArnd Bergmann .write = spufs_wbox_write, 96367207b96SArnd Bergmann .poll = spufs_wbox_poll, 96467207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 96567207b96SArnd Bergmann }; 96667207b96SArnd Bergmann 96767207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 96867207b96SArnd Bergmann size_t len, loff_t *pos) 96967207b96SArnd Bergmann { 9708b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 971c9101bdbSChristoph Hellwig ssize_t ret; 97267207b96SArnd Bergmann u32 wbox_stat; 97367207b96SArnd Bergmann 97467207b96SArnd Bergmann if (len < 4) 97567207b96SArnd Bergmann return -EINVAL; 97667207b96SArnd Bergmann 977c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 978c9101bdbSChristoph Hellwig if (ret) 979c9101bdbSChristoph Hellwig return ret; 9808b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 9818b3d6663SArnd Bergmann spu_release(ctx); 98267207b96SArnd Bergmann 98367207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 98467207b96SArnd Bergmann return -EFAULT; 98567207b96SArnd Bergmann 98667207b96SArnd Bergmann return 4; 98767207b96SArnd Bergmann } 98867207b96SArnd Bergmann 9895dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = { 99067207b96SArnd Bergmann .open = spufs_pipe_open, 99167207b96SArnd Bergmann .read = spufs_wbox_stat_read, 99267207b96SArnd Bergmann }; 99367207b96SArnd Bergmann 9946df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 9956df10a82SMark Nutter { 9966df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 9976df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 99843c2bbd9SChristoph Hellwig 99947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 10006df10a82SMark Nutter file->private_data = ctx; 100143c2bbd9SChristoph Hellwig if (!i->i_openers++) 10026df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 100347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 10046df10a82SMark Nutter return nonseekable_open(inode, file); 10056df10a82SMark Nutter } 10066df10a82SMark Nutter 100743c2bbd9SChristoph Hellwig static int 100843c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file) 100943c2bbd9SChristoph Hellwig { 101043c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 101143c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 101243c2bbd9SChristoph Hellwig 101347d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 101443c2bbd9SChristoph Hellwig if (!--i->i_openers) 101543c2bbd9SChristoph Hellwig ctx->signal1 = NULL; 101647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 101743c2bbd9SChristoph Hellwig return 0; 101843c2bbd9SChristoph Hellwig } 101943c2bbd9SChristoph Hellwig 1020bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 102167207b96SArnd Bergmann size_t len, loff_t *pos) 102267207b96SArnd Bergmann { 102317f88cebSDwayne Grant McConnell int ret = 0; 102467207b96SArnd Bergmann u32 data; 102567207b96SArnd Bergmann 102667207b96SArnd Bergmann if (len < 4) 102767207b96SArnd Bergmann return -EINVAL; 102867207b96SArnd Bergmann 102917f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[3]) { 103017f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[3]; 103117f88cebSDwayne Grant McConnell ret = 4; 103217f88cebSDwayne Grant McConnell } 10338b3d6663SArnd Bergmann 103417f88cebSDwayne Grant McConnell if (!ret) 103517f88cebSDwayne Grant McConnell goto out; 103617f88cebSDwayne Grant McConnell 103767207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 103867207b96SArnd Bergmann return -EFAULT; 103967207b96SArnd Bergmann 104017f88cebSDwayne Grant McConnell out: 104117f88cebSDwayne Grant McConnell return ret; 104267207b96SArnd Bergmann } 104367207b96SArnd Bergmann 1044bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 1045bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1046bf1ab978SDwayne Grant McConnell { 1047bf1ab978SDwayne Grant McConnell int ret; 1048bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1049bf1ab978SDwayne Grant McConnell 1050c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1051c9101bdbSChristoph Hellwig if (ret) 1052c9101bdbSChristoph Hellwig return ret; 1053bf1ab978SDwayne Grant McConnell ret = __spufs_signal1_read(ctx, buf, len, pos); 105427b1ea09SChristoph Hellwig spu_release_saved(ctx); 1055bf1ab978SDwayne Grant McConnell 1056bf1ab978SDwayne Grant McConnell return ret; 1057bf1ab978SDwayne Grant McConnell } 1058bf1ab978SDwayne Grant McConnell 105967207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 106067207b96SArnd Bergmann size_t len, loff_t *pos) 106167207b96SArnd Bergmann { 106267207b96SArnd Bergmann struct spu_context *ctx; 1063c9101bdbSChristoph Hellwig ssize_t ret; 106467207b96SArnd Bergmann u32 data; 106567207b96SArnd Bergmann 106667207b96SArnd Bergmann ctx = file->private_data; 106767207b96SArnd Bergmann 106867207b96SArnd Bergmann if (len < 4) 106967207b96SArnd Bergmann return -EINVAL; 107067207b96SArnd Bergmann 107167207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 107267207b96SArnd Bergmann return -EFAULT; 107367207b96SArnd Bergmann 1074c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1075c9101bdbSChristoph Hellwig if (ret) 1076c9101bdbSChristoph Hellwig return ret; 10778b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 10788b3d6663SArnd Bergmann spu_release(ctx); 107967207b96SArnd Bergmann 108067207b96SArnd Bergmann return 4; 108167207b96SArnd Bergmann } 108267207b96SArnd Bergmann 108378bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma, 108478bde53eSBenjamin Herrenschmidt unsigned long address) 10856df10a82SMark Nutter { 108627d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 108778bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x14000, 0x1000); 108827d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 108927d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 109027d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 109127d5bf2aSBenjamin Herrenschmidt */ 109278bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 109327d5bf2aSBenjamin Herrenschmidt #else 109427d5bf2aSBenjamin Herrenschmidt #error unsupported page size 109527d5bf2aSBenjamin Herrenschmidt #endif 10966df10a82SMark Nutter } 10976df10a82SMark Nutter 10986df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = { 109978bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal1_mmap_nopfn, 11006df10a82SMark Nutter }; 11016df10a82SMark Nutter 11026df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 11036df10a82SMark Nutter { 11046df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 11056df10a82SMark Nutter return -EINVAL; 11066df10a82SMark Nutter 110778bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 11086df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 110923cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 11106df10a82SMark Nutter 11116df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 11126df10a82SMark Nutter return 0; 11136df10a82SMark Nutter } 11146df10a82SMark Nutter 11155dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = { 11166df10a82SMark Nutter .open = spufs_signal1_open, 111743c2bbd9SChristoph Hellwig .release = spufs_signal1_release, 111867207b96SArnd Bergmann .read = spufs_signal1_read, 111967207b96SArnd Bergmann .write = spufs_signal1_write, 11206df10a82SMark Nutter .mmap = spufs_signal1_mmap, 112167207b96SArnd Bergmann }; 112267207b96SArnd Bergmann 1123d054b36fSJeremy Kerr static const struct file_operations spufs_signal1_nosched_fops = { 1124d054b36fSJeremy Kerr .open = spufs_signal1_open, 1125d054b36fSJeremy Kerr .release = spufs_signal1_release, 1126d054b36fSJeremy Kerr .write = spufs_signal1_write, 1127d054b36fSJeremy Kerr .mmap = spufs_signal1_mmap, 1128d054b36fSJeremy Kerr }; 1129d054b36fSJeremy Kerr 11306df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 11316df10a82SMark Nutter { 11326df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 11336df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 113443c2bbd9SChristoph Hellwig 113547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 11366df10a82SMark Nutter file->private_data = ctx; 113743c2bbd9SChristoph Hellwig if (!i->i_openers++) 11386df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 113947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 11406df10a82SMark Nutter return nonseekable_open(inode, file); 11416df10a82SMark Nutter } 11426df10a82SMark Nutter 114343c2bbd9SChristoph Hellwig static int 114443c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file) 114543c2bbd9SChristoph Hellwig { 114643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 114743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 114843c2bbd9SChristoph Hellwig 114947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 115043c2bbd9SChristoph Hellwig if (!--i->i_openers) 115143c2bbd9SChristoph Hellwig ctx->signal2 = NULL; 115247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 115343c2bbd9SChristoph Hellwig return 0; 115443c2bbd9SChristoph Hellwig } 115543c2bbd9SChristoph Hellwig 1156bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 115767207b96SArnd Bergmann size_t len, loff_t *pos) 115867207b96SArnd Bergmann { 115917f88cebSDwayne Grant McConnell int ret = 0; 116067207b96SArnd Bergmann u32 data; 116167207b96SArnd Bergmann 116267207b96SArnd Bergmann if (len < 4) 116367207b96SArnd Bergmann return -EINVAL; 116467207b96SArnd Bergmann 116517f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[4]) { 116617f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[4]; 116717f88cebSDwayne Grant McConnell ret = 4; 116817f88cebSDwayne Grant McConnell } 11698b3d6663SArnd Bergmann 117017f88cebSDwayne Grant McConnell if (!ret) 117117f88cebSDwayne Grant McConnell goto out; 117217f88cebSDwayne Grant McConnell 117367207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 117467207b96SArnd Bergmann return -EFAULT; 117567207b96SArnd Bergmann 117617f88cebSDwayne Grant McConnell out: 1177bf1ab978SDwayne Grant McConnell return ret; 1178bf1ab978SDwayne Grant McConnell } 1179bf1ab978SDwayne Grant McConnell 1180bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 1181bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1182bf1ab978SDwayne Grant McConnell { 1183bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1184bf1ab978SDwayne Grant McConnell int ret; 1185bf1ab978SDwayne Grant McConnell 1186c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1187c9101bdbSChristoph Hellwig if (ret) 1188c9101bdbSChristoph Hellwig return ret; 1189bf1ab978SDwayne Grant McConnell ret = __spufs_signal2_read(ctx, buf, len, pos); 119027b1ea09SChristoph Hellwig spu_release_saved(ctx); 1191bf1ab978SDwayne Grant McConnell 1192bf1ab978SDwayne Grant McConnell return ret; 119367207b96SArnd Bergmann } 119467207b96SArnd Bergmann 119567207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 119667207b96SArnd Bergmann size_t len, loff_t *pos) 119767207b96SArnd Bergmann { 119867207b96SArnd Bergmann struct spu_context *ctx; 1199c9101bdbSChristoph Hellwig ssize_t ret; 120067207b96SArnd Bergmann u32 data; 120167207b96SArnd Bergmann 120267207b96SArnd Bergmann ctx = file->private_data; 120367207b96SArnd Bergmann 120467207b96SArnd Bergmann if (len < 4) 120567207b96SArnd Bergmann return -EINVAL; 120667207b96SArnd Bergmann 120767207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 120867207b96SArnd Bergmann return -EFAULT; 120967207b96SArnd Bergmann 1210c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1211c9101bdbSChristoph Hellwig if (ret) 1212c9101bdbSChristoph Hellwig return ret; 12138b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 12148b3d6663SArnd Bergmann spu_release(ctx); 121567207b96SArnd Bergmann 121667207b96SArnd Bergmann return 4; 121767207b96SArnd Bergmann } 121867207b96SArnd Bergmann 121927d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 122078bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma, 122178bde53eSBenjamin Herrenschmidt unsigned long address) 12226df10a82SMark Nutter { 122327d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 122478bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000); 122527d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 122627d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 122727d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 122827d5bf2aSBenjamin Herrenschmidt */ 122978bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 123027d5bf2aSBenjamin Herrenschmidt #else 123127d5bf2aSBenjamin Herrenschmidt #error unsupported page size 123227d5bf2aSBenjamin Herrenschmidt #endif 12336df10a82SMark Nutter } 12346df10a82SMark Nutter 12356df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = { 123678bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal2_mmap_nopfn, 12376df10a82SMark Nutter }; 12386df10a82SMark Nutter 12396df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 12406df10a82SMark Nutter { 12416df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 12426df10a82SMark Nutter return -EINVAL; 12436df10a82SMark Nutter 124478bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 12456df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 124623cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 12476df10a82SMark Nutter 12486df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 12496df10a82SMark Nutter return 0; 12506df10a82SMark Nutter } 125127d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 125227d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 125327d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 12546df10a82SMark Nutter 12555dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = { 12566df10a82SMark Nutter .open = spufs_signal2_open, 125743c2bbd9SChristoph Hellwig .release = spufs_signal2_release, 125867207b96SArnd Bergmann .read = spufs_signal2_read, 125967207b96SArnd Bergmann .write = spufs_signal2_write, 12606df10a82SMark Nutter .mmap = spufs_signal2_mmap, 126167207b96SArnd Bergmann }; 126267207b96SArnd Bergmann 1263d054b36fSJeremy Kerr static const struct file_operations spufs_signal2_nosched_fops = { 1264d054b36fSJeremy Kerr .open = spufs_signal2_open, 1265d054b36fSJeremy Kerr .release = spufs_signal2_release, 1266d054b36fSJeremy Kerr .write = spufs_signal2_write, 1267d054b36fSJeremy Kerr .mmap = spufs_signal2_mmap, 1268d054b36fSJeremy Kerr }; 1269d054b36fSJeremy Kerr 1270104f0cc2SMichael Ellerman /* 1271104f0cc2SMichael Ellerman * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the 1272104f0cc2SMichael Ellerman * work of acquiring (or not) the SPU context before calling through 1273104f0cc2SMichael Ellerman * to the actual get routine. The set routine is called directly. 1274104f0cc2SMichael Ellerman */ 1275104f0cc2SMichael Ellerman #define SPU_ATTR_NOACQUIRE 0 1276104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE 1 1277104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE_SAVED 2 1278104f0cc2SMichael Ellerman 1279104f0cc2SMichael Ellerman #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ 1280197b1a82SChristoph Hellwig static int __##__get(void *data, u64 *val) \ 1281104f0cc2SMichael Ellerman { \ 1282104f0cc2SMichael Ellerman struct spu_context *ctx = data; \ 1283c9101bdbSChristoph Hellwig int ret = 0; \ 1284104f0cc2SMichael Ellerman \ 1285104f0cc2SMichael Ellerman if (__acquire == SPU_ATTR_ACQUIRE) { \ 1286c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); \ 1287c9101bdbSChristoph Hellwig if (ret) \ 1288c9101bdbSChristoph Hellwig return ret; \ 1289197b1a82SChristoph Hellwig *val = __get(ctx); \ 1290104f0cc2SMichael Ellerman spu_release(ctx); \ 1291104f0cc2SMichael Ellerman } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ 1292c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); \ 1293c9101bdbSChristoph Hellwig if (ret) \ 1294c9101bdbSChristoph Hellwig return ret; \ 1295197b1a82SChristoph Hellwig *val = __get(ctx); \ 1296104f0cc2SMichael Ellerman spu_release_saved(ctx); \ 1297104f0cc2SMichael Ellerman } else \ 1298197b1a82SChristoph Hellwig *val = __get(ctx); \ 1299104f0cc2SMichael Ellerman \ 1300197b1a82SChristoph Hellwig return 0; \ 1301104f0cc2SMichael Ellerman } \ 1302197b1a82SChristoph Hellwig DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); 1303104f0cc2SMichael Ellerman 1304197b1a82SChristoph Hellwig static int spufs_signal1_type_set(void *data, u64 val) 130567207b96SArnd Bergmann { 130667207b96SArnd Bergmann struct spu_context *ctx = data; 1307c9101bdbSChristoph Hellwig int ret; 130867207b96SArnd Bergmann 1309c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1310c9101bdbSChristoph Hellwig if (ret) 1311c9101bdbSChristoph Hellwig return ret; 13128b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 13138b3d6663SArnd Bergmann spu_release(ctx); 1314197b1a82SChristoph Hellwig 1315197b1a82SChristoph Hellwig return 0; 131667207b96SArnd Bergmann } 131767207b96SArnd Bergmann 1318104f0cc2SMichael Ellerman static u64 spufs_signal1_type_get(struct spu_context *ctx) 1319bf1ab978SDwayne Grant McConnell { 1320bf1ab978SDwayne Grant McConnell return ctx->ops->signal1_type_get(ctx); 1321bf1ab978SDwayne Grant McConnell } 1322104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 1323104f0cc2SMichael Ellerman spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); 1324bf1ab978SDwayne Grant McConnell 132567207b96SArnd Bergmann 1326197b1a82SChristoph Hellwig static int spufs_signal2_type_set(void *data, u64 val) 132767207b96SArnd Bergmann { 132867207b96SArnd Bergmann struct spu_context *ctx = data; 1329c9101bdbSChristoph Hellwig int ret; 133067207b96SArnd Bergmann 1331c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1332c9101bdbSChristoph Hellwig if (ret) 1333c9101bdbSChristoph Hellwig return ret; 13348b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 13358b3d6663SArnd Bergmann spu_release(ctx); 1336197b1a82SChristoph Hellwig 1337197b1a82SChristoph Hellwig return 0; 133867207b96SArnd Bergmann } 133967207b96SArnd Bergmann 1340104f0cc2SMichael Ellerman static u64 spufs_signal2_type_get(struct spu_context *ctx) 1341bf1ab978SDwayne Grant McConnell { 1342bf1ab978SDwayne Grant McConnell return ctx->ops->signal2_type_get(ctx); 1343bf1ab978SDwayne Grant McConnell } 1344104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 1345104f0cc2SMichael Ellerman spufs_signal2_type_set, "%llu", SPU_ATTR_ACQUIRE); 134667207b96SArnd Bergmann 134727d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 134878bde53eSBenjamin Herrenschmidt static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, 134978bde53eSBenjamin Herrenschmidt unsigned long address) 1350d9379c4bSarnd@arndb.de { 135178bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x1000); 1352d9379c4bSarnd@arndb.de } 1353d9379c4bSarnd@arndb.de 1354d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = { 135578bde53eSBenjamin Herrenschmidt .nopfn = spufs_mss_mmap_nopfn, 1356d9379c4bSarnd@arndb.de }; 1357d9379c4bSarnd@arndb.de 1358d9379c4bSarnd@arndb.de /* 1359d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 1360d9379c4bSarnd@arndb.de */ 1361d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 1362d9379c4bSarnd@arndb.de { 1363d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 1364d9379c4bSarnd@arndb.de return -EINVAL; 1365d9379c4bSarnd@arndb.de 136678bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 1367d9379c4bSarnd@arndb.de vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 136823cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 1369d9379c4bSarnd@arndb.de 1370d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 1371d9379c4bSarnd@arndb.de return 0; 1372d9379c4bSarnd@arndb.de } 137327d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 137427d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 137527d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1376d9379c4bSarnd@arndb.de 1377d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 1378d9379c4bSarnd@arndb.de { 1379d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 138017e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 1381d9379c4bSarnd@arndb.de 1382d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 138343c2bbd9SChristoph Hellwig 138447d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 138543c2bbd9SChristoph Hellwig if (!i->i_openers++) 138617e0e270SBenjamin Herrenschmidt ctx->mss = inode->i_mapping; 138747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1388d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 1389d9379c4bSarnd@arndb.de } 1390d9379c4bSarnd@arndb.de 139143c2bbd9SChristoph Hellwig static int 139243c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file) 139343c2bbd9SChristoph Hellwig { 139443c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 139543c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 139643c2bbd9SChristoph Hellwig 139747d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 139843c2bbd9SChristoph Hellwig if (!--i->i_openers) 139943c2bbd9SChristoph Hellwig ctx->mss = NULL; 140047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 140143c2bbd9SChristoph Hellwig return 0; 140243c2bbd9SChristoph Hellwig } 140343c2bbd9SChristoph Hellwig 14045dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = { 1405d9379c4bSarnd@arndb.de .open = spufs_mss_open, 140643c2bbd9SChristoph Hellwig .release = spufs_mss_release, 1407d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 140827d5bf2aSBenjamin Herrenschmidt }; 140927d5bf2aSBenjamin Herrenschmidt 141078bde53eSBenjamin Herrenschmidt static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma, 141178bde53eSBenjamin Herrenschmidt unsigned long address) 141227d5bf2aSBenjamin Herrenschmidt { 141378bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x20000); 141427d5bf2aSBenjamin Herrenschmidt } 141527d5bf2aSBenjamin Herrenschmidt 141627d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = { 141778bde53eSBenjamin Herrenschmidt .nopfn = spufs_psmap_mmap_nopfn, 141827d5bf2aSBenjamin Herrenschmidt }; 141927d5bf2aSBenjamin Herrenschmidt 142027d5bf2aSBenjamin Herrenschmidt /* 142127d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 142227d5bf2aSBenjamin Herrenschmidt */ 142327d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 142427d5bf2aSBenjamin Herrenschmidt { 142527d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 142627d5bf2aSBenjamin Herrenschmidt return -EINVAL; 142727d5bf2aSBenjamin Herrenschmidt 142878bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 142927d5bf2aSBenjamin Herrenschmidt vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 143027d5bf2aSBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 143127d5bf2aSBenjamin Herrenschmidt 143227d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 143327d5bf2aSBenjamin Herrenschmidt return 0; 143427d5bf2aSBenjamin Herrenschmidt } 143527d5bf2aSBenjamin Herrenschmidt 143627d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 143727d5bf2aSBenjamin Herrenschmidt { 143827d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 143917e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 144027d5bf2aSBenjamin Herrenschmidt 144147d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 144227d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 144343c2bbd9SChristoph Hellwig if (!i->i_openers++) 144417e0e270SBenjamin Herrenschmidt ctx->psmap = inode->i_mapping; 144547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 144627d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 144727d5bf2aSBenjamin Herrenschmidt } 144827d5bf2aSBenjamin Herrenschmidt 144943c2bbd9SChristoph Hellwig static int 145043c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file) 145143c2bbd9SChristoph Hellwig { 145243c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 145343c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 145443c2bbd9SChristoph Hellwig 145547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 145643c2bbd9SChristoph Hellwig if (!--i->i_openers) 145743c2bbd9SChristoph Hellwig ctx->psmap = NULL; 145847d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 145943c2bbd9SChristoph Hellwig return 0; 146043c2bbd9SChristoph Hellwig } 146143c2bbd9SChristoph Hellwig 14625dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = { 146327d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 146443c2bbd9SChristoph Hellwig .release = spufs_psmap_release, 146527d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1466d9379c4bSarnd@arndb.de }; 1467d9379c4bSarnd@arndb.de 1468d9379c4bSarnd@arndb.de 146927d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 147078bde53eSBenjamin Herrenschmidt static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma, 147178bde53eSBenjamin Herrenschmidt unsigned long address) 14726df10a82SMark Nutter { 147378bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x3000, 0x1000); 14746df10a82SMark Nutter } 14756df10a82SMark Nutter 14766df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = { 147778bde53eSBenjamin Herrenschmidt .nopfn = spufs_mfc_mmap_nopfn, 14786df10a82SMark Nutter }; 14796df10a82SMark Nutter 14806df10a82SMark Nutter /* 14816df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 14826df10a82SMark Nutter */ 14836df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 14846df10a82SMark Nutter { 14856df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 14866df10a82SMark Nutter return -EINVAL; 14876df10a82SMark Nutter 148878bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 14896df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 149023cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 14916df10a82SMark Nutter 14926df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 14936df10a82SMark Nutter return 0; 14946df10a82SMark Nutter } 149527d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 149627d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 149727d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1498a33a7d73SArnd Bergmann 1499a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1500a33a7d73SArnd Bergmann { 1501a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1502a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1503a33a7d73SArnd Bergmann 1504a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1505a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1506a33a7d73SArnd Bergmann return -EINVAL; 1507a33a7d73SArnd Bergmann 1508a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1509a33a7d73SArnd Bergmann return -EBUSY; 1510a33a7d73SArnd Bergmann 151147d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1512a33a7d73SArnd Bergmann file->private_data = ctx; 151343c2bbd9SChristoph Hellwig if (!i->i_openers++) 151417e0e270SBenjamin Herrenschmidt ctx->mfc = inode->i_mapping; 151547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1516a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1517a33a7d73SArnd Bergmann } 1518a33a7d73SArnd Bergmann 151943c2bbd9SChristoph Hellwig static int 152043c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file) 152143c2bbd9SChristoph Hellwig { 152243c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 152343c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 152443c2bbd9SChristoph Hellwig 152547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 152643c2bbd9SChristoph Hellwig if (!--i->i_openers) 152743c2bbd9SChristoph Hellwig ctx->mfc = NULL; 152847d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 152943c2bbd9SChristoph Hellwig return 0; 153043c2bbd9SChristoph Hellwig } 153143c2bbd9SChristoph Hellwig 1532a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1533a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1534a33a7d73SArnd Bergmann { 1535a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1536a33a7d73SArnd Bergmann 1537e65c2f6fSLuke Browning if (!ctx) 1538e65c2f6fSLuke Browning return; 1539e65c2f6fSLuke Browning 1540a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1541a33a7d73SArnd Bergmann 1542a33a7d73SArnd Bergmann pr_debug("%s %s\n", __FUNCTION__, spu->name); 1543a33a7d73SArnd Bergmann if (ctx->mfc_fasync) { 1544a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1545a33a7d73SArnd Bergmann unsigned int mask; 1546a33a7d73SArnd Bergmann 1547a33a7d73SArnd Bergmann /* no need for spu_acquire in interrupt context */ 1548a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1549a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1550a33a7d73SArnd Bergmann 1551a33a7d73SArnd Bergmann mask = 0; 1552a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1553a33a7d73SArnd Bergmann mask |= POLLOUT; 1554a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1555a33a7d73SArnd Bergmann mask |= POLLIN; 1556a33a7d73SArnd Bergmann 1557a33a7d73SArnd Bergmann kill_fasync(&ctx->mfc_fasync, SIGIO, mask); 1558a33a7d73SArnd Bergmann } 1559a33a7d73SArnd Bergmann } 1560a33a7d73SArnd Bergmann 1561a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1562a33a7d73SArnd Bergmann { 1563a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1564a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1565a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1566a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1567a33a7d73SArnd Bergmann if (*status) 1568a33a7d73SArnd Bergmann return 1; 1569a33a7d73SArnd Bergmann 1570a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1571a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1572a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1573a33a7d73SArnd Bergmann return 0; 1574a33a7d73SArnd Bergmann } 1575a33a7d73SArnd Bergmann 1576a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1577a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1578a33a7d73SArnd Bergmann { 1579a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1580a33a7d73SArnd Bergmann int ret = -EINVAL; 1581a33a7d73SArnd Bergmann u32 status; 1582a33a7d73SArnd Bergmann 1583a33a7d73SArnd Bergmann if (size != 4) 1584a33a7d73SArnd Bergmann goto out; 1585a33a7d73SArnd Bergmann 1586c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1587c9101bdbSChristoph Hellwig if (ret) 1588c9101bdbSChristoph Hellwig return ret; 1589c9101bdbSChristoph Hellwig 1590c9101bdbSChristoph Hellwig ret = -EINVAL; 1591a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1592a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1593a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1594a33a7d73SArnd Bergmann ret = -EAGAIN; 1595a33a7d73SArnd Bergmann else 1596c9101bdbSChristoph Hellwig /* XXX(hch): shouldn't we clear ret here? */ 1597a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1598a33a7d73SArnd Bergmann } else { 1599a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1600a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1601a33a7d73SArnd Bergmann } 1602a33a7d73SArnd Bergmann spu_release(ctx); 1603a33a7d73SArnd Bergmann 1604a33a7d73SArnd Bergmann if (ret) 1605a33a7d73SArnd Bergmann goto out; 1606a33a7d73SArnd Bergmann 1607a33a7d73SArnd Bergmann ret = 4; 1608a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1609a33a7d73SArnd Bergmann ret = -EFAULT; 1610a33a7d73SArnd Bergmann 1611a33a7d73SArnd Bergmann out: 1612a33a7d73SArnd Bergmann return ret; 1613a33a7d73SArnd Bergmann } 1614a33a7d73SArnd Bergmann 1615a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1616a33a7d73SArnd Bergmann { 1617a33a7d73SArnd Bergmann pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, 1618a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1619a33a7d73SArnd Bergmann 1620a33a7d73SArnd Bergmann switch (cmd->cmd) { 1621a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1622a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1623a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1624a33a7d73SArnd Bergmann case MFC_GET_CMD: 1625a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1626a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1627a33a7d73SArnd Bergmann break; 1628a33a7d73SArnd Bergmann default: 1629a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1630a33a7d73SArnd Bergmann return -EIO; 1631a33a7d73SArnd Bergmann } 1632a33a7d73SArnd Bergmann 1633a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 1634a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment, ea %lx lsa %x\n", 1635a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1636a33a7d73SArnd Bergmann return -EIO; 1637a33a7d73SArnd Bergmann } 1638a33a7d73SArnd Bergmann 1639a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1640a33a7d73SArnd Bergmann case 1: 1641a33a7d73SArnd Bergmann break; 1642a33a7d73SArnd Bergmann case 2: 1643a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1644a33a7d73SArnd Bergmann goto error; 1645a33a7d73SArnd Bergmann break; 1646a33a7d73SArnd Bergmann case 4: 1647a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1648a33a7d73SArnd Bergmann goto error; 1649a33a7d73SArnd Bergmann break; 1650a33a7d73SArnd Bergmann case 8: 1651a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1652a33a7d73SArnd Bergmann goto error; 1653a33a7d73SArnd Bergmann break; 1654a33a7d73SArnd Bergmann case 0: 1655a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1656a33a7d73SArnd Bergmann goto error; 1657a33a7d73SArnd Bergmann break; 1658a33a7d73SArnd Bergmann error: 1659a33a7d73SArnd Bergmann default: 1660a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1661a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1662a33a7d73SArnd Bergmann return -EIO; 1663a33a7d73SArnd Bergmann } 1664a33a7d73SArnd Bergmann 1665a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1666a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1667a33a7d73SArnd Bergmann return -EIO; 1668a33a7d73SArnd Bergmann } 1669a33a7d73SArnd Bergmann 1670a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1671a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1672a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1673a33a7d73SArnd Bergmann return -EIO; 1674a33a7d73SArnd Bergmann } 1675a33a7d73SArnd Bergmann 1676a33a7d73SArnd Bergmann if (cmd->class) { 1677a33a7d73SArnd Bergmann /* not supported in this version */ 1678a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1679a33a7d73SArnd Bergmann return -EIO; 1680a33a7d73SArnd Bergmann } 1681a33a7d73SArnd Bergmann 1682a33a7d73SArnd Bergmann return 0; 1683a33a7d73SArnd Bergmann } 1684a33a7d73SArnd Bergmann 1685a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1686a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1687a33a7d73SArnd Bergmann int *error) 1688a33a7d73SArnd Bergmann { 1689a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1690a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1691a33a7d73SArnd Bergmann /* wait for any tag group to complete 1692a33a7d73SArnd Bergmann so we have space for the new command */ 1693a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1694a33a7d73SArnd Bergmann /* try again, because the queue might be 1695a33a7d73SArnd Bergmann empty again */ 1696a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1697a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1698a33a7d73SArnd Bergmann return 0; 1699a33a7d73SArnd Bergmann } 1700a33a7d73SArnd Bergmann return 1; 1701a33a7d73SArnd Bergmann } 1702a33a7d73SArnd Bergmann 1703a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1704a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1705a33a7d73SArnd Bergmann { 1706a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1707a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1708a33a7d73SArnd Bergmann int ret = -EINVAL; 1709a33a7d73SArnd Bergmann 1710a33a7d73SArnd Bergmann if (size != sizeof cmd) 1711a33a7d73SArnd Bergmann goto out; 1712a33a7d73SArnd Bergmann 1713a33a7d73SArnd Bergmann ret = -EFAULT; 1714a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1715a33a7d73SArnd Bergmann goto out; 1716a33a7d73SArnd Bergmann 1717a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1718a33a7d73SArnd Bergmann if (ret) 1719a33a7d73SArnd Bergmann goto out; 1720a33a7d73SArnd Bergmann 1721c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1722c9101bdbSChristoph Hellwig if (ret) 1723c9101bdbSChristoph Hellwig goto out; 1724c9101bdbSChristoph Hellwig 172533bfd7a7SArnd Bergmann ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 1726577f8f10SAkinobu Mita if (ret) 1727577f8f10SAkinobu Mita goto out; 1728577f8f10SAkinobu Mita 1729a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1730a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1731a33a7d73SArnd Bergmann } else { 1732a33a7d73SArnd Bergmann int status; 1733a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1734a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1735a33a7d73SArnd Bergmann if (status) 1736a33a7d73SArnd Bergmann ret = status; 1737a33a7d73SArnd Bergmann } 1738a33a7d73SArnd Bergmann 1739a33a7d73SArnd Bergmann if (ret) 1740933b0e35SKazunori Asayama goto out_unlock; 1741a33a7d73SArnd Bergmann 1742a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 17433692dc66SMasato Noguchi ret = size; 1744a33a7d73SArnd Bergmann 1745933b0e35SKazunori Asayama out_unlock: 1746933b0e35SKazunori Asayama spu_release(ctx); 1747a33a7d73SArnd Bergmann out: 1748a33a7d73SArnd Bergmann return ret; 1749a33a7d73SArnd Bergmann } 1750a33a7d73SArnd Bergmann 1751a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) 1752a33a7d73SArnd Bergmann { 1753a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1754a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1755a33a7d73SArnd Bergmann unsigned int mask; 1756a33a7d73SArnd Bergmann 1757933b0e35SKazunori Asayama poll_wait(file, &ctx->mfc_wq, wait); 1758933b0e35SKazunori Asayama 1759c9101bdbSChristoph Hellwig /* 1760c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 1761c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 1762c9101bdbSChristoph Hellwig */ 1763c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 1764a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1765a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1766a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1767a33a7d73SArnd Bergmann spu_release(ctx); 1768a33a7d73SArnd Bergmann 1769a33a7d73SArnd Bergmann mask = 0; 1770a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1771a33a7d73SArnd Bergmann mask |= POLLOUT | POLLWRNORM; 1772a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1773a33a7d73SArnd Bergmann mask |= POLLIN | POLLRDNORM; 1774a33a7d73SArnd Bergmann 1775a33a7d73SArnd Bergmann pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, 1776a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1777a33a7d73SArnd Bergmann 1778a33a7d73SArnd Bergmann return mask; 1779a33a7d73SArnd Bergmann } 1780a33a7d73SArnd Bergmann 178173b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1782a33a7d73SArnd Bergmann { 1783a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1784a33a7d73SArnd Bergmann int ret; 1785a33a7d73SArnd Bergmann 1786c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1787c9101bdbSChristoph Hellwig if (ret) 1788c9101bdbSChristoph Hellwig return ret; 1789a33a7d73SArnd Bergmann #if 0 1790a33a7d73SArnd Bergmann /* this currently hangs */ 1791a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1792a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1793a33a7d73SArnd Bergmann if (ret) 1794a33a7d73SArnd Bergmann goto out; 1795a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1796a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1797a33a7d73SArnd Bergmann out: 1798a33a7d73SArnd Bergmann #else 1799a33a7d73SArnd Bergmann ret = 0; 1800a33a7d73SArnd Bergmann #endif 1801a33a7d73SArnd Bergmann spu_release(ctx); 1802a33a7d73SArnd Bergmann 1803a33a7d73SArnd Bergmann return ret; 1804a33a7d73SArnd Bergmann } 1805a33a7d73SArnd Bergmann 1806a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, 1807a33a7d73SArnd Bergmann int datasync) 1808a33a7d73SArnd Bergmann { 180973b6af8aSAl Viro return spufs_mfc_flush(file, NULL); 1810a33a7d73SArnd Bergmann } 1811a33a7d73SArnd Bergmann 1812a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on) 1813a33a7d73SArnd Bergmann { 1814a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1815a33a7d73SArnd Bergmann 1816a33a7d73SArnd Bergmann return fasync_helper(fd, file, on, &ctx->mfc_fasync); 1817a33a7d73SArnd Bergmann } 1818a33a7d73SArnd Bergmann 18195dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = { 1820a33a7d73SArnd Bergmann .open = spufs_mfc_open, 182143c2bbd9SChristoph Hellwig .release = spufs_mfc_release, 1822a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1823a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1824a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1825a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1826a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 1827a33a7d73SArnd Bergmann .fasync = spufs_mfc_fasync, 18286df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1829a33a7d73SArnd Bergmann }; 1830a33a7d73SArnd Bergmann 1831197b1a82SChristoph Hellwig static int spufs_npc_set(void *data, u64 val) 183267207b96SArnd Bergmann { 183367207b96SArnd Bergmann struct spu_context *ctx = data; 1834c9101bdbSChristoph Hellwig int ret; 1835c9101bdbSChristoph Hellwig 1836c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1837c9101bdbSChristoph Hellwig if (ret) 1838c9101bdbSChristoph Hellwig return ret; 18398b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 18408b3d6663SArnd Bergmann spu_release(ctx); 1841197b1a82SChristoph Hellwig 1842197b1a82SChristoph Hellwig return 0; 184367207b96SArnd Bergmann } 184467207b96SArnd Bergmann 1845104f0cc2SMichael Ellerman static u64 spufs_npc_get(struct spu_context *ctx) 184678810ff6SMichael Ellerman { 184778810ff6SMichael Ellerman return ctx->ops->npc_read(ctx); 184878810ff6SMichael Ellerman } 1849104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 1850104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE); 185167207b96SArnd Bergmann 1852197b1a82SChristoph Hellwig static int spufs_decr_set(void *data, u64 val) 18538b3d6663SArnd Bergmann { 18548b3d6663SArnd Bergmann struct spu_context *ctx = data; 18558b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1856c9101bdbSChristoph Hellwig int ret; 1857c9101bdbSChristoph Hellwig 1858c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1859c9101bdbSChristoph Hellwig if (ret) 1860c9101bdbSChristoph Hellwig return ret; 18618b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 186227b1ea09SChristoph Hellwig spu_release_saved(ctx); 1863197b1a82SChristoph Hellwig 1864197b1a82SChristoph Hellwig return 0; 18658b3d6663SArnd Bergmann } 18668b3d6663SArnd Bergmann 1867104f0cc2SMichael Ellerman static u64 spufs_decr_get(struct spu_context *ctx) 18688b3d6663SArnd Bergmann { 18698b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1870bf1ab978SDwayne Grant McConnell return lscsa->decr.slot[0]; 1871bf1ab978SDwayne Grant McConnell } 1872104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 1873104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); 18748b3d6663SArnd Bergmann 1875197b1a82SChristoph Hellwig static int spufs_decr_status_set(void *data, u64 val) 18768b3d6663SArnd Bergmann { 18778b3d6663SArnd Bergmann struct spu_context *ctx = data; 1878c9101bdbSChristoph Hellwig int ret; 1879c9101bdbSChristoph Hellwig 1880c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1881c9101bdbSChristoph Hellwig if (ret) 1882c9101bdbSChristoph Hellwig return ret; 1883d40a01d4SMasato Noguchi if (val) 1884d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 1885d40a01d4SMasato Noguchi else 1886d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 188727b1ea09SChristoph Hellwig spu_release_saved(ctx); 1888197b1a82SChristoph Hellwig 1889197b1a82SChristoph Hellwig return 0; 18908b3d6663SArnd Bergmann } 18918b3d6663SArnd Bergmann 1892104f0cc2SMichael Ellerman static u64 spufs_decr_status_get(struct spu_context *ctx) 18938b3d6663SArnd Bergmann { 1894d40a01d4SMasato Noguchi if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 1895d40a01d4SMasato Noguchi return SPU_DECR_STATUS_RUNNING; 1896d40a01d4SMasato Noguchi else 1897d40a01d4SMasato Noguchi return 0; 1898bf1ab978SDwayne Grant McConnell } 1899104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 1900104f0cc2SMichael Ellerman spufs_decr_status_set, "0x%llx\n", 1901104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 19028b3d6663SArnd Bergmann 1903197b1a82SChristoph Hellwig static int spufs_event_mask_set(void *data, u64 val) 19048b3d6663SArnd Bergmann { 19058b3d6663SArnd Bergmann struct spu_context *ctx = data; 19068b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1907c9101bdbSChristoph Hellwig int ret; 1908c9101bdbSChristoph Hellwig 1909c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1910c9101bdbSChristoph Hellwig if (ret) 1911c9101bdbSChristoph Hellwig return ret; 19128b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 191327b1ea09SChristoph Hellwig spu_release_saved(ctx); 1914197b1a82SChristoph Hellwig 1915197b1a82SChristoph Hellwig return 0; 19168b3d6663SArnd Bergmann } 19178b3d6663SArnd Bergmann 1918104f0cc2SMichael Ellerman static u64 spufs_event_mask_get(struct spu_context *ctx) 19198b3d6663SArnd Bergmann { 19208b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1921bf1ab978SDwayne Grant McConnell return lscsa->event_mask.slot[0]; 1922bf1ab978SDwayne Grant McConnell } 1923bf1ab978SDwayne Grant McConnell 1924104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 1925104f0cc2SMichael Ellerman spufs_event_mask_set, "0x%llx\n", 1926104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 19278b3d6663SArnd Bergmann 1928104f0cc2SMichael Ellerman static u64 spufs_event_status_get(struct spu_context *ctx) 1929b9e3bd77SDwayne Grant McConnell { 1930b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1931b9e3bd77SDwayne Grant McConnell u64 stat; 1932b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1933b9e3bd77SDwayne Grant McConnell if (stat) 1934bf1ab978SDwayne Grant McConnell return state->spu_chnldata_RW[0]; 1935bf1ab978SDwayne Grant McConnell return 0; 1936bf1ab978SDwayne Grant McConnell } 1937104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1938104f0cc2SMichael Ellerman NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 1939b9e3bd77SDwayne Grant McConnell 1940197b1a82SChristoph Hellwig static int spufs_srr0_set(void *data, u64 val) 19418b3d6663SArnd Bergmann { 19428b3d6663SArnd Bergmann struct spu_context *ctx = data; 19438b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1944c9101bdbSChristoph Hellwig int ret; 1945c9101bdbSChristoph Hellwig 1946c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1947c9101bdbSChristoph Hellwig if (ret) 1948c9101bdbSChristoph Hellwig return ret; 19498b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 195027b1ea09SChristoph Hellwig spu_release_saved(ctx); 1951197b1a82SChristoph Hellwig 1952197b1a82SChristoph Hellwig return 0; 19538b3d6663SArnd Bergmann } 19548b3d6663SArnd Bergmann 1955104f0cc2SMichael Ellerman static u64 spufs_srr0_get(struct spu_context *ctx) 19568b3d6663SArnd Bergmann { 19578b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1958104f0cc2SMichael Ellerman return lscsa->srr0.slot[0]; 19598b3d6663SArnd Bergmann } 1960104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 1961104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 19628b3d6663SArnd Bergmann 1963104f0cc2SMichael Ellerman static u64 spufs_id_get(struct spu_context *ctx) 19647b1a7014Sarnd@arndb.de { 19657b1a7014Sarnd@arndb.de u64 num; 19667b1a7014Sarnd@arndb.de 19677b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 19687b1a7014Sarnd@arndb.de num = ctx->spu->number; 19697b1a7014Sarnd@arndb.de else 19707b1a7014Sarnd@arndb.de num = (unsigned int)-1; 19717b1a7014Sarnd@arndb.de 19727b1a7014Sarnd@arndb.de return num; 19737b1a7014Sarnd@arndb.de } 1974104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", 1975104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE) 19767b1a7014Sarnd@arndb.de 1977104f0cc2SMichael Ellerman static u64 spufs_object_id_get(struct spu_context *ctx) 1978bf1ab978SDwayne Grant McConnell { 1979bf1ab978SDwayne Grant McConnell /* FIXME: Should there really be no locking here? */ 1980104f0cc2SMichael Ellerman return ctx->object_id; 1981bf1ab978SDwayne Grant McConnell } 1982bf1ab978SDwayne Grant McConnell 1983197b1a82SChristoph Hellwig static int spufs_object_id_set(void *data, u64 id) 198486767277SArnd Bergmann { 198586767277SArnd Bergmann struct spu_context *ctx = data; 198686767277SArnd Bergmann ctx->object_id = id; 1987197b1a82SChristoph Hellwig 1988197b1a82SChristoph Hellwig return 0; 198986767277SArnd Bergmann } 199086767277SArnd Bergmann 1991104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 1992104f0cc2SMichael Ellerman spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); 199386767277SArnd Bergmann 1994104f0cc2SMichael Ellerman static u64 spufs_lslr_get(struct spu_context *ctx) 1995bf1ab978SDwayne Grant McConnell { 1996bf1ab978SDwayne Grant McConnell return ctx->csa.priv2.spu_lslr_RW; 1997bf1ab978SDwayne Grant McConnell } 1998104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", 1999104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 2000b9e3bd77SDwayne Grant McConnell 2001b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 2002b9e3bd77SDwayne Grant McConnell { 2003b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 2004b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 2005b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 2006b9e3bd77SDwayne Grant McConnell return 0; 2007b9e3bd77SDwayne Grant McConnell } 2008b9e3bd77SDwayne Grant McConnell 2009cbe709c1SBenjamin Herrenschmidt static int spufs_caps_show(struct seq_file *s, void *private) 2010cbe709c1SBenjamin Herrenschmidt { 2011cbe709c1SBenjamin Herrenschmidt struct spu_context *ctx = s->private; 2012cbe709c1SBenjamin Herrenschmidt 2013cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_NOSCHED)) 2014cbe709c1SBenjamin Herrenschmidt seq_puts(s, "sched\n"); 2015cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_ISOLATE)) 2016cbe709c1SBenjamin Herrenschmidt seq_puts(s, "step\n"); 2017cbe709c1SBenjamin Herrenschmidt return 0; 2018cbe709c1SBenjamin Herrenschmidt } 2019cbe709c1SBenjamin Herrenschmidt 2020cbe709c1SBenjamin Herrenschmidt static int spufs_caps_open(struct inode *inode, struct file *file) 2021cbe709c1SBenjamin Herrenschmidt { 2022cbe709c1SBenjamin Herrenschmidt return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); 2023cbe709c1SBenjamin Herrenschmidt } 2024cbe709c1SBenjamin Herrenschmidt 2025cbe709c1SBenjamin Herrenschmidt static const struct file_operations spufs_caps_fops = { 2026cbe709c1SBenjamin Herrenschmidt .open = spufs_caps_open, 2027cbe709c1SBenjamin Herrenschmidt .read = seq_read, 2028cbe709c1SBenjamin Herrenschmidt .llseek = seq_lseek, 2029cbe709c1SBenjamin Herrenschmidt .release = single_release, 2030cbe709c1SBenjamin Herrenschmidt }; 2031cbe709c1SBenjamin Herrenschmidt 2032bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, 2033bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2034bf1ab978SDwayne Grant McConnell { 2035bf1ab978SDwayne Grant McConnell u32 data; 2036bf1ab978SDwayne Grant McConnell 2037cbea9238SJeremy Kerr /* EOF if there's no entry in the mbox */ 2038cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0x0000ff)) 2039cbea9238SJeremy Kerr return 0; 2040cbea9238SJeremy Kerr 2041bf1ab978SDwayne Grant McConnell data = ctx->csa.prob.pu_mb_R; 2042bf1ab978SDwayne Grant McConnell 2043bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2044bf1ab978SDwayne Grant McConnell } 2045bf1ab978SDwayne Grant McConnell 204669a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 204769a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 204869a2f00cSDwayne Grant McConnell { 2049bf1ab978SDwayne Grant McConnell int ret; 205069a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 205169a2f00cSDwayne Grant McConnell 205269a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 205369a2f00cSDwayne Grant McConnell return -EFAULT; 205469a2f00cSDwayne Grant McConnell 2055c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2056c9101bdbSChristoph Hellwig if (ret) 2057c9101bdbSChristoph Hellwig return ret; 205869a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2059bf1ab978SDwayne Grant McConnell ret = __spufs_mbox_info_read(ctx, buf, len, pos); 206069a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 206127b1ea09SChristoph Hellwig spu_release_saved(ctx); 206269a2f00cSDwayne Grant McConnell 2063bf1ab978SDwayne Grant McConnell return ret; 206469a2f00cSDwayne Grant McConnell } 206569a2f00cSDwayne Grant McConnell 20665dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = { 206769a2f00cSDwayne Grant McConnell .open = spufs_info_open, 206869a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 206969a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 207069a2f00cSDwayne Grant McConnell }; 207169a2f00cSDwayne Grant McConnell 2072bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, 2073bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2074bf1ab978SDwayne Grant McConnell { 2075bf1ab978SDwayne Grant McConnell u32 data; 2076bf1ab978SDwayne Grant McConnell 2077cbea9238SJeremy Kerr /* EOF if there's no entry in the ibox */ 2078cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) 2079cbea9238SJeremy Kerr return 0; 2080cbea9238SJeremy Kerr 2081bf1ab978SDwayne Grant McConnell data = ctx->csa.priv2.puint_mb_R; 2082bf1ab978SDwayne Grant McConnell 2083bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2084bf1ab978SDwayne Grant McConnell } 2085bf1ab978SDwayne Grant McConnell 208669a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 208769a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 208869a2f00cSDwayne Grant McConnell { 208969a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2090bf1ab978SDwayne Grant McConnell int ret; 209169a2f00cSDwayne Grant McConnell 209269a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 209369a2f00cSDwayne Grant McConnell return -EFAULT; 209469a2f00cSDwayne Grant McConnell 2095c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2096c9101bdbSChristoph Hellwig if (ret) 2097c9101bdbSChristoph Hellwig return ret; 209869a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2099bf1ab978SDwayne Grant McConnell ret = __spufs_ibox_info_read(ctx, buf, len, pos); 210069a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 210127b1ea09SChristoph Hellwig spu_release_saved(ctx); 210269a2f00cSDwayne Grant McConnell 2103bf1ab978SDwayne Grant McConnell return ret; 210469a2f00cSDwayne Grant McConnell } 210569a2f00cSDwayne Grant McConnell 21065dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = { 210769a2f00cSDwayne Grant McConnell .open = spufs_info_open, 210869a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 210969a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 211069a2f00cSDwayne Grant McConnell }; 211169a2f00cSDwayne Grant McConnell 2112bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, 2113bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2114bf1ab978SDwayne Grant McConnell { 2115bf1ab978SDwayne Grant McConnell int i, cnt; 2116bf1ab978SDwayne Grant McConnell u32 data[4]; 2117bf1ab978SDwayne Grant McConnell u32 wbox_stat; 2118bf1ab978SDwayne Grant McConnell 2119bf1ab978SDwayne Grant McConnell wbox_stat = ctx->csa.prob.mb_stat_R; 2120bf1ab978SDwayne Grant McConnell cnt = 4 - ((wbox_stat & 0x00ff00) >> 8); 2121bf1ab978SDwayne Grant McConnell for (i = 0; i < cnt; i++) { 2122bf1ab978SDwayne Grant McConnell data[i] = ctx->csa.spu_mailbox_data[i]; 2123bf1ab978SDwayne Grant McConnell } 2124bf1ab978SDwayne Grant McConnell 2125bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, 2126bf1ab978SDwayne Grant McConnell cnt * sizeof(u32)); 2127bf1ab978SDwayne Grant McConnell } 2128bf1ab978SDwayne Grant McConnell 212969a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 213069a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 213169a2f00cSDwayne Grant McConnell { 213269a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2133bf1ab978SDwayne Grant McConnell int ret; 213469a2f00cSDwayne Grant McConnell 213569a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 213669a2f00cSDwayne Grant McConnell return -EFAULT; 213769a2f00cSDwayne Grant McConnell 2138c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2139c9101bdbSChristoph Hellwig if (ret) 2140c9101bdbSChristoph Hellwig return ret; 214169a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2142bf1ab978SDwayne Grant McConnell ret = __spufs_wbox_info_read(ctx, buf, len, pos); 214369a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 214427b1ea09SChristoph Hellwig spu_release_saved(ctx); 214569a2f00cSDwayne Grant McConnell 2146bf1ab978SDwayne Grant McConnell return ret; 214769a2f00cSDwayne Grant McConnell } 214869a2f00cSDwayne Grant McConnell 21495dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = { 215069a2f00cSDwayne Grant McConnell .open = spufs_info_open, 215169a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 215269a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 215369a2f00cSDwayne Grant McConnell }; 215469a2f00cSDwayne Grant McConnell 2155bf1ab978SDwayne Grant McConnell static ssize_t __spufs_dma_info_read(struct spu_context *ctx, 2156bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2157b9e3bd77SDwayne Grant McConnell { 2158b9e3bd77SDwayne Grant McConnell struct spu_dma_info info; 2159b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *spuqp; 2160b9e3bd77SDwayne Grant McConnell int i; 2161b9e3bd77SDwayne Grant McConnell 2162b9e3bd77SDwayne Grant McConnell info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 2163b9e3bd77SDwayne Grant McConnell info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 2164b9e3bd77SDwayne Grant McConnell info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; 2165b9e3bd77SDwayne Grant McConnell info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 2166b9e3bd77SDwayne Grant McConnell info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 2167b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 2168b9e3bd77SDwayne Grant McConnell qp = &info.dma_info_command_data[i]; 2169b9e3bd77SDwayne Grant McConnell spuqp = &ctx->csa.priv2.spuq[i]; 2170b9e3bd77SDwayne Grant McConnell 2171b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 2172b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 2173b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 2174b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 2175b9e3bd77SDwayne Grant McConnell } 2176b9e3bd77SDwayne Grant McConnell 2177b9e3bd77SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2178b9e3bd77SDwayne Grant McConnell sizeof info); 2179b9e3bd77SDwayne Grant McConnell } 2180b9e3bd77SDwayne Grant McConnell 2181bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 2182bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2183bf1ab978SDwayne Grant McConnell { 2184bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2185bf1ab978SDwayne Grant McConnell int ret; 2186bf1ab978SDwayne Grant McConnell 2187bf1ab978SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2188bf1ab978SDwayne Grant McConnell return -EFAULT; 2189bf1ab978SDwayne Grant McConnell 2190c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2191c9101bdbSChristoph Hellwig if (ret) 2192c9101bdbSChristoph Hellwig return ret; 2193bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2194bf1ab978SDwayne Grant McConnell ret = __spufs_dma_info_read(ctx, buf, len, pos); 2195bf1ab978SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 219627b1ea09SChristoph Hellwig spu_release_saved(ctx); 2197bf1ab978SDwayne Grant McConnell 2198bf1ab978SDwayne Grant McConnell return ret; 2199bf1ab978SDwayne Grant McConnell } 2200bf1ab978SDwayne Grant McConnell 22015dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = { 2202b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2203b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 2204b9e3bd77SDwayne Grant McConnell }; 2205b9e3bd77SDwayne Grant McConnell 2206bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, 2207bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2208b9e3bd77SDwayne Grant McConnell { 2209b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 2210b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *puqp; 2211bf1ab978SDwayne Grant McConnell int ret = sizeof info; 2212b9e3bd77SDwayne Grant McConnell int i; 2213b9e3bd77SDwayne Grant McConnell 2214b9e3bd77SDwayne Grant McConnell if (len < ret) 2215b9e3bd77SDwayne Grant McConnell return -EINVAL; 2216b9e3bd77SDwayne Grant McConnell 2217b9e3bd77SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2218b9e3bd77SDwayne Grant McConnell return -EFAULT; 2219b9e3bd77SDwayne Grant McConnell 2220b9e3bd77SDwayne Grant McConnell info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 2221b9e3bd77SDwayne Grant McConnell info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 2222b9e3bd77SDwayne Grant McConnell info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 2223b9e3bd77SDwayne Grant McConnell for (i = 0; i < 8; i++) { 2224b9e3bd77SDwayne Grant McConnell qp = &info.proxydma_info_command_data[i]; 2225b9e3bd77SDwayne Grant McConnell puqp = &ctx->csa.priv2.puq[i]; 2226b9e3bd77SDwayne Grant McConnell 2227b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 2228b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 2229b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 2230b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 2231b9e3bd77SDwayne Grant McConnell } 2232bf1ab978SDwayne Grant McConnell 2233bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2234bf1ab978SDwayne Grant McConnell sizeof info); 2235bf1ab978SDwayne Grant McConnell } 2236bf1ab978SDwayne Grant McConnell 2237bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 2238bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2239bf1ab978SDwayne Grant McConnell { 2240bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2241bf1ab978SDwayne Grant McConnell int ret; 2242bf1ab978SDwayne Grant McConnell 2243c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2244c9101bdbSChristoph Hellwig if (ret) 2245c9101bdbSChristoph Hellwig return ret; 2246bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2247bf1ab978SDwayne Grant McConnell ret = __spufs_proxydma_info_read(ctx, buf, len, pos); 2248b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 224927b1ea09SChristoph Hellwig spu_release_saved(ctx); 2250b9e3bd77SDwayne Grant McConnell 2251b9e3bd77SDwayne Grant McConnell return ret; 2252b9e3bd77SDwayne Grant McConnell } 2253b9e3bd77SDwayne Grant McConnell 22545dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = { 2255b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2256b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 2257b9e3bd77SDwayne Grant McConnell }; 2258b9e3bd77SDwayne Grant McConnell 2259476273adSChristoph Hellwig static int spufs_show_tid(struct seq_file *s, void *private) 2260476273adSChristoph Hellwig { 2261476273adSChristoph Hellwig struct spu_context *ctx = s->private; 2262476273adSChristoph Hellwig 2263476273adSChristoph Hellwig seq_printf(s, "%d\n", ctx->tid); 2264476273adSChristoph Hellwig return 0; 2265476273adSChristoph Hellwig } 2266476273adSChristoph Hellwig 2267476273adSChristoph Hellwig static int spufs_tid_open(struct inode *inode, struct file *file) 2268476273adSChristoph Hellwig { 2269476273adSChristoph Hellwig return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); 2270476273adSChristoph Hellwig } 2271476273adSChristoph Hellwig 2272476273adSChristoph Hellwig static const struct file_operations spufs_tid_fops = { 2273476273adSChristoph Hellwig .open = spufs_tid_open, 2274476273adSChristoph Hellwig .read = seq_read, 2275476273adSChristoph Hellwig .llseek = seq_lseek, 2276476273adSChristoph Hellwig .release = single_release, 2277476273adSChristoph Hellwig }; 2278476273adSChristoph Hellwig 2279e9f8a0b6SChristoph Hellwig static const char *ctx_state_names[] = { 2280e9f8a0b6SChristoph Hellwig "user", "system", "iowait", "loaded" 2281e9f8a0b6SChristoph Hellwig }; 2282e9f8a0b6SChristoph Hellwig 2283e9f8a0b6SChristoph Hellwig static unsigned long long spufs_acct_time(struct spu_context *ctx, 228427ec41d3SAndre Detsch enum spu_utilization_state state) 2285e9f8a0b6SChristoph Hellwig { 228627ec41d3SAndre Detsch struct timespec ts; 228727ec41d3SAndre Detsch unsigned long long time = ctx->stats.times[state]; 2288e9f8a0b6SChristoph Hellwig 228927ec41d3SAndre Detsch /* 229027ec41d3SAndre Detsch * In general, utilization statistics are updated by the controlling 229127ec41d3SAndre Detsch * thread as the spu context moves through various well defined 229227ec41d3SAndre Detsch * state transitions, but if the context is lazily loaded its 229327ec41d3SAndre Detsch * utilization statistics are not updated as the controlling thread 229427ec41d3SAndre Detsch * is not tightly coupled with the execution of the spu context. We 229527ec41d3SAndre Detsch * calculate and apply the time delta from the last recorded state 229627ec41d3SAndre Detsch * of the spu context. 229727ec41d3SAndre Detsch */ 229827ec41d3SAndre Detsch if (ctx->spu && ctx->stats.util_state == state) { 229927ec41d3SAndre Detsch ktime_get_ts(&ts); 230027ec41d3SAndre Detsch time += timespec_to_ns(&ts) - ctx->stats.tstamp; 230127ec41d3SAndre Detsch } 2302e9f8a0b6SChristoph Hellwig 230327ec41d3SAndre Detsch return time / NSEC_PER_MSEC; 2304e9f8a0b6SChristoph Hellwig } 2305e9f8a0b6SChristoph Hellwig 2306e9f8a0b6SChristoph Hellwig static unsigned long long spufs_slb_flts(struct spu_context *ctx) 2307e9f8a0b6SChristoph Hellwig { 2308e9f8a0b6SChristoph Hellwig unsigned long long slb_flts = ctx->stats.slb_flt; 2309e9f8a0b6SChristoph Hellwig 2310e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2311e9f8a0b6SChristoph Hellwig slb_flts += (ctx->spu->stats.slb_flt - 2312e9f8a0b6SChristoph Hellwig ctx->stats.slb_flt_base); 2313e9f8a0b6SChristoph Hellwig } 2314e9f8a0b6SChristoph Hellwig 2315e9f8a0b6SChristoph Hellwig return slb_flts; 2316e9f8a0b6SChristoph Hellwig } 2317e9f8a0b6SChristoph Hellwig 2318e9f8a0b6SChristoph Hellwig static unsigned long long spufs_class2_intrs(struct spu_context *ctx) 2319e9f8a0b6SChristoph Hellwig { 2320e9f8a0b6SChristoph Hellwig unsigned long long class2_intrs = ctx->stats.class2_intr; 2321e9f8a0b6SChristoph Hellwig 2322e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2323e9f8a0b6SChristoph Hellwig class2_intrs += (ctx->spu->stats.class2_intr - 2324e9f8a0b6SChristoph Hellwig ctx->stats.class2_intr_base); 2325e9f8a0b6SChristoph Hellwig } 2326e9f8a0b6SChristoph Hellwig 2327e9f8a0b6SChristoph Hellwig return class2_intrs; 2328e9f8a0b6SChristoph Hellwig } 2329e9f8a0b6SChristoph Hellwig 2330e9f8a0b6SChristoph Hellwig 2331e9f8a0b6SChristoph Hellwig static int spufs_show_stat(struct seq_file *s, void *private) 2332e9f8a0b6SChristoph Hellwig { 2333e9f8a0b6SChristoph Hellwig struct spu_context *ctx = s->private; 2334c9101bdbSChristoph Hellwig int ret; 2335e9f8a0b6SChristoph Hellwig 2336c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 2337c9101bdbSChristoph Hellwig if (ret) 2338c9101bdbSChristoph Hellwig return ret; 2339c9101bdbSChristoph Hellwig 2340e9f8a0b6SChristoph Hellwig seq_printf(s, "%s %llu %llu %llu %llu " 2341e9f8a0b6SChristoph Hellwig "%llu %llu %llu %llu %llu %llu %llu %llu\n", 234227ec41d3SAndre Detsch ctx_state_names[ctx->stats.util_state], 234327ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_USER), 234427ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 234527ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 234627ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 2347e9f8a0b6SChristoph Hellwig ctx->stats.vol_ctx_switch, 2348e9f8a0b6SChristoph Hellwig ctx->stats.invol_ctx_switch, 2349e9f8a0b6SChristoph Hellwig spufs_slb_flts(ctx), 2350e9f8a0b6SChristoph Hellwig ctx->stats.hash_flt, 2351e9f8a0b6SChristoph Hellwig ctx->stats.min_flt, 2352e9f8a0b6SChristoph Hellwig ctx->stats.maj_flt, 2353e9f8a0b6SChristoph Hellwig spufs_class2_intrs(ctx), 2354e9f8a0b6SChristoph Hellwig ctx->stats.libassist); 2355e9f8a0b6SChristoph Hellwig spu_release(ctx); 2356e9f8a0b6SChristoph Hellwig return 0; 2357e9f8a0b6SChristoph Hellwig } 2358e9f8a0b6SChristoph Hellwig 2359e9f8a0b6SChristoph Hellwig static int spufs_stat_open(struct inode *inode, struct file *file) 2360e9f8a0b6SChristoph Hellwig { 2361e9f8a0b6SChristoph Hellwig return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); 2362e9f8a0b6SChristoph Hellwig } 2363e9f8a0b6SChristoph Hellwig 2364e9f8a0b6SChristoph Hellwig static const struct file_operations spufs_stat_fops = { 2365e9f8a0b6SChristoph Hellwig .open = spufs_stat_open, 2366e9f8a0b6SChristoph Hellwig .read = seq_read, 2367e9f8a0b6SChristoph Hellwig .llseek = seq_lseek, 2368e9f8a0b6SChristoph Hellwig .release = single_release, 2369e9f8a0b6SChristoph Hellwig }; 2370e9f8a0b6SChristoph Hellwig 2371e9f8a0b6SChristoph Hellwig 237267207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 2373cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 237467207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 23758b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 237667207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 237767207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 237867207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 237967207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 238067207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 238167207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2382603c4612SJeremy Kerr { "signal1", &spufs_signal1_fops, 0666, }, 2383603c4612SJeremy Kerr { "signal2", &spufs_signal2_fops, 0666, }, 238467207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 238567207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 23866df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 23878b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 2388b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 2389b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 2390b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 2391b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 2392b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 23938b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 23948b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 23958b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 2396b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 239727d5bf2aSBenjamin Herrenschmidt { "psmap", &spufs_psmap_fops, 0666, }, 239886767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 239986767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 240069a2f00cSDwayne Grant McConnell { "mbox_info", &spufs_mbox_info_fops, 0444, }, 240169a2f00cSDwayne Grant McConnell { "ibox_info", &spufs_ibox_info_fops, 0444, }, 240269a2f00cSDwayne Grant McConnell { "wbox_info", &spufs_wbox_info_fops, 0444, }, 2403b9e3bd77SDwayne Grant McConnell { "dma_info", &spufs_dma_info_fops, 0444, }, 2404b9e3bd77SDwayne Grant McConnell { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, 2405476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2406e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 240767207b96SArnd Bergmann {}, 240867207b96SArnd Bergmann }; 24095737edd1SMark Nutter 24105737edd1SMark Nutter struct tree_descr spufs_dir_nosched_contents[] = { 2411cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 24125737edd1SMark Nutter { "mem", &spufs_mem_fops, 0666, }, 24135737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 24145737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 24155737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 24165737edd1SMark Nutter { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 24175737edd1SMark Nutter { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 24185737edd1SMark Nutter { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2419d054b36fSJeremy Kerr { "signal1", &spufs_signal1_nosched_fops, 0222, }, 2420d054b36fSJeremy Kerr { "signal2", &spufs_signal2_nosched_fops, 0222, }, 24215737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 24225737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 24235737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 24245737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 24255737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 24265737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 24275737edd1SMark Nutter { "psmap", &spufs_psmap_fops, 0666, }, 24285737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 24295737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 2430476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2431e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 24325737edd1SMark Nutter {}, 24335737edd1SMark Nutter }; 2434bf1ab978SDwayne Grant McConnell 2435bf1ab978SDwayne Grant McConnell struct spufs_coredump_reader spufs_coredump_read[] = { 24364fca9c42SMichael Ellerman { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, 24374fca9c42SMichael Ellerman { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, 2438104f0cc2SMichael Ellerman { "lslr", NULL, spufs_lslr_get, 19 }, 2439104f0cc2SMichael Ellerman { "decr", NULL, spufs_decr_get, 19 }, 2440104f0cc2SMichael Ellerman { "decr_status", NULL, spufs_decr_status_get, 19 }, 24414fca9c42SMichael Ellerman { "mem", __spufs_mem_read, NULL, LS_SIZE, }, 24424fca9c42SMichael Ellerman { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, 2443104f0cc2SMichael Ellerman { "signal1_type", NULL, spufs_signal1_type_get, 19 }, 24444fca9c42SMichael Ellerman { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, 2445104f0cc2SMichael Ellerman { "signal2_type", NULL, spufs_signal2_type_get, 19 }, 2446104f0cc2SMichael Ellerman { "event_mask", NULL, spufs_event_mask_get, 19 }, 2447104f0cc2SMichael Ellerman { "event_status", NULL, spufs_event_status_get, 19 }, 24484fca9c42SMichael Ellerman { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, 24494fca9c42SMichael Ellerman { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, 24504fca9c42SMichael Ellerman { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, 24514fca9c42SMichael Ellerman { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, 24524fca9c42SMichael Ellerman { "proxydma_info", __spufs_proxydma_info_read, 24534fca9c42SMichael Ellerman NULL, sizeof(struct spu_proxydma_info)}, 2454104f0cc2SMichael Ellerman { "object-id", NULL, spufs_object_id_get, 19 }, 2455104f0cc2SMichael Ellerman { "npc", NULL, spufs_npc_get, 19 }, 2456936d5bf1SMichael Ellerman { NULL }, 2457bf1ab978SDwayne Grant McConnell }; 2458