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 428b3d6663SArnd Bergmann 4367207b96SArnd Bergmann static int 4467207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 4567207b96SArnd Bergmann { 4667207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 476df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 486df10a82SMark Nutter file->private_data = ctx; 496df10a82SMark Nutter file->f_mapping = inode->i_mapping; 506df10a82SMark Nutter ctx->local_store = inode->i_mapping; 5167207b96SArnd Bergmann return 0; 5267207b96SArnd Bergmann } 5367207b96SArnd Bergmann 5467207b96SArnd Bergmann static ssize_t 5567207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 5667207b96SArnd Bergmann size_t size, loff_t *pos) 5767207b96SArnd Bergmann { 588b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 598b3d6663SArnd Bergmann char *local_store; 6067207b96SArnd Bergmann int ret; 6167207b96SArnd Bergmann 628b3d6663SArnd Bergmann spu_acquire(ctx); 6367207b96SArnd Bergmann 648b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 658b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE); 6667207b96SArnd Bergmann 678b3d6663SArnd Bergmann spu_release(ctx); 6867207b96SArnd Bergmann return ret; 6967207b96SArnd Bergmann } 7067207b96SArnd Bergmann 7167207b96SArnd Bergmann static ssize_t 7267207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 7367207b96SArnd Bergmann size_t size, loff_t *pos) 7467207b96SArnd Bergmann { 7567207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 768b3d6663SArnd Bergmann char *local_store; 778b3d6663SArnd Bergmann int ret; 7867207b96SArnd Bergmann 7967207b96SArnd Bergmann size = min_t(ssize_t, LS_SIZE - *pos, size); 8067207b96SArnd Bergmann if (size <= 0) 8167207b96SArnd Bergmann return -EFBIG; 8267207b96SArnd Bergmann *pos += size; 838b3d6663SArnd Bergmann 848b3d6663SArnd Bergmann spu_acquire(ctx); 858b3d6663SArnd Bergmann 868b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 878b3d6663SArnd Bergmann ret = copy_from_user(local_store + *pos - size, 8867207b96SArnd Bergmann buffer, size) ? -EFAULT : size; 898b3d6663SArnd Bergmann 908b3d6663SArnd Bergmann spu_release(ctx); 918b3d6663SArnd Bergmann return ret; 9267207b96SArnd Bergmann } 9367207b96SArnd Bergmann 948b3d6663SArnd Bergmann static struct page * 958b3d6663SArnd Bergmann spufs_mem_mmap_nopage(struct vm_area_struct *vma, 968b3d6663SArnd Bergmann unsigned long address, int *type) 978b3d6663SArnd Bergmann { 988b3d6663SArnd Bergmann struct page *page = NOPAGE_SIGBUS; 998b3d6663SArnd Bergmann 1008b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 1018b3d6663SArnd Bergmann unsigned long offset = address - vma->vm_start; 1028b3d6663SArnd Bergmann offset += vma->vm_pgoff << PAGE_SHIFT; 1038b3d6663SArnd Bergmann 1048b3d6663SArnd Bergmann spu_acquire(ctx); 1058b3d6663SArnd Bergmann 106ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 107ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 108*932f535dSArnd Bergmann & ~_PAGE_NO_CACHE); 1098b3d6663SArnd Bergmann page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); 110ac91cb8dSArnd Bergmann } else { 111ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 112*932f535dSArnd Bergmann | _PAGE_NO_CACHE); 1138b3d6663SArnd Bergmann page = pfn_to_page((ctx->spu->local_store_phys + offset) 1148b3d6663SArnd Bergmann >> PAGE_SHIFT); 115ac91cb8dSArnd Bergmann } 1168b3d6663SArnd Bergmann spu_release(ctx); 1178b3d6663SArnd Bergmann 1188b3d6663SArnd Bergmann if (type) 1198b3d6663SArnd Bergmann *type = VM_FAULT_MINOR; 1208b3d6663SArnd Bergmann 121d88cfffaSArnd Bergmann page_cache_get(page); 1228b3d6663SArnd Bergmann return page; 1238b3d6663SArnd Bergmann } 1248b3d6663SArnd Bergmann 1258b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = { 1268b3d6663SArnd Bergmann .nopage = spufs_mem_mmap_nopage, 1278b3d6663SArnd Bergmann }; 1288b3d6663SArnd Bergmann 12967207b96SArnd Bergmann static int 13067207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 13167207b96SArnd Bergmann { 1328b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 1338b3d6663SArnd Bergmann return -EINVAL; 13467207b96SArnd Bergmann 1355c3ecd65SChristoph Hellwig vma->vm_flags |= VM_IO; 13667207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 13767207b96SArnd Bergmann | _PAGE_NO_CACHE); 1388b3d6663SArnd Bergmann 1398b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 14067207b96SArnd Bergmann return 0; 14167207b96SArnd Bergmann } 14267207b96SArnd Bergmann 14367207b96SArnd Bergmann static struct file_operations spufs_mem_fops = { 14467207b96SArnd Bergmann .open = spufs_mem_open, 14567207b96SArnd Bergmann .read = spufs_mem_read, 14667207b96SArnd Bergmann .write = spufs_mem_write, 1478b3d6663SArnd Bergmann .llseek = generic_file_llseek, 14867207b96SArnd Bergmann .mmap = spufs_mem_mmap, 1498b3d6663SArnd Bergmann }; 1508b3d6663SArnd Bergmann 1516df10a82SMark Nutter static struct page *spufs_ps_nopage(struct vm_area_struct *vma, 1526df10a82SMark Nutter unsigned long address, 15327d5bf2aSBenjamin Herrenschmidt int *type, unsigned long ps_offs, 15427d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 1556df10a82SMark Nutter { 1566df10a82SMark Nutter struct page *page = NOPAGE_SIGBUS; 1576df10a82SMark Nutter int fault_type = VM_FAULT_SIGBUS; 1586df10a82SMark Nutter struct spu_context *ctx = vma->vm_file->private_data; 1596df10a82SMark Nutter unsigned long offset = address - vma->vm_start; 1606df10a82SMark Nutter unsigned long area; 1616df10a82SMark Nutter int ret; 1626df10a82SMark Nutter 1636df10a82SMark Nutter offset += vma->vm_pgoff << PAGE_SHIFT; 16427d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 1656df10a82SMark Nutter goto out; 1666df10a82SMark Nutter 1676df10a82SMark Nutter ret = spu_acquire_runnable(ctx); 1686df10a82SMark Nutter if (ret) 1696df10a82SMark Nutter goto out; 1706df10a82SMark Nutter 1716df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 1726df10a82SMark Nutter page = pfn_to_page((area + offset) >> PAGE_SHIFT); 1736df10a82SMark Nutter fault_type = VM_FAULT_MINOR; 1746df10a82SMark Nutter page_cache_get(page); 1756df10a82SMark Nutter 1766df10a82SMark Nutter spu_release(ctx); 1776df10a82SMark Nutter 1786df10a82SMark Nutter out: 1796df10a82SMark Nutter if (type) 1806df10a82SMark Nutter *type = fault_type; 1816df10a82SMark Nutter 1826df10a82SMark Nutter return page; 1836df10a82SMark Nutter } 1846df10a82SMark Nutter 18527d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1866df10a82SMark Nutter static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, 1876df10a82SMark Nutter unsigned long address, int *type) 1886df10a82SMark Nutter { 18927d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000); 1906df10a82SMark Nutter } 1916df10a82SMark Nutter 1926df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = { 1936df10a82SMark Nutter .nopage = spufs_cntl_mmap_nopage, 1946df10a82SMark Nutter }; 1956df10a82SMark Nutter 1966df10a82SMark Nutter /* 1976df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 1986df10a82SMark Nutter */ 1996df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 2006df10a82SMark Nutter { 2016df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 2026df10a82SMark Nutter return -EINVAL; 2036df10a82SMark Nutter 2045c3ecd65SChristoph Hellwig vma->vm_flags |= VM_IO; 2056df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 20623cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 2076df10a82SMark Nutter 2086df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 2096df10a82SMark Nutter return 0; 2106df10a82SMark Nutter } 21127d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 21227d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 21327d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 2146df10a82SMark Nutter 215e1dbff2bSArnd Bergmann static u64 spufs_cntl_get(void *data) 216e1dbff2bSArnd Bergmann { 217e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 218e1dbff2bSArnd Bergmann u64 val; 219e1dbff2bSArnd Bergmann 220e1dbff2bSArnd Bergmann spu_acquire(ctx); 221e1dbff2bSArnd Bergmann val = ctx->ops->status_read(ctx); 222e1dbff2bSArnd Bergmann spu_release(ctx); 223e1dbff2bSArnd Bergmann 224e1dbff2bSArnd Bergmann return val; 225e1dbff2bSArnd Bergmann } 226e1dbff2bSArnd Bergmann 227e1dbff2bSArnd Bergmann static void spufs_cntl_set(void *data, u64 val) 228e1dbff2bSArnd Bergmann { 229e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 230e1dbff2bSArnd Bergmann 231e1dbff2bSArnd Bergmann spu_acquire(ctx); 232e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 233e1dbff2bSArnd Bergmann spu_release(ctx); 234e1dbff2bSArnd Bergmann } 235e1dbff2bSArnd Bergmann 2366df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 2376df10a82SMark Nutter { 2386df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 2396df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 2406df10a82SMark Nutter 2416df10a82SMark Nutter file->private_data = ctx; 2426df10a82SMark Nutter file->f_mapping = inode->i_mapping; 2436df10a82SMark Nutter ctx->cntl = inode->i_mapping; 244e1dbff2bSArnd Bergmann return simple_attr_open(inode, file, spufs_cntl_get, 245e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 2466df10a82SMark Nutter } 2476df10a82SMark Nutter 2486df10a82SMark Nutter static struct file_operations spufs_cntl_fops = { 2496df10a82SMark Nutter .open = spufs_cntl_open, 250654e4aeeSNoguchi, Masato .release = simple_attr_close, 251e1dbff2bSArnd Bergmann .read = simple_attr_read, 252e1dbff2bSArnd Bergmann .write = simple_attr_write, 2536df10a82SMark Nutter .mmap = spufs_cntl_mmap, 2546df10a82SMark Nutter }; 2556df10a82SMark Nutter 2568b3d6663SArnd Bergmann static int 2578b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 2588b3d6663SArnd Bergmann { 2598b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 2608b3d6663SArnd Bergmann file->private_data = i->i_ctx; 2618b3d6663SArnd Bergmann return 0; 2628b3d6663SArnd Bergmann } 2638b3d6663SArnd Bergmann 2648b3d6663SArnd Bergmann static ssize_t 2658b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 2668b3d6663SArnd Bergmann size_t size, loff_t *pos) 2678b3d6663SArnd Bergmann { 2688b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 2698b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 2708b3d6663SArnd Bergmann int ret; 2718b3d6663SArnd Bergmann 2728b3d6663SArnd Bergmann spu_acquire_saved(ctx); 2738b3d6663SArnd Bergmann 2748b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 2758b3d6663SArnd Bergmann lscsa->gprs, sizeof lscsa->gprs); 2768b3d6663SArnd Bergmann 2778b3d6663SArnd Bergmann spu_release(ctx); 2788b3d6663SArnd Bergmann return ret; 2798b3d6663SArnd Bergmann } 2808b3d6663SArnd Bergmann 2818b3d6663SArnd Bergmann static ssize_t 2828b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 2838b3d6663SArnd Bergmann size_t size, loff_t *pos) 2848b3d6663SArnd Bergmann { 2858b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 2868b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 2878b3d6663SArnd Bergmann int ret; 2888b3d6663SArnd Bergmann 2898b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 2908b3d6663SArnd Bergmann if (size <= 0) 2918b3d6663SArnd Bergmann return -EFBIG; 2928b3d6663SArnd Bergmann *pos += size; 2938b3d6663SArnd Bergmann 2948b3d6663SArnd Bergmann spu_acquire_saved(ctx); 2958b3d6663SArnd Bergmann 2968b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 2978b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 2988b3d6663SArnd Bergmann 2998b3d6663SArnd Bergmann spu_release(ctx); 3008b3d6663SArnd Bergmann return ret; 3018b3d6663SArnd Bergmann } 3028b3d6663SArnd Bergmann 3038b3d6663SArnd Bergmann static struct file_operations spufs_regs_fops = { 3048b3d6663SArnd Bergmann .open = spufs_regs_open, 3058b3d6663SArnd Bergmann .read = spufs_regs_read, 3068b3d6663SArnd Bergmann .write = spufs_regs_write, 3078b3d6663SArnd Bergmann .llseek = generic_file_llseek, 3088b3d6663SArnd Bergmann }; 3098b3d6663SArnd Bergmann 3108b3d6663SArnd Bergmann static ssize_t 3118b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 3128b3d6663SArnd Bergmann size_t size, loff_t * pos) 3138b3d6663SArnd Bergmann { 3148b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3158b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 3168b3d6663SArnd Bergmann int ret; 3178b3d6663SArnd Bergmann 3188b3d6663SArnd Bergmann spu_acquire_saved(ctx); 3198b3d6663SArnd Bergmann 3208b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 3218b3d6663SArnd Bergmann &lscsa->fpcr, sizeof(lscsa->fpcr)); 3228b3d6663SArnd Bergmann 3238b3d6663SArnd Bergmann spu_release(ctx); 3248b3d6663SArnd Bergmann return ret; 3258b3d6663SArnd Bergmann } 3268b3d6663SArnd Bergmann 3278b3d6663SArnd Bergmann static ssize_t 3288b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 3298b3d6663SArnd Bergmann size_t size, loff_t * pos) 3308b3d6663SArnd Bergmann { 3318b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3328b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 3338b3d6663SArnd Bergmann int ret; 3348b3d6663SArnd Bergmann 3358b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 3368b3d6663SArnd Bergmann if (size <= 0) 3378b3d6663SArnd Bergmann return -EFBIG; 3388b3d6663SArnd Bergmann *pos += size; 3398b3d6663SArnd Bergmann 3408b3d6663SArnd Bergmann spu_acquire_saved(ctx); 3418b3d6663SArnd Bergmann 3428b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 3438b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 3448b3d6663SArnd Bergmann 3458b3d6663SArnd Bergmann spu_release(ctx); 3468b3d6663SArnd Bergmann return ret; 3478b3d6663SArnd Bergmann } 3488b3d6663SArnd Bergmann 3498b3d6663SArnd Bergmann static struct file_operations spufs_fpcr_fops = { 3508b3d6663SArnd Bergmann .open = spufs_regs_open, 3518b3d6663SArnd Bergmann .read = spufs_fpcr_read, 3528b3d6663SArnd Bergmann .write = spufs_fpcr_write, 35367207b96SArnd Bergmann .llseek = generic_file_llseek, 35467207b96SArnd Bergmann }; 35567207b96SArnd Bergmann 35667207b96SArnd Bergmann /* generic open function for all pipe-like files */ 35767207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 35867207b96SArnd Bergmann { 35967207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 36067207b96SArnd Bergmann file->private_data = i->i_ctx; 36167207b96SArnd Bergmann 36267207b96SArnd Bergmann return nonseekable_open(inode, file); 36367207b96SArnd Bergmann } 36467207b96SArnd Bergmann 365cdcc89bbSArnd Bergmann /* 366cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 367cdcc89bbSArnd Bergmann * one of the conditions becomes true: 368cdcc89bbSArnd Bergmann * 369cdcc89bbSArnd Bergmann * - no more data available in the mailbox 370cdcc89bbSArnd Bergmann * - end of the user provided buffer 371cdcc89bbSArnd Bergmann * - end of the mapped area 372cdcc89bbSArnd Bergmann */ 37367207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 37467207b96SArnd Bergmann size_t len, loff_t *pos) 37567207b96SArnd Bergmann { 3768b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 377cdcc89bbSArnd Bergmann u32 mbox_data, __user *udata; 378cdcc89bbSArnd Bergmann ssize_t count; 37967207b96SArnd Bergmann 38067207b96SArnd Bergmann if (len < 4) 38167207b96SArnd Bergmann return -EINVAL; 38267207b96SArnd Bergmann 383cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 38467207b96SArnd Bergmann return -EFAULT; 38567207b96SArnd Bergmann 386cdcc89bbSArnd Bergmann udata = (void __user *)buf; 387cdcc89bbSArnd Bergmann 388cdcc89bbSArnd Bergmann spu_acquire(ctx); 389274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 390cdcc89bbSArnd Bergmann int ret; 391cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 392cdcc89bbSArnd Bergmann if (ret == 0) 393cdcc89bbSArnd Bergmann break; 394cdcc89bbSArnd Bergmann 395cdcc89bbSArnd Bergmann /* 396cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 397cdcc89bbSArnd Bergmann * but still need to return the data we have 398cdcc89bbSArnd Bergmann * read successfully so far. 399cdcc89bbSArnd Bergmann */ 400cdcc89bbSArnd Bergmann ret = __put_user(mbox_data, udata); 401cdcc89bbSArnd Bergmann if (ret) { 402cdcc89bbSArnd Bergmann if (!count) 403cdcc89bbSArnd Bergmann count = -EFAULT; 404cdcc89bbSArnd Bergmann break; 405cdcc89bbSArnd Bergmann } 406cdcc89bbSArnd Bergmann } 407cdcc89bbSArnd Bergmann spu_release(ctx); 408cdcc89bbSArnd Bergmann 409cdcc89bbSArnd Bergmann if (!count) 410cdcc89bbSArnd Bergmann count = -EAGAIN; 411cdcc89bbSArnd Bergmann 412cdcc89bbSArnd Bergmann return count; 41367207b96SArnd Bergmann } 41467207b96SArnd Bergmann 41567207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = { 41667207b96SArnd Bergmann .open = spufs_pipe_open, 41767207b96SArnd Bergmann .read = spufs_mbox_read, 41867207b96SArnd Bergmann }; 41967207b96SArnd Bergmann 42067207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 42167207b96SArnd Bergmann size_t len, loff_t *pos) 42267207b96SArnd Bergmann { 4238b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 42467207b96SArnd Bergmann u32 mbox_stat; 42567207b96SArnd Bergmann 42667207b96SArnd Bergmann if (len < 4) 42767207b96SArnd Bergmann return -EINVAL; 42867207b96SArnd Bergmann 4298b3d6663SArnd Bergmann spu_acquire(ctx); 4308b3d6663SArnd Bergmann 4318b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 4328b3d6663SArnd Bergmann 4338b3d6663SArnd Bergmann spu_release(ctx); 43467207b96SArnd Bergmann 43567207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 43667207b96SArnd Bergmann return -EFAULT; 43767207b96SArnd Bergmann 43867207b96SArnd Bergmann return 4; 43967207b96SArnd Bergmann } 44067207b96SArnd Bergmann 44167207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = { 44267207b96SArnd Bergmann .open = spufs_pipe_open, 44367207b96SArnd Bergmann .read = spufs_mbox_stat_read, 44467207b96SArnd Bergmann }; 44567207b96SArnd Bergmann 44667207b96SArnd Bergmann /* low-level ibox access function */ 4478b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 44867207b96SArnd Bergmann { 4498b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 45067207b96SArnd Bergmann } 45167207b96SArnd Bergmann 45267207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 45367207b96SArnd Bergmann { 4548b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 4558b3d6663SArnd Bergmann 4568b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 4578b3d6663SArnd Bergmann } 4588b3d6663SArnd Bergmann 4598b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 4608b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 4618b3d6663SArnd Bergmann { 4628b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 4638b3d6663SArnd Bergmann 4648b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 4658b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 46667207b96SArnd Bergmann } 46767207b96SArnd Bergmann 468cdcc89bbSArnd Bergmann /* 469cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 470cdcc89bbSArnd Bergmann * one of the conditions becomes true: 471cdcc89bbSArnd Bergmann * 472cdcc89bbSArnd Bergmann * - no more data available in the mailbox 473cdcc89bbSArnd Bergmann * - end of the user provided buffer 474cdcc89bbSArnd Bergmann * - end of the mapped area 475cdcc89bbSArnd Bergmann * 476cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 477cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 478cdcc89bbSArnd Bergmann * read something. 479cdcc89bbSArnd Bergmann */ 48067207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 48167207b96SArnd Bergmann size_t len, loff_t *pos) 48267207b96SArnd Bergmann { 4838b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 484cdcc89bbSArnd Bergmann u32 ibox_data, __user *udata; 485cdcc89bbSArnd Bergmann ssize_t count; 48667207b96SArnd Bergmann 48767207b96SArnd Bergmann if (len < 4) 48867207b96SArnd Bergmann return -EINVAL; 48967207b96SArnd Bergmann 490cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 491cdcc89bbSArnd Bergmann return -EFAULT; 492cdcc89bbSArnd Bergmann 493cdcc89bbSArnd Bergmann udata = (void __user *)buf; 494cdcc89bbSArnd Bergmann 4958b3d6663SArnd Bergmann spu_acquire(ctx); 49667207b96SArnd Bergmann 497cdcc89bbSArnd Bergmann /* wait only for the first element */ 498cdcc89bbSArnd Bergmann count = 0; 49967207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 5008b3d6663SArnd Bergmann if (!spu_ibox_read(ctx, &ibox_data)) 501cdcc89bbSArnd Bergmann count = -EAGAIN; 50267207b96SArnd Bergmann } else { 503cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 504cdcc89bbSArnd Bergmann } 505cdcc89bbSArnd Bergmann if (count) 506cdcc89bbSArnd Bergmann goto out; 507cdcc89bbSArnd Bergmann 508cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 509cdcc89bbSArnd Bergmann count = __put_user(ibox_data, udata); 510cdcc89bbSArnd Bergmann if (count) 511cdcc89bbSArnd Bergmann goto out; 512cdcc89bbSArnd Bergmann 513cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 514cdcc89bbSArnd Bergmann int ret; 515cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 516cdcc89bbSArnd Bergmann if (ret == 0) 517cdcc89bbSArnd Bergmann break; 518cdcc89bbSArnd Bergmann /* 519cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 520cdcc89bbSArnd Bergmann * but still need to return the data we have 521cdcc89bbSArnd Bergmann * read successfully so far. 522cdcc89bbSArnd Bergmann */ 523cdcc89bbSArnd Bergmann ret = __put_user(ibox_data, udata); 524cdcc89bbSArnd Bergmann if (ret) 525cdcc89bbSArnd Bergmann break; 52667207b96SArnd Bergmann } 52767207b96SArnd Bergmann 528cdcc89bbSArnd Bergmann out: 5298b3d6663SArnd Bergmann spu_release(ctx); 5308b3d6663SArnd Bergmann 531cdcc89bbSArnd Bergmann return count; 53267207b96SArnd Bergmann } 53367207b96SArnd Bergmann 53467207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 53567207b96SArnd Bergmann { 5368b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 53767207b96SArnd Bergmann unsigned int mask; 53867207b96SArnd Bergmann 5398b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 54067207b96SArnd Bergmann 5413a843d7cSArnd Bergmann spu_acquire(ctx); 5423a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 5433a843d7cSArnd Bergmann spu_release(ctx); 54467207b96SArnd Bergmann 54567207b96SArnd Bergmann return mask; 54667207b96SArnd Bergmann } 54767207b96SArnd Bergmann 54867207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = { 54967207b96SArnd Bergmann .open = spufs_pipe_open, 55067207b96SArnd Bergmann .read = spufs_ibox_read, 55167207b96SArnd Bergmann .poll = spufs_ibox_poll, 55267207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 55367207b96SArnd Bergmann }; 55467207b96SArnd Bergmann 55567207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 55667207b96SArnd Bergmann size_t len, loff_t *pos) 55767207b96SArnd Bergmann { 5588b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 55967207b96SArnd Bergmann u32 ibox_stat; 56067207b96SArnd Bergmann 56167207b96SArnd Bergmann if (len < 4) 56267207b96SArnd Bergmann return -EINVAL; 56367207b96SArnd Bergmann 5648b3d6663SArnd Bergmann spu_acquire(ctx); 5658b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 5668b3d6663SArnd Bergmann spu_release(ctx); 56767207b96SArnd Bergmann 56867207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 56967207b96SArnd Bergmann return -EFAULT; 57067207b96SArnd Bergmann 57167207b96SArnd Bergmann return 4; 57267207b96SArnd Bergmann } 57367207b96SArnd Bergmann 57467207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = { 57567207b96SArnd Bergmann .open = spufs_pipe_open, 57667207b96SArnd Bergmann .read = spufs_ibox_stat_read, 57767207b96SArnd Bergmann }; 57867207b96SArnd Bergmann 57967207b96SArnd Bergmann /* low-level mailbox write */ 5808b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 58167207b96SArnd Bergmann { 5828b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 58367207b96SArnd Bergmann } 58467207b96SArnd Bergmann 58567207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 58667207b96SArnd Bergmann { 5878b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5888b3d6663SArnd Bergmann int ret; 5898b3d6663SArnd Bergmann 5908b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 5918b3d6663SArnd Bergmann 5928b3d6663SArnd Bergmann return ret; 5938b3d6663SArnd Bergmann } 5948b3d6663SArnd Bergmann 5958b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 5968b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 5978b3d6663SArnd Bergmann { 5988b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 5998b3d6663SArnd Bergmann 6008b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 6018b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 60267207b96SArnd Bergmann } 60367207b96SArnd Bergmann 604cdcc89bbSArnd Bergmann /* 605cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 606cdcc89bbSArnd Bergmann * one of the conditions becomes true: 607cdcc89bbSArnd Bergmann * 608cdcc89bbSArnd Bergmann * - the mailbox is full 609cdcc89bbSArnd Bergmann * - end of the user provided buffer 610cdcc89bbSArnd Bergmann * - end of the mapped area 611cdcc89bbSArnd Bergmann * 612cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 613cdcc89bbSArnd Bergmann * space is availabyl, but return when we have been able to 614cdcc89bbSArnd Bergmann * write something. 615cdcc89bbSArnd Bergmann */ 61667207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 61767207b96SArnd Bergmann size_t len, loff_t *pos) 61867207b96SArnd Bergmann { 6198b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 620cdcc89bbSArnd Bergmann u32 wbox_data, __user *udata; 621cdcc89bbSArnd Bergmann ssize_t count; 62267207b96SArnd Bergmann 62367207b96SArnd Bergmann if (len < 4) 62467207b96SArnd Bergmann return -EINVAL; 62567207b96SArnd Bergmann 626cdcc89bbSArnd Bergmann udata = (void __user *)buf; 627cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_READ, buf, len)) 628cdcc89bbSArnd Bergmann return -EFAULT; 629cdcc89bbSArnd Bergmann 630cdcc89bbSArnd Bergmann if (__get_user(wbox_data, udata)) 63167207b96SArnd Bergmann return -EFAULT; 63267207b96SArnd Bergmann 6338b3d6663SArnd Bergmann spu_acquire(ctx); 6348b3d6663SArnd Bergmann 635cdcc89bbSArnd Bergmann /* 636cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 637cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 638cdcc89bbSArnd Bergmann */ 639cdcc89bbSArnd Bergmann count = 0; 64067207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 6418b3d6663SArnd Bergmann if (!spu_wbox_write(ctx, wbox_data)) 642cdcc89bbSArnd Bergmann count = -EAGAIN; 64367207b96SArnd Bergmann } else { 644cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 64567207b96SArnd Bergmann } 64667207b96SArnd Bergmann 647cdcc89bbSArnd Bergmann if (count) 648cdcc89bbSArnd Bergmann goto out; 6498b3d6663SArnd Bergmann 650cdcc89bbSArnd Bergmann /* write aѕ much as possible */ 651cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 652cdcc89bbSArnd Bergmann int ret; 653cdcc89bbSArnd Bergmann ret = __get_user(wbox_data, udata); 654cdcc89bbSArnd Bergmann if (ret) 655cdcc89bbSArnd Bergmann break; 656cdcc89bbSArnd Bergmann 657cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 658cdcc89bbSArnd Bergmann if (ret == 0) 659cdcc89bbSArnd Bergmann break; 660cdcc89bbSArnd Bergmann } 661cdcc89bbSArnd Bergmann 662cdcc89bbSArnd Bergmann out: 663cdcc89bbSArnd Bergmann spu_release(ctx); 664cdcc89bbSArnd Bergmann return count; 66567207b96SArnd Bergmann } 66667207b96SArnd Bergmann 66767207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 66867207b96SArnd Bergmann { 6698b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 67067207b96SArnd Bergmann unsigned int mask; 67167207b96SArnd Bergmann 6728b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 67367207b96SArnd Bergmann 6743a843d7cSArnd Bergmann spu_acquire(ctx); 6753a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 6763a843d7cSArnd Bergmann spu_release(ctx); 67767207b96SArnd Bergmann 67867207b96SArnd Bergmann return mask; 67967207b96SArnd Bergmann } 68067207b96SArnd Bergmann 68167207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = { 68267207b96SArnd Bergmann .open = spufs_pipe_open, 68367207b96SArnd Bergmann .write = spufs_wbox_write, 68467207b96SArnd Bergmann .poll = spufs_wbox_poll, 68567207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 68667207b96SArnd Bergmann }; 68767207b96SArnd Bergmann 68867207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 68967207b96SArnd Bergmann size_t len, loff_t *pos) 69067207b96SArnd Bergmann { 6918b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 69267207b96SArnd Bergmann u32 wbox_stat; 69367207b96SArnd Bergmann 69467207b96SArnd Bergmann if (len < 4) 69567207b96SArnd Bergmann return -EINVAL; 69667207b96SArnd Bergmann 6978b3d6663SArnd Bergmann spu_acquire(ctx); 6988b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 6998b3d6663SArnd Bergmann spu_release(ctx); 70067207b96SArnd Bergmann 70167207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 70267207b96SArnd Bergmann return -EFAULT; 70367207b96SArnd Bergmann 70467207b96SArnd Bergmann return 4; 70567207b96SArnd Bergmann } 70667207b96SArnd Bergmann 70767207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = { 70867207b96SArnd Bergmann .open = spufs_pipe_open, 70967207b96SArnd Bergmann .read = spufs_wbox_stat_read, 71067207b96SArnd Bergmann }; 71167207b96SArnd Bergmann 7126df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 7136df10a82SMark Nutter { 7146df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 7156df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 7166df10a82SMark Nutter file->private_data = ctx; 7176df10a82SMark Nutter file->f_mapping = inode->i_mapping; 7186df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 7196df10a82SMark Nutter return nonseekable_open(inode, file); 7206df10a82SMark Nutter } 7216df10a82SMark Nutter 72267207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 72367207b96SArnd Bergmann size_t len, loff_t *pos) 72467207b96SArnd Bergmann { 7258b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 72617f88cebSDwayne Grant McConnell int ret = 0; 72767207b96SArnd Bergmann u32 data; 72867207b96SArnd Bergmann 72967207b96SArnd Bergmann if (len < 4) 73067207b96SArnd Bergmann return -EINVAL; 73167207b96SArnd Bergmann 73217f88cebSDwayne Grant McConnell spu_acquire_saved(ctx); 73317f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[3]) { 73417f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[3]; 73517f88cebSDwayne Grant McConnell ret = 4; 73617f88cebSDwayne Grant McConnell } 7378b3d6663SArnd Bergmann spu_release(ctx); 7388b3d6663SArnd Bergmann 73917f88cebSDwayne Grant McConnell if (!ret) 74017f88cebSDwayne Grant McConnell goto out; 74117f88cebSDwayne Grant McConnell 74267207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 74367207b96SArnd Bergmann return -EFAULT; 74467207b96SArnd Bergmann 74517f88cebSDwayne Grant McConnell out: 74617f88cebSDwayne Grant McConnell return ret; 74767207b96SArnd Bergmann } 74867207b96SArnd Bergmann 74967207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 75067207b96SArnd Bergmann size_t len, loff_t *pos) 75167207b96SArnd Bergmann { 75267207b96SArnd Bergmann struct spu_context *ctx; 75367207b96SArnd Bergmann u32 data; 75467207b96SArnd Bergmann 75567207b96SArnd Bergmann ctx = file->private_data; 75667207b96SArnd Bergmann 75767207b96SArnd Bergmann if (len < 4) 75867207b96SArnd Bergmann return -EINVAL; 75967207b96SArnd Bergmann 76067207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 76167207b96SArnd Bergmann return -EFAULT; 76267207b96SArnd Bergmann 7638b3d6663SArnd Bergmann spu_acquire(ctx); 7648b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 7658b3d6663SArnd Bergmann spu_release(ctx); 76667207b96SArnd Bergmann 76767207b96SArnd Bergmann return 4; 76867207b96SArnd Bergmann } 76967207b96SArnd Bergmann 7706df10a82SMark Nutter static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, 7716df10a82SMark Nutter unsigned long address, int *type) 7726df10a82SMark Nutter { 77327d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 77427d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000); 77527d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 77627d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 77727d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 77827d5bf2aSBenjamin Herrenschmidt */ 77927d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); 78027d5bf2aSBenjamin Herrenschmidt #else 78127d5bf2aSBenjamin Herrenschmidt #error unsupported page size 78227d5bf2aSBenjamin Herrenschmidt #endif 7836df10a82SMark Nutter } 7846df10a82SMark Nutter 7856df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = { 7866df10a82SMark Nutter .nopage = spufs_signal1_mmap_nopage, 7876df10a82SMark Nutter }; 7886df10a82SMark Nutter 7896df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 7906df10a82SMark Nutter { 7916df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 7926df10a82SMark Nutter return -EINVAL; 7936df10a82SMark Nutter 7945c3ecd65SChristoph Hellwig vma->vm_flags |= VM_IO; 7956df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 79623cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 7976df10a82SMark Nutter 7986df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 7996df10a82SMark Nutter return 0; 8006df10a82SMark Nutter } 8016df10a82SMark Nutter 80267207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = { 8036df10a82SMark Nutter .open = spufs_signal1_open, 80467207b96SArnd Bergmann .read = spufs_signal1_read, 80567207b96SArnd Bergmann .write = spufs_signal1_write, 8066df10a82SMark Nutter .mmap = spufs_signal1_mmap, 80767207b96SArnd Bergmann }; 80867207b96SArnd Bergmann 8096df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 8106df10a82SMark Nutter { 8116df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 8126df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 8136df10a82SMark Nutter file->private_data = ctx; 8146df10a82SMark Nutter file->f_mapping = inode->i_mapping; 8156df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 8166df10a82SMark Nutter return nonseekable_open(inode, file); 8176df10a82SMark Nutter } 8186df10a82SMark Nutter 81967207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 82067207b96SArnd Bergmann size_t len, loff_t *pos) 82167207b96SArnd Bergmann { 82217f88cebSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 82317f88cebSDwayne Grant McConnell int ret = 0; 82467207b96SArnd Bergmann u32 data; 82567207b96SArnd Bergmann 82667207b96SArnd Bergmann if (len < 4) 82767207b96SArnd Bergmann return -EINVAL; 82867207b96SArnd Bergmann 82917f88cebSDwayne Grant McConnell spu_acquire_saved(ctx); 83017f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[4]) { 83117f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[4]; 83217f88cebSDwayne Grant McConnell ret = 4; 83317f88cebSDwayne Grant McConnell } 8348b3d6663SArnd Bergmann spu_release(ctx); 8358b3d6663SArnd Bergmann 83617f88cebSDwayne Grant McConnell if (!ret) 83717f88cebSDwayne Grant McConnell goto out; 83817f88cebSDwayne Grant McConnell 83967207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 84067207b96SArnd Bergmann return -EFAULT; 84167207b96SArnd Bergmann 84217f88cebSDwayne Grant McConnell out: 84367207b96SArnd Bergmann return 4; 84467207b96SArnd Bergmann } 84567207b96SArnd Bergmann 84667207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 84767207b96SArnd Bergmann size_t len, loff_t *pos) 84867207b96SArnd Bergmann { 84967207b96SArnd Bergmann struct spu_context *ctx; 85067207b96SArnd Bergmann u32 data; 85167207b96SArnd Bergmann 85267207b96SArnd Bergmann ctx = file->private_data; 85367207b96SArnd Bergmann 85467207b96SArnd Bergmann if (len < 4) 85567207b96SArnd Bergmann return -EINVAL; 85667207b96SArnd Bergmann 85767207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 85867207b96SArnd Bergmann return -EFAULT; 85967207b96SArnd Bergmann 8608b3d6663SArnd Bergmann spu_acquire(ctx); 8618b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 8628b3d6663SArnd Bergmann spu_release(ctx); 86367207b96SArnd Bergmann 86467207b96SArnd Bergmann return 4; 86567207b96SArnd Bergmann } 86667207b96SArnd Bergmann 86727d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 8686df10a82SMark Nutter static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, 8696df10a82SMark Nutter unsigned long address, int *type) 8706df10a82SMark Nutter { 87127d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 87227d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000); 87327d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 87427d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 87527d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 87627d5bf2aSBenjamin Herrenschmidt */ 87727d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); 87827d5bf2aSBenjamin Herrenschmidt #else 87927d5bf2aSBenjamin Herrenschmidt #error unsupported page size 88027d5bf2aSBenjamin Herrenschmidt #endif 8816df10a82SMark Nutter } 8826df10a82SMark Nutter 8836df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = { 8846df10a82SMark Nutter .nopage = spufs_signal2_mmap_nopage, 8856df10a82SMark Nutter }; 8866df10a82SMark Nutter 8876df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 8886df10a82SMark Nutter { 8896df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 8906df10a82SMark Nutter return -EINVAL; 8916df10a82SMark Nutter 8925c3ecd65SChristoph Hellwig vma->vm_flags |= VM_IO; 8936df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 89423cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 8956df10a82SMark Nutter 8966df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 8976df10a82SMark Nutter return 0; 8986df10a82SMark Nutter } 89927d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 90027d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 90127d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 9026df10a82SMark Nutter 90367207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = { 9046df10a82SMark Nutter .open = spufs_signal2_open, 90567207b96SArnd Bergmann .read = spufs_signal2_read, 90667207b96SArnd Bergmann .write = spufs_signal2_write, 9076df10a82SMark Nutter .mmap = spufs_signal2_mmap, 90867207b96SArnd Bergmann }; 90967207b96SArnd Bergmann 91067207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val) 91167207b96SArnd Bergmann { 91267207b96SArnd Bergmann struct spu_context *ctx = data; 91367207b96SArnd Bergmann 9148b3d6663SArnd Bergmann spu_acquire(ctx); 9158b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 9168b3d6663SArnd Bergmann spu_release(ctx); 91767207b96SArnd Bergmann } 91867207b96SArnd Bergmann 91967207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data) 92067207b96SArnd Bergmann { 92167207b96SArnd Bergmann struct spu_context *ctx = data; 9228b3d6663SArnd Bergmann u64 ret; 9238b3d6663SArnd Bergmann 9248b3d6663SArnd Bergmann spu_acquire(ctx); 9258b3d6663SArnd Bergmann ret = ctx->ops->signal1_type_get(ctx); 9268b3d6663SArnd Bergmann spu_release(ctx); 9278b3d6663SArnd Bergmann 9288b3d6663SArnd Bergmann return ret; 92967207b96SArnd Bergmann } 93067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 93167207b96SArnd Bergmann spufs_signal1_type_set, "%llu"); 93267207b96SArnd Bergmann 93367207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val) 93467207b96SArnd Bergmann { 93567207b96SArnd Bergmann struct spu_context *ctx = data; 93667207b96SArnd Bergmann 9378b3d6663SArnd Bergmann spu_acquire(ctx); 9388b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 9398b3d6663SArnd Bergmann spu_release(ctx); 94067207b96SArnd Bergmann } 94167207b96SArnd Bergmann 94267207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data) 94367207b96SArnd Bergmann { 94467207b96SArnd Bergmann struct spu_context *ctx = data; 9458b3d6663SArnd Bergmann u64 ret; 9468b3d6663SArnd Bergmann 9478b3d6663SArnd Bergmann spu_acquire(ctx); 9488b3d6663SArnd Bergmann ret = ctx->ops->signal2_type_get(ctx); 9498b3d6663SArnd Bergmann spu_release(ctx); 9508b3d6663SArnd Bergmann 9518b3d6663SArnd Bergmann return ret; 95267207b96SArnd Bergmann } 95367207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 95467207b96SArnd Bergmann spufs_signal2_type_set, "%llu"); 95567207b96SArnd Bergmann 95627d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 957d9379c4bSarnd@arndb.de static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, 958d9379c4bSarnd@arndb.de unsigned long address, int *type) 959d9379c4bSarnd@arndb.de { 96027d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000); 961d9379c4bSarnd@arndb.de } 962d9379c4bSarnd@arndb.de 963d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = { 964d9379c4bSarnd@arndb.de .nopage = spufs_mss_mmap_nopage, 965d9379c4bSarnd@arndb.de }; 966d9379c4bSarnd@arndb.de 967d9379c4bSarnd@arndb.de /* 968d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 969d9379c4bSarnd@arndb.de */ 970d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 971d9379c4bSarnd@arndb.de { 972d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 973d9379c4bSarnd@arndb.de return -EINVAL; 974d9379c4bSarnd@arndb.de 9755c3ecd65SChristoph Hellwig vma->vm_flags |= VM_IO; 976d9379c4bSarnd@arndb.de vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 97723cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 978d9379c4bSarnd@arndb.de 979d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 980d9379c4bSarnd@arndb.de return 0; 981d9379c4bSarnd@arndb.de } 98227d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 98327d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 98427d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 985d9379c4bSarnd@arndb.de 986d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 987d9379c4bSarnd@arndb.de { 988d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 989d9379c4bSarnd@arndb.de 990d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 991d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 992d9379c4bSarnd@arndb.de } 993d9379c4bSarnd@arndb.de 994d9379c4bSarnd@arndb.de static struct file_operations spufs_mss_fops = { 995d9379c4bSarnd@arndb.de .open = spufs_mss_open, 996d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 99727d5bf2aSBenjamin Herrenschmidt }; 99827d5bf2aSBenjamin Herrenschmidt 99927d5bf2aSBenjamin Herrenschmidt static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma, 100027d5bf2aSBenjamin Herrenschmidt unsigned long address, int *type) 100127d5bf2aSBenjamin Herrenschmidt { 100227d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000); 100327d5bf2aSBenjamin Herrenschmidt } 100427d5bf2aSBenjamin Herrenschmidt 100527d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = { 100627d5bf2aSBenjamin Herrenschmidt .nopage = spufs_psmap_mmap_nopage, 100727d5bf2aSBenjamin Herrenschmidt }; 100827d5bf2aSBenjamin Herrenschmidt 100927d5bf2aSBenjamin Herrenschmidt /* 101027d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 101127d5bf2aSBenjamin Herrenschmidt */ 101227d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 101327d5bf2aSBenjamin Herrenschmidt { 101427d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 101527d5bf2aSBenjamin Herrenschmidt return -EINVAL; 101627d5bf2aSBenjamin Herrenschmidt 10175c3ecd65SChristoph Hellwig vma->vm_flags |= VM_IO; 101827d5bf2aSBenjamin Herrenschmidt vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 101927d5bf2aSBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 102027d5bf2aSBenjamin Herrenschmidt 102127d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 102227d5bf2aSBenjamin Herrenschmidt return 0; 102327d5bf2aSBenjamin Herrenschmidt } 102427d5bf2aSBenjamin Herrenschmidt 102527d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 102627d5bf2aSBenjamin Herrenschmidt { 102727d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 102827d5bf2aSBenjamin Herrenschmidt 102927d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 103027d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 103127d5bf2aSBenjamin Herrenschmidt } 103227d5bf2aSBenjamin Herrenschmidt 103327d5bf2aSBenjamin Herrenschmidt static struct file_operations spufs_psmap_fops = { 103427d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 103527d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1036d9379c4bSarnd@arndb.de }; 1037d9379c4bSarnd@arndb.de 1038d9379c4bSarnd@arndb.de 103927d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 10406df10a82SMark Nutter static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, 10416df10a82SMark Nutter unsigned long address, int *type) 10426df10a82SMark Nutter { 104327d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000); 10446df10a82SMark Nutter } 10456df10a82SMark Nutter 10466df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = { 10476df10a82SMark Nutter .nopage = spufs_mfc_mmap_nopage, 10486df10a82SMark Nutter }; 10496df10a82SMark Nutter 10506df10a82SMark Nutter /* 10516df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 10526df10a82SMark Nutter */ 10536df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 10546df10a82SMark Nutter { 10556df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 10566df10a82SMark Nutter return -EINVAL; 10576df10a82SMark Nutter 10585c3ecd65SChristoph Hellwig vma->vm_flags |= VM_IO; 10596df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 106023cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 10616df10a82SMark Nutter 10626df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 10636df10a82SMark Nutter return 0; 10646df10a82SMark Nutter } 106527d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 106627d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 106727d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1068a33a7d73SArnd Bergmann 1069a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1070a33a7d73SArnd Bergmann { 1071a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1072a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1073a33a7d73SArnd Bergmann 1074a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1075a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1076a33a7d73SArnd Bergmann return -EINVAL; 1077a33a7d73SArnd Bergmann 1078a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1079a33a7d73SArnd Bergmann return -EBUSY; 1080a33a7d73SArnd Bergmann 1081a33a7d73SArnd Bergmann file->private_data = ctx; 1082a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1083a33a7d73SArnd Bergmann } 1084a33a7d73SArnd Bergmann 1085a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1086a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1087a33a7d73SArnd Bergmann { 1088a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1089a33a7d73SArnd Bergmann 1090a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1091a33a7d73SArnd Bergmann 1092a33a7d73SArnd Bergmann pr_debug("%s %s\n", __FUNCTION__, spu->name); 1093a33a7d73SArnd Bergmann if (ctx->mfc_fasync) { 1094a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1095a33a7d73SArnd Bergmann unsigned int mask; 1096a33a7d73SArnd Bergmann 1097a33a7d73SArnd Bergmann /* no need for spu_acquire in interrupt context */ 1098a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1099a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1100a33a7d73SArnd Bergmann 1101a33a7d73SArnd Bergmann mask = 0; 1102a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1103a33a7d73SArnd Bergmann mask |= POLLOUT; 1104a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1105a33a7d73SArnd Bergmann mask |= POLLIN; 1106a33a7d73SArnd Bergmann 1107a33a7d73SArnd Bergmann kill_fasync(&ctx->mfc_fasync, SIGIO, mask); 1108a33a7d73SArnd Bergmann } 1109a33a7d73SArnd Bergmann } 1110a33a7d73SArnd Bergmann 1111a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1112a33a7d73SArnd Bergmann { 1113a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1114a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1115a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1116a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1117a33a7d73SArnd Bergmann if (*status) 1118a33a7d73SArnd Bergmann return 1; 1119a33a7d73SArnd Bergmann 1120a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1121a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1122a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1123a33a7d73SArnd Bergmann return 0; 1124a33a7d73SArnd Bergmann } 1125a33a7d73SArnd Bergmann 1126a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1127a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1128a33a7d73SArnd Bergmann { 1129a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1130a33a7d73SArnd Bergmann int ret = -EINVAL; 1131a33a7d73SArnd Bergmann u32 status; 1132a33a7d73SArnd Bergmann 1133a33a7d73SArnd Bergmann if (size != 4) 1134a33a7d73SArnd Bergmann goto out; 1135a33a7d73SArnd Bergmann 1136a33a7d73SArnd Bergmann spu_acquire(ctx); 1137a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1138a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1139a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1140a33a7d73SArnd Bergmann ret = -EAGAIN; 1141a33a7d73SArnd Bergmann else 1142a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1143a33a7d73SArnd Bergmann } else { 1144a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1145a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1146a33a7d73SArnd Bergmann } 1147a33a7d73SArnd Bergmann spu_release(ctx); 1148a33a7d73SArnd Bergmann 1149a33a7d73SArnd Bergmann if (ret) 1150a33a7d73SArnd Bergmann goto out; 1151a33a7d73SArnd Bergmann 1152a33a7d73SArnd Bergmann ret = 4; 1153a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1154a33a7d73SArnd Bergmann ret = -EFAULT; 1155a33a7d73SArnd Bergmann 1156a33a7d73SArnd Bergmann out: 1157a33a7d73SArnd Bergmann return ret; 1158a33a7d73SArnd Bergmann } 1159a33a7d73SArnd Bergmann 1160a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1161a33a7d73SArnd Bergmann { 1162a33a7d73SArnd Bergmann pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, 1163a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1164a33a7d73SArnd Bergmann 1165a33a7d73SArnd Bergmann switch (cmd->cmd) { 1166a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1167a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1168a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1169a33a7d73SArnd Bergmann case MFC_GET_CMD: 1170a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1171a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1172a33a7d73SArnd Bergmann break; 1173a33a7d73SArnd Bergmann default: 1174a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1175a33a7d73SArnd Bergmann return -EIO; 1176a33a7d73SArnd Bergmann } 1177a33a7d73SArnd Bergmann 1178a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 1179a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment, ea %lx lsa %x\n", 1180a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1181a33a7d73SArnd Bergmann return -EIO; 1182a33a7d73SArnd Bergmann } 1183a33a7d73SArnd Bergmann 1184a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1185a33a7d73SArnd Bergmann case 1: 1186a33a7d73SArnd Bergmann break; 1187a33a7d73SArnd Bergmann case 2: 1188a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1189a33a7d73SArnd Bergmann goto error; 1190a33a7d73SArnd Bergmann break; 1191a33a7d73SArnd Bergmann case 4: 1192a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1193a33a7d73SArnd Bergmann goto error; 1194a33a7d73SArnd Bergmann break; 1195a33a7d73SArnd Bergmann case 8: 1196a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1197a33a7d73SArnd Bergmann goto error; 1198a33a7d73SArnd Bergmann break; 1199a33a7d73SArnd Bergmann case 0: 1200a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1201a33a7d73SArnd Bergmann goto error; 1202a33a7d73SArnd Bergmann break; 1203a33a7d73SArnd Bergmann error: 1204a33a7d73SArnd Bergmann default: 1205a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1206a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1207a33a7d73SArnd Bergmann return -EIO; 1208a33a7d73SArnd Bergmann } 1209a33a7d73SArnd Bergmann 1210a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1211a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1212a33a7d73SArnd Bergmann return -EIO; 1213a33a7d73SArnd Bergmann } 1214a33a7d73SArnd Bergmann 1215a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1216a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1217a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1218a33a7d73SArnd Bergmann return -EIO; 1219a33a7d73SArnd Bergmann } 1220a33a7d73SArnd Bergmann 1221a33a7d73SArnd Bergmann if (cmd->class) { 1222a33a7d73SArnd Bergmann /* not supported in this version */ 1223a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1224a33a7d73SArnd Bergmann return -EIO; 1225a33a7d73SArnd Bergmann } 1226a33a7d73SArnd Bergmann 1227a33a7d73SArnd Bergmann return 0; 1228a33a7d73SArnd Bergmann } 1229a33a7d73SArnd Bergmann 1230a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1231a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1232a33a7d73SArnd Bergmann int *error) 1233a33a7d73SArnd Bergmann { 1234a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1235a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1236a33a7d73SArnd Bergmann /* wait for any tag group to complete 1237a33a7d73SArnd Bergmann so we have space for the new command */ 1238a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1239a33a7d73SArnd Bergmann /* try again, because the queue might be 1240a33a7d73SArnd Bergmann empty again */ 1241a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1242a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1243a33a7d73SArnd Bergmann return 0; 1244a33a7d73SArnd Bergmann } 1245a33a7d73SArnd Bergmann return 1; 1246a33a7d73SArnd Bergmann } 1247a33a7d73SArnd Bergmann 1248a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1249a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1250a33a7d73SArnd Bergmann { 1251a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1252a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1253a33a7d73SArnd Bergmann int ret = -EINVAL; 1254a33a7d73SArnd Bergmann 1255a33a7d73SArnd Bergmann if (size != sizeof cmd) 1256a33a7d73SArnd Bergmann goto out; 1257a33a7d73SArnd Bergmann 1258a33a7d73SArnd Bergmann ret = -EFAULT; 1259a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1260a33a7d73SArnd Bergmann goto out; 1261a33a7d73SArnd Bergmann 1262a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1263a33a7d73SArnd Bergmann if (ret) 1264a33a7d73SArnd Bergmann goto out; 1265a33a7d73SArnd Bergmann 1266a33a7d73SArnd Bergmann spu_acquire_runnable(ctx); 1267a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1268a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1269a33a7d73SArnd Bergmann } else { 1270a33a7d73SArnd Bergmann int status; 1271a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1272a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1273a33a7d73SArnd Bergmann if (status) 1274a33a7d73SArnd Bergmann ret = status; 1275a33a7d73SArnd Bergmann } 1276a33a7d73SArnd Bergmann spu_release(ctx); 1277a33a7d73SArnd Bergmann 1278a33a7d73SArnd Bergmann if (ret) 1279a33a7d73SArnd Bergmann goto out; 1280a33a7d73SArnd Bergmann 1281a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 1282a33a7d73SArnd Bergmann 1283a33a7d73SArnd Bergmann out: 1284a33a7d73SArnd Bergmann return ret; 1285a33a7d73SArnd Bergmann } 1286a33a7d73SArnd Bergmann 1287a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) 1288a33a7d73SArnd Bergmann { 1289a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1290a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1291a33a7d73SArnd Bergmann unsigned int mask; 1292a33a7d73SArnd Bergmann 1293a33a7d73SArnd Bergmann spu_acquire(ctx); 1294a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1295a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1296a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1297a33a7d73SArnd Bergmann spu_release(ctx); 1298a33a7d73SArnd Bergmann 1299a33a7d73SArnd Bergmann poll_wait(file, &ctx->mfc_wq, wait); 1300a33a7d73SArnd Bergmann 1301a33a7d73SArnd Bergmann mask = 0; 1302a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1303a33a7d73SArnd Bergmann mask |= POLLOUT | POLLWRNORM; 1304a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1305a33a7d73SArnd Bergmann mask |= POLLIN | POLLRDNORM; 1306a33a7d73SArnd Bergmann 1307a33a7d73SArnd Bergmann pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, 1308a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1309a33a7d73SArnd Bergmann 1310a33a7d73SArnd Bergmann return mask; 1311a33a7d73SArnd Bergmann } 1312a33a7d73SArnd Bergmann 131373b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1314a33a7d73SArnd Bergmann { 1315a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1316a33a7d73SArnd Bergmann int ret; 1317a33a7d73SArnd Bergmann 1318a33a7d73SArnd Bergmann spu_acquire(ctx); 1319a33a7d73SArnd Bergmann #if 0 1320a33a7d73SArnd Bergmann /* this currently hangs */ 1321a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1322a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1323a33a7d73SArnd Bergmann if (ret) 1324a33a7d73SArnd Bergmann goto out; 1325a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1326a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1327a33a7d73SArnd Bergmann out: 1328a33a7d73SArnd Bergmann #else 1329a33a7d73SArnd Bergmann ret = 0; 1330a33a7d73SArnd Bergmann #endif 1331a33a7d73SArnd Bergmann spu_release(ctx); 1332a33a7d73SArnd Bergmann 1333a33a7d73SArnd Bergmann return ret; 1334a33a7d73SArnd Bergmann } 1335a33a7d73SArnd Bergmann 1336a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, 1337a33a7d73SArnd Bergmann int datasync) 1338a33a7d73SArnd Bergmann { 133973b6af8aSAl Viro return spufs_mfc_flush(file, NULL); 1340a33a7d73SArnd Bergmann } 1341a33a7d73SArnd Bergmann 1342a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on) 1343a33a7d73SArnd Bergmann { 1344a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1345a33a7d73SArnd Bergmann 1346a33a7d73SArnd Bergmann return fasync_helper(fd, file, on, &ctx->mfc_fasync); 1347a33a7d73SArnd Bergmann } 1348a33a7d73SArnd Bergmann 1349a33a7d73SArnd Bergmann static struct file_operations spufs_mfc_fops = { 1350a33a7d73SArnd Bergmann .open = spufs_mfc_open, 1351a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1352a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1353a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1354a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1355a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 1356a33a7d73SArnd Bergmann .fasync = spufs_mfc_fasync, 13576df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1358a33a7d73SArnd Bergmann }; 1359a33a7d73SArnd Bergmann 1360099814bbSJeremy Kerr 1361099814bbSJeremy Kerr static int spufs_recycle_open(struct inode *inode, struct file *file) 1362099814bbSJeremy Kerr { 1363099814bbSJeremy Kerr file->private_data = SPUFS_I(inode)->i_ctx; 1364099814bbSJeremy Kerr return nonseekable_open(inode, file); 1365099814bbSJeremy Kerr } 1366099814bbSJeremy Kerr 1367099814bbSJeremy Kerr static ssize_t spufs_recycle_write(struct file *file, 1368099814bbSJeremy Kerr const char __user *buffer, size_t size, loff_t *pos) 1369099814bbSJeremy Kerr { 1370099814bbSJeremy Kerr struct spu_context *ctx = file->private_data; 1371099814bbSJeremy Kerr int ret; 1372099814bbSJeremy Kerr 1373099814bbSJeremy Kerr if (!(ctx->flags & SPU_CREATE_ISOLATE)) 1374099814bbSJeremy Kerr return -EINVAL; 1375099814bbSJeremy Kerr 1376099814bbSJeremy Kerr if (size < 1) 1377099814bbSJeremy Kerr return -EINVAL; 1378099814bbSJeremy Kerr 1379099814bbSJeremy Kerr ret = spu_recycle_isolated(ctx); 1380099814bbSJeremy Kerr 1381099814bbSJeremy Kerr if (ret) 1382099814bbSJeremy Kerr return ret; 1383099814bbSJeremy Kerr return size; 1384099814bbSJeremy Kerr } 1385099814bbSJeremy Kerr 1386099814bbSJeremy Kerr static struct file_operations spufs_recycle_fops = { 1387099814bbSJeremy Kerr .open = spufs_recycle_open, 1388099814bbSJeremy Kerr .write = spufs_recycle_write, 1389099814bbSJeremy Kerr }; 1390099814bbSJeremy Kerr 139167207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val) 139267207b96SArnd Bergmann { 139367207b96SArnd Bergmann struct spu_context *ctx = data; 13948b3d6663SArnd Bergmann spu_acquire(ctx); 13958b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 13968b3d6663SArnd Bergmann spu_release(ctx); 139767207b96SArnd Bergmann } 139867207b96SArnd Bergmann 139967207b96SArnd Bergmann static u64 spufs_npc_get(void *data) 140067207b96SArnd Bergmann { 140167207b96SArnd Bergmann struct spu_context *ctx = data; 140267207b96SArnd Bergmann u64 ret; 14038b3d6663SArnd Bergmann spu_acquire(ctx); 14048b3d6663SArnd Bergmann ret = ctx->ops->npc_read(ctx); 14058b3d6663SArnd Bergmann spu_release(ctx); 140667207b96SArnd Bergmann return ret; 140767207b96SArnd Bergmann } 14089b5047e2SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 14099b5047e2SDwayne Grant McConnell "0x%llx\n") 141067207b96SArnd Bergmann 14118b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val) 14128b3d6663SArnd Bergmann { 14138b3d6663SArnd Bergmann struct spu_context *ctx = data; 14148b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14158b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14168b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 14178b3d6663SArnd Bergmann spu_release(ctx); 14188b3d6663SArnd Bergmann } 14198b3d6663SArnd Bergmann 14208b3d6663SArnd Bergmann static u64 spufs_decr_get(void *data) 14218b3d6663SArnd Bergmann { 14228b3d6663SArnd Bergmann struct spu_context *ctx = data; 14238b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14248b3d6663SArnd Bergmann u64 ret; 14258b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14268b3d6663SArnd Bergmann ret = lscsa->decr.slot[0]; 14278b3d6663SArnd Bergmann spu_release(ctx); 14288b3d6663SArnd Bergmann return ret; 14298b3d6663SArnd Bergmann } 14308b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 14319b5047e2SDwayne Grant McConnell "0x%llx\n") 14328b3d6663SArnd Bergmann 14338b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val) 14348b3d6663SArnd Bergmann { 14358b3d6663SArnd Bergmann struct spu_context *ctx = data; 14368b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14378b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14388b3d6663SArnd Bergmann lscsa->decr_status.slot[0] = (u32) val; 14398b3d6663SArnd Bergmann spu_release(ctx); 14408b3d6663SArnd Bergmann } 14418b3d6663SArnd Bergmann 14428b3d6663SArnd Bergmann static u64 spufs_decr_status_get(void *data) 14438b3d6663SArnd Bergmann { 14448b3d6663SArnd Bergmann struct spu_context *ctx = data; 14458b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14468b3d6663SArnd Bergmann u64 ret; 14478b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14488b3d6663SArnd Bergmann ret = lscsa->decr_status.slot[0]; 14498b3d6663SArnd Bergmann spu_release(ctx); 14508b3d6663SArnd Bergmann return ret; 14518b3d6663SArnd Bergmann } 14528b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 14539b5047e2SDwayne Grant McConnell spufs_decr_status_set, "0x%llx\n") 14548b3d6663SArnd Bergmann 14558b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val) 14568b3d6663SArnd Bergmann { 14578b3d6663SArnd Bergmann struct spu_context *ctx = data; 14588b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14598b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14608b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 14618b3d6663SArnd Bergmann spu_release(ctx); 14628b3d6663SArnd Bergmann } 14638b3d6663SArnd Bergmann 14648b3d6663SArnd Bergmann static u64 spufs_event_mask_get(void *data) 14658b3d6663SArnd Bergmann { 14668b3d6663SArnd Bergmann struct spu_context *ctx = data; 14678b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14688b3d6663SArnd Bergmann u64 ret; 14698b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14708b3d6663SArnd Bergmann ret = lscsa->event_mask.slot[0]; 14718b3d6663SArnd Bergmann spu_release(ctx); 14728b3d6663SArnd Bergmann return ret; 14738b3d6663SArnd Bergmann } 14748b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 14759b5047e2SDwayne Grant McConnell spufs_event_mask_set, "0x%llx\n") 14768b3d6663SArnd Bergmann 1477b9e3bd77SDwayne Grant McConnell static u64 spufs_event_status_get(void *data) 1478b9e3bd77SDwayne Grant McConnell { 1479b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = data; 1480b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1481b9e3bd77SDwayne Grant McConnell u64 ret = 0; 1482b9e3bd77SDwayne Grant McConnell u64 stat; 1483b9e3bd77SDwayne Grant McConnell 1484b9e3bd77SDwayne Grant McConnell spu_acquire_saved(ctx); 1485b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1486b9e3bd77SDwayne Grant McConnell if (stat) 1487b9e3bd77SDwayne Grant McConnell ret = state->spu_chnldata_RW[0]; 1488b9e3bd77SDwayne Grant McConnell spu_release(ctx); 1489b9e3bd77SDwayne Grant McConnell return ret; 1490b9e3bd77SDwayne Grant McConnell } 1491b9e3bd77SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1492b9e3bd77SDwayne Grant McConnell NULL, "0x%llx\n") 1493b9e3bd77SDwayne Grant McConnell 14948b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val) 14958b3d6663SArnd Bergmann { 14968b3d6663SArnd Bergmann struct spu_context *ctx = data; 14978b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14988b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14998b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 15008b3d6663SArnd Bergmann spu_release(ctx); 15018b3d6663SArnd Bergmann } 15028b3d6663SArnd Bergmann 15038b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data) 15048b3d6663SArnd Bergmann { 15058b3d6663SArnd Bergmann struct spu_context *ctx = data; 15068b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 15078b3d6663SArnd Bergmann u64 ret; 15088b3d6663SArnd Bergmann spu_acquire_saved(ctx); 15098b3d6663SArnd Bergmann ret = lscsa->srr0.slot[0]; 15108b3d6663SArnd Bergmann spu_release(ctx); 15118b3d6663SArnd Bergmann return ret; 15128b3d6663SArnd Bergmann } 15138b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 15149b5047e2SDwayne Grant McConnell "0x%llx\n") 15158b3d6663SArnd Bergmann 15167b1a7014Sarnd@arndb.de static u64 spufs_id_get(void *data) 15177b1a7014Sarnd@arndb.de { 15187b1a7014Sarnd@arndb.de struct spu_context *ctx = data; 15197b1a7014Sarnd@arndb.de u64 num; 15207b1a7014Sarnd@arndb.de 15217b1a7014Sarnd@arndb.de spu_acquire(ctx); 15227b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 15237b1a7014Sarnd@arndb.de num = ctx->spu->number; 15247b1a7014Sarnd@arndb.de else 15257b1a7014Sarnd@arndb.de num = (unsigned int)-1; 15267b1a7014Sarnd@arndb.de spu_release(ctx); 15277b1a7014Sarnd@arndb.de 15287b1a7014Sarnd@arndb.de return num; 15297b1a7014Sarnd@arndb.de } 1530e45d6634SAl Viro DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") 15317b1a7014Sarnd@arndb.de 153286767277SArnd Bergmann static u64 spufs_object_id_get(void *data) 153386767277SArnd Bergmann { 153486767277SArnd Bergmann struct spu_context *ctx = data; 153586767277SArnd Bergmann return ctx->object_id; 153686767277SArnd Bergmann } 153786767277SArnd Bergmann 153886767277SArnd Bergmann static void spufs_object_id_set(void *data, u64 id) 153986767277SArnd Bergmann { 154086767277SArnd Bergmann struct spu_context *ctx = data; 154186767277SArnd Bergmann ctx->object_id = id; 154286767277SArnd Bergmann } 154386767277SArnd Bergmann 154486767277SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 154586767277SArnd Bergmann spufs_object_id_set, "0x%llx\n"); 154686767277SArnd Bergmann 1547b9e3bd77SDwayne Grant McConnell static u64 spufs_lslr_get(void *data) 1548b9e3bd77SDwayne Grant McConnell { 1549b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = data; 1550b9e3bd77SDwayne Grant McConnell u64 ret; 1551b9e3bd77SDwayne Grant McConnell 1552b9e3bd77SDwayne Grant McConnell spu_acquire_saved(ctx); 1553b9e3bd77SDwayne Grant McConnell ret = ctx->csa.priv2.spu_lslr_RW; 1554b9e3bd77SDwayne Grant McConnell spu_release(ctx); 1555b9e3bd77SDwayne Grant McConnell 1556b9e3bd77SDwayne Grant McConnell return ret; 1557b9e3bd77SDwayne Grant McConnell } 1558b9e3bd77SDwayne Grant McConnell DEFINE_SIMPLE_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n") 1559b9e3bd77SDwayne Grant McConnell 1560b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 1561b9e3bd77SDwayne Grant McConnell { 1562b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 1563b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 1564b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 1565b9e3bd77SDwayne Grant McConnell return 0; 1566b9e3bd77SDwayne Grant McConnell } 1567b9e3bd77SDwayne Grant McConnell 156869a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 156969a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 157069a2f00cSDwayne Grant McConnell { 157169a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 157269a2f00cSDwayne Grant McConnell u32 mbox_stat; 157369a2f00cSDwayne Grant McConnell u32 data; 157469a2f00cSDwayne Grant McConnell 157569a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 157669a2f00cSDwayne Grant McConnell return -EFAULT; 157769a2f00cSDwayne Grant McConnell 157869a2f00cSDwayne Grant McConnell spu_acquire_saved(ctx); 157969a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 158069a2f00cSDwayne Grant McConnell mbox_stat = ctx->csa.prob.mb_stat_R; 158169a2f00cSDwayne Grant McConnell if (mbox_stat & 0x0000ff) { 158269a2f00cSDwayne Grant McConnell data = ctx->csa.prob.pu_mb_R; 158369a2f00cSDwayne Grant McConnell } 158469a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 158569a2f00cSDwayne Grant McConnell spu_release(ctx); 158669a2f00cSDwayne Grant McConnell 158769a2f00cSDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 158869a2f00cSDwayne Grant McConnell } 158969a2f00cSDwayne Grant McConnell 159069a2f00cSDwayne Grant McConnell static struct file_operations spufs_mbox_info_fops = { 159169a2f00cSDwayne Grant McConnell .open = spufs_info_open, 159269a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 159369a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 159469a2f00cSDwayne Grant McConnell }; 159569a2f00cSDwayne Grant McConnell 159669a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 159769a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 159869a2f00cSDwayne Grant McConnell { 159969a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 160069a2f00cSDwayne Grant McConnell u32 ibox_stat; 160169a2f00cSDwayne Grant McConnell u32 data; 160269a2f00cSDwayne Grant McConnell 160369a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 160469a2f00cSDwayne Grant McConnell return -EFAULT; 160569a2f00cSDwayne Grant McConnell 160669a2f00cSDwayne Grant McConnell spu_acquire_saved(ctx); 160769a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 160869a2f00cSDwayne Grant McConnell ibox_stat = ctx->csa.prob.mb_stat_R; 160969a2f00cSDwayne Grant McConnell if (ibox_stat & 0xff0000) { 161069a2f00cSDwayne Grant McConnell data = ctx->csa.priv2.puint_mb_R; 161169a2f00cSDwayne Grant McConnell } 161269a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 161369a2f00cSDwayne Grant McConnell spu_release(ctx); 161469a2f00cSDwayne Grant McConnell 161569a2f00cSDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 161669a2f00cSDwayne Grant McConnell } 161769a2f00cSDwayne Grant McConnell 161869a2f00cSDwayne Grant McConnell static struct file_operations spufs_ibox_info_fops = { 161969a2f00cSDwayne Grant McConnell .open = spufs_info_open, 162069a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 162169a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 162269a2f00cSDwayne Grant McConnell }; 162369a2f00cSDwayne Grant McConnell 162469a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 162569a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 162669a2f00cSDwayne Grant McConnell { 162769a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 162869a2f00cSDwayne Grant McConnell int i, cnt; 162969a2f00cSDwayne Grant McConnell u32 data[4]; 163069a2f00cSDwayne Grant McConnell u32 wbox_stat; 163169a2f00cSDwayne Grant McConnell 163269a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 163369a2f00cSDwayne Grant McConnell return -EFAULT; 163469a2f00cSDwayne Grant McConnell 163569a2f00cSDwayne Grant McConnell spu_acquire_saved(ctx); 163669a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 163769a2f00cSDwayne Grant McConnell wbox_stat = ctx->csa.prob.mb_stat_R; 163869a2f00cSDwayne Grant McConnell cnt = (wbox_stat & 0x00ff00) >> 8; 163969a2f00cSDwayne Grant McConnell for (i = 0; i < cnt; i++) { 164069a2f00cSDwayne Grant McConnell data[i] = ctx->csa.spu_mailbox_data[i]; 164169a2f00cSDwayne Grant McConnell } 164269a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 164369a2f00cSDwayne Grant McConnell spu_release(ctx); 164469a2f00cSDwayne Grant McConnell 164569a2f00cSDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, 164669a2f00cSDwayne Grant McConnell cnt * sizeof(u32)); 164769a2f00cSDwayne Grant McConnell } 164869a2f00cSDwayne Grant McConnell 164969a2f00cSDwayne Grant McConnell static struct file_operations spufs_wbox_info_fops = { 165069a2f00cSDwayne Grant McConnell .open = spufs_info_open, 165169a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 165269a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 165369a2f00cSDwayne Grant McConnell }; 165469a2f00cSDwayne Grant McConnell 1655b9e3bd77SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 1656b9e3bd77SDwayne Grant McConnell size_t len, loff_t *pos) 1657b9e3bd77SDwayne Grant McConnell { 1658b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1659b9e3bd77SDwayne Grant McConnell struct spu_dma_info info; 1660b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *spuqp; 1661b9e3bd77SDwayne Grant McConnell int i; 1662b9e3bd77SDwayne Grant McConnell 1663b9e3bd77SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 1664b9e3bd77SDwayne Grant McConnell return -EFAULT; 1665b9e3bd77SDwayne Grant McConnell 1666b9e3bd77SDwayne Grant McConnell spu_acquire_saved(ctx); 1667b9e3bd77SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 1668b9e3bd77SDwayne Grant McConnell info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 1669b9e3bd77SDwayne Grant McConnell info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 1670b9e3bd77SDwayne Grant McConnell info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; 1671b9e3bd77SDwayne Grant McConnell info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 1672b9e3bd77SDwayne Grant McConnell info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 1673b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 1674b9e3bd77SDwayne Grant McConnell qp = &info.dma_info_command_data[i]; 1675b9e3bd77SDwayne Grant McConnell spuqp = &ctx->csa.priv2.spuq[i]; 1676b9e3bd77SDwayne Grant McConnell 1677b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 1678b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 1679b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 1680b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 1681b9e3bd77SDwayne Grant McConnell } 1682b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 1683b9e3bd77SDwayne Grant McConnell spu_release(ctx); 1684b9e3bd77SDwayne Grant McConnell 1685b9e3bd77SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 1686b9e3bd77SDwayne Grant McConnell sizeof info); 1687b9e3bd77SDwayne Grant McConnell } 1688b9e3bd77SDwayne Grant McConnell 1689b9e3bd77SDwayne Grant McConnell static struct file_operations spufs_dma_info_fops = { 1690b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 1691b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 1692b9e3bd77SDwayne Grant McConnell }; 1693b9e3bd77SDwayne Grant McConnell 1694b9e3bd77SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 1695b9e3bd77SDwayne Grant McConnell size_t len, loff_t *pos) 1696b9e3bd77SDwayne Grant McConnell { 1697b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1698b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 1699b9e3bd77SDwayne Grant McConnell int ret = sizeof info; 1700b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *puqp; 1701b9e3bd77SDwayne Grant McConnell int i; 1702b9e3bd77SDwayne Grant McConnell 1703b9e3bd77SDwayne Grant McConnell if (len < ret) 1704b9e3bd77SDwayne Grant McConnell return -EINVAL; 1705b9e3bd77SDwayne Grant McConnell 1706b9e3bd77SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 1707b9e3bd77SDwayne Grant McConnell return -EFAULT; 1708b9e3bd77SDwayne Grant McConnell 1709b9e3bd77SDwayne Grant McConnell spu_acquire_saved(ctx); 1710b9e3bd77SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 1711b9e3bd77SDwayne Grant McConnell info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 1712b9e3bd77SDwayne Grant McConnell info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 1713b9e3bd77SDwayne Grant McConnell info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 1714b9e3bd77SDwayne Grant McConnell for (i = 0; i < 8; i++) { 1715b9e3bd77SDwayne Grant McConnell qp = &info.proxydma_info_command_data[i]; 1716b9e3bd77SDwayne Grant McConnell puqp = &ctx->csa.priv2.puq[i]; 1717b9e3bd77SDwayne Grant McConnell 1718b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 1719b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 1720b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 1721b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 1722b9e3bd77SDwayne Grant McConnell } 1723b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 1724b9e3bd77SDwayne Grant McConnell spu_release(ctx); 1725b9e3bd77SDwayne Grant McConnell 1726b9e3bd77SDwayne Grant McConnell if (copy_to_user(buf, &info, sizeof info)) 1727b9e3bd77SDwayne Grant McConnell ret = -EFAULT; 1728b9e3bd77SDwayne Grant McConnell 1729b9e3bd77SDwayne Grant McConnell return ret; 1730b9e3bd77SDwayne Grant McConnell } 1731b9e3bd77SDwayne Grant McConnell 1732b9e3bd77SDwayne Grant McConnell static struct file_operations spufs_proxydma_info_fops = { 1733b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 1734b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 1735b9e3bd77SDwayne Grant McConnell }; 1736b9e3bd77SDwayne Grant McConnell 173767207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 173867207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 17398b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 174067207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 174167207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 174267207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 174367207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 174467207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 174567207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 174667207b96SArnd Bergmann { "signal1", &spufs_signal1_fops, 0666, }, 174767207b96SArnd Bergmann { "signal2", &spufs_signal2_fops, 0666, }, 174867207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 174967207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 17506df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 17518b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 1752b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 1753b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 1754b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 1755b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 1756b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 17578b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 17588b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 17598b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 1760b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 176127d5bf2aSBenjamin Herrenschmidt { "psmap", &spufs_psmap_fops, 0666, }, 176286767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 176386767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 176469a2f00cSDwayne Grant McConnell { "mbox_info", &spufs_mbox_info_fops, 0444, }, 176569a2f00cSDwayne Grant McConnell { "ibox_info", &spufs_ibox_info_fops, 0444, }, 176669a2f00cSDwayne Grant McConnell { "wbox_info", &spufs_wbox_info_fops, 0444, }, 1767b9e3bd77SDwayne Grant McConnell { "dma_info", &spufs_dma_info_fops, 0444, }, 1768b9e3bd77SDwayne Grant McConnell { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, 176967207b96SArnd Bergmann {}, 177067207b96SArnd Bergmann }; 17715737edd1SMark Nutter 17725737edd1SMark Nutter struct tree_descr spufs_dir_nosched_contents[] = { 17735737edd1SMark Nutter { "mem", &spufs_mem_fops, 0666, }, 17745737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 17755737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 17765737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 17775737edd1SMark Nutter { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 17785737edd1SMark Nutter { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 17795737edd1SMark Nutter { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 17805737edd1SMark Nutter { "signal1", &spufs_signal1_fops, 0666, }, 17815737edd1SMark Nutter { "signal2", &spufs_signal2_fops, 0666, }, 17825737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 17835737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 17845737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 17855737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 17865737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 17875737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 17885737edd1SMark Nutter { "psmap", &spufs_psmap_fops, 0666, }, 17895737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 17905737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 1791099814bbSJeremy Kerr { "recycle", &spufs_recycle_fops, 0222, }, 17925737edd1SMark Nutter {}, 17935737edd1SMark Nutter }; 1794