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 1058b3d6663SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) 1068b3d6663SArnd Bergmann page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); 1078b3d6663SArnd Bergmann else 1088b3d6663SArnd Bergmann page = pfn_to_page((ctx->spu->local_store_phys + offset) 1098b3d6663SArnd Bergmann >> PAGE_SHIFT); 1108b3d6663SArnd Bergmann 1118b3d6663SArnd Bergmann spu_release(ctx); 1128b3d6663SArnd Bergmann 1138b3d6663SArnd Bergmann if (type) 1148b3d6663SArnd Bergmann *type = VM_FAULT_MINOR; 1158b3d6663SArnd Bergmann 116d88cfffaSArnd Bergmann page_cache_get(page); 1178b3d6663SArnd Bergmann return page; 1188b3d6663SArnd Bergmann } 1198b3d6663SArnd Bergmann 1208b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = { 1218b3d6663SArnd Bergmann .nopage = spufs_mem_mmap_nopage, 1228b3d6663SArnd Bergmann }; 1238b3d6663SArnd Bergmann 12467207b96SArnd Bergmann static int 12567207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 12667207b96SArnd Bergmann { 1278b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 1288b3d6663SArnd Bergmann return -EINVAL; 12967207b96SArnd Bergmann 1308b3d6663SArnd Bergmann /* FIXME: */ 13167207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 13267207b96SArnd Bergmann | _PAGE_NO_CACHE); 1338b3d6663SArnd Bergmann 1348b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 13567207b96SArnd Bergmann return 0; 13667207b96SArnd Bergmann } 13767207b96SArnd Bergmann 13867207b96SArnd Bergmann static struct file_operations spufs_mem_fops = { 13967207b96SArnd Bergmann .open = spufs_mem_open, 14067207b96SArnd Bergmann .read = spufs_mem_read, 14167207b96SArnd Bergmann .write = spufs_mem_write, 1428b3d6663SArnd Bergmann .llseek = generic_file_llseek, 14367207b96SArnd Bergmann .mmap = spufs_mem_mmap, 1448b3d6663SArnd Bergmann }; 1458b3d6663SArnd Bergmann 1466df10a82SMark Nutter static struct page *spufs_ps_nopage(struct vm_area_struct *vma, 1476df10a82SMark Nutter unsigned long address, 14827d5bf2aSBenjamin Herrenschmidt int *type, unsigned long ps_offs, 14927d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 1506df10a82SMark Nutter { 1516df10a82SMark Nutter struct page *page = NOPAGE_SIGBUS; 1526df10a82SMark Nutter int fault_type = VM_FAULT_SIGBUS; 1536df10a82SMark Nutter struct spu_context *ctx = vma->vm_file->private_data; 1546df10a82SMark Nutter unsigned long offset = address - vma->vm_start; 1556df10a82SMark Nutter unsigned long area; 1566df10a82SMark Nutter int ret; 1576df10a82SMark Nutter 1586df10a82SMark Nutter offset += vma->vm_pgoff << PAGE_SHIFT; 15927d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 1606df10a82SMark Nutter goto out; 1616df10a82SMark Nutter 1626df10a82SMark Nutter ret = spu_acquire_runnable(ctx); 1636df10a82SMark Nutter if (ret) 1646df10a82SMark Nutter goto out; 1656df10a82SMark Nutter 1666df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 1676df10a82SMark Nutter page = pfn_to_page((area + offset) >> PAGE_SHIFT); 1686df10a82SMark Nutter fault_type = VM_FAULT_MINOR; 1696df10a82SMark Nutter page_cache_get(page); 1706df10a82SMark Nutter 1716df10a82SMark Nutter spu_release(ctx); 1726df10a82SMark Nutter 1736df10a82SMark Nutter out: 1746df10a82SMark Nutter if (type) 1756df10a82SMark Nutter *type = fault_type; 1766df10a82SMark Nutter 1776df10a82SMark Nutter return page; 1786df10a82SMark Nutter } 1796df10a82SMark Nutter 18027d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1816df10a82SMark Nutter static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, 1826df10a82SMark Nutter unsigned long address, int *type) 1836df10a82SMark Nutter { 18427d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000); 1856df10a82SMark Nutter } 1866df10a82SMark Nutter 1876df10a82SMark Nutter static struct vm_operations_struct spufs_cntl_mmap_vmops = { 1886df10a82SMark Nutter .nopage = spufs_cntl_mmap_nopage, 1896df10a82SMark Nutter }; 1906df10a82SMark Nutter 1916df10a82SMark Nutter /* 1926df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 1936df10a82SMark Nutter */ 1946df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 1956df10a82SMark Nutter { 1966df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 1976df10a82SMark Nutter return -EINVAL; 1986df10a82SMark Nutter 1996df10a82SMark Nutter vma->vm_flags |= VM_RESERVED; 2006df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 20123cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 2026df10a82SMark Nutter 2036df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 2046df10a82SMark Nutter return 0; 2056df10a82SMark Nutter } 20627d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 20727d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 20827d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 2096df10a82SMark Nutter 2106df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 2116df10a82SMark Nutter { 2126df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 2136df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 2146df10a82SMark Nutter 2156df10a82SMark Nutter file->private_data = ctx; 2166df10a82SMark Nutter file->f_mapping = inode->i_mapping; 2176df10a82SMark Nutter ctx->cntl = inode->i_mapping; 2186df10a82SMark Nutter return 0; 2196df10a82SMark Nutter } 2206df10a82SMark Nutter 2216df10a82SMark Nutter static ssize_t 2226df10a82SMark Nutter spufs_cntl_read(struct file *file, char __user *buffer, 2236df10a82SMark Nutter size_t size, loff_t *pos) 2246df10a82SMark Nutter { 2256df10a82SMark Nutter /* FIXME: read from spu status */ 2266df10a82SMark Nutter return -EINVAL; 2276df10a82SMark Nutter } 2286df10a82SMark Nutter 2296df10a82SMark Nutter static ssize_t 2306df10a82SMark Nutter spufs_cntl_write(struct file *file, const char __user *buffer, 2316df10a82SMark Nutter size_t size, loff_t *pos) 2326df10a82SMark Nutter { 2336df10a82SMark Nutter /* FIXME: write to runctl bit */ 2346df10a82SMark Nutter return -EINVAL; 2356df10a82SMark Nutter } 2366df10a82SMark Nutter 2376df10a82SMark Nutter static struct file_operations spufs_cntl_fops = { 2386df10a82SMark Nutter .open = spufs_cntl_open, 2396df10a82SMark Nutter .read = spufs_cntl_read, 2406df10a82SMark Nutter .write = spufs_cntl_write, 2416df10a82SMark Nutter .mmap = spufs_cntl_mmap, 2426df10a82SMark Nutter }; 2436df10a82SMark Nutter 2448b3d6663SArnd Bergmann static int 2458b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 2468b3d6663SArnd Bergmann { 2478b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 2488b3d6663SArnd Bergmann file->private_data = i->i_ctx; 2498b3d6663SArnd Bergmann return 0; 2508b3d6663SArnd Bergmann } 2518b3d6663SArnd Bergmann 2528b3d6663SArnd Bergmann static ssize_t 2538b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 2548b3d6663SArnd Bergmann size_t size, loff_t *pos) 2558b3d6663SArnd Bergmann { 2568b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 2578b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 2588b3d6663SArnd Bergmann int ret; 2598b3d6663SArnd Bergmann 2608b3d6663SArnd Bergmann spu_acquire_saved(ctx); 2618b3d6663SArnd Bergmann 2628b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 2638b3d6663SArnd Bergmann lscsa->gprs, sizeof lscsa->gprs); 2648b3d6663SArnd Bergmann 2658b3d6663SArnd Bergmann spu_release(ctx); 2668b3d6663SArnd Bergmann return ret; 2678b3d6663SArnd Bergmann } 2688b3d6663SArnd Bergmann 2698b3d6663SArnd Bergmann static ssize_t 2708b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 2718b3d6663SArnd Bergmann size_t size, loff_t *pos) 2728b3d6663SArnd Bergmann { 2738b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 2748b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 2758b3d6663SArnd Bergmann int ret; 2768b3d6663SArnd Bergmann 2778b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 2788b3d6663SArnd Bergmann if (size <= 0) 2798b3d6663SArnd Bergmann return -EFBIG; 2808b3d6663SArnd Bergmann *pos += size; 2818b3d6663SArnd Bergmann 2828b3d6663SArnd Bergmann spu_acquire_saved(ctx); 2838b3d6663SArnd Bergmann 2848b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 2858b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 2868b3d6663SArnd Bergmann 2878b3d6663SArnd Bergmann spu_release(ctx); 2888b3d6663SArnd Bergmann return ret; 2898b3d6663SArnd Bergmann } 2908b3d6663SArnd Bergmann 2918b3d6663SArnd Bergmann static struct file_operations spufs_regs_fops = { 2928b3d6663SArnd Bergmann .open = spufs_regs_open, 2938b3d6663SArnd Bergmann .read = spufs_regs_read, 2948b3d6663SArnd Bergmann .write = spufs_regs_write, 2958b3d6663SArnd Bergmann .llseek = generic_file_llseek, 2968b3d6663SArnd Bergmann }; 2978b3d6663SArnd Bergmann 2988b3d6663SArnd Bergmann static ssize_t 2998b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 3008b3d6663SArnd Bergmann size_t size, loff_t * pos) 3018b3d6663SArnd Bergmann { 3028b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3038b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 3048b3d6663SArnd Bergmann int ret; 3058b3d6663SArnd Bergmann 3068b3d6663SArnd Bergmann spu_acquire_saved(ctx); 3078b3d6663SArnd Bergmann 3088b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 3098b3d6663SArnd Bergmann &lscsa->fpcr, sizeof(lscsa->fpcr)); 3108b3d6663SArnd Bergmann 3118b3d6663SArnd Bergmann spu_release(ctx); 3128b3d6663SArnd Bergmann return ret; 3138b3d6663SArnd Bergmann } 3148b3d6663SArnd Bergmann 3158b3d6663SArnd Bergmann static ssize_t 3168b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 3178b3d6663SArnd Bergmann size_t size, loff_t * pos) 3188b3d6663SArnd Bergmann { 3198b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3208b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 3218b3d6663SArnd Bergmann int ret; 3228b3d6663SArnd Bergmann 3238b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 3248b3d6663SArnd Bergmann if (size <= 0) 3258b3d6663SArnd Bergmann return -EFBIG; 3268b3d6663SArnd Bergmann *pos += size; 3278b3d6663SArnd Bergmann 3288b3d6663SArnd Bergmann spu_acquire_saved(ctx); 3298b3d6663SArnd Bergmann 3308b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 3318b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 3328b3d6663SArnd Bergmann 3338b3d6663SArnd Bergmann spu_release(ctx); 3348b3d6663SArnd Bergmann return ret; 3358b3d6663SArnd Bergmann } 3368b3d6663SArnd Bergmann 3378b3d6663SArnd Bergmann static struct file_operations spufs_fpcr_fops = { 3388b3d6663SArnd Bergmann .open = spufs_regs_open, 3398b3d6663SArnd Bergmann .read = spufs_fpcr_read, 3408b3d6663SArnd Bergmann .write = spufs_fpcr_write, 34167207b96SArnd Bergmann .llseek = generic_file_llseek, 34267207b96SArnd Bergmann }; 34367207b96SArnd Bergmann 34467207b96SArnd Bergmann /* generic open function for all pipe-like files */ 34567207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 34667207b96SArnd Bergmann { 34767207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 34867207b96SArnd Bergmann file->private_data = i->i_ctx; 34967207b96SArnd Bergmann 35067207b96SArnd Bergmann return nonseekable_open(inode, file); 35167207b96SArnd Bergmann } 35267207b96SArnd Bergmann 35367207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 35467207b96SArnd Bergmann size_t len, loff_t *pos) 35567207b96SArnd Bergmann { 3568b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 35767207b96SArnd Bergmann u32 mbox_data; 3588b3d6663SArnd Bergmann int ret; 35967207b96SArnd Bergmann 36067207b96SArnd Bergmann if (len < 4) 36167207b96SArnd Bergmann return -EINVAL; 36267207b96SArnd Bergmann 3638b3d6663SArnd Bergmann spu_acquire(ctx); 3648b3d6663SArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 3658b3d6663SArnd Bergmann spu_release(ctx); 36667207b96SArnd Bergmann 3678b3d6663SArnd Bergmann if (!ret) 3688b3d6663SArnd Bergmann return -EAGAIN; 36967207b96SArnd Bergmann 37067207b96SArnd Bergmann if (copy_to_user(buf, &mbox_data, sizeof mbox_data)) 37167207b96SArnd Bergmann return -EFAULT; 37267207b96SArnd Bergmann 37367207b96SArnd Bergmann return 4; 37467207b96SArnd Bergmann } 37567207b96SArnd Bergmann 37667207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = { 37767207b96SArnd Bergmann .open = spufs_pipe_open, 37867207b96SArnd Bergmann .read = spufs_mbox_read, 37967207b96SArnd Bergmann }; 38067207b96SArnd Bergmann 38167207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 38267207b96SArnd Bergmann size_t len, loff_t *pos) 38367207b96SArnd Bergmann { 3848b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 38567207b96SArnd Bergmann u32 mbox_stat; 38667207b96SArnd Bergmann 38767207b96SArnd Bergmann if (len < 4) 38867207b96SArnd Bergmann return -EINVAL; 38967207b96SArnd Bergmann 3908b3d6663SArnd Bergmann spu_acquire(ctx); 3918b3d6663SArnd Bergmann 3928b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 3938b3d6663SArnd Bergmann 3948b3d6663SArnd Bergmann spu_release(ctx); 39567207b96SArnd Bergmann 39667207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 39767207b96SArnd Bergmann return -EFAULT; 39867207b96SArnd Bergmann 39967207b96SArnd Bergmann return 4; 40067207b96SArnd Bergmann } 40167207b96SArnd Bergmann 40267207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = { 40367207b96SArnd Bergmann .open = spufs_pipe_open, 40467207b96SArnd Bergmann .read = spufs_mbox_stat_read, 40567207b96SArnd Bergmann }; 40667207b96SArnd Bergmann 40767207b96SArnd Bergmann /* low-level ibox access function */ 4088b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 40967207b96SArnd Bergmann { 4108b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 41167207b96SArnd Bergmann } 41267207b96SArnd Bergmann 41367207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 41467207b96SArnd Bergmann { 4158b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 4168b3d6663SArnd Bergmann 4178b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 4188b3d6663SArnd Bergmann } 4198b3d6663SArnd Bergmann 4208b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 4218b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 4228b3d6663SArnd Bergmann { 4238b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 4248b3d6663SArnd Bergmann 4258b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 4268b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 42767207b96SArnd Bergmann } 42867207b96SArnd Bergmann 42967207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 43067207b96SArnd Bergmann size_t len, loff_t *pos) 43167207b96SArnd Bergmann { 4328b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 43367207b96SArnd Bergmann u32 ibox_data; 43467207b96SArnd Bergmann ssize_t ret; 43567207b96SArnd Bergmann 43667207b96SArnd Bergmann if (len < 4) 43767207b96SArnd Bergmann return -EINVAL; 43867207b96SArnd Bergmann 4398b3d6663SArnd Bergmann spu_acquire(ctx); 44067207b96SArnd Bergmann 44167207b96SArnd Bergmann ret = 0; 44267207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 4438b3d6663SArnd Bergmann if (!spu_ibox_read(ctx, &ibox_data)) 44467207b96SArnd Bergmann ret = -EAGAIN; 44567207b96SArnd Bergmann } else { 4468b3d6663SArnd Bergmann ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 44767207b96SArnd Bergmann } 44867207b96SArnd Bergmann 4498b3d6663SArnd Bergmann spu_release(ctx); 4508b3d6663SArnd Bergmann 45167207b96SArnd Bergmann if (ret) 45267207b96SArnd Bergmann return ret; 45367207b96SArnd Bergmann 45467207b96SArnd Bergmann ret = 4; 45567207b96SArnd Bergmann if (copy_to_user(buf, &ibox_data, sizeof ibox_data)) 45667207b96SArnd Bergmann ret = -EFAULT; 45767207b96SArnd Bergmann 45867207b96SArnd Bergmann return ret; 45967207b96SArnd Bergmann } 46067207b96SArnd Bergmann 46167207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 46267207b96SArnd Bergmann { 4638b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 46467207b96SArnd Bergmann unsigned int mask; 46567207b96SArnd Bergmann 4668b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 46767207b96SArnd Bergmann 4683a843d7cSArnd Bergmann spu_acquire(ctx); 4693a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 4703a843d7cSArnd Bergmann spu_release(ctx); 47167207b96SArnd Bergmann 47267207b96SArnd Bergmann return mask; 47367207b96SArnd Bergmann } 47467207b96SArnd Bergmann 47567207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = { 47667207b96SArnd Bergmann .open = spufs_pipe_open, 47767207b96SArnd Bergmann .read = spufs_ibox_read, 47867207b96SArnd Bergmann .poll = spufs_ibox_poll, 47967207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 48067207b96SArnd Bergmann }; 48167207b96SArnd Bergmann 48267207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 48367207b96SArnd Bergmann size_t len, loff_t *pos) 48467207b96SArnd Bergmann { 4858b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 48667207b96SArnd Bergmann u32 ibox_stat; 48767207b96SArnd Bergmann 48867207b96SArnd Bergmann if (len < 4) 48967207b96SArnd Bergmann return -EINVAL; 49067207b96SArnd Bergmann 4918b3d6663SArnd Bergmann spu_acquire(ctx); 4928b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 4938b3d6663SArnd Bergmann spu_release(ctx); 49467207b96SArnd Bergmann 49567207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 49667207b96SArnd Bergmann return -EFAULT; 49767207b96SArnd Bergmann 49867207b96SArnd Bergmann return 4; 49967207b96SArnd Bergmann } 50067207b96SArnd Bergmann 50167207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = { 50267207b96SArnd Bergmann .open = spufs_pipe_open, 50367207b96SArnd Bergmann .read = spufs_ibox_stat_read, 50467207b96SArnd Bergmann }; 50567207b96SArnd Bergmann 50667207b96SArnd Bergmann /* low-level mailbox write */ 5078b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 50867207b96SArnd Bergmann { 5098b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 51067207b96SArnd Bergmann } 51167207b96SArnd Bergmann 51267207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 51367207b96SArnd Bergmann { 5148b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5158b3d6663SArnd Bergmann int ret; 5168b3d6663SArnd Bergmann 5178b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 5188b3d6663SArnd Bergmann 5198b3d6663SArnd Bergmann return ret; 5208b3d6663SArnd Bergmann } 5218b3d6663SArnd Bergmann 5228b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 5238b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 5248b3d6663SArnd Bergmann { 5258b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 5268b3d6663SArnd Bergmann 5278b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 5288b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 52967207b96SArnd Bergmann } 53067207b96SArnd Bergmann 53167207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 53267207b96SArnd Bergmann size_t len, loff_t *pos) 53367207b96SArnd Bergmann { 5348b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 53567207b96SArnd Bergmann u32 wbox_data; 53667207b96SArnd Bergmann int ret; 53767207b96SArnd Bergmann 53867207b96SArnd Bergmann if (len < 4) 53967207b96SArnd Bergmann return -EINVAL; 54067207b96SArnd Bergmann 54167207b96SArnd Bergmann if (copy_from_user(&wbox_data, buf, sizeof wbox_data)) 54267207b96SArnd Bergmann return -EFAULT; 54367207b96SArnd Bergmann 5448b3d6663SArnd Bergmann spu_acquire(ctx); 5458b3d6663SArnd Bergmann 54667207b96SArnd Bergmann ret = 0; 54767207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 5488b3d6663SArnd Bergmann if (!spu_wbox_write(ctx, wbox_data)) 54967207b96SArnd Bergmann ret = -EAGAIN; 55067207b96SArnd Bergmann } else { 5518b3d6663SArnd Bergmann ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 55267207b96SArnd Bergmann } 55367207b96SArnd Bergmann 5548b3d6663SArnd Bergmann spu_release(ctx); 5558b3d6663SArnd Bergmann 55667207b96SArnd Bergmann return ret ? ret : sizeof wbox_data; 55767207b96SArnd Bergmann } 55867207b96SArnd Bergmann 55967207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 56067207b96SArnd Bergmann { 5618b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 56267207b96SArnd Bergmann unsigned int mask; 56367207b96SArnd Bergmann 5648b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 56567207b96SArnd Bergmann 5663a843d7cSArnd Bergmann spu_acquire(ctx); 5673a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 5683a843d7cSArnd Bergmann spu_release(ctx); 56967207b96SArnd Bergmann 57067207b96SArnd Bergmann return mask; 57167207b96SArnd Bergmann } 57267207b96SArnd Bergmann 57367207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = { 57467207b96SArnd Bergmann .open = spufs_pipe_open, 57567207b96SArnd Bergmann .write = spufs_wbox_write, 57667207b96SArnd Bergmann .poll = spufs_wbox_poll, 57767207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 57867207b96SArnd Bergmann }; 57967207b96SArnd Bergmann 58067207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 58167207b96SArnd Bergmann size_t len, loff_t *pos) 58267207b96SArnd Bergmann { 5838b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 58467207b96SArnd Bergmann u32 wbox_stat; 58567207b96SArnd Bergmann 58667207b96SArnd Bergmann if (len < 4) 58767207b96SArnd Bergmann return -EINVAL; 58867207b96SArnd Bergmann 5898b3d6663SArnd Bergmann spu_acquire(ctx); 5908b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 5918b3d6663SArnd Bergmann spu_release(ctx); 59267207b96SArnd Bergmann 59367207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 59467207b96SArnd Bergmann return -EFAULT; 59567207b96SArnd Bergmann 59667207b96SArnd Bergmann return 4; 59767207b96SArnd Bergmann } 59867207b96SArnd Bergmann 59967207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = { 60067207b96SArnd Bergmann .open = spufs_pipe_open, 60167207b96SArnd Bergmann .read = spufs_wbox_stat_read, 60267207b96SArnd Bergmann }; 60367207b96SArnd Bergmann 6046df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 6056df10a82SMark Nutter { 6066df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 6076df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 6086df10a82SMark Nutter file->private_data = ctx; 6096df10a82SMark Nutter file->f_mapping = inode->i_mapping; 6106df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 6116df10a82SMark Nutter return nonseekable_open(inode, file); 6126df10a82SMark Nutter } 6136df10a82SMark Nutter 61467207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 61567207b96SArnd Bergmann size_t len, loff_t *pos) 61667207b96SArnd Bergmann { 6178b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 61867207b96SArnd Bergmann u32 data; 61967207b96SArnd Bergmann 62067207b96SArnd Bergmann if (len < 4) 62167207b96SArnd Bergmann return -EINVAL; 62267207b96SArnd Bergmann 6238b3d6663SArnd Bergmann spu_acquire(ctx); 6248b3d6663SArnd Bergmann data = ctx->ops->signal1_read(ctx); 6258b3d6663SArnd Bergmann spu_release(ctx); 6268b3d6663SArnd Bergmann 62767207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 62867207b96SArnd Bergmann return -EFAULT; 62967207b96SArnd Bergmann 63067207b96SArnd Bergmann return 4; 63167207b96SArnd Bergmann } 63267207b96SArnd Bergmann 63367207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 63467207b96SArnd Bergmann size_t len, loff_t *pos) 63567207b96SArnd Bergmann { 63667207b96SArnd Bergmann struct spu_context *ctx; 63767207b96SArnd Bergmann u32 data; 63867207b96SArnd Bergmann 63967207b96SArnd Bergmann ctx = file->private_data; 64067207b96SArnd Bergmann 64167207b96SArnd Bergmann if (len < 4) 64267207b96SArnd Bergmann return -EINVAL; 64367207b96SArnd Bergmann 64467207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 64567207b96SArnd Bergmann return -EFAULT; 64667207b96SArnd Bergmann 6478b3d6663SArnd Bergmann spu_acquire(ctx); 6488b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 6498b3d6663SArnd Bergmann spu_release(ctx); 65067207b96SArnd Bergmann 65167207b96SArnd Bergmann return 4; 65267207b96SArnd Bergmann } 65367207b96SArnd Bergmann 6546df10a82SMark Nutter static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, 6556df10a82SMark Nutter unsigned long address, int *type) 6566df10a82SMark Nutter { 65727d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 65827d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000); 65927d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 66027d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 66127d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 66227d5bf2aSBenjamin Herrenschmidt */ 66327d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); 66427d5bf2aSBenjamin Herrenschmidt #else 66527d5bf2aSBenjamin Herrenschmidt #error unsupported page size 66627d5bf2aSBenjamin Herrenschmidt #endif 6676df10a82SMark Nutter } 6686df10a82SMark Nutter 6696df10a82SMark Nutter static struct vm_operations_struct spufs_signal1_mmap_vmops = { 6706df10a82SMark Nutter .nopage = spufs_signal1_mmap_nopage, 6716df10a82SMark Nutter }; 6726df10a82SMark Nutter 6736df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 6746df10a82SMark Nutter { 6756df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 6766df10a82SMark Nutter return -EINVAL; 6776df10a82SMark Nutter 6786df10a82SMark Nutter vma->vm_flags |= VM_RESERVED; 6796df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 68023cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 6816df10a82SMark Nutter 6826df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 6836df10a82SMark Nutter return 0; 6846df10a82SMark Nutter } 6856df10a82SMark Nutter 68667207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = { 6876df10a82SMark Nutter .open = spufs_signal1_open, 68867207b96SArnd Bergmann .read = spufs_signal1_read, 68967207b96SArnd Bergmann .write = spufs_signal1_write, 6906df10a82SMark Nutter .mmap = spufs_signal1_mmap, 69167207b96SArnd Bergmann }; 69267207b96SArnd Bergmann 6936df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 6946df10a82SMark Nutter { 6956df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 6966df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 6976df10a82SMark Nutter file->private_data = ctx; 6986df10a82SMark Nutter file->f_mapping = inode->i_mapping; 6996df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 7006df10a82SMark Nutter return nonseekable_open(inode, file); 7016df10a82SMark Nutter } 7026df10a82SMark Nutter 70367207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 70467207b96SArnd Bergmann size_t len, loff_t *pos) 70567207b96SArnd Bergmann { 70667207b96SArnd Bergmann struct spu_context *ctx; 70767207b96SArnd Bergmann u32 data; 70867207b96SArnd Bergmann 70967207b96SArnd Bergmann ctx = file->private_data; 71067207b96SArnd Bergmann 71167207b96SArnd Bergmann if (len < 4) 71267207b96SArnd Bergmann return -EINVAL; 71367207b96SArnd Bergmann 7148b3d6663SArnd Bergmann spu_acquire(ctx); 7158b3d6663SArnd Bergmann data = ctx->ops->signal2_read(ctx); 7168b3d6663SArnd Bergmann spu_release(ctx); 7178b3d6663SArnd Bergmann 71867207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 71967207b96SArnd Bergmann return -EFAULT; 72067207b96SArnd Bergmann 72167207b96SArnd Bergmann return 4; 72267207b96SArnd Bergmann } 72367207b96SArnd Bergmann 72467207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 72567207b96SArnd Bergmann size_t len, loff_t *pos) 72667207b96SArnd Bergmann { 72767207b96SArnd Bergmann struct spu_context *ctx; 72867207b96SArnd Bergmann u32 data; 72967207b96SArnd Bergmann 73067207b96SArnd Bergmann ctx = file->private_data; 73167207b96SArnd Bergmann 73267207b96SArnd Bergmann if (len < 4) 73367207b96SArnd Bergmann return -EINVAL; 73467207b96SArnd Bergmann 73567207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 73667207b96SArnd Bergmann return -EFAULT; 73767207b96SArnd Bergmann 7388b3d6663SArnd Bergmann spu_acquire(ctx); 7398b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 7408b3d6663SArnd Bergmann spu_release(ctx); 74167207b96SArnd Bergmann 74267207b96SArnd Bergmann return 4; 74367207b96SArnd Bergmann } 74467207b96SArnd Bergmann 74527d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 7466df10a82SMark Nutter static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, 7476df10a82SMark Nutter unsigned long address, int *type) 7486df10a82SMark Nutter { 74927d5bf2aSBenjamin Herrenschmidt #if PAGE_SIZE == 0x1000 75027d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000); 75127d5bf2aSBenjamin Herrenschmidt #elif PAGE_SIZE == 0x10000 75227d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 75327d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 75427d5bf2aSBenjamin Herrenschmidt */ 75527d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); 75627d5bf2aSBenjamin Herrenschmidt #else 75727d5bf2aSBenjamin Herrenschmidt #error unsupported page size 75827d5bf2aSBenjamin Herrenschmidt #endif 7596df10a82SMark Nutter } 7606df10a82SMark Nutter 7616df10a82SMark Nutter static struct vm_operations_struct spufs_signal2_mmap_vmops = { 7626df10a82SMark Nutter .nopage = spufs_signal2_mmap_nopage, 7636df10a82SMark Nutter }; 7646df10a82SMark Nutter 7656df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 7666df10a82SMark Nutter { 7676df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 7686df10a82SMark Nutter return -EINVAL; 7696df10a82SMark Nutter 7706df10a82SMark Nutter /* FIXME: */ 7716df10a82SMark Nutter vma->vm_flags |= VM_RESERVED; 7726df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 77323cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 7746df10a82SMark Nutter 7756df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 7766df10a82SMark Nutter return 0; 7776df10a82SMark Nutter } 77827d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 77927d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 78027d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 7816df10a82SMark Nutter 78267207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = { 7836df10a82SMark Nutter .open = spufs_signal2_open, 78467207b96SArnd Bergmann .read = spufs_signal2_read, 78567207b96SArnd Bergmann .write = spufs_signal2_write, 7866df10a82SMark Nutter .mmap = spufs_signal2_mmap, 78767207b96SArnd Bergmann }; 78867207b96SArnd Bergmann 78967207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val) 79067207b96SArnd Bergmann { 79167207b96SArnd Bergmann struct spu_context *ctx = data; 79267207b96SArnd Bergmann 7938b3d6663SArnd Bergmann spu_acquire(ctx); 7948b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 7958b3d6663SArnd Bergmann spu_release(ctx); 79667207b96SArnd Bergmann } 79767207b96SArnd Bergmann 79867207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data) 79967207b96SArnd Bergmann { 80067207b96SArnd Bergmann struct spu_context *ctx = data; 8018b3d6663SArnd Bergmann u64 ret; 8028b3d6663SArnd Bergmann 8038b3d6663SArnd Bergmann spu_acquire(ctx); 8048b3d6663SArnd Bergmann ret = ctx->ops->signal1_type_get(ctx); 8058b3d6663SArnd Bergmann spu_release(ctx); 8068b3d6663SArnd Bergmann 8078b3d6663SArnd Bergmann return ret; 80867207b96SArnd Bergmann } 80967207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 81067207b96SArnd Bergmann spufs_signal1_type_set, "%llu"); 81167207b96SArnd Bergmann 81267207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val) 81367207b96SArnd Bergmann { 81467207b96SArnd Bergmann struct spu_context *ctx = data; 81567207b96SArnd Bergmann 8168b3d6663SArnd Bergmann spu_acquire(ctx); 8178b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 8188b3d6663SArnd Bergmann spu_release(ctx); 81967207b96SArnd Bergmann } 82067207b96SArnd Bergmann 82167207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data) 82267207b96SArnd Bergmann { 82367207b96SArnd Bergmann struct spu_context *ctx = data; 8248b3d6663SArnd Bergmann u64 ret; 8258b3d6663SArnd Bergmann 8268b3d6663SArnd Bergmann spu_acquire(ctx); 8278b3d6663SArnd Bergmann ret = ctx->ops->signal2_type_get(ctx); 8288b3d6663SArnd Bergmann spu_release(ctx); 8298b3d6663SArnd Bergmann 8308b3d6663SArnd Bergmann return ret; 83167207b96SArnd Bergmann } 83267207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 83367207b96SArnd Bergmann spufs_signal2_type_set, "%llu"); 83467207b96SArnd Bergmann 83527d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 836d9379c4bSarnd@arndb.de static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, 837d9379c4bSarnd@arndb.de unsigned long address, int *type) 838d9379c4bSarnd@arndb.de { 83927d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000); 840d9379c4bSarnd@arndb.de } 841d9379c4bSarnd@arndb.de 842d9379c4bSarnd@arndb.de static struct vm_operations_struct spufs_mss_mmap_vmops = { 843d9379c4bSarnd@arndb.de .nopage = spufs_mss_mmap_nopage, 844d9379c4bSarnd@arndb.de }; 845d9379c4bSarnd@arndb.de 846d9379c4bSarnd@arndb.de /* 847d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 848d9379c4bSarnd@arndb.de */ 849d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 850d9379c4bSarnd@arndb.de { 851d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 852d9379c4bSarnd@arndb.de return -EINVAL; 853d9379c4bSarnd@arndb.de 854d9379c4bSarnd@arndb.de vma->vm_flags |= VM_RESERVED; 855d9379c4bSarnd@arndb.de vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 85623cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 857d9379c4bSarnd@arndb.de 858d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 859d9379c4bSarnd@arndb.de return 0; 860d9379c4bSarnd@arndb.de } 86127d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 86227d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 86327d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 864d9379c4bSarnd@arndb.de 865d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 866d9379c4bSarnd@arndb.de { 867d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 868d9379c4bSarnd@arndb.de 869d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 870d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 871d9379c4bSarnd@arndb.de } 872d9379c4bSarnd@arndb.de 873d9379c4bSarnd@arndb.de static struct file_operations spufs_mss_fops = { 874d9379c4bSarnd@arndb.de .open = spufs_mss_open, 875d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 87627d5bf2aSBenjamin Herrenschmidt }; 87727d5bf2aSBenjamin Herrenschmidt 87827d5bf2aSBenjamin Herrenschmidt static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma, 87927d5bf2aSBenjamin Herrenschmidt unsigned long address, int *type) 88027d5bf2aSBenjamin Herrenschmidt { 88127d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000); 88227d5bf2aSBenjamin Herrenschmidt } 88327d5bf2aSBenjamin Herrenschmidt 88427d5bf2aSBenjamin Herrenschmidt static struct vm_operations_struct spufs_psmap_mmap_vmops = { 88527d5bf2aSBenjamin Herrenschmidt .nopage = spufs_psmap_mmap_nopage, 88627d5bf2aSBenjamin Herrenschmidt }; 88727d5bf2aSBenjamin Herrenschmidt 88827d5bf2aSBenjamin Herrenschmidt /* 88927d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 89027d5bf2aSBenjamin Herrenschmidt */ 89127d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 89227d5bf2aSBenjamin Herrenschmidt { 89327d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 89427d5bf2aSBenjamin Herrenschmidt return -EINVAL; 89527d5bf2aSBenjamin Herrenschmidt 89627d5bf2aSBenjamin Herrenschmidt vma->vm_flags |= VM_RESERVED; 89727d5bf2aSBenjamin Herrenschmidt vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 89827d5bf2aSBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 89927d5bf2aSBenjamin Herrenschmidt 90027d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 90127d5bf2aSBenjamin Herrenschmidt return 0; 90227d5bf2aSBenjamin Herrenschmidt } 90327d5bf2aSBenjamin Herrenschmidt 90427d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 90527d5bf2aSBenjamin Herrenschmidt { 90627d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 90727d5bf2aSBenjamin Herrenschmidt 90827d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 90927d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 91027d5bf2aSBenjamin Herrenschmidt } 91127d5bf2aSBenjamin Herrenschmidt 91227d5bf2aSBenjamin Herrenschmidt static struct file_operations spufs_psmap_fops = { 91327d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 91427d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 915d9379c4bSarnd@arndb.de }; 916d9379c4bSarnd@arndb.de 917d9379c4bSarnd@arndb.de 91827d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 9196df10a82SMark Nutter static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, 9206df10a82SMark Nutter unsigned long address, int *type) 9216df10a82SMark Nutter { 92227d5bf2aSBenjamin Herrenschmidt return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000); 9236df10a82SMark Nutter } 9246df10a82SMark Nutter 9256df10a82SMark Nutter static struct vm_operations_struct spufs_mfc_mmap_vmops = { 9266df10a82SMark Nutter .nopage = spufs_mfc_mmap_nopage, 9276df10a82SMark Nutter }; 9286df10a82SMark Nutter 9296df10a82SMark Nutter /* 9306df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 9316df10a82SMark Nutter */ 9326df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 9336df10a82SMark Nutter { 9346df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 9356df10a82SMark Nutter return -EINVAL; 9366df10a82SMark Nutter 9376df10a82SMark Nutter vma->vm_flags |= VM_RESERVED; 9386df10a82SMark Nutter vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 93923cc7701SBenjamin Herrenschmidt | _PAGE_NO_CACHE | _PAGE_GUARDED); 9406df10a82SMark Nutter 9416df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 9426df10a82SMark Nutter return 0; 9436df10a82SMark Nutter } 94427d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 94527d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 94627d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 947a33a7d73SArnd Bergmann 948a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 949a33a7d73SArnd Bergmann { 950a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 951a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 952a33a7d73SArnd Bergmann 953a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 954a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 955a33a7d73SArnd Bergmann return -EINVAL; 956a33a7d73SArnd Bergmann 957a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 958a33a7d73SArnd Bergmann return -EBUSY; 959a33a7d73SArnd Bergmann 960a33a7d73SArnd Bergmann file->private_data = ctx; 961a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 962a33a7d73SArnd Bergmann } 963a33a7d73SArnd Bergmann 964a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 965a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 966a33a7d73SArnd Bergmann { 967a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 968a33a7d73SArnd Bergmann 969a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 970a33a7d73SArnd Bergmann 971a33a7d73SArnd Bergmann pr_debug("%s %s\n", __FUNCTION__, spu->name); 972a33a7d73SArnd Bergmann if (ctx->mfc_fasync) { 973a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 974a33a7d73SArnd Bergmann unsigned int mask; 975a33a7d73SArnd Bergmann 976a33a7d73SArnd Bergmann /* no need for spu_acquire in interrupt context */ 977a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 978a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 979a33a7d73SArnd Bergmann 980a33a7d73SArnd Bergmann mask = 0; 981a33a7d73SArnd Bergmann if (free_elements & 0xffff) 982a33a7d73SArnd Bergmann mask |= POLLOUT; 983a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 984a33a7d73SArnd Bergmann mask |= POLLIN; 985a33a7d73SArnd Bergmann 986a33a7d73SArnd Bergmann kill_fasync(&ctx->mfc_fasync, SIGIO, mask); 987a33a7d73SArnd Bergmann } 988a33a7d73SArnd Bergmann } 989a33a7d73SArnd Bergmann 990a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 991a33a7d73SArnd Bergmann { 992a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 993a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 994a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 995a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 996a33a7d73SArnd Bergmann if (*status) 997a33a7d73SArnd Bergmann return 1; 998a33a7d73SArnd Bergmann 999a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1000a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1001a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1002a33a7d73SArnd Bergmann return 0; 1003a33a7d73SArnd Bergmann } 1004a33a7d73SArnd Bergmann 1005a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1006a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1007a33a7d73SArnd Bergmann { 1008a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1009a33a7d73SArnd Bergmann int ret = -EINVAL; 1010a33a7d73SArnd Bergmann u32 status; 1011a33a7d73SArnd Bergmann 1012a33a7d73SArnd Bergmann if (size != 4) 1013a33a7d73SArnd Bergmann goto out; 1014a33a7d73SArnd Bergmann 1015a33a7d73SArnd Bergmann spu_acquire(ctx); 1016a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1017a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1018a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1019a33a7d73SArnd Bergmann ret = -EAGAIN; 1020a33a7d73SArnd Bergmann else 1021a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1022a33a7d73SArnd Bergmann } else { 1023a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1024a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1025a33a7d73SArnd Bergmann } 1026a33a7d73SArnd Bergmann spu_release(ctx); 1027a33a7d73SArnd Bergmann 1028a33a7d73SArnd Bergmann if (ret) 1029a33a7d73SArnd Bergmann goto out; 1030a33a7d73SArnd Bergmann 1031a33a7d73SArnd Bergmann ret = 4; 1032a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1033a33a7d73SArnd Bergmann ret = -EFAULT; 1034a33a7d73SArnd Bergmann 1035a33a7d73SArnd Bergmann out: 1036a33a7d73SArnd Bergmann return ret; 1037a33a7d73SArnd Bergmann } 1038a33a7d73SArnd Bergmann 1039a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1040a33a7d73SArnd Bergmann { 1041a33a7d73SArnd Bergmann pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, 1042a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1043a33a7d73SArnd Bergmann 1044a33a7d73SArnd Bergmann switch (cmd->cmd) { 1045a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1046a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1047a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1048a33a7d73SArnd Bergmann case MFC_GET_CMD: 1049a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1050a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1051a33a7d73SArnd Bergmann break; 1052a33a7d73SArnd Bergmann default: 1053a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1054a33a7d73SArnd Bergmann return -EIO; 1055a33a7d73SArnd Bergmann } 1056a33a7d73SArnd Bergmann 1057a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 1058a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment, ea %lx lsa %x\n", 1059a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1060a33a7d73SArnd Bergmann return -EIO; 1061a33a7d73SArnd Bergmann } 1062a33a7d73SArnd Bergmann 1063a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1064a33a7d73SArnd Bergmann case 1: 1065a33a7d73SArnd Bergmann break; 1066a33a7d73SArnd Bergmann case 2: 1067a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1068a33a7d73SArnd Bergmann goto error; 1069a33a7d73SArnd Bergmann break; 1070a33a7d73SArnd Bergmann case 4: 1071a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1072a33a7d73SArnd Bergmann goto error; 1073a33a7d73SArnd Bergmann break; 1074a33a7d73SArnd Bergmann case 8: 1075a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1076a33a7d73SArnd Bergmann goto error; 1077a33a7d73SArnd Bergmann break; 1078a33a7d73SArnd Bergmann case 0: 1079a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1080a33a7d73SArnd Bergmann goto error; 1081a33a7d73SArnd Bergmann break; 1082a33a7d73SArnd Bergmann error: 1083a33a7d73SArnd Bergmann default: 1084a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1085a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1086a33a7d73SArnd Bergmann return -EIO; 1087a33a7d73SArnd Bergmann } 1088a33a7d73SArnd Bergmann 1089a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1090a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1091a33a7d73SArnd Bergmann return -EIO; 1092a33a7d73SArnd Bergmann } 1093a33a7d73SArnd Bergmann 1094a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1095a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1096a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1097a33a7d73SArnd Bergmann return -EIO; 1098a33a7d73SArnd Bergmann } 1099a33a7d73SArnd Bergmann 1100a33a7d73SArnd Bergmann if (cmd->class) { 1101a33a7d73SArnd Bergmann /* not supported in this version */ 1102a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1103a33a7d73SArnd Bergmann return -EIO; 1104a33a7d73SArnd Bergmann } 1105a33a7d73SArnd Bergmann 1106a33a7d73SArnd Bergmann return 0; 1107a33a7d73SArnd Bergmann } 1108a33a7d73SArnd Bergmann 1109a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1110a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1111a33a7d73SArnd Bergmann int *error) 1112a33a7d73SArnd Bergmann { 1113a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1114a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1115a33a7d73SArnd Bergmann /* wait for any tag group to complete 1116a33a7d73SArnd Bergmann so we have space for the new command */ 1117a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1118a33a7d73SArnd Bergmann /* try again, because the queue might be 1119a33a7d73SArnd Bergmann empty again */ 1120a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1121a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1122a33a7d73SArnd Bergmann return 0; 1123a33a7d73SArnd Bergmann } 1124a33a7d73SArnd Bergmann return 1; 1125a33a7d73SArnd Bergmann } 1126a33a7d73SArnd Bergmann 1127a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1128a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1129a33a7d73SArnd Bergmann { 1130a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1131a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1132a33a7d73SArnd Bergmann int ret = -EINVAL; 1133a33a7d73SArnd Bergmann 1134a33a7d73SArnd Bergmann if (size != sizeof cmd) 1135a33a7d73SArnd Bergmann goto out; 1136a33a7d73SArnd Bergmann 1137a33a7d73SArnd Bergmann ret = -EFAULT; 1138a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1139a33a7d73SArnd Bergmann goto out; 1140a33a7d73SArnd Bergmann 1141a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1142a33a7d73SArnd Bergmann if (ret) 1143a33a7d73SArnd Bergmann goto out; 1144a33a7d73SArnd Bergmann 1145a33a7d73SArnd Bergmann spu_acquire_runnable(ctx); 1146a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1147a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1148a33a7d73SArnd Bergmann } else { 1149a33a7d73SArnd Bergmann int status; 1150a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1151a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1152a33a7d73SArnd Bergmann if (status) 1153a33a7d73SArnd Bergmann ret = status; 1154a33a7d73SArnd Bergmann } 1155a33a7d73SArnd Bergmann spu_release(ctx); 1156a33a7d73SArnd Bergmann 1157a33a7d73SArnd Bergmann if (ret) 1158a33a7d73SArnd Bergmann goto out; 1159a33a7d73SArnd Bergmann 1160a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 1161a33a7d73SArnd Bergmann 1162a33a7d73SArnd Bergmann out: 1163a33a7d73SArnd Bergmann return ret; 1164a33a7d73SArnd Bergmann } 1165a33a7d73SArnd Bergmann 1166a33a7d73SArnd Bergmann static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) 1167a33a7d73SArnd Bergmann { 1168a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1169a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 1170a33a7d73SArnd Bergmann unsigned int mask; 1171a33a7d73SArnd Bergmann 1172a33a7d73SArnd Bergmann spu_acquire(ctx); 1173a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1174a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1175a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1176a33a7d73SArnd Bergmann spu_release(ctx); 1177a33a7d73SArnd Bergmann 1178a33a7d73SArnd Bergmann poll_wait(file, &ctx->mfc_wq, wait); 1179a33a7d73SArnd Bergmann 1180a33a7d73SArnd Bergmann mask = 0; 1181a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1182a33a7d73SArnd Bergmann mask |= POLLOUT | POLLWRNORM; 1183a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1184a33a7d73SArnd Bergmann mask |= POLLIN | POLLRDNORM; 1185a33a7d73SArnd Bergmann 1186a33a7d73SArnd Bergmann pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, 1187a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1188a33a7d73SArnd Bergmann 1189a33a7d73SArnd Bergmann return mask; 1190a33a7d73SArnd Bergmann } 1191a33a7d73SArnd Bergmann 119273b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1193a33a7d73SArnd Bergmann { 1194a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1195a33a7d73SArnd Bergmann int ret; 1196a33a7d73SArnd Bergmann 1197a33a7d73SArnd Bergmann spu_acquire(ctx); 1198a33a7d73SArnd Bergmann #if 0 1199a33a7d73SArnd Bergmann /* this currently hangs */ 1200a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1201a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1202a33a7d73SArnd Bergmann if (ret) 1203a33a7d73SArnd Bergmann goto out; 1204a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1205a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1206a33a7d73SArnd Bergmann out: 1207a33a7d73SArnd Bergmann #else 1208a33a7d73SArnd Bergmann ret = 0; 1209a33a7d73SArnd Bergmann #endif 1210a33a7d73SArnd Bergmann spu_release(ctx); 1211a33a7d73SArnd Bergmann 1212a33a7d73SArnd Bergmann return ret; 1213a33a7d73SArnd Bergmann } 1214a33a7d73SArnd Bergmann 1215a33a7d73SArnd Bergmann static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, 1216a33a7d73SArnd Bergmann int datasync) 1217a33a7d73SArnd Bergmann { 121873b6af8aSAl Viro return spufs_mfc_flush(file, NULL); 1219a33a7d73SArnd Bergmann } 1220a33a7d73SArnd Bergmann 1221a33a7d73SArnd Bergmann static int spufs_mfc_fasync(int fd, struct file *file, int on) 1222a33a7d73SArnd Bergmann { 1223a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1224a33a7d73SArnd Bergmann 1225a33a7d73SArnd Bergmann return fasync_helper(fd, file, on, &ctx->mfc_fasync); 1226a33a7d73SArnd Bergmann } 1227a33a7d73SArnd Bergmann 1228a33a7d73SArnd Bergmann static struct file_operations spufs_mfc_fops = { 1229a33a7d73SArnd Bergmann .open = spufs_mfc_open, 1230a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1231a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1232a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1233a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1234a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 1235a33a7d73SArnd Bergmann .fasync = spufs_mfc_fasync, 12366df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1237a33a7d73SArnd Bergmann }; 1238a33a7d73SArnd Bergmann 123967207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val) 124067207b96SArnd Bergmann { 124167207b96SArnd Bergmann struct spu_context *ctx = data; 12428b3d6663SArnd Bergmann spu_acquire(ctx); 12438b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 12448b3d6663SArnd Bergmann spu_release(ctx); 124567207b96SArnd Bergmann } 124667207b96SArnd Bergmann 124767207b96SArnd Bergmann static u64 spufs_npc_get(void *data) 124867207b96SArnd Bergmann { 124967207b96SArnd Bergmann struct spu_context *ctx = data; 125067207b96SArnd Bergmann u64 ret; 12518b3d6663SArnd Bergmann spu_acquire(ctx); 12528b3d6663SArnd Bergmann ret = ctx->ops->npc_read(ctx); 12538b3d6663SArnd Bergmann spu_release(ctx); 125467207b96SArnd Bergmann return ret; 125567207b96SArnd Bergmann } 125667207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n") 125767207b96SArnd Bergmann 12588b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val) 12598b3d6663SArnd Bergmann { 12608b3d6663SArnd Bergmann struct spu_context *ctx = data; 12618b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 12628b3d6663SArnd Bergmann spu_acquire_saved(ctx); 12638b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 12648b3d6663SArnd Bergmann spu_release(ctx); 12658b3d6663SArnd Bergmann } 12668b3d6663SArnd Bergmann 12678b3d6663SArnd Bergmann static u64 spufs_decr_get(void *data) 12688b3d6663SArnd Bergmann { 12698b3d6663SArnd Bergmann struct spu_context *ctx = data; 12708b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 12718b3d6663SArnd Bergmann u64 ret; 12728b3d6663SArnd Bergmann spu_acquire_saved(ctx); 12738b3d6663SArnd Bergmann ret = lscsa->decr.slot[0]; 12748b3d6663SArnd Bergmann spu_release(ctx); 12758b3d6663SArnd Bergmann return ret; 12768b3d6663SArnd Bergmann } 12778b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 12788b3d6663SArnd Bergmann "%llx\n") 12798b3d6663SArnd Bergmann 12808b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val) 12818b3d6663SArnd Bergmann { 12828b3d6663SArnd Bergmann struct spu_context *ctx = data; 12838b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 12848b3d6663SArnd Bergmann spu_acquire_saved(ctx); 12858b3d6663SArnd Bergmann lscsa->decr_status.slot[0] = (u32) val; 12868b3d6663SArnd Bergmann spu_release(ctx); 12878b3d6663SArnd Bergmann } 12888b3d6663SArnd Bergmann 12898b3d6663SArnd Bergmann static u64 spufs_decr_status_get(void *data) 12908b3d6663SArnd Bergmann { 12918b3d6663SArnd Bergmann struct spu_context *ctx = data; 12928b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 12938b3d6663SArnd Bergmann u64 ret; 12948b3d6663SArnd Bergmann spu_acquire_saved(ctx); 12958b3d6663SArnd Bergmann ret = lscsa->decr_status.slot[0]; 12968b3d6663SArnd Bergmann spu_release(ctx); 12978b3d6663SArnd Bergmann return ret; 12988b3d6663SArnd Bergmann } 12998b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 13008b3d6663SArnd Bergmann spufs_decr_status_set, "%llx\n") 13018b3d6663SArnd Bergmann 13028b3d6663SArnd Bergmann static void spufs_spu_tag_mask_set(void *data, u64 val) 13038b3d6663SArnd Bergmann { 13048b3d6663SArnd Bergmann struct spu_context *ctx = data; 13058b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13068b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13078b3d6663SArnd Bergmann lscsa->tag_mask.slot[0] = (u32) val; 13088b3d6663SArnd Bergmann spu_release(ctx); 13098b3d6663SArnd Bergmann } 13108b3d6663SArnd Bergmann 13118b3d6663SArnd Bergmann static u64 spufs_spu_tag_mask_get(void *data) 13128b3d6663SArnd Bergmann { 13138b3d6663SArnd Bergmann struct spu_context *ctx = data; 13148b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13158b3d6663SArnd Bergmann u64 ret; 13168b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13178b3d6663SArnd Bergmann ret = lscsa->tag_mask.slot[0]; 13188b3d6663SArnd Bergmann spu_release(ctx); 13198b3d6663SArnd Bergmann return ret; 13208b3d6663SArnd Bergmann } 13218b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get, 13228b3d6663SArnd Bergmann spufs_spu_tag_mask_set, "%llx\n") 13238b3d6663SArnd Bergmann 13248b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val) 13258b3d6663SArnd Bergmann { 13268b3d6663SArnd Bergmann struct spu_context *ctx = data; 13278b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13288b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13298b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 13308b3d6663SArnd Bergmann spu_release(ctx); 13318b3d6663SArnd Bergmann } 13328b3d6663SArnd Bergmann 13338b3d6663SArnd Bergmann static u64 spufs_event_mask_get(void *data) 13348b3d6663SArnd Bergmann { 13358b3d6663SArnd Bergmann struct spu_context *ctx = data; 13368b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13378b3d6663SArnd Bergmann u64 ret; 13388b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13398b3d6663SArnd Bergmann ret = lscsa->event_mask.slot[0]; 13408b3d6663SArnd Bergmann spu_release(ctx); 13418b3d6663SArnd Bergmann return ret; 13428b3d6663SArnd Bergmann } 13438b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 13448b3d6663SArnd Bergmann spufs_event_mask_set, "%llx\n") 13458b3d6663SArnd Bergmann 13468b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val) 13478b3d6663SArnd Bergmann { 13488b3d6663SArnd Bergmann struct spu_context *ctx = data; 13498b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13508b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13518b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 13528b3d6663SArnd Bergmann spu_release(ctx); 13538b3d6663SArnd Bergmann } 13548b3d6663SArnd Bergmann 13558b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data) 13568b3d6663SArnd Bergmann { 13578b3d6663SArnd Bergmann struct spu_context *ctx = data; 13588b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 13598b3d6663SArnd Bergmann u64 ret; 13608b3d6663SArnd Bergmann spu_acquire_saved(ctx); 13618b3d6663SArnd Bergmann ret = lscsa->srr0.slot[0]; 13628b3d6663SArnd Bergmann spu_release(ctx); 13638b3d6663SArnd Bergmann return ret; 13648b3d6663SArnd Bergmann } 13658b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 13668b3d6663SArnd Bergmann "%llx\n") 13678b3d6663SArnd Bergmann 13687b1a7014Sarnd@arndb.de static u64 spufs_id_get(void *data) 13697b1a7014Sarnd@arndb.de { 13707b1a7014Sarnd@arndb.de struct spu_context *ctx = data; 13717b1a7014Sarnd@arndb.de u64 num; 13727b1a7014Sarnd@arndb.de 13737b1a7014Sarnd@arndb.de spu_acquire(ctx); 13747b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 13757b1a7014Sarnd@arndb.de num = ctx->spu->number; 13767b1a7014Sarnd@arndb.de else 13777b1a7014Sarnd@arndb.de num = (unsigned int)-1; 13787b1a7014Sarnd@arndb.de spu_release(ctx); 13797b1a7014Sarnd@arndb.de 13807b1a7014Sarnd@arndb.de return num; 13817b1a7014Sarnd@arndb.de } 1382e45d6634SAl Viro DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") 13837b1a7014Sarnd@arndb.de 138467207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 138567207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 13868b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 138767207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 138867207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 138967207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 139067207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 139167207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 139267207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 139367207b96SArnd Bergmann { "signal1", &spufs_signal1_fops, 0666, }, 139467207b96SArnd Bergmann { "signal2", &spufs_signal2_fops, 0666, }, 139567207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 139667207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 1397d9379c4bSarnd@arndb.de { "mss", &spufs_mss_fops, 0666, }, 1398a33a7d73SArnd Bergmann { "mfc", &spufs_mfc_fops, 0666, }, 13996df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 140067207b96SArnd Bergmann { "npc", &spufs_npc_ops, 0666, }, 14018b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 14028b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 14038b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 14048b3d6663SArnd Bergmann { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, }, 14058b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 14068b3d6663SArnd Bergmann { "srr0", &spufs_srr0_ops, 0666, }, 14077b1a7014Sarnd@arndb.de { "phys-id", &spufs_id_ops, 0666, }, 140827d5bf2aSBenjamin Herrenschmidt { "psmap", &spufs_psmap_fops, 0666, }, 140967207b96SArnd Bergmann {}, 141067207b96SArnd Bergmann }; 1411