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> 3567207b96SArnd Bergmann #include <asm/uaccess.h> 3667207b96SArnd Bergmann 3767207b96SArnd Bergmann #include "spufs.h" 3867207b96SArnd Bergmann 3927d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 4027d5bf2aSBenjamin Herrenschmidt 418b3d6663SArnd Bergmann 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; 476df10a82SMark Nutter file->private_data = ctx; 486df10a82SMark Nutter file->f_mapping = inode->i_mapping; 496df10a82SMark Nutter ctx->local_store = inode->i_mapping; 5067207b96SArnd Bergmann return 0; 5167207b96SArnd Bergmann } 5267207b96SArnd Bergmann 5367207b96SArnd Bergmann static ssize_t 5467207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 5567207b96SArnd Bergmann size_t size, loff_t *pos) 5667207b96SArnd Bergmann { 578b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 588b3d6663SArnd Bergmann char *local_store; 5967207b96SArnd Bergmann int ret; 6067207b96SArnd Bergmann 618b3d6663SArnd Bergmann spu_acquire(ctx); 6267207b96SArnd Bergmann 638b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 648b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE); 6567207b96SArnd Bergmann 668b3d6663SArnd Bergmann spu_release(ctx); 6767207b96SArnd Bergmann return ret; 6867207b96SArnd Bergmann } 6967207b96SArnd Bergmann 7067207b96SArnd Bergmann static ssize_t 7167207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 7267207b96SArnd Bergmann size_t size, loff_t *pos) 7367207b96SArnd Bergmann { 7467207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 758b3d6663SArnd Bergmann char *local_store; 768b3d6663SArnd Bergmann int ret; 7767207b96SArnd Bergmann 7867207b96SArnd Bergmann size = min_t(ssize_t, LS_SIZE - *pos, size); 7967207b96SArnd Bergmann if (size <= 0) 8067207b96SArnd Bergmann return -EFBIG; 8167207b96SArnd Bergmann *pos += size; 828b3d6663SArnd Bergmann 838b3d6663SArnd Bergmann spu_acquire(ctx); 848b3d6663SArnd Bergmann 858b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 868b3d6663SArnd Bergmann ret = copy_from_user(local_store + *pos - size, 8767207b96SArnd Bergmann buffer, size) ? -EFAULT : size; 888b3d6663SArnd Bergmann 898b3d6663SArnd Bergmann spu_release(ctx); 908b3d6663SArnd Bergmann return ret; 9167207b96SArnd Bergmann } 9267207b96SArnd Bergmann 938b3d6663SArnd Bergmann static struct page * 948b3d6663SArnd Bergmann spufs_mem_mmap_nopage(struct vm_area_struct *vma, 958b3d6663SArnd Bergmann unsigned long address, int *type) 968b3d6663SArnd Bergmann { 978b3d6663SArnd Bergmann struct page *page = NOPAGE_SIGBUS; 988b3d6663SArnd Bergmann 998b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 1008b3d6663SArnd Bergmann unsigned long offset = address - vma->vm_start; 1018b3d6663SArnd Bergmann offset += vma->vm_pgoff << PAGE_SHIFT; 1028b3d6663SArnd Bergmann 1038b3d6663SArnd Bergmann spu_acquire(ctx); 1048b3d6663SArnd Bergmann 105ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 106ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 107ac91cb8dSArnd Bergmann & ~(_PAGE_NO_CACHE | _PAGE_GUARDED)); 1088b3d6663SArnd Bergmann page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); 109ac91cb8dSArnd Bergmann } else { 110ac91cb8dSArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 111ac91cb8dSArnd Bergmann | _PAGE_NO_CACHE | _PAGE_GUARDED); 1128b3d6663SArnd Bergmann page = pfn_to_page((ctx->spu->local_store_phys + offset) 1138b3d6663SArnd Bergmann >> PAGE_SHIFT); 114ac91cb8dSArnd Bergmann } 1158b3d6663SArnd Bergmann spu_release(ctx); 1168b3d6663SArnd Bergmann 1178b3d6663SArnd Bergmann if (type) 1188b3d6663SArnd Bergmann *type = VM_FAULT_MINOR; 1198b3d6663SArnd Bergmann 120d88cfffaSArnd Bergmann page_cache_get(page); 1218b3d6663SArnd Bergmann return page; 1228b3d6663SArnd Bergmann } 1238b3d6663SArnd Bergmann 1248b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = { 1258b3d6663SArnd Bergmann .nopage = spufs_mem_mmap_nopage, 1268b3d6663SArnd Bergmann }; 1278b3d6663SArnd Bergmann 12867207b96SArnd Bergmann static int 12967207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 13067207b96SArnd Bergmann { 1318b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 1328b3d6663SArnd Bergmann return -EINVAL; 13367207b96SArnd Bergmann 1348b3d6663SArnd Bergmann /* FIXME: */ 13567207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 13667207b96SArnd Bergmann | _PAGE_NO_CACHE); 1378b3d6663SArnd Bergmann 1388b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 13967207b96SArnd Bergmann return 0; 14067207b96SArnd Bergmann } 14167207b96SArnd Bergmann 14267207b96SArnd Bergmann static struct file_operations spufs_mem_fops = { 14367207b96SArnd Bergmann .open = spufs_mem_open, 14467207b96SArnd Bergmann .read = spufs_mem_read, 14567207b96SArnd Bergmann .write = spufs_mem_write, 1468b3d6663SArnd Bergmann .llseek = generic_file_llseek, 14767207b96SArnd Bergmann .mmap = spufs_mem_mmap, 1488b3d6663SArnd Bergmann }; 1498b3d6663SArnd Bergmann 1506df10a82SMark Nutter static struct page *spufs_ps_nopage(struct vm_area_struct *vma, 1516df10a82SMark Nutter unsigned long address, 15227d5bf2aSBenjamin Herrenschmidt int *type, unsigned long ps_offs, 15327d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 1546df10a82SMark Nutter { 1556df10a82SMark Nutter struct page *page = NOPAGE_SIGBUS; 1566df10a82SMark Nutter int fault_type = VM_FAULT_SIGBUS; 1576df10a82SMark Nutter struct spu_context *ctx = vma->vm_file->private_data; 1586df10a82SMark Nutter unsigned long offset = address - vma->vm_start; 1596df10a82SMark Nutter unsigned long area; 1606df10a82SMark Nutter int ret; 1616df10a82SMark Nutter 1626df10a82SMark Nutter offset += vma->vm_pgoff << PAGE_SHIFT; 16327d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 1646df10a82SMark Nutter goto out; 1656df10a82SMark Nutter 1666df10a82SMark Nutter ret = spu_acquire_runnable(ctx); 1676df10a82SMark Nutter if (ret) 1686df10a82SMark Nutter goto out; 1696df10a82SMark Nutter 1706df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 1716df10a82SMark Nutter page = pfn_to_page((area + offset) >> PAGE_SHIFT); 1726df10a82SMark Nutter fault_type = VM_FAULT_MINOR; 1736df10a82SMark Nutter page_cache_get(page); 1746df10a82SMark Nutter 1756df10a82SMark Nutter spu_release(ctx); 1766df10a82SMark Nutter 1776df10a82SMark Nutter out: 1786df10a82SMark Nutter if (type) 1796df10a82SMark Nutter *type = fault_type; 1806df10a82SMark Nutter 1816df10a82SMark Nutter return page; 1826df10a82SMark Nutter } 1836df10a82SMark Nutter 18427d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1856df10a82SMark Nutter static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, 1866df10a82SMark Nutter unsigned long address, int *type) 1876df10a82SMark Nutter { 18827d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000); 1896df10a82SMark Nutter } 1906df10a82SMark Nutter 1916df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = { 1926df10a82SMark Nutter .nopage = spufs_cntl_mmap_nopage, 1936df10a82SMark Nutter }; 1946df10a82SMark Nutter 1956df10a82SMark Nutter /* 1966df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 1976df10a82SMark Nutter */ 1986df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 1996df10a82SMark Nutter { 2006df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 2016df10a82SMark Nutter return -EINVAL; 2026df10a82SMark Nutter 2036df10a82SMark Nutter vma->vm_flags |= VM_RESERVED; 2046df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 20523cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 2066df10a82SMark Nutter 2076df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 2086df10a82SMark Nutter return 0; 2096df10a82SMark Nutter } 21027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 21127d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 21227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 2136df10a82SMark Nutter 214e1dbff2bSArnd Bergmann static u64 spufs_cntl_get(void *data) 215e1dbff2bSArnd Bergmann { 216e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 217e1dbff2bSArnd Bergmann u64 val; 218e1dbff2bSArnd Bergmann 219e1dbff2bSArnd Bergmann spu_acquire(ctx); 220e1dbff2bSArnd Bergmann val = ctx->ops->status_read(ctx); 221e1dbff2bSArnd Bergmann spu_release(ctx); 222e1dbff2bSArnd Bergmann 223e1dbff2bSArnd Bergmann return val; 224e1dbff2bSArnd Bergmann } 225e1dbff2bSArnd Bergmann 226e1dbff2bSArnd Bergmann static void spufs_cntl_set(void *data, u64 val) 227e1dbff2bSArnd Bergmann { 228e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 229e1dbff2bSArnd Bergmann 230e1dbff2bSArnd Bergmann spu_acquire(ctx); 231e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 232e1dbff2bSArnd Bergmann spu_release(ctx); 233e1dbff2bSArnd Bergmann } 234e1dbff2bSArnd Bergmann 2356df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 2366df10a82SMark Nutter { 2376df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 2386df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 2396df10a82SMark Nutter 2406df10a82SMark Nutter file->private_data = ctx; 2416df10a82SMark Nutter file->f_mapping = inode->i_mapping; 2426df10a82SMark Nutter ctx->cntl = inode->i_mapping; 243e1dbff2bSArnd Bergmann return simple_attr_open(inode, file, spufs_cntl_get, 244e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 2456df10a82SMark Nutter } 2466df10a82SMark Nutter 2476df10a82SMark Nutter static struct file_operations spufs_cntl_fops = { 2486df10a82SMark Nutter .open = spufs_cntl_open, 249*654e4aeeSNoguchi, Masato .release = simple_attr_close, 250e1dbff2bSArnd Bergmann .read = simple_attr_read, 251e1dbff2bSArnd Bergmann .write = simple_attr_write, 2526df10a82SMark Nutter .mmap = spufs_cntl_mmap, 2536df10a82SMark Nutter }; 2546df10a82SMark Nutter 2558b3d6663SArnd Bergmann static int 2568b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 2578b3d6663SArnd Bergmann { 2588b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 2598b3d6663SArnd Bergmann file->private_data = i->i_ctx; 2608b3d6663SArnd Bergmann return 0; 2618b3d6663SArnd Bergmann } 2628b3d6663SArnd Bergmann 2638b3d6663SArnd Bergmann static ssize_t 2648b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 2658b3d6663SArnd Bergmann size_t size, loff_t *pos) 2668b3d6663SArnd Bergmann { 2678b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 2688b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 2698b3d6663SArnd Bergmann int ret; 2708b3d6663SArnd Bergmann 2718b3d6663SArnd Bergmann spu_acquire_saved(ctx); 2728b3d6663SArnd Bergmann 2738b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 2748b3d6663SArnd Bergmann lscsa->gprs, sizeof lscsa->gprs); 2758b3d6663SArnd Bergmann 2768b3d6663SArnd Bergmann spu_release(ctx); 2778b3d6663SArnd Bergmann return ret; 2788b3d6663SArnd Bergmann } 2798b3d6663SArnd Bergmann 2808b3d6663SArnd Bergmann static ssize_t 2818b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 2828b3d6663SArnd Bergmann size_t size, loff_t *pos) 2838b3d6663SArnd Bergmann { 2848b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 2858b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 2868b3d6663SArnd Bergmann int ret; 2878b3d6663SArnd Bergmann 2888b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 2898b3d6663SArnd Bergmann if (size <= 0) 2908b3d6663SArnd Bergmann return -EFBIG; 2918b3d6663SArnd Bergmann *pos += size; 2928b3d6663SArnd Bergmann 2938b3d6663SArnd Bergmann spu_acquire_saved(ctx); 2948b3d6663SArnd Bergmann 2958b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 2968b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 2978b3d6663SArnd Bergmann 2988b3d6663SArnd Bergmann spu_release(ctx); 2998b3d6663SArnd Bergmann return ret; 3008b3d6663SArnd Bergmann } 3018b3d6663SArnd Bergmann 3028b3d6663SArnd Bergmann static struct file_operations spufs_regs_fops = { 3038b3d6663SArnd Bergmann .open = spufs_regs_open, 3048b3d6663SArnd Bergmann .read = spufs_regs_read, 3058b3d6663SArnd Bergmann .write = spufs_regs_write, 3068b3d6663SArnd Bergmann .llseek = generic_file_llseek, 3078b3d6663SArnd Bergmann }; 3088b3d6663SArnd Bergmann 3098b3d6663SArnd Bergmann static ssize_t 3108b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 3118b3d6663SArnd Bergmann size_t size, loff_t * pos) 3128b3d6663SArnd Bergmann { 3138b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3148b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 3158b3d6663SArnd Bergmann int ret; 3168b3d6663SArnd Bergmann 3178b3d6663SArnd Bergmann spu_acquire_saved(ctx); 3188b3d6663SArnd Bergmann 3198b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 3208b3d6663SArnd Bergmann &lscsa->fpcr, sizeof(lscsa->fpcr)); 3218b3d6663SArnd Bergmann 3228b3d6663SArnd Bergmann spu_release(ctx); 3238b3d6663SArnd Bergmann return ret; 3248b3d6663SArnd Bergmann } 3258b3d6663SArnd Bergmann 3268b3d6663SArnd Bergmann static ssize_t 3278b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 3288b3d6663SArnd Bergmann size_t size, loff_t * pos) 3298b3d6663SArnd Bergmann { 3308b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3318b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 3328b3d6663SArnd Bergmann int ret; 3338b3d6663SArnd Bergmann 3348b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 3358b3d6663SArnd Bergmann if (size <= 0) 3368b3d6663SArnd Bergmann return -EFBIG; 3378b3d6663SArnd Bergmann *pos += size; 3388b3d6663SArnd Bergmann 3398b3d6663SArnd Bergmann spu_acquire_saved(ctx); 3408b3d6663SArnd Bergmann 3418b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 3428b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 3438b3d6663SArnd Bergmann 3448b3d6663SArnd Bergmann spu_release(ctx); 3458b3d6663SArnd Bergmann return ret; 3468b3d6663SArnd Bergmann } 3478b3d6663SArnd Bergmann 3488b3d6663SArnd Bergmann static struct file_operations spufs_fpcr_fops = { 3498b3d6663SArnd Bergmann .open = spufs_regs_open, 3508b3d6663SArnd Bergmann .read = spufs_fpcr_read, 3518b3d6663SArnd Bergmann .write = spufs_fpcr_write, 35267207b96SArnd Bergmann .llseek = generic_file_llseek, 35367207b96SArnd Bergmann }; 35467207b96SArnd Bergmann 35567207b96SArnd Bergmann /* generic open function for all pipe-like files */ 35667207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 35767207b96SArnd Bergmann { 35867207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 35967207b96SArnd Bergmann file->private_data = i->i_ctx; 36067207b96SArnd Bergmann 36167207b96SArnd Bergmann return nonseekable_open(inode, file); 36267207b96SArnd Bergmann } 36367207b96SArnd Bergmann 364cdcc89bbSArnd Bergmann /* 365cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 366cdcc89bbSArnd Bergmann * one of the conditions becomes true: 367cdcc89bbSArnd Bergmann * 368cdcc89bbSArnd Bergmann * - no more data available in the mailbox 369cdcc89bbSArnd Bergmann * - end of the user provided buffer 370cdcc89bbSArnd Bergmann * - end of the mapped area 371cdcc89bbSArnd Bergmann */ 37267207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 37367207b96SArnd Bergmann size_t len, loff_t *pos) 37467207b96SArnd Bergmann { 3758b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 376cdcc89bbSArnd Bergmann u32 mbox_data, __user *udata; 377cdcc89bbSArnd Bergmann ssize_t count; 37867207b96SArnd Bergmann 37967207b96SArnd Bergmann if (len < 4) 38067207b96SArnd Bergmann return -EINVAL; 38167207b96SArnd Bergmann 382cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 38367207b96SArnd Bergmann return -EFAULT; 38467207b96SArnd Bergmann 385cdcc89bbSArnd Bergmann udata = (void __user *)buf; 386cdcc89bbSArnd Bergmann 387cdcc89bbSArnd Bergmann spu_acquire(ctx); 388cdcc89bbSArnd Bergmann for (count = 0; count <= len; count += 4, udata++) { 389cdcc89bbSArnd Bergmann int ret; 390cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 391cdcc89bbSArnd Bergmann if (ret == 0) 392cdcc89bbSArnd Bergmann break; 393cdcc89bbSArnd Bergmann 394cdcc89bbSArnd Bergmann /* 395cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 396cdcc89bbSArnd Bergmann * but still need to return the data we have 397cdcc89bbSArnd Bergmann * read successfully so far. 398cdcc89bbSArnd Bergmann */ 399cdcc89bbSArnd Bergmann ret = __put_user(mbox_data, udata); 400cdcc89bbSArnd Bergmann if (ret) { 401cdcc89bbSArnd Bergmann if (!count) 402cdcc89bbSArnd Bergmann count = -EFAULT; 403cdcc89bbSArnd Bergmann break; 404cdcc89bbSArnd Bergmann } 405cdcc89bbSArnd Bergmann } 406cdcc89bbSArnd Bergmann spu_release(ctx); 407cdcc89bbSArnd Bergmann 408cdcc89bbSArnd Bergmann if (!count) 409cdcc89bbSArnd Bergmann count = -EAGAIN; 410cdcc89bbSArnd Bergmann 411cdcc89bbSArnd Bergmann return count; 41267207b96SArnd Bergmann } 41367207b96SArnd Bergmann 41467207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = { 41567207b96SArnd Bergmann .open = spufs_pipe_open, 41667207b96SArnd Bergmann .read = spufs_mbox_read, 41767207b96SArnd Bergmann }; 41867207b96SArnd Bergmann 41967207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 42067207b96SArnd Bergmann size_t len, loff_t *pos) 42167207b96SArnd Bergmann { 4228b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 42367207b96SArnd Bergmann u32 mbox_stat; 42467207b96SArnd Bergmann 42567207b96SArnd Bergmann if (len < 4) 42667207b96SArnd Bergmann return -EINVAL; 42767207b96SArnd Bergmann 4288b3d6663SArnd Bergmann spu_acquire(ctx); 4298b3d6663SArnd Bergmann 4308b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 4318b3d6663SArnd Bergmann 4328b3d6663SArnd Bergmann spu_release(ctx); 43367207b96SArnd Bergmann 43467207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 43567207b96SArnd Bergmann return -EFAULT; 43667207b96SArnd Bergmann 43767207b96SArnd Bergmann return 4; 43867207b96SArnd Bergmann } 43967207b96SArnd Bergmann 44067207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = { 44167207b96SArnd Bergmann .open = spufs_pipe_open, 44267207b96SArnd Bergmann .read = spufs_mbox_stat_read, 44367207b96SArnd Bergmann }; 44467207b96SArnd Bergmann 44567207b96SArnd Bergmann /* low-level ibox access function */ 4468b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 44767207b96SArnd Bergmann { 4488b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 44967207b96SArnd Bergmann } 45067207b96SArnd Bergmann 45167207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 45267207b96SArnd Bergmann { 4538b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 4548b3d6663SArnd Bergmann 4558b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 4568b3d6663SArnd Bergmann } 4578b3d6663SArnd Bergmann 4588b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 4598b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 4608b3d6663SArnd Bergmann { 4618b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 4628b3d6663SArnd Bergmann 4638b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 4648b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 46567207b96SArnd Bergmann } 46667207b96SArnd Bergmann 467cdcc89bbSArnd Bergmann /* 468cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 469cdcc89bbSArnd Bergmann * one of the conditions becomes true: 470cdcc89bbSArnd Bergmann * 471cdcc89bbSArnd Bergmann * - no more data available in the mailbox 472cdcc89bbSArnd Bergmann * - end of the user provided buffer 473cdcc89bbSArnd Bergmann * - end of the mapped area 474cdcc89bbSArnd Bergmann * 475cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 476cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 477cdcc89bbSArnd Bergmann * read something. 478cdcc89bbSArnd Bergmann */ 47967207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 48067207b96SArnd Bergmann size_t len, loff_t *pos) 48167207b96SArnd Bergmann { 4828b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 483cdcc89bbSArnd Bergmann u32 ibox_data, __user *udata; 484cdcc89bbSArnd Bergmann ssize_t count; 48567207b96SArnd Bergmann 48667207b96SArnd Bergmann if (len < 4) 48767207b96SArnd Bergmann return -EINVAL; 48867207b96SArnd Bergmann 489cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 490cdcc89bbSArnd Bergmann return -EFAULT; 491cdcc89bbSArnd Bergmann 492cdcc89bbSArnd Bergmann udata = (void __user *)buf; 493cdcc89bbSArnd Bergmann 4948b3d6663SArnd Bergmann spu_acquire(ctx); 49567207b96SArnd Bergmann 496cdcc89bbSArnd Bergmann /* wait only for the first element */ 497cdcc89bbSArnd Bergmann count = 0; 49867207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 4998b3d6663SArnd Bergmann if (!spu_ibox_read(ctx, &ibox_data)) 500cdcc89bbSArnd Bergmann count = -EAGAIN; 50167207b96SArnd Bergmann } else { 502cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 503cdcc89bbSArnd Bergmann } 504cdcc89bbSArnd Bergmann if (count) 505cdcc89bbSArnd Bergmann goto out; 506cdcc89bbSArnd Bergmann 507cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 508cdcc89bbSArnd Bergmann count = __put_user(ibox_data, udata); 509cdcc89bbSArnd Bergmann if (count) 510cdcc89bbSArnd Bergmann goto out; 511cdcc89bbSArnd Bergmann 512cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 513cdcc89bbSArnd Bergmann int ret; 514cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 515cdcc89bbSArnd Bergmann if (ret == 0) 516cdcc89bbSArnd Bergmann break; 517cdcc89bbSArnd Bergmann /* 518cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 519cdcc89bbSArnd Bergmann * but still need to return the data we have 520cdcc89bbSArnd Bergmann * read successfully so far. 521cdcc89bbSArnd Bergmann */ 522cdcc89bbSArnd Bergmann ret = __put_user(ibox_data, udata); 523cdcc89bbSArnd Bergmann if (ret) 524cdcc89bbSArnd Bergmann break; 52567207b96SArnd Bergmann } 52667207b96SArnd Bergmann 527cdcc89bbSArnd Bergmann out: 5288b3d6663SArnd Bergmann spu_release(ctx); 5298b3d6663SArnd Bergmann 530cdcc89bbSArnd Bergmann return count; 53167207b96SArnd Bergmann } 53267207b96SArnd Bergmann 53367207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 53467207b96SArnd Bergmann { 5358b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 53667207b96SArnd Bergmann unsigned int mask; 53767207b96SArnd Bergmann 5388b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 53967207b96SArnd Bergmann 5403a843d7cSArnd Bergmann spu_acquire(ctx); 5413a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 5423a843d7cSArnd Bergmann spu_release(ctx); 54367207b96SArnd Bergmann 54467207b96SArnd Bergmann return mask; 54567207b96SArnd Bergmann } 54667207b96SArnd Bergmann 54767207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = { 54867207b96SArnd Bergmann .open = spufs_pipe_open, 54967207b96SArnd Bergmann .read = spufs_ibox_read, 55067207b96SArnd Bergmann .poll = spufs_ibox_poll, 55167207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 55267207b96SArnd Bergmann }; 55367207b96SArnd Bergmann 55467207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 55567207b96SArnd Bergmann size_t len, loff_t *pos) 55667207b96SArnd Bergmann { 5578b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 55867207b96SArnd Bergmann u32 ibox_stat; 55967207b96SArnd Bergmann 56067207b96SArnd Bergmann if (len < 4) 56167207b96SArnd Bergmann return -EINVAL; 56267207b96SArnd Bergmann 5638b3d6663SArnd Bergmann spu_acquire(ctx); 5648b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 5658b3d6663SArnd Bergmann spu_release(ctx); 56667207b96SArnd Bergmann 56767207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 56867207b96SArnd Bergmann return -EFAULT; 56967207b96SArnd Bergmann 57067207b96SArnd Bergmann return 4; 57167207b96SArnd Bergmann } 57267207b96SArnd Bergmann 57367207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = { 57467207b96SArnd Bergmann .open = spufs_pipe_open, 57567207b96SArnd Bergmann .read = spufs_ibox_stat_read, 57667207b96SArnd Bergmann }; 57767207b96SArnd Bergmann 57867207b96SArnd Bergmann /* low-level mailbox write */ 5798b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 58067207b96SArnd Bergmann { 5818b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 58267207b96SArnd Bergmann } 58367207b96SArnd Bergmann 58467207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 58567207b96SArnd Bergmann { 5868b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5878b3d6663SArnd Bergmann int ret; 5888b3d6663SArnd Bergmann 5898b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 5908b3d6663SArnd Bergmann 5918b3d6663SArnd Bergmann return ret; 5928b3d6663SArnd Bergmann } 5938b3d6663SArnd Bergmann 5948b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 5958b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 5968b3d6663SArnd Bergmann { 5978b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 5988b3d6663SArnd Bergmann 5998b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 6008b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 60167207b96SArnd Bergmann } 60267207b96SArnd Bergmann 603cdcc89bbSArnd Bergmann /* 604cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 605cdcc89bbSArnd Bergmann * one of the conditions becomes true: 606cdcc89bbSArnd Bergmann * 607cdcc89bbSArnd Bergmann * - the mailbox is full 608cdcc89bbSArnd Bergmann * - end of the user provided buffer 609cdcc89bbSArnd Bergmann * - end of the mapped area 610cdcc89bbSArnd Bergmann * 611cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 612cdcc89bbSArnd Bergmann * space is availabyl, but return when we have been able to 613cdcc89bbSArnd Bergmann * write something. 614cdcc89bbSArnd Bergmann */ 61567207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 61667207b96SArnd Bergmann size_t len, loff_t *pos) 61767207b96SArnd Bergmann { 6188b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 619cdcc89bbSArnd Bergmann u32 wbox_data, __user *udata; 620cdcc89bbSArnd Bergmann ssize_t count; 62167207b96SArnd Bergmann 62267207b96SArnd Bergmann if (len < 4) 62367207b96SArnd Bergmann return -EINVAL; 62467207b96SArnd Bergmann 625cdcc89bbSArnd Bergmann udata = (void __user *)buf; 626cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_READ, buf, len)) 627cdcc89bbSArnd Bergmann return -EFAULT; 628cdcc89bbSArnd Bergmann 629cdcc89bbSArnd Bergmann if (__get_user(wbox_data, udata)) 63067207b96SArnd Bergmann return -EFAULT; 63167207b96SArnd Bergmann 6328b3d6663SArnd Bergmann spu_acquire(ctx); 6338b3d6663SArnd Bergmann 634cdcc89bbSArnd Bergmann /* 635cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 636cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 637cdcc89bbSArnd Bergmann */ 638cdcc89bbSArnd Bergmann count = 0; 63967207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 6408b3d6663SArnd Bergmann if (!spu_wbox_write(ctx, wbox_data)) 641cdcc89bbSArnd Bergmann count = -EAGAIN; 64267207b96SArnd Bergmann } else { 643cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 64467207b96SArnd Bergmann } 64567207b96SArnd Bergmann 646cdcc89bbSArnd Bergmann if (count) 647cdcc89bbSArnd Bergmann goto out; 6488b3d6663SArnd Bergmann 649cdcc89bbSArnd Bergmann /* write aѕ much as possible */ 650cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 651cdcc89bbSArnd Bergmann int ret; 652cdcc89bbSArnd Bergmann ret = __get_user(wbox_data, udata); 653cdcc89bbSArnd Bergmann if (ret) 654cdcc89bbSArnd Bergmann break; 655cdcc89bbSArnd Bergmann 656cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 657cdcc89bbSArnd Bergmann if (ret == 0) 658cdcc89bbSArnd Bergmann break; 659cdcc89bbSArnd Bergmann } 660cdcc89bbSArnd Bergmann 661cdcc89bbSArnd Bergmann out: 662cdcc89bbSArnd Bergmann spu_release(ctx); 663cdcc89bbSArnd Bergmann return count; 66467207b96SArnd Bergmann } 66567207b96SArnd Bergmann 66667207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 66767207b96SArnd Bergmann { 6688b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 66967207b96SArnd Bergmann unsigned int mask; 67067207b96SArnd Bergmann 6718b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 67267207b96SArnd Bergmann 6733a843d7cSArnd Bergmann spu_acquire(ctx); 6743a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 6753a843d7cSArnd Bergmann spu_release(ctx); 67667207b96SArnd Bergmann 67767207b96SArnd Bergmann return mask; 67867207b96SArnd Bergmann } 67967207b96SArnd Bergmann 68067207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = { 68167207b96SArnd Bergmann .open = spufs_pipe_open, 68267207b96SArnd Bergmann .write = spufs_wbox_write, 68367207b96SArnd Bergmann .poll = spufs_wbox_poll, 68467207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 68567207b96SArnd Bergmann }; 68667207b96SArnd Bergmann 68767207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 68867207b96SArnd Bergmann size_t len, loff_t *pos) 68967207b96SArnd Bergmann { 6908b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 69167207b96SArnd Bergmann u32 wbox_stat; 69267207b96SArnd Bergmann 69367207b96SArnd Bergmann if (len < 4) 69467207b96SArnd Bergmann return -EINVAL; 69567207b96SArnd Bergmann 6968b3d6663SArnd Bergmann spu_acquire(ctx); 6978b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 6988b3d6663SArnd Bergmann spu_release(ctx); 69967207b96SArnd Bergmann 70067207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 70167207b96SArnd Bergmann return -EFAULT; 70267207b96SArnd Bergmann 70367207b96SArnd Bergmann return 4; 70467207b96SArnd Bergmann } 70567207b96SArnd Bergmann 70667207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = { 70767207b96SArnd Bergmann .open = spufs_pipe_open, 70867207b96SArnd Bergmann .read = spufs_wbox_stat_read, 70967207b96SArnd Bergmann }; 71067207b96SArnd Bergmann 7116df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 7126df10a82SMark Nutter { 7136df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 7146df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 7156df10a82SMark Nutter file->private_data = ctx; 7166df10a82SMark Nutter file->f_mapping = inode->i_mapping; 7176df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 7186df10a82SMark Nutter return nonseekable_open(inode, file); 7196df10a82SMark Nutter } 7206df10a82SMark Nutter 72167207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 72267207b96SArnd Bergmann size_t len, loff_t *pos) 72367207b96SArnd Bergmann { 7248b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 72567207b96SArnd Bergmann u32 data; 72667207b96SArnd Bergmann 72767207b96SArnd Bergmann if (len < 4) 72867207b96SArnd Bergmann return -EINVAL; 72967207b96SArnd Bergmann 7308b3d6663SArnd Bergmann spu_acquire(ctx); 7318b3d6663SArnd Bergmann data = ctx->ops->signal1_read(ctx); 7328b3d6663SArnd Bergmann spu_release(ctx); 7338b3d6663SArnd Bergmann 73467207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 73567207b96SArnd Bergmann return -EFAULT; 73667207b96SArnd Bergmann 73767207b96SArnd Bergmann return 4; 73867207b96SArnd Bergmann } 73967207b96SArnd Bergmann 74067207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 74167207b96SArnd Bergmann size_t len, loff_t *pos) 74267207b96SArnd Bergmann { 74367207b96SArnd Bergmann struct spu_context *ctx; 74467207b96SArnd Bergmann u32 data; 74567207b96SArnd Bergmann 74667207b96SArnd Bergmann ctx = file->private_data; 74767207b96SArnd Bergmann 74867207b96SArnd Bergmann if (len < 4) 74967207b96SArnd Bergmann return -EINVAL; 75067207b96SArnd Bergmann 75167207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 75267207b96SArnd Bergmann return -EFAULT; 75367207b96SArnd Bergmann 7548b3d6663SArnd Bergmann spu_acquire(ctx); 7558b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 7568b3d6663SArnd Bergmann spu_release(ctx); 75767207b96SArnd Bergmann 75867207b96SArnd Bergmann return 4; 75967207b96SArnd Bergmann } 76067207b96SArnd Bergmann 7616df10a82SMark Nutter static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, 7626df10a82SMark Nutter unsigned long address, int *type) 7636df10a82SMark Nutter { 76427d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 76527d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000); 76627d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 76727d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 76827d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 76927d5bf2aSBenjamin Herrenschmidt */ 77027d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); 77127d5bf2aSBenjamin Herrenschmidt #else 77227d5bf2aSBenjamin Herrenschmidt #error unsupported page size 77327d5bf2aSBenjamin Herrenschmidt #endif 7746df10a82SMark Nutter } 7756df10a82SMark Nutter 7766df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = { 7776df10a82SMark Nutter .nopage = spufs_signal1_mmap_nopage, 7786df10a82SMark Nutter }; 7796df10a82SMark Nutter 7806df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 7816df10a82SMark Nutter { 7826df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 7836df10a82SMark Nutter return -EINVAL; 7846df10a82SMark Nutter 7856df10a82SMark Nutter vma->vm_flags |= VM_RESERVED; 7866df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 78723cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 7886df10a82SMark Nutter 7896df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 7906df10a82SMark Nutter return 0; 7916df10a82SMark Nutter } 7926df10a82SMark Nutter 79367207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = { 7946df10a82SMark Nutter .open = spufs_signal1_open, 79567207b96SArnd Bergmann .read = spufs_signal1_read, 79667207b96SArnd Bergmann .write = spufs_signal1_write, 7976df10a82SMark Nutter .mmap = spufs_signal1_mmap, 79867207b96SArnd Bergmann }; 79967207b96SArnd Bergmann 8006df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 8016df10a82SMark Nutter { 8026df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 8036df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 8046df10a82SMark Nutter file->private_data = ctx; 8056df10a82SMark Nutter file->f_mapping = inode->i_mapping; 8066df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 8076df10a82SMark Nutter return nonseekable_open(inode, file); 8086df10a82SMark Nutter } 8096df10a82SMark Nutter 81067207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 81167207b96SArnd Bergmann size_t len, loff_t *pos) 81267207b96SArnd Bergmann { 81367207b96SArnd Bergmann struct spu_context *ctx; 81467207b96SArnd Bergmann u32 data; 81567207b96SArnd Bergmann 81667207b96SArnd Bergmann ctx = file->private_data; 81767207b96SArnd Bergmann 81867207b96SArnd Bergmann if (len < 4) 81967207b96SArnd Bergmann return -EINVAL; 82067207b96SArnd Bergmann 8218b3d6663SArnd Bergmann spu_acquire(ctx); 8228b3d6663SArnd Bergmann data = ctx->ops->signal2_read(ctx); 8238b3d6663SArnd Bergmann spu_release(ctx); 8248b3d6663SArnd Bergmann 82567207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 82667207b96SArnd Bergmann return -EFAULT; 82767207b96SArnd Bergmann 82867207b96SArnd Bergmann return 4; 82967207b96SArnd Bergmann } 83067207b96SArnd Bergmann 83167207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 83267207b96SArnd Bergmann size_t len, loff_t *pos) 83367207b96SArnd Bergmann { 83467207b96SArnd Bergmann struct spu_context *ctx; 83567207b96SArnd Bergmann u32 data; 83667207b96SArnd Bergmann 83767207b96SArnd Bergmann ctx = file->private_data; 83867207b96SArnd Bergmann 83967207b96SArnd Bergmann if (len < 4) 84067207b96SArnd Bergmann return -EINVAL; 84167207b96SArnd Bergmann 84267207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 84367207b96SArnd Bergmann return -EFAULT; 84467207b96SArnd Bergmann 8458b3d6663SArnd Bergmann spu_acquire(ctx); 8468b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 8478b3d6663SArnd Bergmann spu_release(ctx); 84867207b96SArnd Bergmann 84967207b96SArnd Bergmann return 4; 85067207b96SArnd Bergmann } 85167207b96SArnd Bergmann 85227d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 8536df10a82SMark Nutter static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, 8546df10a82SMark Nutter unsigned long address, int *type) 8556df10a82SMark Nutter { 85627d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 85727d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000); 85827d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 85927d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 86027d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 86127d5bf2aSBenjamin Herrenschmidt */ 86227d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); 86327d5bf2aSBenjamin Herrenschmidt #else 86427d5bf2aSBenjamin Herrenschmidt #error unsupported page size 86527d5bf2aSBenjamin Herrenschmidt #endif 8666df10a82SMark Nutter } 8676df10a82SMark Nutter 8686df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = { 8696df10a82SMark Nutter .nopage = spufs_signal2_mmap_nopage, 8706df10a82SMark Nutter }; 8716df10a82SMark Nutter 8726df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 8736df10a82SMark Nutter { 8746df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 8756df10a82SMark Nutter return -EINVAL; 8766df10a82SMark Nutter 8776df10a82SMark Nutter /* FIXME: */ 8786df10a82SMark Nutter vma->vm_flags |= VM_RESERVED; 8796df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 88023cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 8816df10a82SMark Nutter 8826df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 8836df10a82SMark Nutter return 0; 8846df10a82SMark Nutter } 88527d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 88627d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 88727d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 8886df10a82SMark Nutter 88967207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = { 8906df10a82SMark Nutter .open = spufs_signal2_open, 89167207b96SArnd Bergmann .read = spufs_signal2_read, 89267207b96SArnd Bergmann .write = spufs_signal2_write, 8936df10a82SMark Nutter .mmap = spufs_signal2_mmap, 89467207b96SArnd Bergmann }; 89567207b96SArnd Bergmann 89667207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val) 89767207b96SArnd Bergmann { 89867207b96SArnd Bergmann struct spu_context *ctx = data; 89967207b96SArnd Bergmann 9008b3d6663SArnd Bergmann spu_acquire(ctx); 9018b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 9028b3d6663SArnd Bergmann spu_release(ctx); 90367207b96SArnd Bergmann } 90467207b96SArnd Bergmann 90567207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data) 90667207b96SArnd Bergmann { 90767207b96SArnd Bergmann struct spu_context *ctx = data; 9088b3d6663SArnd Bergmann u64 ret; 9098b3d6663SArnd Bergmann 9108b3d6663SArnd Bergmann spu_acquire(ctx); 9118b3d6663SArnd Bergmann ret = ctx->ops->signal1_type_get(ctx); 9128b3d6663SArnd Bergmann spu_release(ctx); 9138b3d6663SArnd Bergmann 9148b3d6663SArnd Bergmann return ret; 91567207b96SArnd Bergmann } 91667207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 91767207b96SArnd Bergmann spufs_signal1_type_set, "%llu"); 91867207b96SArnd Bergmann 91967207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val) 92067207b96SArnd Bergmann { 92167207b96SArnd Bergmann struct spu_context *ctx = data; 92267207b96SArnd Bergmann 9238b3d6663SArnd Bergmann spu_acquire(ctx); 9248b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 9258b3d6663SArnd Bergmann spu_release(ctx); 92667207b96SArnd Bergmann } 92767207b96SArnd Bergmann 92867207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data) 92967207b96SArnd Bergmann { 93067207b96SArnd Bergmann struct spu_context *ctx = data; 9318b3d6663SArnd Bergmann u64 ret; 9328b3d6663SArnd Bergmann 9338b3d6663SArnd Bergmann spu_acquire(ctx); 9348b3d6663SArnd Bergmann ret = ctx->ops->signal2_type_get(ctx); 9358b3d6663SArnd Bergmann spu_release(ctx); 9368b3d6663SArnd Bergmann 9378b3d6663SArnd Bergmann return ret; 93867207b96SArnd Bergmann } 93967207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 94067207b96SArnd Bergmann spufs_signal2_type_set, "%llu"); 94167207b96SArnd Bergmann 94227d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 943d9379c4bSarnd@arndb.de static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, 944d9379c4bSarnd@arndb.de unsigned long address, int *type) 945d9379c4bSarnd@arndb.de { 94627d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000); 947d9379c4bSarnd@arndb.de } 948d9379c4bSarnd@arndb.de 949d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = { 950d9379c4bSarnd@arndb.de .nopage = spufs_mss_mmap_nopage, 951d9379c4bSarnd@arndb.de }; 952d9379c4bSarnd@arndb.de 953d9379c4bSarnd@arndb.de /* 954d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 955d9379c4bSarnd@arndb.de */ 956d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 957d9379c4bSarnd@arndb.de { 958d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 959d9379c4bSarnd@arndb.de return -EINVAL; 960d9379c4bSarnd@arndb.de 961d9379c4bSarnd@arndb.de vma->vm_flags |= VM_RESERVED; 962d9379c4bSarnd@arndb.de vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 96323cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 964d9379c4bSarnd@arndb.de 965d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 966d9379c4bSarnd@arndb.de return 0; 967d9379c4bSarnd@arndb.de } 96827d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 96927d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 97027d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 971d9379c4bSarnd@arndb.de 972d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 973d9379c4bSarnd@arndb.de { 974d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 975d9379c4bSarnd@arndb.de 976d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 977d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 978d9379c4bSarnd@arndb.de } 979d9379c4bSarnd@arndb.de 980d9379c4bSarnd@arndb.de static struct file_operations spufs_mss_fops = { 981d9379c4bSarnd@arndb.de .open = spufs_mss_open, 982d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 98327d5bf2aSBenjamin Herrenschmidt }; 98427d5bf2aSBenjamin Herrenschmidt 98527d5bf2aSBenjamin Herrenschmidt static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma, 98627d5bf2aSBenjamin Herrenschmidt unsigned long address, int *type) 98727d5bf2aSBenjamin Herrenschmidt { 98827d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000); 98927d5bf2aSBenjamin Herrenschmidt } 99027d5bf2aSBenjamin Herrenschmidt 99127d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = { 99227d5bf2aSBenjamin Herrenschmidt .nopage = spufs_psmap_mmap_nopage, 99327d5bf2aSBenjamin Herrenschmidt }; 99427d5bf2aSBenjamin Herrenschmidt 99527d5bf2aSBenjamin Herrenschmidt /* 99627d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 99727d5bf2aSBenjamin Herrenschmidt */ 99827d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 99927d5bf2aSBenjamin Herrenschmidt { 100027d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 100127d5bf2aSBenjamin Herrenschmidt return -EINVAL; 100227d5bf2aSBenjamin Herrenschmidt 100327d5bf2aSBenjamin Herrenschmidt vma->vm_flags |= VM_RESERVED; 100427d5bf2aSBenjamin Herrenschmidt vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 100527d5bf2aSBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 100627d5bf2aSBenjamin Herrenschmidt 100727d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 100827d5bf2aSBenjamin Herrenschmidt return 0; 100927d5bf2aSBenjamin Herrenschmidt } 101027d5bf2aSBenjamin Herrenschmidt 101127d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 101227d5bf2aSBenjamin Herrenschmidt { 101327d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 101427d5bf2aSBenjamin Herrenschmidt 101527d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 101627d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 101727d5bf2aSBenjamin Herrenschmidt } 101827d5bf2aSBenjamin Herrenschmidt 101927d5bf2aSBenjamin Herrenschmidt static struct file_operations spufs_psmap_fops = { 102027d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 102127d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1022d9379c4bSarnd@arndb.de }; 1023d9379c4bSarnd@arndb.de 1024d9379c4bSarnd@arndb.de 102527d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 10266df10a82SMark Nutter static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, 10276df10a82SMark Nutter unsigned long address, int *type) 10286df10a82SMark Nutter { 102927d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000); 10306df10a82SMark Nutter } 10316df10a82SMark Nutter 10326df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = { 10336df10a82SMark Nutter .nopage = spufs_mfc_mmap_nopage, 10346df10a82SMark Nutter }; 10356df10a82SMark Nutter 10366df10a82SMark Nutter /* 10376df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 10386df10a82SMark Nutter */ 10396df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 10406df10a82SMark Nutter { 10416df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 10426df10a82SMark Nutter return -EINVAL; 10436df10a82SMark Nutter 10446df10a82SMark Nutter vma->vm_flags |= VM_RESERVED; 10456df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 104623cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 10476df10a82SMark Nutter 10486df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 10496df10a82SMark Nutter return 0; 10506df10a82SMark Nutter } 105127d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 105227d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 105327d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1054a33a7d73SArnd Bergmann 1055a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1056a33a7d73SArnd Bergmann { 1057a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1058a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1059a33a7d73SArnd Bergmann 1060a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1061a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1062a33a7d73SArnd Bergmann return -EINVAL; 1063a33a7d73SArnd Bergmann 1064a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1065a33a7d73SArnd Bergmann return -EBUSY; 1066a33a7d73SArnd Bergmann 1067a33a7d73SArnd Bergmann file->private_data = ctx; 1068a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1069a33a7d73SArnd Bergmann } 1070a33a7d73SArnd Bergmann 1071a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1072a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1073a33a7d73SArnd Bergmann { 1074a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1075a33a7d73SArnd Bergmann 1076a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1077a33a7d73SArnd Bergmann 1078a33a7d73SArnd Bergmann pr_debug("%s %s\n", __FUNCTION__, spu->name); 1079a33a7d73SArnd Bergmann if (ctx->mfc_fasync) { 1080a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1081a33a7d73SArnd Bergmann unsigned int mask; 1082a33a7d73SArnd Bergmann 1083a33a7d73SArnd Bergmann /* no need for spu_acquire in interrupt context */ 1084a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1085a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1086a33a7d73SArnd Bergmann 1087a33a7d73SArnd Bergmann mask = 0; 1088a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1089a33a7d73SArnd Bergmann mask |= POLLOUT; 1090a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1091a33a7d73SArnd Bergmann mask |= POLLIN; 1092a33a7d73SArnd Bergmann 1093a33a7d73SArnd Bergmann kill_fasync(&ctx->mfc_fasync, SIGIO, mask); 1094a33a7d73SArnd Bergmann } 1095a33a7d73SArnd Bergmann } 1096a33a7d73SArnd Bergmann 1097a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1098a33a7d73SArnd Bergmann { 1099a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1100a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1101a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1102a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1103a33a7d73SArnd Bergmann if (*status) 1104a33a7d73SArnd Bergmann return 1; 1105a33a7d73SArnd Bergmann 1106a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1107a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1108a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1109a33a7d73SArnd Bergmann return 0; 1110a33a7d73SArnd Bergmann } 1111a33a7d73SArnd Bergmann 1112a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1113a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1114a33a7d73SArnd Bergmann { 1115a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1116a33a7d73SArnd Bergmann int ret = -EINVAL; 1117a33a7d73SArnd Bergmann u32 status; 1118a33a7d73SArnd Bergmann 1119a33a7d73SArnd Bergmann if (size != 4) 1120a33a7d73SArnd Bergmann goto out; 1121a33a7d73SArnd Bergmann 1122a33a7d73SArnd Bergmann spu_acquire(ctx); 1123a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1124a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1125a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1126a33a7d73SArnd Bergmann ret = -EAGAIN; 1127a33a7d73SArnd Bergmann else 1128a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1129a33a7d73SArnd Bergmann } else { 1130a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1131a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1132a33a7d73SArnd Bergmann } 1133a33a7d73SArnd Bergmann spu_release(ctx); 1134a33a7d73SArnd Bergmann 1135a33a7d73SArnd Bergmann if (ret) 1136a33a7d73SArnd Bergmann goto out; 1137a33a7d73SArnd Bergmann 1138a33a7d73SArnd Bergmann ret = 4; 1139a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1140a33a7d73SArnd Bergmann ret = -EFAULT; 1141a33a7d73SArnd Bergmann 1142a33a7d73SArnd Bergmann out: 1143a33a7d73SArnd Bergmann return ret; 1144a33a7d73SArnd Bergmann } 1145a33a7d73SArnd Bergmann 1146a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1147a33a7d73SArnd Bergmann { 1148a33a7d73SArnd Bergmann pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, 1149a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1150a33a7d73SArnd Bergmann 1151a33a7d73SArnd Bergmann switch (cmd->cmd) { 1152a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1153a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1154a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1155a33a7d73SArnd Bergmann case MFC_GET_CMD: 1156a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1157a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1158a33a7d73SArnd Bergmann break; 1159a33a7d73SArnd Bergmann default: 1160a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1161a33a7d73SArnd Bergmann return -EIO; 1162a33a7d73SArnd Bergmann } 1163a33a7d73SArnd Bergmann 1164a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 1165a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment, ea %lx lsa %x\n", 1166a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1167a33a7d73SArnd Bergmann return -EIO; 1168a33a7d73SArnd Bergmann } 1169a33a7d73SArnd Bergmann 1170a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1171a33a7d73SArnd Bergmann case 1: 1172a33a7d73SArnd Bergmann break; 1173a33a7d73SArnd Bergmann case 2: 1174a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1175a33a7d73SArnd Bergmann goto error; 1176a33a7d73SArnd Bergmann break; 1177a33a7d73SArnd Bergmann case 4: 1178a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1179a33a7d73SArnd Bergmann goto error; 1180a33a7d73SArnd Bergmann break; 1181a33a7d73SArnd Bergmann case 8: 1182a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1183a33a7d73SArnd Bergmann goto error; 1184a33a7d73SArnd Bergmann break; 1185a33a7d73SArnd Bergmann case 0: 1186a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1187a33a7d73SArnd Bergmann goto error; 1188a33a7d73SArnd Bergmann break; 1189a33a7d73SArnd Bergmann error: 1190a33a7d73SArnd Bergmann default: 1191a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1192a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1193a33a7d73SArnd Bergmann return -EIO; 1194a33a7d73SArnd Bergmann } 1195a33a7d73SArnd Bergmann 1196a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1197a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1198a33a7d73SArnd Bergmann return -EIO; 1199a33a7d73SArnd Bergmann } 1200a33a7d73SArnd Bergmann 1201a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1202a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1203a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1204a33a7d73SArnd Bergmann return -EIO; 1205a33a7d73SArnd Bergmann } 1206a33a7d73SArnd Bergmann 1207a33a7d73SArnd Bergmann if (cmd->class) { 1208a33a7d73SArnd Bergmann /* not supported in this version */ 1209a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1210a33a7d73SArnd Bergmann return -EIO; 1211a33a7d73SArnd Bergmann } 1212a33a7d73SArnd Bergmann 1213a33a7d73SArnd Bergmann return 0; 1214a33a7d73SArnd Bergmann } 1215a33a7d73SArnd Bergmann 1216a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1217a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1218a33a7d73SArnd Bergmann int *error) 1219a33a7d73SArnd Bergmann { 1220a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1221a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1222a33a7d73SArnd Bergmann /* wait for any tag group to complete 1223a33a7d73SArnd Bergmann so we have space for the new command */ 1224a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1225a33a7d73SArnd Bergmann /* try again, because the queue might be 1226a33a7d73SArnd Bergmann empty again */ 1227a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1228a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1229a33a7d73SArnd Bergmann return 0; 1230a33a7d73SArnd Bergmann } 1231a33a7d73SArnd Bergmann return 1; 1232a33a7d73SArnd Bergmann } 1233a33a7d73SArnd Bergmann 1234a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1235a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1236a33a7d73SArnd Bergmann { 1237a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1238a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1239a33a7d73SArnd Bergmann int ret = -EINVAL; 1240a33a7d73SArnd Bergmann 1241a33a7d73SArnd Bergmann if (size != sizeof cmd) 1242a33a7d73SArnd Bergmann goto out; 1243a33a7d73SArnd Bergmann 1244a33a7d73SArnd Bergmann ret = -EFAULT; 1245a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1246a33a7d73SArnd Bergmann goto out; 1247a33a7d73SArnd Bergmann 1248a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1249a33a7d73SArnd Bergmann if (ret) 1250a33a7d73SArnd Bergmann goto out; 1251a33a7d73SArnd Bergmann 1252a33a7d73SArnd Bergmann spu_acquire_runnable(ctx); 1253a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1254a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1255a33a7d73SArnd Bergmann } else { 1256a33a7d73SArnd Bergmann int status; 1257a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1258a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1259a33a7d73SArnd Bergmann if (status) 1260a33a7d73SArnd Bergmann ret = status; 1261a33a7d73SArnd Bergmann } 1262a33a7d73SArnd Bergmann spu_release(ctx); 1263a33a7d73SArnd Bergmann 1264a33a7d73SArnd Bergmann if (ret) 1265a33a7d73SArnd Bergmann goto out; 1266a33a7d73SArnd Bergmann 1267a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 1268a33a7d73SArnd Bergmann 1269a33a7d73SArnd Bergmann out: 1270a33a7d73SArnd Bergmann return ret; 1271a33a7d73SArnd Bergmann } 1272a33a7d73SArnd Bergmann 1273a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) 1274a33a7d73SArnd Bergmann { 1275a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1276a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1277a33a7d73SArnd Bergmann unsigned int mask; 1278a33a7d73SArnd Bergmann 1279a33a7d73SArnd Bergmann spu_acquire(ctx); 1280a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1281a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1282a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1283a33a7d73SArnd Bergmann spu_release(ctx); 1284a33a7d73SArnd Bergmann 1285a33a7d73SArnd Bergmann poll_wait(file, &ctx->mfc_wq, wait); 1286a33a7d73SArnd Bergmann 1287a33a7d73SArnd Bergmann mask = 0; 1288a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1289a33a7d73SArnd Bergmann mask |= POLLOUT | POLLWRNORM; 1290a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1291a33a7d73SArnd Bergmann mask |= POLLIN | POLLRDNORM; 1292a33a7d73SArnd Bergmann 1293a33a7d73SArnd Bergmann pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, 1294a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1295a33a7d73SArnd Bergmann 1296a33a7d73SArnd Bergmann return mask; 1297a33a7d73SArnd Bergmann } 1298a33a7d73SArnd Bergmann 129973b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1300a33a7d73SArnd Bergmann { 1301a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1302a33a7d73SArnd Bergmann int ret; 1303a33a7d73SArnd Bergmann 1304a33a7d73SArnd Bergmann spu_acquire(ctx); 1305a33a7d73SArnd Bergmann #if 0 1306a33a7d73SArnd Bergmann /* this currently hangs */ 1307a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1308a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1309a33a7d73SArnd Bergmann if (ret) 1310a33a7d73SArnd Bergmann goto out; 1311a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1312a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1313a33a7d73SArnd Bergmann out: 1314a33a7d73SArnd Bergmann #else 1315a33a7d73SArnd Bergmann ret = 0; 1316a33a7d73SArnd Bergmann #endif 1317a33a7d73SArnd Bergmann spu_release(ctx); 1318a33a7d73SArnd Bergmann 1319a33a7d73SArnd Bergmann return ret; 1320a33a7d73SArnd Bergmann } 1321a33a7d73SArnd Bergmann 1322a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, 1323a33a7d73SArnd Bergmann int datasync) 1324a33a7d73SArnd Bergmann { 132573b6af8aSAl Viro return spufs_mfc_flush(file, NULL); 1326a33a7d73SArnd Bergmann } 1327a33a7d73SArnd Bergmann 1328a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on) 1329a33a7d73SArnd Bergmann { 1330a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1331a33a7d73SArnd Bergmann 1332a33a7d73SArnd Bergmann return fasync_helper(fd, file, on, &ctx->mfc_fasync); 1333a33a7d73SArnd Bergmann } 1334a33a7d73SArnd Bergmann 1335a33a7d73SArnd Bergmann static struct file_operations spufs_mfc_fops = { 1336a33a7d73SArnd Bergmann .open = spufs_mfc_open, 1337a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1338a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1339a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1340a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1341a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 1342a33a7d73SArnd Bergmann .fasync = spufs_mfc_fasync, 13436df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1344a33a7d73SArnd Bergmann }; 1345a33a7d73SArnd Bergmann 134667207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val) 134767207b96SArnd Bergmann { 134867207b96SArnd Bergmann struct spu_context *ctx = data; 13498b3d6663SArnd Bergmann spu_acquire(ctx); 13508b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 13518b3d6663SArnd Bergmann spu_release(ctx); 135267207b96SArnd Bergmann } 135367207b96SArnd Bergmann 135467207b96SArnd Bergmann static u64 spufs_npc_get(void *data) 135567207b96SArnd Bergmann { 135667207b96SArnd Bergmann struct spu_context *ctx = data; 135767207b96SArnd Bergmann u64 ret; 13588b3d6663SArnd Bergmann spu_acquire(ctx); 13598b3d6663SArnd Bergmann ret = ctx->ops->npc_read(ctx); 13608b3d6663SArnd Bergmann spu_release(ctx); 136167207b96SArnd Bergmann return ret; 136267207b96SArnd Bergmann } 136367207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n") 136467207b96SArnd Bergmann 13658b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val) 13668b3d6663SArnd Bergmann { 13678b3d6663SArnd Bergmann struct spu_context *ctx = data; 13688b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13698b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13708b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 13718b3d6663SArnd Bergmann spu_release(ctx); 13728b3d6663SArnd Bergmann } 13738b3d6663SArnd Bergmann 13748b3d6663SArnd Bergmann static u64 spufs_decr_get(void *data) 13758b3d6663SArnd Bergmann { 13768b3d6663SArnd Bergmann struct spu_context *ctx = data; 13778b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13788b3d6663SArnd Bergmann u64 ret; 13798b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13808b3d6663SArnd Bergmann ret = lscsa->decr.slot[0]; 13818b3d6663SArnd Bergmann spu_release(ctx); 13828b3d6663SArnd Bergmann return ret; 13838b3d6663SArnd Bergmann } 13848b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 13858b3d6663SArnd Bergmann "%llx\n") 13868b3d6663SArnd Bergmann 13878b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val) 13888b3d6663SArnd Bergmann { 13898b3d6663SArnd Bergmann struct spu_context *ctx = data; 13908b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13918b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13928b3d6663SArnd Bergmann lscsa->decr_status.slot[0] = (u32) val; 13938b3d6663SArnd Bergmann spu_release(ctx); 13948b3d6663SArnd Bergmann } 13958b3d6663SArnd Bergmann 13968b3d6663SArnd Bergmann static u64 spufs_decr_status_get(void *data) 13978b3d6663SArnd Bergmann { 13988b3d6663SArnd Bergmann struct spu_context *ctx = data; 13998b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14008b3d6663SArnd Bergmann u64 ret; 14018b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14028b3d6663SArnd Bergmann ret = lscsa->decr_status.slot[0]; 14038b3d6663SArnd Bergmann spu_release(ctx); 14048b3d6663SArnd Bergmann return ret; 14058b3d6663SArnd Bergmann } 14068b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 14078b3d6663SArnd Bergmann spufs_decr_status_set, "%llx\n") 14088b3d6663SArnd Bergmann 14098b3d6663SArnd Bergmann static void spufs_spu_tag_mask_set(void *data, u64 val) 14108b3d6663SArnd Bergmann { 14118b3d6663SArnd Bergmann struct spu_context *ctx = data; 14128b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14138b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14148b3d6663SArnd Bergmann lscsa->tag_mask.slot[0] = (u32) val; 14158b3d6663SArnd Bergmann spu_release(ctx); 14168b3d6663SArnd Bergmann } 14178b3d6663SArnd Bergmann 14188b3d6663SArnd Bergmann static u64 spufs_spu_tag_mask_get(void *data) 14198b3d6663SArnd Bergmann { 14208b3d6663SArnd Bergmann struct spu_context *ctx = data; 14218b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14228b3d6663SArnd Bergmann u64 ret; 14238b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14248b3d6663SArnd Bergmann ret = lscsa->tag_mask.slot[0]; 14258b3d6663SArnd Bergmann spu_release(ctx); 14268b3d6663SArnd Bergmann return ret; 14278b3d6663SArnd Bergmann } 14288b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get, 14298b3d6663SArnd Bergmann spufs_spu_tag_mask_set, "%llx\n") 14308b3d6663SArnd Bergmann 14318b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val) 14328b3d6663SArnd Bergmann { 14338b3d6663SArnd Bergmann struct spu_context *ctx = data; 14348b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14358b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14368b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 14378b3d6663SArnd Bergmann spu_release(ctx); 14388b3d6663SArnd Bergmann } 14398b3d6663SArnd Bergmann 14408b3d6663SArnd Bergmann static u64 spufs_event_mask_get(void *data) 14418b3d6663SArnd Bergmann { 14428b3d6663SArnd Bergmann struct spu_context *ctx = data; 14438b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14448b3d6663SArnd Bergmann u64 ret; 14458b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14468b3d6663SArnd Bergmann ret = lscsa->event_mask.slot[0]; 14478b3d6663SArnd Bergmann spu_release(ctx); 14488b3d6663SArnd Bergmann return ret; 14498b3d6663SArnd Bergmann } 14508b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 14518b3d6663SArnd Bergmann spufs_event_mask_set, "%llx\n") 14528b3d6663SArnd Bergmann 14538b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val) 14548b3d6663SArnd Bergmann { 14558b3d6663SArnd Bergmann struct spu_context *ctx = data; 14568b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14578b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14588b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 14598b3d6663SArnd Bergmann spu_release(ctx); 14608b3d6663SArnd Bergmann } 14618b3d6663SArnd Bergmann 14628b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data) 14638b3d6663SArnd Bergmann { 14648b3d6663SArnd Bergmann struct spu_context *ctx = data; 14658b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 14668b3d6663SArnd Bergmann u64 ret; 14678b3d6663SArnd Bergmann spu_acquire_saved(ctx); 14688b3d6663SArnd Bergmann ret = lscsa->srr0.slot[0]; 14698b3d6663SArnd Bergmann spu_release(ctx); 14708b3d6663SArnd Bergmann return ret; 14718b3d6663SArnd Bergmann } 14728b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 14738b3d6663SArnd Bergmann "%llx\n") 14748b3d6663SArnd Bergmann 14757b1a7014Sarnd@arndb.de static u64 spufs_id_get(void *data) 14767b1a7014Sarnd@arndb.de { 14777b1a7014Sarnd@arndb.de struct spu_context *ctx = data; 14787b1a7014Sarnd@arndb.de u64 num; 14797b1a7014Sarnd@arndb.de 14807b1a7014Sarnd@arndb.de spu_acquire(ctx); 14817b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 14827b1a7014Sarnd@arndb.de num = ctx->spu->number; 14837b1a7014Sarnd@arndb.de else 14847b1a7014Sarnd@arndb.de num = (unsigned int)-1; 14857b1a7014Sarnd@arndb.de spu_release(ctx); 14867b1a7014Sarnd@arndb.de 14877b1a7014Sarnd@arndb.de return num; 14887b1a7014Sarnd@arndb.de } 1489e45d6634SAl Viro DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") 14907b1a7014Sarnd@arndb.de 149186767277SArnd Bergmann static u64 spufs_object_id_get(void *data) 149286767277SArnd Bergmann { 149386767277SArnd Bergmann struct spu_context *ctx = data; 149486767277SArnd Bergmann return ctx->object_id; 149586767277SArnd Bergmann } 149686767277SArnd Bergmann 149786767277SArnd Bergmann static void spufs_object_id_set(void *data, u64 id) 149886767277SArnd Bergmann { 149986767277SArnd Bergmann struct spu_context *ctx = data; 150086767277SArnd Bergmann ctx->object_id = id; 150186767277SArnd Bergmann } 150286767277SArnd Bergmann 150386767277SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 150486767277SArnd Bergmann spufs_object_id_set, "0x%llx\n"); 150586767277SArnd Bergmann 150667207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 150767207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 15088b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 150967207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 151067207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 151167207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 151267207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 151367207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 151467207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 151567207b96SArnd Bergmann { "signal1", &spufs_signal1_fops, 0666, }, 151667207b96SArnd Bergmann { "signal2", &spufs_signal2_fops, 0666, }, 151767207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 151867207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 1519d9379c4bSarnd@arndb.de { "mss", &spufs_mss_fops, 0666, }, 1520a33a7d73SArnd Bergmann { "mfc", &spufs_mfc_fops, 0666, }, 15216df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 152267207b96SArnd Bergmann { "npc", &spufs_npc_ops, 0666, }, 15238b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 15248b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 15258b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 15268b3d6663SArnd Bergmann { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, }, 15278b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 15288b3d6663SArnd Bergmann { "srr0", &spufs_srr0_ops, 0666, }, 152927d5bf2aSBenjamin Herrenschmidt { "psmap", &spufs_psmap_fops, 0666, }, 153086767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 153186767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 153267207b96SArnd Bergmann {}, 153367207b96SArnd Bergmann }; 1534