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> 3167207b96SArnd Bergmann 3267207b96SArnd Bergmann #include <asm/io.h> 3367207b96SArnd Bergmann #include <asm/semaphore.h> 3467207b96SArnd Bergmann #include <asm/spu.h> 35b9e3bd77SDwayne Grant McConnell #include <asm/spu_info.h> 3667207b96SArnd Bergmann #include <asm/uaccess.h> 3767207b96SArnd Bergmann 3867207b96SArnd Bergmann #include "spufs.h" 3967207b96SArnd Bergmann 4027d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 4127d5bf2aSBenjamin Herrenschmidt 4267207b96SArnd Bergmann static int 4367207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 4467207b96SArnd Bergmann { 4567207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 466df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 4743c2bbd9SChristoph Hellwig 4843c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 496df10a82SMark Nutter file->private_data = ctx; 5043c2bbd9SChristoph Hellwig if (!i->i_openers++) 516df10a82SMark Nutter ctx->local_store = inode->i_mapping; 5243c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 5343c2bbd9SChristoph Hellwig smp_wmb(); 5443c2bbd9SChristoph Hellwig return 0; 5543c2bbd9SChristoph Hellwig } 5643c2bbd9SChristoph Hellwig 5743c2bbd9SChristoph Hellwig static int 5843c2bbd9SChristoph Hellwig spufs_mem_release(struct inode *inode, struct file *file) 5943c2bbd9SChristoph Hellwig { 6043c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 6143c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 6243c2bbd9SChristoph Hellwig 6343c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 6443c2bbd9SChristoph Hellwig if (!--i->i_openers) 6543c2bbd9SChristoph Hellwig ctx->local_store = NULL; 6643c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 6717e0e270SBenjamin Herrenschmidt smp_wmb(); 6867207b96SArnd Bergmann return 0; 6967207b96SArnd Bergmann } 7067207b96SArnd Bergmann 7167207b96SArnd Bergmann static ssize_t 72bf1ab978SDwayne Grant McConnell __spufs_mem_read(struct spu_context *ctx, char __user *buffer, 73bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 74bf1ab978SDwayne Grant McConnell { 75bf1ab978SDwayne Grant McConnell char *local_store = ctx->ops->get_ls(ctx); 76bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, local_store, 77bf1ab978SDwayne Grant McConnell LS_SIZE); 78bf1ab978SDwayne Grant McConnell } 79bf1ab978SDwayne Grant McConnell 80bf1ab978SDwayne Grant McConnell static ssize_t 8167207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 8267207b96SArnd Bergmann size_t size, loff_t *pos) 8367207b96SArnd Bergmann { 84bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 85aa0ed2bdSArnd Bergmann ssize_t ret; 8667207b96SArnd Bergmann 878b3d6663SArnd Bergmann spu_acquire(ctx); 88bf1ab978SDwayne Grant McConnell ret = __spufs_mem_read(ctx, buffer, size, pos); 898b3d6663SArnd Bergmann spu_release(ctx); 9067207b96SArnd Bergmann return ret; 9167207b96SArnd Bergmann } 9267207b96SArnd Bergmann 9367207b96SArnd Bergmann static ssize_t 9467207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 95aa0ed2bdSArnd Bergmann size_t size, loff_t *ppos) 9667207b96SArnd Bergmann { 9767207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 988b3d6663SArnd Bergmann char *local_store; 99aa0ed2bdSArnd Bergmann loff_t pos = *ppos; 1008b3d6663SArnd Bergmann int ret; 10167207b96SArnd Bergmann 102aa0ed2bdSArnd Bergmann if (pos < 0) 103aa0ed2bdSArnd Bergmann return -EINVAL; 104aa0ed2bdSArnd Bergmann if (pos > LS_SIZE) 10567207b96SArnd Bergmann return -EFBIG; 106aa0ed2bdSArnd Bergmann if (size > LS_SIZE - pos) 107aa0ed2bdSArnd Bergmann size = LS_SIZE - pos; 1088b3d6663SArnd Bergmann 1098b3d6663SArnd Bergmann spu_acquire(ctx); 1108b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 111aa0ed2bdSArnd Bergmann ret = copy_from_user(local_store + pos, buffer, size); 1128b3d6663SArnd Bergmann spu_release(ctx); 113aa0ed2bdSArnd Bergmann 114aa0ed2bdSArnd Bergmann if (ret) 115aa0ed2bdSArnd Bergmann return -EFAULT; 116aa0ed2bdSArnd Bergmann *ppos = pos + size; 117aa0ed2bdSArnd Bergmann return size; 11867207b96SArnd Bergmann } 11967207b96SArnd Bergmann 12078bde53eSBenjamin Herrenschmidt static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, 12178bde53eSBenjamin Herrenschmidt unsigned long address) 1228b3d6663SArnd Bergmann { 1238b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 12478bde53eSBenjamin Herrenschmidt unsigned long pfn, offset = address - vma->vm_start; 12578bde53eSBenjamin Herrenschmidt 1268b3d6663SArnd Bergmann offset += vma->vm_pgoff << PAGE_SHIFT; 1278b3d6663SArnd Bergmann 128128b8546SMasato Noguchi if (offset >= LS_SIZE) 129128b8546SMasato Noguchi return NOPFN_SIGBUS; 130128b8546SMasato Noguchi 1318b3d6663SArnd Bergmann spu_acquire(ctx); 1328b3d6663SArnd Bergmann 133ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 134ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 135932f535dSArnd Bergmann & ~_PAGE_NO_CACHE); 13678bde53eSBenjamin Herrenschmidt pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); 137ac91cb8dSArnd Bergmann } else { 138ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 139932f535dSArnd Bergmann | _PAGE_NO_CACHE); 14078bde53eSBenjamin Herrenschmidt pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; 141ac91cb8dSArnd Bergmann } 14278bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, pfn); 14378bde53eSBenjamin Herrenschmidt 1448b3d6663SArnd Bergmann spu_release(ctx); 1458b3d6663SArnd Bergmann 14678bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 1478b3d6663SArnd Bergmann } 1488b3d6663SArnd Bergmann 14978bde53eSBenjamin Herrenschmidt 1508b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = { 15178bde53eSBenjamin Herrenschmidt .nopfn = spufs_mem_mmap_nopfn, 1528b3d6663SArnd Bergmann }; 1538b3d6663SArnd Bergmann 15467207b96SArnd Bergmann static int 15567207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 15667207b96SArnd Bergmann { 1578b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 1588b3d6663SArnd Bergmann return -EINVAL; 15967207b96SArnd Bergmann 16078bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 16167207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 16267207b96SArnd Bergmann | _PAGE_NO_CACHE); 1638b3d6663SArnd Bergmann 1648b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 16567207b96SArnd Bergmann return 0; 16667207b96SArnd Bergmann } 16767207b96SArnd Bergmann 1685dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = { 16967207b96SArnd Bergmann .open = spufs_mem_open, 17043c2bbd9SChristoph Hellwig .release = spufs_mem_release, 17167207b96SArnd Bergmann .read = spufs_mem_read, 17267207b96SArnd Bergmann .write = spufs_mem_write, 1738b3d6663SArnd Bergmann .llseek = generic_file_llseek, 17467207b96SArnd Bergmann .mmap = spufs_mem_mmap, 1758b3d6663SArnd Bergmann }; 1768b3d6663SArnd Bergmann 17778bde53eSBenjamin Herrenschmidt static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, 1786df10a82SMark Nutter unsigned long address, 17978bde53eSBenjamin Herrenschmidt unsigned long ps_offs, 18027d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 1816df10a82SMark Nutter { 1826df10a82SMark Nutter struct spu_context *ctx = vma->vm_file->private_data; 18378bde53eSBenjamin Herrenschmidt unsigned long area, offset = address - vma->vm_start; 1846df10a82SMark Nutter int ret; 1856df10a82SMark Nutter 1866df10a82SMark Nutter offset += vma->vm_pgoff << PAGE_SHIFT; 18727d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 18878bde53eSBenjamin Herrenschmidt return NOPFN_SIGBUS; 1896df10a82SMark Nutter 19078bde53eSBenjamin Herrenschmidt /* error here usually means a signal.. we might want to test 19178bde53eSBenjamin Herrenschmidt * the error code more precisely though 19278bde53eSBenjamin Herrenschmidt */ 19326bec673SChristoph Hellwig ret = spu_acquire_runnable(ctx, 0); 1946df10a82SMark Nutter if (ret) 19578bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 1966df10a82SMark Nutter 1976df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 19878bde53eSBenjamin Herrenschmidt vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); 1996df10a82SMark Nutter spu_release(ctx); 2006df10a82SMark Nutter 20178bde53eSBenjamin Herrenschmidt return NOPFN_REFAULT; 2026df10a82SMark Nutter } 2036df10a82SMark Nutter 20427d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 20578bde53eSBenjamin Herrenschmidt static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, 20678bde53eSBenjamin Herrenschmidt unsigned long address) 2076df10a82SMark Nutter { 20878bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x4000, 0x1000); 2096df10a82SMark Nutter } 2106df10a82SMark Nutter 2116df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = { 21278bde53eSBenjamin Herrenschmidt .nopfn = spufs_cntl_mmap_nopfn, 2136df10a82SMark Nutter }; 2146df10a82SMark Nutter 2156df10a82SMark Nutter /* 2166df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 2176df10a82SMark Nutter */ 2186df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 2196df10a82SMark Nutter { 2206df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 2216df10a82SMark Nutter return -EINVAL; 2226df10a82SMark Nutter 22378bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 2246df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 22523cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 2266df10a82SMark Nutter 2276df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 2286df10a82SMark Nutter return 0; 2296df10a82SMark Nutter } 23027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 23127d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 23227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 2336df10a82SMark Nutter 234e1dbff2bSArnd Bergmann static u64 spufs_cntl_get(void *data) 235e1dbff2bSArnd Bergmann { 236e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 237e1dbff2bSArnd Bergmann u64 val; 238e1dbff2bSArnd Bergmann 239e1dbff2bSArnd Bergmann spu_acquire(ctx); 240e1dbff2bSArnd Bergmann val = ctx->ops->status_read(ctx); 241e1dbff2bSArnd Bergmann spu_release(ctx); 242e1dbff2bSArnd Bergmann 243e1dbff2bSArnd Bergmann return val; 244e1dbff2bSArnd Bergmann } 245e1dbff2bSArnd Bergmann 246e1dbff2bSArnd Bergmann static void spufs_cntl_set(void *data, u64 val) 247e1dbff2bSArnd Bergmann { 248e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 249e1dbff2bSArnd Bergmann 250e1dbff2bSArnd Bergmann spu_acquire(ctx); 251e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 252e1dbff2bSArnd Bergmann spu_release(ctx); 253e1dbff2bSArnd Bergmann } 254e1dbff2bSArnd Bergmann 2556df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 2566df10a82SMark Nutter { 2576df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 2586df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 2596df10a82SMark Nutter 26043c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 2616df10a82SMark Nutter file->private_data = ctx; 26243c2bbd9SChristoph Hellwig if (!i->i_openers++) 2636df10a82SMark Nutter ctx->cntl = inode->i_mapping; 26443c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 26517e0e270SBenjamin Herrenschmidt smp_wmb(); 266e1dbff2bSArnd Bergmann return simple_attr_open(inode, file, spufs_cntl_get, 267e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 2686df10a82SMark Nutter } 2696df10a82SMark Nutter 27043c2bbd9SChristoph Hellwig static int 27143c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file) 27243c2bbd9SChristoph Hellwig { 27343c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 27443c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 27543c2bbd9SChristoph Hellwig 27643c2bbd9SChristoph Hellwig simple_attr_close(inode, file); 27743c2bbd9SChristoph Hellwig 27843c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 27943c2bbd9SChristoph Hellwig if (!--i->i_openers) 28043c2bbd9SChristoph Hellwig ctx->cntl = NULL; 28143c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 28243c2bbd9SChristoph Hellwig smp_wmb(); 28343c2bbd9SChristoph Hellwig return 0; 28443c2bbd9SChristoph Hellwig } 28543c2bbd9SChristoph Hellwig 2865dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = { 2876df10a82SMark Nutter .open = spufs_cntl_open, 28843c2bbd9SChristoph Hellwig .release = spufs_cntl_release, 289e1dbff2bSArnd Bergmann .read = simple_attr_read, 290e1dbff2bSArnd Bergmann .write = simple_attr_write, 2916df10a82SMark Nutter .mmap = spufs_cntl_mmap, 2926df10a82SMark Nutter }; 2936df10a82SMark Nutter 2948b3d6663SArnd Bergmann static int 2958b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 2968b3d6663SArnd Bergmann { 2978b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 2988b3d6663SArnd Bergmann file->private_data = i->i_ctx; 2998b3d6663SArnd Bergmann return 0; 3008b3d6663SArnd Bergmann } 3018b3d6663SArnd Bergmann 3028b3d6663SArnd Bergmann static ssize_t 303bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer, 304bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 305bf1ab978SDwayne Grant McConnell { 306bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 307bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 308bf1ab978SDwayne Grant McConnell lscsa->gprs, sizeof lscsa->gprs); 309bf1ab978SDwayne Grant McConnell } 310bf1ab978SDwayne Grant McConnell 311bf1ab978SDwayne Grant McConnell static ssize_t 3128b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 3138b3d6663SArnd Bergmann size_t size, loff_t *pos) 3148b3d6663SArnd Bergmann { 3158b3d6663SArnd Bergmann int ret; 316bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 3178b3d6663SArnd Bergmann 3188b3d6663SArnd Bergmann spu_acquire_saved(ctx); 319bf1ab978SDwayne Grant McConnell ret = __spufs_regs_read(ctx, buffer, size, pos); 3208b3d6663SArnd Bergmann spu_release(ctx); 3218b3d6663SArnd Bergmann return ret; 3228b3d6663SArnd Bergmann } 3238b3d6663SArnd Bergmann 3248b3d6663SArnd Bergmann static ssize_t 3258b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 3268b3d6663SArnd Bergmann size_t size, loff_t *pos) 3278b3d6663SArnd Bergmann { 3288b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3298b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 3308b3d6663SArnd Bergmann int ret; 3318b3d6663SArnd Bergmann 3328b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 3338b3d6663SArnd Bergmann if (size <= 0) 3348b3d6663SArnd Bergmann return -EFBIG; 3358b3d6663SArnd Bergmann *pos += size; 3368b3d6663SArnd Bergmann 3378b3d6663SArnd Bergmann spu_acquire_saved(ctx); 3388b3d6663SArnd Bergmann 3398b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 3408b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 3418b3d6663SArnd Bergmann 3428b3d6663SArnd Bergmann spu_release(ctx); 3438b3d6663SArnd Bergmann return ret; 3448b3d6663SArnd Bergmann } 3458b3d6663SArnd Bergmann 3465dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = { 3478b3d6663SArnd Bergmann .open = spufs_regs_open, 3488b3d6663SArnd Bergmann .read = spufs_regs_read, 3498b3d6663SArnd Bergmann .write = spufs_regs_write, 3508b3d6663SArnd Bergmann .llseek = generic_file_llseek, 3518b3d6663SArnd Bergmann }; 3528b3d6663SArnd Bergmann 3538b3d6663SArnd Bergmann static ssize_t 354bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, 355bf1ab978SDwayne Grant McConnell size_t size, loff_t * pos) 356bf1ab978SDwayne Grant McConnell { 357bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 358bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 359bf1ab978SDwayne Grant McConnell &lscsa->fpcr, sizeof(lscsa->fpcr)); 360bf1ab978SDwayne Grant McConnell } 361bf1ab978SDwayne Grant McConnell 362bf1ab978SDwayne Grant McConnell static ssize_t 3638b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 3648b3d6663SArnd Bergmann size_t size, loff_t * pos) 3658b3d6663SArnd Bergmann { 3668b3d6663SArnd Bergmann int ret; 367bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 3688b3d6663SArnd Bergmann 3698b3d6663SArnd Bergmann spu_acquire_saved(ctx); 370bf1ab978SDwayne Grant McConnell ret = __spufs_fpcr_read(ctx, buffer, size, pos); 3718b3d6663SArnd Bergmann spu_release(ctx); 3728b3d6663SArnd Bergmann return ret; 3738b3d6663SArnd Bergmann } 3748b3d6663SArnd Bergmann 3758b3d6663SArnd Bergmann static ssize_t 3768b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 3778b3d6663SArnd Bergmann size_t size, loff_t * pos) 3788b3d6663SArnd Bergmann { 3798b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3808b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 3818b3d6663SArnd Bergmann int ret; 3828b3d6663SArnd Bergmann 3838b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 3848b3d6663SArnd Bergmann if (size <= 0) 3858b3d6663SArnd Bergmann return -EFBIG; 3868b3d6663SArnd Bergmann *pos += size; 3878b3d6663SArnd Bergmann 3888b3d6663SArnd Bergmann spu_acquire_saved(ctx); 3898b3d6663SArnd Bergmann 3908b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 3918b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 3928b3d6663SArnd Bergmann 3938b3d6663SArnd Bergmann spu_release(ctx); 3948b3d6663SArnd Bergmann return ret; 3958b3d6663SArnd Bergmann } 3968b3d6663SArnd Bergmann 3975dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = { 3988b3d6663SArnd Bergmann .open = spufs_regs_open, 3998b3d6663SArnd Bergmann .read = spufs_fpcr_read, 4008b3d6663SArnd Bergmann .write = spufs_fpcr_write, 40167207b96SArnd Bergmann .llseek = generic_file_llseek, 40267207b96SArnd Bergmann }; 40367207b96SArnd Bergmann 40467207b96SArnd Bergmann /* generic open function for all pipe-like files */ 40567207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 40667207b96SArnd Bergmann { 40767207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 40867207b96SArnd Bergmann file->private_data = i->i_ctx; 40967207b96SArnd Bergmann 41067207b96SArnd Bergmann return nonseekable_open(inode, file); 41167207b96SArnd Bergmann } 41267207b96SArnd Bergmann 413cdcc89bbSArnd Bergmann /* 414cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 415cdcc89bbSArnd Bergmann * one of the conditions becomes true: 416cdcc89bbSArnd Bergmann * 417cdcc89bbSArnd Bergmann * - no more data available in the mailbox 418cdcc89bbSArnd Bergmann * - end of the user provided buffer 419cdcc89bbSArnd Bergmann * - end of the mapped area 420cdcc89bbSArnd Bergmann */ 42167207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 42267207b96SArnd Bergmann size_t len, loff_t *pos) 42367207b96SArnd Bergmann { 4248b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 425cdcc89bbSArnd Bergmann u32 mbox_data, __user *udata; 426cdcc89bbSArnd Bergmann ssize_t count; 42767207b96SArnd Bergmann 42867207b96SArnd Bergmann if (len < 4) 42967207b96SArnd Bergmann return -EINVAL; 43067207b96SArnd Bergmann 431cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 43267207b96SArnd Bergmann return -EFAULT; 43367207b96SArnd Bergmann 434cdcc89bbSArnd Bergmann udata = (void __user *)buf; 435cdcc89bbSArnd Bergmann 436cdcc89bbSArnd Bergmann spu_acquire(ctx); 437274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 438cdcc89bbSArnd Bergmann int ret; 439cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 440cdcc89bbSArnd Bergmann if (ret == 0) 441cdcc89bbSArnd Bergmann break; 442cdcc89bbSArnd Bergmann 443cdcc89bbSArnd Bergmann /* 444cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 445cdcc89bbSArnd Bergmann * but still need to return the data we have 446cdcc89bbSArnd Bergmann * read successfully so far. 447cdcc89bbSArnd Bergmann */ 448cdcc89bbSArnd Bergmann ret = __put_user(mbox_data, udata); 449cdcc89bbSArnd Bergmann if (ret) { 450cdcc89bbSArnd Bergmann if (!count) 451cdcc89bbSArnd Bergmann count = -EFAULT; 452cdcc89bbSArnd Bergmann break; 453cdcc89bbSArnd Bergmann } 454cdcc89bbSArnd Bergmann } 455cdcc89bbSArnd Bergmann spu_release(ctx); 456cdcc89bbSArnd Bergmann 457cdcc89bbSArnd Bergmann if (!count) 458cdcc89bbSArnd Bergmann count = -EAGAIN; 459cdcc89bbSArnd Bergmann 460cdcc89bbSArnd Bergmann return count; 46167207b96SArnd Bergmann } 46267207b96SArnd Bergmann 4635dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = { 46467207b96SArnd Bergmann .open = spufs_pipe_open, 46567207b96SArnd Bergmann .read = spufs_mbox_read, 46667207b96SArnd Bergmann }; 46767207b96SArnd Bergmann 46867207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 46967207b96SArnd Bergmann size_t len, loff_t *pos) 47067207b96SArnd Bergmann { 4718b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 47267207b96SArnd Bergmann u32 mbox_stat; 47367207b96SArnd Bergmann 47467207b96SArnd Bergmann if (len < 4) 47567207b96SArnd Bergmann return -EINVAL; 47667207b96SArnd Bergmann 4778b3d6663SArnd Bergmann spu_acquire(ctx); 4788b3d6663SArnd Bergmann 4798b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 4808b3d6663SArnd Bergmann 4818b3d6663SArnd Bergmann spu_release(ctx); 48267207b96SArnd Bergmann 48367207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 48467207b96SArnd Bergmann return -EFAULT; 48567207b96SArnd Bergmann 48667207b96SArnd Bergmann return 4; 48767207b96SArnd Bergmann } 48867207b96SArnd Bergmann 4895dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = { 49067207b96SArnd Bergmann .open = spufs_pipe_open, 49167207b96SArnd Bergmann .read = spufs_mbox_stat_read, 49267207b96SArnd Bergmann }; 49367207b96SArnd Bergmann 49467207b96SArnd Bergmann /* low-level ibox access function */ 4958b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 49667207b96SArnd Bergmann { 4978b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 49867207b96SArnd Bergmann } 49967207b96SArnd Bergmann 50067207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 50167207b96SArnd Bergmann { 5028b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5038b3d6663SArnd Bergmann 5048b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 5058b3d6663SArnd Bergmann } 5068b3d6663SArnd Bergmann 5078b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 5088b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 5098b3d6663SArnd Bergmann { 5108b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 5118b3d6663SArnd Bergmann 5128b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 5138b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 51467207b96SArnd Bergmann } 51567207b96SArnd Bergmann 516cdcc89bbSArnd Bergmann /* 517cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 518cdcc89bbSArnd Bergmann * one of the conditions becomes true: 519cdcc89bbSArnd Bergmann * 520cdcc89bbSArnd Bergmann * - no more data available in the mailbox 521cdcc89bbSArnd Bergmann * - end of the user provided buffer 522cdcc89bbSArnd Bergmann * - end of the mapped area 523cdcc89bbSArnd Bergmann * 524cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 525cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 526cdcc89bbSArnd Bergmann * read something. 527cdcc89bbSArnd Bergmann */ 52867207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 52967207b96SArnd Bergmann size_t len, loff_t *pos) 53067207b96SArnd Bergmann { 5318b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 532cdcc89bbSArnd Bergmann u32 ibox_data, __user *udata; 533cdcc89bbSArnd Bergmann ssize_t count; 53467207b96SArnd Bergmann 53567207b96SArnd Bergmann if (len < 4) 53667207b96SArnd Bergmann return -EINVAL; 53767207b96SArnd Bergmann 538cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 539cdcc89bbSArnd Bergmann return -EFAULT; 540cdcc89bbSArnd Bergmann 541cdcc89bbSArnd Bergmann udata = (void __user *)buf; 542cdcc89bbSArnd Bergmann 5438b3d6663SArnd Bergmann spu_acquire(ctx); 54467207b96SArnd Bergmann 545cdcc89bbSArnd Bergmann /* wait only for the first element */ 546cdcc89bbSArnd Bergmann count = 0; 54767207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 5488b3d6663SArnd Bergmann if (!spu_ibox_read(ctx, &ibox_data)) 549cdcc89bbSArnd Bergmann count = -EAGAIN; 55067207b96SArnd Bergmann } else { 551cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 552cdcc89bbSArnd Bergmann } 553cdcc89bbSArnd Bergmann if (count) 554cdcc89bbSArnd Bergmann goto out; 555cdcc89bbSArnd Bergmann 556cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 557cdcc89bbSArnd Bergmann count = __put_user(ibox_data, udata); 558cdcc89bbSArnd Bergmann if (count) 559cdcc89bbSArnd Bergmann goto out; 560cdcc89bbSArnd Bergmann 561cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 562cdcc89bbSArnd Bergmann int ret; 563cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 564cdcc89bbSArnd Bergmann if (ret == 0) 565cdcc89bbSArnd Bergmann break; 566cdcc89bbSArnd Bergmann /* 567cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 568cdcc89bbSArnd Bergmann * but still need to return the data we have 569cdcc89bbSArnd Bergmann * read successfully so far. 570cdcc89bbSArnd Bergmann */ 571cdcc89bbSArnd Bergmann ret = __put_user(ibox_data, udata); 572cdcc89bbSArnd Bergmann if (ret) 573cdcc89bbSArnd Bergmann break; 57467207b96SArnd Bergmann } 57567207b96SArnd Bergmann 576cdcc89bbSArnd Bergmann out: 5778b3d6663SArnd Bergmann spu_release(ctx); 5788b3d6663SArnd Bergmann 579cdcc89bbSArnd Bergmann return count; 58067207b96SArnd Bergmann } 58167207b96SArnd Bergmann 58267207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 58367207b96SArnd Bergmann { 5848b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 58567207b96SArnd Bergmann unsigned int mask; 58667207b96SArnd Bergmann 5878b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 58867207b96SArnd Bergmann 5893a843d7cSArnd Bergmann spu_acquire(ctx); 5903a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 5913a843d7cSArnd Bergmann spu_release(ctx); 59267207b96SArnd Bergmann 59367207b96SArnd Bergmann return mask; 59467207b96SArnd Bergmann } 59567207b96SArnd Bergmann 5965dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = { 59767207b96SArnd Bergmann .open = spufs_pipe_open, 59867207b96SArnd Bergmann .read = spufs_ibox_read, 59967207b96SArnd Bergmann .poll = spufs_ibox_poll, 60067207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 60167207b96SArnd Bergmann }; 60267207b96SArnd Bergmann 60367207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 60467207b96SArnd Bergmann size_t len, loff_t *pos) 60567207b96SArnd Bergmann { 6068b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 60767207b96SArnd Bergmann u32 ibox_stat; 60867207b96SArnd Bergmann 60967207b96SArnd Bergmann if (len < 4) 61067207b96SArnd Bergmann return -EINVAL; 61167207b96SArnd Bergmann 6128b3d6663SArnd Bergmann spu_acquire(ctx); 6138b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 6148b3d6663SArnd Bergmann spu_release(ctx); 61567207b96SArnd Bergmann 61667207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 61767207b96SArnd Bergmann return -EFAULT; 61867207b96SArnd Bergmann 61967207b96SArnd Bergmann return 4; 62067207b96SArnd Bergmann } 62167207b96SArnd Bergmann 6225dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = { 62367207b96SArnd Bergmann .open = spufs_pipe_open, 62467207b96SArnd Bergmann .read = spufs_ibox_stat_read, 62567207b96SArnd Bergmann }; 62667207b96SArnd Bergmann 62767207b96SArnd Bergmann /* low-level mailbox write */ 6288b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 62967207b96SArnd Bergmann { 6308b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 63167207b96SArnd Bergmann } 63267207b96SArnd Bergmann 63367207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 63467207b96SArnd Bergmann { 6358b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 6368b3d6663SArnd Bergmann int ret; 6378b3d6663SArnd Bergmann 6388b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 6398b3d6663SArnd Bergmann 6408b3d6663SArnd Bergmann return ret; 6418b3d6663SArnd Bergmann } 6428b3d6663SArnd Bergmann 6438b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 6448b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 6458b3d6663SArnd Bergmann { 6468b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 6478b3d6663SArnd Bergmann 6488b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 6498b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 65067207b96SArnd Bergmann } 65167207b96SArnd Bergmann 652cdcc89bbSArnd Bergmann /* 653cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 654cdcc89bbSArnd Bergmann * one of the conditions becomes true: 655cdcc89bbSArnd Bergmann * 656cdcc89bbSArnd Bergmann * - the mailbox is full 657cdcc89bbSArnd Bergmann * - end of the user provided buffer 658cdcc89bbSArnd Bergmann * - end of the mapped area 659cdcc89bbSArnd Bergmann * 660cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 661cdcc89bbSArnd Bergmann * space is availabyl, but return when we have been able to 662cdcc89bbSArnd Bergmann * write something. 663cdcc89bbSArnd Bergmann */ 66467207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 66567207b96SArnd Bergmann size_t len, loff_t *pos) 66667207b96SArnd Bergmann { 6678b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 668cdcc89bbSArnd Bergmann u32 wbox_data, __user *udata; 669cdcc89bbSArnd Bergmann ssize_t count; 67067207b96SArnd Bergmann 67167207b96SArnd Bergmann if (len < 4) 67267207b96SArnd Bergmann return -EINVAL; 67367207b96SArnd Bergmann 674cdcc89bbSArnd Bergmann udata = (void __user *)buf; 675cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_READ, buf, len)) 676cdcc89bbSArnd Bergmann return -EFAULT; 677cdcc89bbSArnd Bergmann 678cdcc89bbSArnd Bergmann if (__get_user(wbox_data, udata)) 67967207b96SArnd Bergmann return -EFAULT; 68067207b96SArnd Bergmann 6818b3d6663SArnd Bergmann spu_acquire(ctx); 6828b3d6663SArnd Bergmann 683cdcc89bbSArnd Bergmann /* 684cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 685cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 686cdcc89bbSArnd Bergmann */ 687cdcc89bbSArnd Bergmann count = 0; 68867207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 6898b3d6663SArnd Bergmann if (!spu_wbox_write(ctx, wbox_data)) 690cdcc89bbSArnd Bergmann count = -EAGAIN; 69167207b96SArnd Bergmann } else { 692cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 69367207b96SArnd Bergmann } 69467207b96SArnd Bergmann 695cdcc89bbSArnd Bergmann if (count) 696cdcc89bbSArnd Bergmann goto out; 6978b3d6663SArnd Bergmann 698cdcc89bbSArnd Bergmann /* write aѕ much as possible */ 699cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 700cdcc89bbSArnd Bergmann int ret; 701cdcc89bbSArnd Bergmann ret = __get_user(wbox_data, udata); 702cdcc89bbSArnd Bergmann if (ret) 703cdcc89bbSArnd Bergmann break; 704cdcc89bbSArnd Bergmann 705cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 706cdcc89bbSArnd Bergmann if (ret == 0) 707cdcc89bbSArnd Bergmann break; 708cdcc89bbSArnd Bergmann } 709cdcc89bbSArnd Bergmann 710cdcc89bbSArnd Bergmann out: 711cdcc89bbSArnd Bergmann spu_release(ctx); 712cdcc89bbSArnd Bergmann return count; 71367207b96SArnd Bergmann } 71467207b96SArnd Bergmann 71567207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 71667207b96SArnd Bergmann { 7178b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 71867207b96SArnd Bergmann unsigned int mask; 71967207b96SArnd Bergmann 7208b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 72167207b96SArnd Bergmann 7223a843d7cSArnd Bergmann spu_acquire(ctx); 7233a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 7243a843d7cSArnd Bergmann spu_release(ctx); 72567207b96SArnd Bergmann 72667207b96SArnd Bergmann return mask; 72767207b96SArnd Bergmann } 72867207b96SArnd Bergmann 7295dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = { 73067207b96SArnd Bergmann .open = spufs_pipe_open, 73167207b96SArnd Bergmann .write = spufs_wbox_write, 73267207b96SArnd Bergmann .poll = spufs_wbox_poll, 73367207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 73467207b96SArnd Bergmann }; 73567207b96SArnd Bergmann 73667207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 73767207b96SArnd Bergmann size_t len, loff_t *pos) 73867207b96SArnd Bergmann { 7398b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 74067207b96SArnd Bergmann u32 wbox_stat; 74167207b96SArnd Bergmann 74267207b96SArnd Bergmann if (len < 4) 74367207b96SArnd Bergmann return -EINVAL; 74467207b96SArnd Bergmann 7458b3d6663SArnd Bergmann spu_acquire(ctx); 7468b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 7478b3d6663SArnd Bergmann spu_release(ctx); 74867207b96SArnd Bergmann 74967207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 75067207b96SArnd Bergmann return -EFAULT; 75167207b96SArnd Bergmann 75267207b96SArnd Bergmann return 4; 75367207b96SArnd Bergmann } 75467207b96SArnd Bergmann 7555dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = { 75667207b96SArnd Bergmann .open = spufs_pipe_open, 75767207b96SArnd Bergmann .read = spufs_wbox_stat_read, 75867207b96SArnd Bergmann }; 75967207b96SArnd Bergmann 7606df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 7616df10a82SMark Nutter { 7626df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 7636df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 76443c2bbd9SChristoph Hellwig 76543c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 7666df10a82SMark Nutter file->private_data = ctx; 76743c2bbd9SChristoph Hellwig if (!i->i_openers++) 7686df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 76943c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 77017e0e270SBenjamin Herrenschmidt smp_wmb(); 7716df10a82SMark Nutter return nonseekable_open(inode, file); 7726df10a82SMark Nutter } 7736df10a82SMark Nutter 77443c2bbd9SChristoph Hellwig static int 77543c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file) 77643c2bbd9SChristoph Hellwig { 77743c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 77843c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 77943c2bbd9SChristoph Hellwig 78043c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 78143c2bbd9SChristoph Hellwig if (!--i->i_openers) 78243c2bbd9SChristoph Hellwig ctx->signal1 = NULL; 78343c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 78443c2bbd9SChristoph Hellwig smp_wmb(); 78543c2bbd9SChristoph Hellwig return 0; 78643c2bbd9SChristoph Hellwig } 78743c2bbd9SChristoph Hellwig 788bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 78967207b96SArnd Bergmann size_t len, loff_t *pos) 79067207b96SArnd Bergmann { 79117f88cebSDwayne Grant McConnell int ret = 0; 79267207b96SArnd Bergmann u32 data; 79367207b96SArnd Bergmann 79467207b96SArnd Bergmann if (len < 4) 79567207b96SArnd Bergmann return -EINVAL; 79667207b96SArnd Bergmann 79717f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[3]) { 79817f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[3]; 79917f88cebSDwayne Grant McConnell ret = 4; 80017f88cebSDwayne Grant McConnell } 8018b3d6663SArnd Bergmann 80217f88cebSDwayne Grant McConnell if (!ret) 80317f88cebSDwayne Grant McConnell goto out; 80417f88cebSDwayne Grant McConnell 80567207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 80667207b96SArnd Bergmann return -EFAULT; 80767207b96SArnd Bergmann 80817f88cebSDwayne Grant McConnell out: 80917f88cebSDwayne Grant McConnell return ret; 81067207b96SArnd Bergmann } 81167207b96SArnd Bergmann 812bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 813bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 814bf1ab978SDwayne Grant McConnell { 815bf1ab978SDwayne Grant McConnell int ret; 816bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 817bf1ab978SDwayne Grant McConnell 818bf1ab978SDwayne Grant McConnell spu_acquire_saved(ctx); 819bf1ab978SDwayne Grant McConnell ret = __spufs_signal1_read(ctx, buf, len, pos); 820bf1ab978SDwayne Grant McConnell spu_release(ctx); 821bf1ab978SDwayne Grant McConnell 822bf1ab978SDwayne Grant McConnell return ret; 823bf1ab978SDwayne Grant McConnell } 824bf1ab978SDwayne Grant McConnell 82567207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 82667207b96SArnd Bergmann size_t len, loff_t *pos) 82767207b96SArnd Bergmann { 82867207b96SArnd Bergmann struct spu_context *ctx; 82967207b96SArnd Bergmann u32 data; 83067207b96SArnd Bergmann 83167207b96SArnd Bergmann ctx = file->private_data; 83267207b96SArnd Bergmann 83367207b96SArnd Bergmann if (len < 4) 83467207b96SArnd Bergmann return -EINVAL; 83567207b96SArnd Bergmann 83667207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 83767207b96SArnd Bergmann return -EFAULT; 83867207b96SArnd Bergmann 8398b3d6663SArnd Bergmann spu_acquire(ctx); 8408b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 8418b3d6663SArnd Bergmann spu_release(ctx); 84267207b96SArnd Bergmann 84367207b96SArnd Bergmann return 4; 84467207b96SArnd Bergmann } 84567207b96SArnd Bergmann 84678bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma, 84778bde53eSBenjamin Herrenschmidt unsigned long address) 8486df10a82SMark Nutter { 84927d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 85078bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x14000, 0x1000); 85127d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 85227d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 85327d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 85427d5bf2aSBenjamin Herrenschmidt */ 85578bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 85627d5bf2aSBenjamin Herrenschmidt #else 85727d5bf2aSBenjamin Herrenschmidt #error unsupported page size 85827d5bf2aSBenjamin Herrenschmidt #endif 8596df10a82SMark Nutter } 8606df10a82SMark Nutter 8616df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = { 86278bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal1_mmap_nopfn, 8636df10a82SMark Nutter }; 8646df10a82SMark Nutter 8656df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 8666df10a82SMark Nutter { 8676df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 8686df10a82SMark Nutter return -EINVAL; 8696df10a82SMark Nutter 87078bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 8716df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 87223cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 8736df10a82SMark Nutter 8746df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 8756df10a82SMark Nutter return 0; 8766df10a82SMark Nutter } 8776df10a82SMark Nutter 8785dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = { 8796df10a82SMark Nutter .open = spufs_signal1_open, 88043c2bbd9SChristoph Hellwig .release = spufs_signal1_release, 88167207b96SArnd Bergmann .read = spufs_signal1_read, 88267207b96SArnd Bergmann .write = spufs_signal1_write, 8836df10a82SMark Nutter .mmap = spufs_signal1_mmap, 88467207b96SArnd Bergmann }; 88567207b96SArnd Bergmann 8866df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 8876df10a82SMark Nutter { 8886df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 8896df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 89043c2bbd9SChristoph Hellwig 89143c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 8926df10a82SMark Nutter file->private_data = ctx; 89343c2bbd9SChristoph Hellwig if (!i->i_openers++) 8946df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 89543c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 89617e0e270SBenjamin Herrenschmidt smp_wmb(); 8976df10a82SMark Nutter return nonseekable_open(inode, file); 8986df10a82SMark Nutter } 8996df10a82SMark Nutter 90043c2bbd9SChristoph Hellwig static int 90143c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file) 90243c2bbd9SChristoph Hellwig { 90343c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 90443c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 90543c2bbd9SChristoph Hellwig 90643c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 90743c2bbd9SChristoph Hellwig if (!--i->i_openers) 90843c2bbd9SChristoph Hellwig ctx->signal2 = NULL; 90943c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 91043c2bbd9SChristoph Hellwig smp_wmb(); 91143c2bbd9SChristoph Hellwig return 0; 91243c2bbd9SChristoph Hellwig } 91343c2bbd9SChristoph Hellwig 914bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 91567207b96SArnd Bergmann size_t len, loff_t *pos) 91667207b96SArnd Bergmann { 91717f88cebSDwayne Grant McConnell int ret = 0; 91867207b96SArnd Bergmann u32 data; 91967207b96SArnd Bergmann 92067207b96SArnd Bergmann if (len < 4) 92167207b96SArnd Bergmann return -EINVAL; 92267207b96SArnd Bergmann 92317f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[4]) { 92417f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[4]; 92517f88cebSDwayne Grant McConnell ret = 4; 92617f88cebSDwayne Grant McConnell } 9278b3d6663SArnd Bergmann 92817f88cebSDwayne Grant McConnell if (!ret) 92917f88cebSDwayne Grant McConnell goto out; 93017f88cebSDwayne Grant McConnell 93167207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 93267207b96SArnd Bergmann return -EFAULT; 93367207b96SArnd Bergmann 93417f88cebSDwayne Grant McConnell out: 935bf1ab978SDwayne Grant McConnell return ret; 936bf1ab978SDwayne Grant McConnell } 937bf1ab978SDwayne Grant McConnell 938bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 939bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 940bf1ab978SDwayne Grant McConnell { 941bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 942bf1ab978SDwayne Grant McConnell int ret; 943bf1ab978SDwayne Grant McConnell 944bf1ab978SDwayne Grant McConnell spu_acquire_saved(ctx); 945bf1ab978SDwayne Grant McConnell ret = __spufs_signal2_read(ctx, buf, len, pos); 946bf1ab978SDwayne Grant McConnell spu_release(ctx); 947bf1ab978SDwayne Grant McConnell 948bf1ab978SDwayne Grant McConnell return ret; 94967207b96SArnd Bergmann } 95067207b96SArnd Bergmann 95167207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 95267207b96SArnd Bergmann size_t len, loff_t *pos) 95367207b96SArnd Bergmann { 95467207b96SArnd Bergmann struct spu_context *ctx; 95567207b96SArnd Bergmann u32 data; 95667207b96SArnd Bergmann 95767207b96SArnd Bergmann ctx = file->private_data; 95867207b96SArnd Bergmann 95967207b96SArnd Bergmann if (len < 4) 96067207b96SArnd Bergmann return -EINVAL; 96167207b96SArnd Bergmann 96267207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 96367207b96SArnd Bergmann return -EFAULT; 96467207b96SArnd Bergmann 9658b3d6663SArnd Bergmann spu_acquire(ctx); 9668b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 9678b3d6663SArnd Bergmann spu_release(ctx); 96867207b96SArnd Bergmann 96967207b96SArnd Bergmann return 4; 97067207b96SArnd Bergmann } 97167207b96SArnd Bergmann 97227d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 97378bde53eSBenjamin Herrenschmidt static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma, 97478bde53eSBenjamin Herrenschmidt unsigned long address) 9756df10a82SMark Nutter { 97627d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 97778bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000); 97827d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 97927d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 98027d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 98127d5bf2aSBenjamin Herrenschmidt */ 98278bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); 98327d5bf2aSBenjamin Herrenschmidt #else 98427d5bf2aSBenjamin Herrenschmidt #error unsupported page size 98527d5bf2aSBenjamin Herrenschmidt #endif 9866df10a82SMark Nutter } 9876df10a82SMark Nutter 9886df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = { 98978bde53eSBenjamin Herrenschmidt .nopfn = spufs_signal2_mmap_nopfn, 9906df10a82SMark Nutter }; 9916df10a82SMark Nutter 9926df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 9936df10a82SMark Nutter { 9946df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 9956df10a82SMark Nutter return -EINVAL; 9966df10a82SMark Nutter 99778bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 9986df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 99923cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 10006df10a82SMark Nutter 10016df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 10026df10a82SMark Nutter return 0; 10036df10a82SMark Nutter } 100427d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 100527d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 100627d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 10076df10a82SMark Nutter 10085dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = { 10096df10a82SMark Nutter .open = spufs_signal2_open, 101043c2bbd9SChristoph Hellwig .release = spufs_signal2_release, 101167207b96SArnd Bergmann .read = spufs_signal2_read, 101267207b96SArnd Bergmann .write = spufs_signal2_write, 10136df10a82SMark Nutter .mmap = spufs_signal2_mmap, 101467207b96SArnd Bergmann }; 101567207b96SArnd Bergmann 101667207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val) 101767207b96SArnd Bergmann { 101867207b96SArnd Bergmann struct spu_context *ctx = data; 101967207b96SArnd Bergmann 10208b3d6663SArnd Bergmann spu_acquire(ctx); 10218b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 10228b3d6663SArnd Bergmann spu_release(ctx); 102367207b96SArnd Bergmann } 102467207b96SArnd Bergmann 1025bf1ab978SDwayne Grant McConnell static u64 __spufs_signal1_type_get(void *data) 1026bf1ab978SDwayne Grant McConnell { 1027bf1ab978SDwayne Grant McConnell struct spu_context *ctx = data; 1028bf1ab978SDwayne Grant McConnell return ctx->ops->signal1_type_get(ctx); 1029bf1ab978SDwayne Grant McConnell } 1030bf1ab978SDwayne Grant McConnell 103167207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data) 103267207b96SArnd Bergmann { 103367207b96SArnd Bergmann struct spu_context *ctx = data; 10348b3d6663SArnd Bergmann u64 ret; 10358b3d6663SArnd Bergmann 10368b3d6663SArnd Bergmann spu_acquire(ctx); 1037bf1ab978SDwayne Grant McConnell ret = __spufs_signal1_type_get(data); 10388b3d6663SArnd Bergmann spu_release(ctx); 10398b3d6663SArnd Bergmann 10408b3d6663SArnd Bergmann return ret; 104167207b96SArnd Bergmann } 104267207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 104367207b96SArnd Bergmann spufs_signal1_type_set, "%llu"); 104467207b96SArnd Bergmann 104567207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val) 104667207b96SArnd Bergmann { 104767207b96SArnd Bergmann struct spu_context *ctx = data; 104867207b96SArnd Bergmann 10498b3d6663SArnd Bergmann spu_acquire(ctx); 10508b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 10518b3d6663SArnd Bergmann spu_release(ctx); 105267207b96SArnd Bergmann } 105367207b96SArnd Bergmann 1054bf1ab978SDwayne Grant McConnell static u64 __spufs_signal2_type_get(void *data) 1055bf1ab978SDwayne Grant McConnell { 1056bf1ab978SDwayne Grant McConnell struct spu_context *ctx = data; 1057bf1ab978SDwayne Grant McConnell return ctx->ops->signal2_type_get(ctx); 1058bf1ab978SDwayne Grant McConnell } 1059bf1ab978SDwayne Grant McConnell 106067207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data) 106167207b96SArnd Bergmann { 106267207b96SArnd Bergmann struct spu_context *ctx = data; 10638b3d6663SArnd Bergmann u64 ret; 10648b3d6663SArnd Bergmann 10658b3d6663SArnd Bergmann spu_acquire(ctx); 1066bf1ab978SDwayne Grant McConnell ret = __spufs_signal2_type_get(data); 10678b3d6663SArnd Bergmann spu_release(ctx); 10688b3d6663SArnd Bergmann 10698b3d6663SArnd Bergmann return ret; 107067207b96SArnd Bergmann } 107167207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 107267207b96SArnd Bergmann spufs_signal2_type_set, "%llu"); 107367207b96SArnd Bergmann 107427d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 107578bde53eSBenjamin Herrenschmidt static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, 107678bde53eSBenjamin Herrenschmidt unsigned long address) 1077d9379c4bSarnd@arndb.de { 107878bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x1000); 1079d9379c4bSarnd@arndb.de } 1080d9379c4bSarnd@arndb.de 1081d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = { 108278bde53eSBenjamin Herrenschmidt .nopfn = spufs_mss_mmap_nopfn, 1083d9379c4bSarnd@arndb.de }; 1084d9379c4bSarnd@arndb.de 1085d9379c4bSarnd@arndb.de /* 1086d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 1087d9379c4bSarnd@arndb.de */ 1088d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 1089d9379c4bSarnd@arndb.de { 1090d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 1091d9379c4bSarnd@arndb.de return -EINVAL; 1092d9379c4bSarnd@arndb.de 109378bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 1094d9379c4bSarnd@arndb.de vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 109523cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 1096d9379c4bSarnd@arndb.de 1097d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 1098d9379c4bSarnd@arndb.de return 0; 1099d9379c4bSarnd@arndb.de } 110027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 110127d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 110227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1103d9379c4bSarnd@arndb.de 1104d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 1105d9379c4bSarnd@arndb.de { 1106d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 110717e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 1108d9379c4bSarnd@arndb.de 1109d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 111043c2bbd9SChristoph Hellwig 111143c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 111243c2bbd9SChristoph Hellwig if (!i->i_openers++) 111317e0e270SBenjamin Herrenschmidt ctx->mss = inode->i_mapping; 111443c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 111517e0e270SBenjamin Herrenschmidt smp_wmb(); 1116d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 1117d9379c4bSarnd@arndb.de } 1118d9379c4bSarnd@arndb.de 111943c2bbd9SChristoph Hellwig static int 112043c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file) 112143c2bbd9SChristoph Hellwig { 112243c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 112343c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 112443c2bbd9SChristoph Hellwig 112543c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 112643c2bbd9SChristoph Hellwig if (!--i->i_openers) 112743c2bbd9SChristoph Hellwig ctx->mss = NULL; 112843c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 112943c2bbd9SChristoph Hellwig smp_wmb(); 113043c2bbd9SChristoph Hellwig return 0; 113143c2bbd9SChristoph Hellwig } 113243c2bbd9SChristoph Hellwig 11335dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = { 1134d9379c4bSarnd@arndb.de .open = spufs_mss_open, 113543c2bbd9SChristoph Hellwig .release = spufs_mss_release, 1136d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 113727d5bf2aSBenjamin Herrenschmidt }; 113827d5bf2aSBenjamin Herrenschmidt 113978bde53eSBenjamin Herrenschmidt static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma, 114078bde53eSBenjamin Herrenschmidt unsigned long address) 114127d5bf2aSBenjamin Herrenschmidt { 114278bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x0000, 0x20000); 114327d5bf2aSBenjamin Herrenschmidt } 114427d5bf2aSBenjamin Herrenschmidt 114527d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = { 114678bde53eSBenjamin Herrenschmidt .nopfn = spufs_psmap_mmap_nopfn, 114727d5bf2aSBenjamin Herrenschmidt }; 114827d5bf2aSBenjamin Herrenschmidt 114927d5bf2aSBenjamin Herrenschmidt /* 115027d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 115127d5bf2aSBenjamin Herrenschmidt */ 115227d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 115327d5bf2aSBenjamin Herrenschmidt { 115427d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 115527d5bf2aSBenjamin Herrenschmidt return -EINVAL; 115627d5bf2aSBenjamin Herrenschmidt 115778bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 115827d5bf2aSBenjamin Herrenschmidt vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 115927d5bf2aSBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 116027d5bf2aSBenjamin Herrenschmidt 116127d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 116227d5bf2aSBenjamin Herrenschmidt return 0; 116327d5bf2aSBenjamin Herrenschmidt } 116427d5bf2aSBenjamin Herrenschmidt 116527d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 116627d5bf2aSBenjamin Herrenschmidt { 116727d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 116817e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 116927d5bf2aSBenjamin Herrenschmidt 117043c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 117127d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 117243c2bbd9SChristoph Hellwig if (!i->i_openers++) 117317e0e270SBenjamin Herrenschmidt ctx->psmap = inode->i_mapping; 117443c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 117517e0e270SBenjamin Herrenschmidt smp_wmb(); 117627d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 117727d5bf2aSBenjamin Herrenschmidt } 117827d5bf2aSBenjamin Herrenschmidt 117943c2bbd9SChristoph Hellwig static int 118043c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file) 118143c2bbd9SChristoph Hellwig { 118243c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 118343c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 118443c2bbd9SChristoph Hellwig 118543c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 118643c2bbd9SChristoph Hellwig if (!--i->i_openers) 118743c2bbd9SChristoph Hellwig ctx->psmap = NULL; 118843c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 118943c2bbd9SChristoph Hellwig smp_wmb(); 119043c2bbd9SChristoph Hellwig return 0; 119143c2bbd9SChristoph Hellwig } 119243c2bbd9SChristoph Hellwig 11935dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = { 119427d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 119543c2bbd9SChristoph Hellwig .release = spufs_psmap_release, 119627d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1197d9379c4bSarnd@arndb.de }; 1198d9379c4bSarnd@arndb.de 1199d9379c4bSarnd@arndb.de 120027d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 120178bde53eSBenjamin Herrenschmidt static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma, 120278bde53eSBenjamin Herrenschmidt unsigned long address) 12036df10a82SMark Nutter { 120478bde53eSBenjamin Herrenschmidt return spufs_ps_nopfn(vma, address, 0x3000, 0x1000); 12056df10a82SMark Nutter } 12066df10a82SMark Nutter 12076df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = { 120878bde53eSBenjamin Herrenschmidt .nopfn = spufs_mfc_mmap_nopfn, 12096df10a82SMark Nutter }; 12106df10a82SMark Nutter 12116df10a82SMark Nutter /* 12126df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 12136df10a82SMark Nutter */ 12146df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 12156df10a82SMark Nutter { 12166df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 12176df10a82SMark Nutter return -EINVAL; 12186df10a82SMark Nutter 121978bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 12206df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 122123cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 12226df10a82SMark Nutter 12236df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 12246df10a82SMark Nutter return 0; 12256df10a82SMark Nutter } 122627d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 122727d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 122827d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1229a33a7d73SArnd Bergmann 1230a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1231a33a7d73SArnd Bergmann { 1232a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1233a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1234a33a7d73SArnd Bergmann 1235a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1236a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1237a33a7d73SArnd Bergmann return -EINVAL; 1238a33a7d73SArnd Bergmann 1239a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1240a33a7d73SArnd Bergmann return -EBUSY; 1241a33a7d73SArnd Bergmann 124243c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 1243a33a7d73SArnd Bergmann file->private_data = ctx; 124443c2bbd9SChristoph Hellwig if (!i->i_openers++) 124517e0e270SBenjamin Herrenschmidt ctx->mfc = inode->i_mapping; 124643c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 124717e0e270SBenjamin Herrenschmidt smp_wmb(); 1248a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1249a33a7d73SArnd Bergmann } 1250a33a7d73SArnd Bergmann 125143c2bbd9SChristoph Hellwig static int 125243c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file) 125343c2bbd9SChristoph Hellwig { 125443c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 125543c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 125643c2bbd9SChristoph Hellwig 125743c2bbd9SChristoph Hellwig spin_lock(&ctx->mapping_lock); 125843c2bbd9SChristoph Hellwig if (!--i->i_openers) 125943c2bbd9SChristoph Hellwig ctx->mfc = NULL; 126043c2bbd9SChristoph Hellwig spin_unlock(&ctx->mapping_lock); 126143c2bbd9SChristoph Hellwig smp_wmb(); 126243c2bbd9SChristoph Hellwig return 0; 126343c2bbd9SChristoph Hellwig } 126443c2bbd9SChristoph Hellwig 1265a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1266a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1267a33a7d73SArnd Bergmann { 1268a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1269a33a7d73SArnd Bergmann 1270a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1271a33a7d73SArnd Bergmann 1272a33a7d73SArnd Bergmann pr_debug("%s %s\n", __FUNCTION__, spu->name); 1273a33a7d73SArnd Bergmann if (ctx->mfc_fasync) { 1274a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1275a33a7d73SArnd Bergmann unsigned int mask; 1276a33a7d73SArnd Bergmann 1277a33a7d73SArnd Bergmann /* no need for spu_acquire in interrupt context */ 1278a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1279a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1280a33a7d73SArnd Bergmann 1281a33a7d73SArnd Bergmann mask = 0; 1282a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1283a33a7d73SArnd Bergmann mask |= POLLOUT; 1284a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1285a33a7d73SArnd Bergmann mask |= POLLIN; 1286a33a7d73SArnd Bergmann 1287a33a7d73SArnd Bergmann kill_fasync(&ctx->mfc_fasync, SIGIO, mask); 1288a33a7d73SArnd Bergmann } 1289a33a7d73SArnd Bergmann } 1290a33a7d73SArnd Bergmann 1291a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1292a33a7d73SArnd Bergmann { 1293a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1294a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1295a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1296a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1297a33a7d73SArnd Bergmann if (*status) 1298a33a7d73SArnd Bergmann return 1; 1299a33a7d73SArnd Bergmann 1300a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1301a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1302a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1303a33a7d73SArnd Bergmann return 0; 1304a33a7d73SArnd Bergmann } 1305a33a7d73SArnd Bergmann 1306a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1307a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1308a33a7d73SArnd Bergmann { 1309a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1310a33a7d73SArnd Bergmann int ret = -EINVAL; 1311a33a7d73SArnd Bergmann u32 status; 1312a33a7d73SArnd Bergmann 1313a33a7d73SArnd Bergmann if (size != 4) 1314a33a7d73SArnd Bergmann goto out; 1315a33a7d73SArnd Bergmann 1316a33a7d73SArnd Bergmann spu_acquire(ctx); 1317a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1318a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1319a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1320a33a7d73SArnd Bergmann ret = -EAGAIN; 1321a33a7d73SArnd Bergmann else 1322a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1323a33a7d73SArnd Bergmann } else { 1324a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1325a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1326a33a7d73SArnd Bergmann } 1327a33a7d73SArnd Bergmann spu_release(ctx); 1328a33a7d73SArnd Bergmann 1329a33a7d73SArnd Bergmann if (ret) 1330a33a7d73SArnd Bergmann goto out; 1331a33a7d73SArnd Bergmann 1332a33a7d73SArnd Bergmann ret = 4; 1333a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1334a33a7d73SArnd Bergmann ret = -EFAULT; 1335a33a7d73SArnd Bergmann 1336a33a7d73SArnd Bergmann out: 1337a33a7d73SArnd Bergmann return ret; 1338a33a7d73SArnd Bergmann } 1339a33a7d73SArnd Bergmann 1340a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1341a33a7d73SArnd Bergmann { 1342a33a7d73SArnd Bergmann pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, 1343a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1344a33a7d73SArnd Bergmann 1345a33a7d73SArnd Bergmann switch (cmd->cmd) { 1346a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1347a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1348a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1349a33a7d73SArnd Bergmann case MFC_GET_CMD: 1350a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1351a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1352a33a7d73SArnd Bergmann break; 1353a33a7d73SArnd Bergmann default: 1354a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1355a33a7d73SArnd Bergmann return -EIO; 1356a33a7d73SArnd Bergmann } 1357a33a7d73SArnd Bergmann 1358a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 1359a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment, ea %lx lsa %x\n", 1360a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1361a33a7d73SArnd Bergmann return -EIO; 1362a33a7d73SArnd Bergmann } 1363a33a7d73SArnd Bergmann 1364a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1365a33a7d73SArnd Bergmann case 1: 1366a33a7d73SArnd Bergmann break; 1367a33a7d73SArnd Bergmann case 2: 1368a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1369a33a7d73SArnd Bergmann goto error; 1370a33a7d73SArnd Bergmann break; 1371a33a7d73SArnd Bergmann case 4: 1372a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1373a33a7d73SArnd Bergmann goto error; 1374a33a7d73SArnd Bergmann break; 1375a33a7d73SArnd Bergmann case 8: 1376a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1377a33a7d73SArnd Bergmann goto error; 1378a33a7d73SArnd Bergmann break; 1379a33a7d73SArnd Bergmann case 0: 1380a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1381a33a7d73SArnd Bergmann goto error; 1382a33a7d73SArnd Bergmann break; 1383a33a7d73SArnd Bergmann error: 1384a33a7d73SArnd Bergmann default: 1385a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1386a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1387a33a7d73SArnd Bergmann return -EIO; 1388a33a7d73SArnd Bergmann } 1389a33a7d73SArnd Bergmann 1390a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1391a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1392a33a7d73SArnd Bergmann return -EIO; 1393a33a7d73SArnd Bergmann } 1394a33a7d73SArnd Bergmann 1395a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1396a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1397a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1398a33a7d73SArnd Bergmann return -EIO; 1399a33a7d73SArnd Bergmann } 1400a33a7d73SArnd Bergmann 1401a33a7d73SArnd Bergmann if (cmd->class) { 1402a33a7d73SArnd Bergmann /* not supported in this version */ 1403a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1404a33a7d73SArnd Bergmann return -EIO; 1405a33a7d73SArnd Bergmann } 1406a33a7d73SArnd Bergmann 1407a33a7d73SArnd Bergmann return 0; 1408a33a7d73SArnd Bergmann } 1409a33a7d73SArnd Bergmann 1410a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1411a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1412a33a7d73SArnd Bergmann int *error) 1413a33a7d73SArnd Bergmann { 1414a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1415a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1416a33a7d73SArnd Bergmann /* wait for any tag group to complete 1417a33a7d73SArnd Bergmann so we have space for the new command */ 1418a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1419a33a7d73SArnd Bergmann /* try again, because the queue might be 1420a33a7d73SArnd Bergmann empty again */ 1421a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1422a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1423a33a7d73SArnd Bergmann return 0; 1424a33a7d73SArnd Bergmann } 1425a33a7d73SArnd Bergmann return 1; 1426a33a7d73SArnd Bergmann } 1427a33a7d73SArnd Bergmann 1428a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1429a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1430a33a7d73SArnd Bergmann { 1431a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1432a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1433a33a7d73SArnd Bergmann int ret = -EINVAL; 1434a33a7d73SArnd Bergmann 1435a33a7d73SArnd Bergmann if (size != sizeof cmd) 1436a33a7d73SArnd Bergmann goto out; 1437a33a7d73SArnd Bergmann 1438a33a7d73SArnd Bergmann ret = -EFAULT; 1439a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1440a33a7d73SArnd Bergmann goto out; 1441a33a7d73SArnd Bergmann 1442a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1443a33a7d73SArnd Bergmann if (ret) 1444a33a7d73SArnd Bergmann goto out; 1445a33a7d73SArnd Bergmann 1446577f8f10SAkinobu Mita ret = spu_acquire_runnable(ctx, 0); 1447577f8f10SAkinobu Mita if (ret) 1448577f8f10SAkinobu Mita goto out; 1449577f8f10SAkinobu Mita 1450a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1451a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1452a33a7d73SArnd Bergmann } else { 1453a33a7d73SArnd Bergmann int status; 1454a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1455a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1456a33a7d73SArnd Bergmann if (status) 1457a33a7d73SArnd Bergmann ret = status; 1458a33a7d73SArnd Bergmann } 1459a33a7d73SArnd Bergmann spu_release(ctx); 1460a33a7d73SArnd Bergmann 1461a33a7d73SArnd Bergmann if (ret) 1462a33a7d73SArnd Bergmann goto out; 1463a33a7d73SArnd Bergmann 1464a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 14653692dc66SMasato Noguchi ret = size; 1466a33a7d73SArnd Bergmann 1467a33a7d73SArnd Bergmann out: 1468a33a7d73SArnd Bergmann return ret; 1469a33a7d73SArnd Bergmann } 1470a33a7d73SArnd Bergmann 1471a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) 1472a33a7d73SArnd Bergmann { 1473a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1474a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1475a33a7d73SArnd Bergmann unsigned int mask; 1476a33a7d73SArnd Bergmann 1477a33a7d73SArnd Bergmann spu_acquire(ctx); 1478a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1479a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1480a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1481a33a7d73SArnd Bergmann spu_release(ctx); 1482a33a7d73SArnd Bergmann 1483a33a7d73SArnd Bergmann poll_wait(file, &ctx->mfc_wq, wait); 1484a33a7d73SArnd Bergmann 1485a33a7d73SArnd Bergmann mask = 0; 1486a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1487a33a7d73SArnd Bergmann mask |= POLLOUT | POLLWRNORM; 1488a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1489a33a7d73SArnd Bergmann mask |= POLLIN | POLLRDNORM; 1490a33a7d73SArnd Bergmann 1491a33a7d73SArnd Bergmann pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, 1492a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1493a33a7d73SArnd Bergmann 1494a33a7d73SArnd Bergmann return mask; 1495a33a7d73SArnd Bergmann } 1496a33a7d73SArnd Bergmann 149773b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1498a33a7d73SArnd Bergmann { 1499a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1500a33a7d73SArnd Bergmann int ret; 1501a33a7d73SArnd Bergmann 1502a33a7d73SArnd Bergmann spu_acquire(ctx); 1503a33a7d73SArnd Bergmann #if 0 1504a33a7d73SArnd Bergmann /* this currently hangs */ 1505a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1506a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1507a33a7d73SArnd Bergmann if (ret) 1508a33a7d73SArnd Bergmann goto out; 1509a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1510a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1511a33a7d73SArnd Bergmann out: 1512a33a7d73SArnd Bergmann #else 1513a33a7d73SArnd Bergmann ret = 0; 1514a33a7d73SArnd Bergmann #endif 1515a33a7d73SArnd Bergmann spu_release(ctx); 1516a33a7d73SArnd Bergmann 1517a33a7d73SArnd Bergmann return ret; 1518a33a7d73SArnd Bergmann } 1519a33a7d73SArnd Bergmann 1520a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, 1521a33a7d73SArnd Bergmann int datasync) 1522a33a7d73SArnd Bergmann { 152373b6af8aSAl Viro return spufs_mfc_flush(file, NULL); 1524a33a7d73SArnd Bergmann } 1525a33a7d73SArnd Bergmann 1526a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on) 1527a33a7d73SArnd Bergmann { 1528a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1529a33a7d73SArnd Bergmann 1530a33a7d73SArnd Bergmann return fasync_helper(fd, file, on, &ctx->mfc_fasync); 1531a33a7d73SArnd Bergmann } 1532a33a7d73SArnd Bergmann 15335dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = { 1534a33a7d73SArnd Bergmann .open = spufs_mfc_open, 153543c2bbd9SChristoph Hellwig .release = spufs_mfc_release, 1536a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1537a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1538a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1539a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1540a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 1541a33a7d73SArnd Bergmann .fasync = spufs_mfc_fasync, 15426df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1543a33a7d73SArnd Bergmann }; 1544a33a7d73SArnd Bergmann 154567207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val) 154667207b96SArnd Bergmann { 154767207b96SArnd Bergmann struct spu_context *ctx = data; 15488b3d6663SArnd Bergmann spu_acquire(ctx); 15498b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 15508b3d6663SArnd Bergmann spu_release(ctx); 155167207b96SArnd Bergmann } 155267207b96SArnd Bergmann 155367207b96SArnd Bergmann static u64 spufs_npc_get(void *data) 155467207b96SArnd Bergmann { 155567207b96SArnd Bergmann struct spu_context *ctx = data; 155667207b96SArnd Bergmann u64 ret; 15578b3d6663SArnd Bergmann spu_acquire(ctx); 15588b3d6663SArnd Bergmann ret = ctx->ops->npc_read(ctx); 15598b3d6663SArnd Bergmann spu_release(ctx); 156067207b96SArnd Bergmann return ret; 156167207b96SArnd Bergmann } 15629b5047e2SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 15639b5047e2SDwayne Grant McConnell "0x%llx\n") 156467207b96SArnd Bergmann 15658b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val) 15668b3d6663SArnd Bergmann { 15678b3d6663SArnd Bergmann struct spu_context *ctx = data; 15688b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 15698b3d6663SArnd Bergmann spu_acquire_saved(ctx); 15708b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 15718b3d6663SArnd Bergmann spu_release(ctx); 15728b3d6663SArnd Bergmann } 15738b3d6663SArnd Bergmann 1574bf1ab978SDwayne Grant McConnell static u64 __spufs_decr_get(void *data) 15758b3d6663SArnd Bergmann { 15768b3d6663SArnd Bergmann struct spu_context *ctx = data; 15778b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1578bf1ab978SDwayne Grant McConnell return lscsa->decr.slot[0]; 1579bf1ab978SDwayne Grant McConnell } 1580bf1ab978SDwayne Grant McConnell 1581bf1ab978SDwayne Grant McConnell static u64 spufs_decr_get(void *data) 1582bf1ab978SDwayne Grant McConnell { 1583bf1ab978SDwayne Grant McConnell struct spu_context *ctx = data; 15848b3d6663SArnd Bergmann u64 ret; 15858b3d6663SArnd Bergmann spu_acquire_saved(ctx); 1586bf1ab978SDwayne Grant McConnell ret = __spufs_decr_get(data); 15878b3d6663SArnd Bergmann spu_release(ctx); 15888b3d6663SArnd Bergmann return ret; 15898b3d6663SArnd Bergmann } 15908b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 15919b5047e2SDwayne Grant McConnell "0x%llx\n") 15928b3d6663SArnd Bergmann 15938b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val) 15948b3d6663SArnd Bergmann { 15958b3d6663SArnd Bergmann struct spu_context *ctx = data; 15968b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 15978b3d6663SArnd Bergmann spu_acquire_saved(ctx); 15988b3d6663SArnd Bergmann lscsa->decr_status.slot[0] = (u32) val; 15998b3d6663SArnd Bergmann spu_release(ctx); 16008b3d6663SArnd Bergmann } 16018b3d6663SArnd Bergmann 1602bf1ab978SDwayne Grant McConnell static u64 __spufs_decr_status_get(void *data) 16038b3d6663SArnd Bergmann { 16048b3d6663SArnd Bergmann struct spu_context *ctx = data; 16058b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1606bf1ab978SDwayne Grant McConnell return lscsa->decr_status.slot[0]; 1607bf1ab978SDwayne Grant McConnell } 1608bf1ab978SDwayne Grant McConnell 1609bf1ab978SDwayne Grant McConnell static u64 spufs_decr_status_get(void *data) 1610bf1ab978SDwayne Grant McConnell { 1611bf1ab978SDwayne Grant McConnell struct spu_context *ctx = data; 16128b3d6663SArnd Bergmann u64 ret; 16138b3d6663SArnd Bergmann spu_acquire_saved(ctx); 1614bf1ab978SDwayne Grant McConnell ret = __spufs_decr_status_get(data); 16158b3d6663SArnd Bergmann spu_release(ctx); 16168b3d6663SArnd Bergmann return ret; 16178b3d6663SArnd Bergmann } 16188b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 16199b5047e2SDwayne Grant McConnell spufs_decr_status_set, "0x%llx\n") 16208b3d6663SArnd Bergmann 16218b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val) 16228b3d6663SArnd Bergmann { 16238b3d6663SArnd Bergmann struct spu_context *ctx = data; 16248b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 16258b3d6663SArnd Bergmann spu_acquire_saved(ctx); 16268b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 16278b3d6663SArnd Bergmann spu_release(ctx); 16288b3d6663SArnd Bergmann } 16298b3d6663SArnd Bergmann 1630bf1ab978SDwayne Grant McConnell static u64 __spufs_event_mask_get(void *data) 16318b3d6663SArnd Bergmann { 16328b3d6663SArnd Bergmann struct spu_context *ctx = data; 16338b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1634bf1ab978SDwayne Grant McConnell return lscsa->event_mask.slot[0]; 1635bf1ab978SDwayne Grant McConnell } 1636bf1ab978SDwayne Grant McConnell 1637bf1ab978SDwayne Grant McConnell static u64 spufs_event_mask_get(void *data) 1638bf1ab978SDwayne Grant McConnell { 1639bf1ab978SDwayne Grant McConnell struct spu_context *ctx = data; 16408b3d6663SArnd Bergmann u64 ret; 16418b3d6663SArnd Bergmann spu_acquire_saved(ctx); 1642bf1ab978SDwayne Grant McConnell ret = __spufs_event_mask_get(data); 16438b3d6663SArnd Bergmann spu_release(ctx); 16448b3d6663SArnd Bergmann return ret; 16458b3d6663SArnd Bergmann } 16468b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 16479b5047e2SDwayne Grant McConnell spufs_event_mask_set, "0x%llx\n") 16488b3d6663SArnd Bergmann 1649bf1ab978SDwayne Grant McConnell static u64 __spufs_event_status_get(void *data) 1650b9e3bd77SDwayne Grant McConnell { 1651b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = data; 1652b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1653b9e3bd77SDwayne Grant McConnell u64 stat; 1654b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1655b9e3bd77SDwayne Grant McConnell if (stat) 1656bf1ab978SDwayne Grant McConnell return state->spu_chnldata_RW[0]; 1657bf1ab978SDwayne Grant McConnell return 0; 1658bf1ab978SDwayne Grant McConnell } 1659bf1ab978SDwayne Grant McConnell 1660bf1ab978SDwayne Grant McConnell static u64 spufs_event_status_get(void *data) 1661bf1ab978SDwayne Grant McConnell { 1662bf1ab978SDwayne Grant McConnell struct spu_context *ctx = data; 1663bf1ab978SDwayne Grant McConnell u64 ret = 0; 1664bf1ab978SDwayne Grant McConnell 1665bf1ab978SDwayne Grant McConnell spu_acquire_saved(ctx); 1666bf1ab978SDwayne Grant McConnell ret = __spufs_event_status_get(data); 1667b9e3bd77SDwayne Grant McConnell spu_release(ctx); 1668b9e3bd77SDwayne Grant McConnell return ret; 1669b9e3bd77SDwayne Grant McConnell } 1670b9e3bd77SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1671b9e3bd77SDwayne Grant McConnell NULL, "0x%llx\n") 1672b9e3bd77SDwayne Grant McConnell 16738b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val) 16748b3d6663SArnd Bergmann { 16758b3d6663SArnd Bergmann struct spu_context *ctx = data; 16768b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 16778b3d6663SArnd Bergmann spu_acquire_saved(ctx); 16788b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 16798b3d6663SArnd Bergmann spu_release(ctx); 16808b3d6663SArnd Bergmann } 16818b3d6663SArnd Bergmann 16828b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data) 16838b3d6663SArnd Bergmann { 16848b3d6663SArnd Bergmann struct spu_context *ctx = data; 16858b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 16868b3d6663SArnd Bergmann u64 ret; 16878b3d6663SArnd Bergmann spu_acquire_saved(ctx); 16888b3d6663SArnd Bergmann ret = lscsa->srr0.slot[0]; 16898b3d6663SArnd Bergmann spu_release(ctx); 16908b3d6663SArnd Bergmann return ret; 16918b3d6663SArnd Bergmann } 16928b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 16939b5047e2SDwayne Grant McConnell "0x%llx\n") 16948b3d6663SArnd Bergmann 16957b1a7014Sarnd@arndb.de static u64 spufs_id_get(void *data) 16967b1a7014Sarnd@arndb.de { 16977b1a7014Sarnd@arndb.de struct spu_context *ctx = data; 16987b1a7014Sarnd@arndb.de u64 num; 16997b1a7014Sarnd@arndb.de 17007b1a7014Sarnd@arndb.de spu_acquire(ctx); 17017b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 17027b1a7014Sarnd@arndb.de num = ctx->spu->number; 17037b1a7014Sarnd@arndb.de else 17047b1a7014Sarnd@arndb.de num = (unsigned int)-1; 17057b1a7014Sarnd@arndb.de spu_release(ctx); 17067b1a7014Sarnd@arndb.de 17077b1a7014Sarnd@arndb.de return num; 17087b1a7014Sarnd@arndb.de } 1709e45d6634SAl Viro DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") 17107b1a7014Sarnd@arndb.de 1711bf1ab978SDwayne Grant McConnell static u64 __spufs_object_id_get(void *data) 171286767277SArnd Bergmann { 171386767277SArnd Bergmann struct spu_context *ctx = data; 171486767277SArnd Bergmann return ctx->object_id; 171586767277SArnd Bergmann } 171686767277SArnd Bergmann 1717bf1ab978SDwayne Grant McConnell static u64 spufs_object_id_get(void *data) 1718bf1ab978SDwayne Grant McConnell { 1719bf1ab978SDwayne Grant McConnell /* FIXME: Should there really be no locking here? */ 1720bf1ab978SDwayne Grant McConnell return __spufs_object_id_get(data); 1721bf1ab978SDwayne Grant McConnell } 1722bf1ab978SDwayne Grant McConnell 172386767277SArnd Bergmann static void spufs_object_id_set(void *data, u64 id) 172486767277SArnd Bergmann { 172586767277SArnd Bergmann struct spu_context *ctx = data; 172686767277SArnd Bergmann ctx->object_id = id; 172786767277SArnd Bergmann } 172886767277SArnd Bergmann 172986767277SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 173086767277SArnd Bergmann spufs_object_id_set, "0x%llx\n"); 173186767277SArnd Bergmann 1732bf1ab978SDwayne Grant McConnell static u64 __spufs_lslr_get(void *data) 1733bf1ab978SDwayne Grant McConnell { 1734bf1ab978SDwayne Grant McConnell struct spu_context *ctx = data; 1735bf1ab978SDwayne Grant McConnell return ctx->csa.priv2.spu_lslr_RW; 1736bf1ab978SDwayne Grant McConnell } 1737bf1ab978SDwayne Grant McConnell 1738b9e3bd77SDwayne Grant McConnell static u64 spufs_lslr_get(void *data) 1739b9e3bd77SDwayne Grant McConnell { 1740b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = data; 1741b9e3bd77SDwayne Grant McConnell u64 ret; 1742b9e3bd77SDwayne Grant McConnell 1743b9e3bd77SDwayne Grant McConnell spu_acquire_saved(ctx); 1744bf1ab978SDwayne Grant McConnell ret = __spufs_lslr_get(data); 1745b9e3bd77SDwayne Grant McConnell spu_release(ctx); 1746b9e3bd77SDwayne Grant McConnell 1747b9e3bd77SDwayne Grant McConnell return ret; 1748b9e3bd77SDwayne Grant McConnell } 1749b9e3bd77SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n") 1750b9e3bd77SDwayne Grant McConnell 1751b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 1752b9e3bd77SDwayne Grant McConnell { 1753b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 1754b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 1755b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 1756b9e3bd77SDwayne Grant McConnell return 0; 1757b9e3bd77SDwayne Grant McConnell } 1758b9e3bd77SDwayne Grant McConnell 1759bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, 1760bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 1761bf1ab978SDwayne Grant McConnell { 1762bf1ab978SDwayne Grant McConnell u32 mbox_stat; 1763bf1ab978SDwayne Grant McConnell u32 data; 1764bf1ab978SDwayne Grant McConnell 1765bf1ab978SDwayne Grant McConnell mbox_stat = ctx->csa.prob.mb_stat_R; 1766bf1ab978SDwayne Grant McConnell if (mbox_stat & 0x0000ff) { 1767bf1ab978SDwayne Grant McConnell data = ctx->csa.prob.pu_mb_R; 1768bf1ab978SDwayne Grant McConnell } 1769bf1ab978SDwayne Grant McConnell 1770bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 1771bf1ab978SDwayne Grant McConnell } 1772bf1ab978SDwayne Grant McConnell 177369a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 177469a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 177569a2f00cSDwayne Grant McConnell { 1776bf1ab978SDwayne Grant McConnell int ret; 177769a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 177869a2f00cSDwayne Grant McConnell 177969a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 178069a2f00cSDwayne Grant McConnell return -EFAULT; 178169a2f00cSDwayne Grant McConnell 178269a2f00cSDwayne Grant McConnell spu_acquire_saved(ctx); 178369a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 1784bf1ab978SDwayne Grant McConnell ret = __spufs_mbox_info_read(ctx, buf, len, pos); 178569a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 178669a2f00cSDwayne Grant McConnell spu_release(ctx); 178769a2f00cSDwayne Grant McConnell 1788bf1ab978SDwayne Grant McConnell return ret; 178969a2f00cSDwayne Grant McConnell } 179069a2f00cSDwayne Grant McConnell 17915dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = { 179269a2f00cSDwayne Grant McConnell .open = spufs_info_open, 179369a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 179469a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 179569a2f00cSDwayne Grant McConnell }; 179669a2f00cSDwayne Grant McConnell 1797bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, 1798bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 1799bf1ab978SDwayne Grant McConnell { 1800bf1ab978SDwayne Grant McConnell u32 ibox_stat; 1801bf1ab978SDwayne Grant McConnell u32 data; 1802bf1ab978SDwayne Grant McConnell 1803bf1ab978SDwayne Grant McConnell ibox_stat = ctx->csa.prob.mb_stat_R; 1804bf1ab978SDwayne Grant McConnell if (ibox_stat & 0xff0000) { 1805bf1ab978SDwayne Grant McConnell data = ctx->csa.priv2.puint_mb_R; 1806bf1ab978SDwayne Grant McConnell } 1807bf1ab978SDwayne Grant McConnell 1808bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 1809bf1ab978SDwayne Grant McConnell } 1810bf1ab978SDwayne Grant McConnell 181169a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 181269a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 181369a2f00cSDwayne Grant McConnell { 181469a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1815bf1ab978SDwayne Grant McConnell int ret; 181669a2f00cSDwayne Grant McConnell 181769a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 181869a2f00cSDwayne Grant McConnell return -EFAULT; 181969a2f00cSDwayne Grant McConnell 182069a2f00cSDwayne Grant McConnell spu_acquire_saved(ctx); 182169a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 1822bf1ab978SDwayne Grant McConnell ret = __spufs_ibox_info_read(ctx, buf, len, pos); 182369a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 182469a2f00cSDwayne Grant McConnell spu_release(ctx); 182569a2f00cSDwayne Grant McConnell 1826bf1ab978SDwayne Grant McConnell return ret; 182769a2f00cSDwayne Grant McConnell } 182869a2f00cSDwayne Grant McConnell 18295dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = { 183069a2f00cSDwayne Grant McConnell .open = spufs_info_open, 183169a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 183269a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 183369a2f00cSDwayne Grant McConnell }; 183469a2f00cSDwayne Grant McConnell 1835bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, 1836bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 1837bf1ab978SDwayne Grant McConnell { 1838bf1ab978SDwayne Grant McConnell int i, cnt; 1839bf1ab978SDwayne Grant McConnell u32 data[4]; 1840bf1ab978SDwayne Grant McConnell u32 wbox_stat; 1841bf1ab978SDwayne Grant McConnell 1842bf1ab978SDwayne Grant McConnell wbox_stat = ctx->csa.prob.mb_stat_R; 1843bf1ab978SDwayne Grant McConnell cnt = 4 - ((wbox_stat & 0x00ff00) >> 8); 1844bf1ab978SDwayne Grant McConnell for (i = 0; i < cnt; i++) { 1845bf1ab978SDwayne Grant McConnell data[i] = ctx->csa.spu_mailbox_data[i]; 1846bf1ab978SDwayne Grant McConnell } 1847bf1ab978SDwayne Grant McConnell 1848bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, 1849bf1ab978SDwayne Grant McConnell cnt * sizeof(u32)); 1850bf1ab978SDwayne Grant McConnell } 1851bf1ab978SDwayne Grant McConnell 185269a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 185369a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 185469a2f00cSDwayne Grant McConnell { 185569a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1856bf1ab978SDwayne Grant McConnell int ret; 185769a2f00cSDwayne Grant McConnell 185869a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 185969a2f00cSDwayne Grant McConnell return -EFAULT; 186069a2f00cSDwayne Grant McConnell 186169a2f00cSDwayne Grant McConnell spu_acquire_saved(ctx); 186269a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 1863bf1ab978SDwayne Grant McConnell ret = __spufs_wbox_info_read(ctx, buf, len, pos); 186469a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 186569a2f00cSDwayne Grant McConnell spu_release(ctx); 186669a2f00cSDwayne Grant McConnell 1867bf1ab978SDwayne Grant McConnell return ret; 186869a2f00cSDwayne Grant McConnell } 186969a2f00cSDwayne Grant McConnell 18705dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = { 187169a2f00cSDwayne Grant McConnell .open = spufs_info_open, 187269a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 187369a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 187469a2f00cSDwayne Grant McConnell }; 187569a2f00cSDwayne Grant McConnell 1876bf1ab978SDwayne Grant McConnell static ssize_t __spufs_dma_info_read(struct spu_context *ctx, 1877bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 1878b9e3bd77SDwayne Grant McConnell { 1879b9e3bd77SDwayne Grant McConnell struct spu_dma_info info; 1880b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *spuqp; 1881b9e3bd77SDwayne Grant McConnell int i; 1882b9e3bd77SDwayne Grant McConnell 1883b9e3bd77SDwayne Grant McConnell info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 1884b9e3bd77SDwayne Grant McConnell info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 1885b9e3bd77SDwayne Grant McConnell info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; 1886b9e3bd77SDwayne Grant McConnell info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 1887b9e3bd77SDwayne Grant McConnell info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 1888b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 1889b9e3bd77SDwayne Grant McConnell qp = &info.dma_info_command_data[i]; 1890b9e3bd77SDwayne Grant McConnell spuqp = &ctx->csa.priv2.spuq[i]; 1891b9e3bd77SDwayne Grant McConnell 1892b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 1893b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 1894b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 1895b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 1896b9e3bd77SDwayne Grant McConnell } 1897b9e3bd77SDwayne Grant McConnell 1898b9e3bd77SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 1899b9e3bd77SDwayne Grant McConnell sizeof info); 1900b9e3bd77SDwayne Grant McConnell } 1901b9e3bd77SDwayne Grant McConnell 1902bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 1903bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1904bf1ab978SDwayne Grant McConnell { 1905bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1906bf1ab978SDwayne Grant McConnell int ret; 1907bf1ab978SDwayne Grant McConnell 1908bf1ab978SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 1909bf1ab978SDwayne Grant McConnell return -EFAULT; 1910bf1ab978SDwayne Grant McConnell 1911bf1ab978SDwayne Grant McConnell spu_acquire_saved(ctx); 1912bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 1913bf1ab978SDwayne Grant McConnell ret = __spufs_dma_info_read(ctx, buf, len, pos); 1914bf1ab978SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 1915bf1ab978SDwayne Grant McConnell spu_release(ctx); 1916bf1ab978SDwayne Grant McConnell 1917bf1ab978SDwayne Grant McConnell return ret; 1918bf1ab978SDwayne Grant McConnell } 1919bf1ab978SDwayne Grant McConnell 19205dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = { 1921b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 1922b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 1923b9e3bd77SDwayne Grant McConnell }; 1924b9e3bd77SDwayne Grant McConnell 1925bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, 1926bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 1927b9e3bd77SDwayne Grant McConnell { 1928b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 1929b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *puqp; 1930bf1ab978SDwayne Grant McConnell int ret = sizeof info; 1931b9e3bd77SDwayne Grant McConnell int i; 1932b9e3bd77SDwayne Grant McConnell 1933b9e3bd77SDwayne Grant McConnell if (len < ret) 1934b9e3bd77SDwayne Grant McConnell return -EINVAL; 1935b9e3bd77SDwayne Grant McConnell 1936b9e3bd77SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 1937b9e3bd77SDwayne Grant McConnell return -EFAULT; 1938b9e3bd77SDwayne Grant McConnell 1939b9e3bd77SDwayne Grant McConnell info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 1940b9e3bd77SDwayne Grant McConnell info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 1941b9e3bd77SDwayne Grant McConnell info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 1942b9e3bd77SDwayne Grant McConnell for (i = 0; i < 8; i++) { 1943b9e3bd77SDwayne Grant McConnell qp = &info.proxydma_info_command_data[i]; 1944b9e3bd77SDwayne Grant McConnell puqp = &ctx->csa.priv2.puq[i]; 1945b9e3bd77SDwayne Grant McConnell 1946b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 1947b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 1948b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 1949b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 1950b9e3bd77SDwayne Grant McConnell } 1951bf1ab978SDwayne Grant McConnell 1952bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 1953bf1ab978SDwayne Grant McConnell sizeof info); 1954bf1ab978SDwayne Grant McConnell } 1955bf1ab978SDwayne Grant McConnell 1956bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 1957bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1958bf1ab978SDwayne Grant McConnell { 1959bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1960bf1ab978SDwayne Grant McConnell int ret; 1961bf1ab978SDwayne Grant McConnell 1962bf1ab978SDwayne Grant McConnell spu_acquire_saved(ctx); 1963bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 1964bf1ab978SDwayne Grant McConnell ret = __spufs_proxydma_info_read(ctx, buf, len, pos); 1965b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 1966b9e3bd77SDwayne Grant McConnell spu_release(ctx); 1967b9e3bd77SDwayne Grant McConnell 1968b9e3bd77SDwayne Grant McConnell return ret; 1969b9e3bd77SDwayne Grant McConnell } 1970b9e3bd77SDwayne Grant McConnell 19715dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = { 1972b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 1973b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 1974b9e3bd77SDwayne Grant McConnell }; 1975b9e3bd77SDwayne Grant McConnell 197667207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 197767207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 19788b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 197967207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 198067207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 198167207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 198267207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 198367207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 198467207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 198567207b96SArnd Bergmann { "signal1", &spufs_signal1_fops, 0666, }, 198667207b96SArnd Bergmann { "signal2", &spufs_signal2_fops, 0666, }, 198767207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 198867207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 19896df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 19908b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 1991b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 1992b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 1993b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 1994b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 1995b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 19968b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 19978b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 19988b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 1999b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 200027d5bf2aSBenjamin Herrenschmidt { "psmap", &spufs_psmap_fops, 0666, }, 200186767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 200286767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 200369a2f00cSDwayne Grant McConnell { "mbox_info", &spufs_mbox_info_fops, 0444, }, 200469a2f00cSDwayne Grant McConnell { "ibox_info", &spufs_ibox_info_fops, 0444, }, 200569a2f00cSDwayne Grant McConnell { "wbox_info", &spufs_wbox_info_fops, 0444, }, 2006b9e3bd77SDwayne Grant McConnell { "dma_info", &spufs_dma_info_fops, 0444, }, 2007b9e3bd77SDwayne Grant McConnell { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, 200867207b96SArnd Bergmann {}, 200967207b96SArnd Bergmann }; 20105737edd1SMark Nutter 20115737edd1SMark Nutter struct tree_descr spufs_dir_nosched_contents[] = { 20125737edd1SMark Nutter { "mem", &spufs_mem_fops, 0666, }, 20135737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 20145737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 20155737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 20165737edd1SMark Nutter { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 20175737edd1SMark Nutter { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 20185737edd1SMark Nutter { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 20195737edd1SMark Nutter { "signal1", &spufs_signal1_fops, 0666, }, 20205737edd1SMark Nutter { "signal2", &spufs_signal2_fops, 0666, }, 20215737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 20225737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 20235737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 20245737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 20255737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 20265737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 20275737edd1SMark Nutter { "psmap", &spufs_psmap_fops, 0666, }, 20285737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 20295737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 20305737edd1SMark Nutter {}, 20315737edd1SMark Nutter }; 2032bf1ab978SDwayne Grant McConnell 2033bf1ab978SDwayne Grant McConnell struct spufs_coredump_reader spufs_coredump_read[] = { 2034bf1ab978SDwayne Grant McConnell { "regs", __spufs_regs_read, NULL, 128 * 16 }, 2035bf1ab978SDwayne Grant McConnell { "fpcr", __spufs_fpcr_read, NULL, 16 }, 2036bf1ab978SDwayne Grant McConnell { "lslr", NULL, __spufs_lslr_get, 11 }, 2037bf1ab978SDwayne Grant McConnell { "decr", NULL, __spufs_decr_get, 11 }, 2038bf1ab978SDwayne Grant McConnell { "decr_status", NULL, __spufs_decr_status_get, 11 }, 2039bf1ab978SDwayne Grant McConnell { "mem", __spufs_mem_read, NULL, 256 * 1024, }, 2040bf1ab978SDwayne Grant McConnell { "signal1", __spufs_signal1_read, NULL, 4 }, 2041bf1ab978SDwayne Grant McConnell { "signal1_type", NULL, __spufs_signal1_type_get, 2 }, 2042bf1ab978SDwayne Grant McConnell { "signal2", __spufs_signal2_read, NULL, 4 }, 2043bf1ab978SDwayne Grant McConnell { "signal2_type", NULL, __spufs_signal2_type_get, 2 }, 2044bf1ab978SDwayne Grant McConnell { "event_mask", NULL, __spufs_event_mask_get, 8 }, 2045bf1ab978SDwayne Grant McConnell { "event_status", NULL, __spufs_event_status_get, 8 }, 2046bf1ab978SDwayne Grant McConnell { "mbox_info", __spufs_mbox_info_read, NULL, 4 }, 2047bf1ab978SDwayne Grant McConnell { "ibox_info", __spufs_ibox_info_read, NULL, 4 }, 2048bf1ab978SDwayne Grant McConnell { "wbox_info", __spufs_wbox_info_read, NULL, 16 }, 2049bf1ab978SDwayne Grant McConnell { "dma_info", __spufs_dma_info_read, NULL, 69 * 8 }, 2050bf1ab978SDwayne Grant McConnell { "proxydma_info", __spufs_proxydma_info_read, NULL, 35 * 8 }, 2051bf1ab978SDwayne Grant McConnell { "object-id", NULL, __spufs_object_id_get, 19 }, 2052bf1ab978SDwayne Grant McConnell { }, 2053bf1ab978SDwayne Grant McConnell }; 2054bf1ab978SDwayne Grant McConnell int spufs_coredump_num_notes = ARRAY_SIZE(spufs_coredump_read) - 1; 2055bf1ab978SDwayne Grant McConnell 2056