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 2367207b96SArnd Bergmann #include <linux/fs.h> 2467207b96SArnd Bergmann #include <linux/ioctl.h> 2567207b96SArnd Bergmann #include <linux/module.h> 26d88cfffaSArnd Bergmann #include <linux/pagemap.h> 2767207b96SArnd Bergmann #include <linux/poll.h> 285110459fSArnd Bergmann #include <linux/ptrace.h> 2967207b96SArnd Bergmann 3067207b96SArnd Bergmann #include <asm/io.h> 3167207b96SArnd Bergmann #include <asm/semaphore.h> 3267207b96SArnd Bergmann #include <asm/spu.h> 3367207b96SArnd Bergmann #include <asm/uaccess.h> 3467207b96SArnd Bergmann 3567207b96SArnd Bergmann #include "spufs.h" 3667207b96SArnd Bergmann 378b3d6663SArnd Bergmann 3867207b96SArnd Bergmann static int 3967207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 4067207b96SArnd Bergmann { 4167207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 4267207b96SArnd Bergmann file->private_data = i->i_ctx; 438b3d6663SArnd Bergmann file->f_mapping = i->i_ctx->local_store; 4467207b96SArnd Bergmann return 0; 4567207b96SArnd Bergmann } 4667207b96SArnd Bergmann 4767207b96SArnd Bergmann static ssize_t 4867207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 4967207b96SArnd Bergmann size_t size, loff_t *pos) 5067207b96SArnd Bergmann { 518b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 528b3d6663SArnd Bergmann char *local_store; 5367207b96SArnd Bergmann int ret; 5467207b96SArnd Bergmann 558b3d6663SArnd Bergmann spu_acquire(ctx); 5667207b96SArnd Bergmann 578b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 588b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE); 5967207b96SArnd Bergmann 608b3d6663SArnd Bergmann spu_release(ctx); 6167207b96SArnd Bergmann return ret; 6267207b96SArnd Bergmann } 6367207b96SArnd Bergmann 6467207b96SArnd Bergmann static ssize_t 6567207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 6667207b96SArnd Bergmann size_t size, loff_t *pos) 6767207b96SArnd Bergmann { 6867207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 698b3d6663SArnd Bergmann char *local_store; 708b3d6663SArnd Bergmann int ret; 7167207b96SArnd Bergmann 7267207b96SArnd Bergmann size = min_t(ssize_t, LS_SIZE - *pos, size); 7367207b96SArnd Bergmann if (size <= 0) 7467207b96SArnd Bergmann return -EFBIG; 7567207b96SArnd Bergmann *pos += size; 768b3d6663SArnd Bergmann 778b3d6663SArnd Bergmann spu_acquire(ctx); 788b3d6663SArnd Bergmann 798b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 808b3d6663SArnd Bergmann ret = copy_from_user(local_store + *pos - size, 8167207b96SArnd Bergmann buffer, size) ? -EFAULT : size; 828b3d6663SArnd Bergmann 838b3d6663SArnd Bergmann spu_release(ctx); 848b3d6663SArnd Bergmann return ret; 8567207b96SArnd Bergmann } 8667207b96SArnd Bergmann 878b3d6663SArnd Bergmann #ifdef CONFIG_SPARSEMEM 888b3d6663SArnd Bergmann static struct page * 898b3d6663SArnd Bergmann spufs_mem_mmap_nopage(struct vm_area_struct *vma, 908b3d6663SArnd Bergmann unsigned long address, int *type) 918b3d6663SArnd Bergmann { 928b3d6663SArnd Bergmann struct page *page = NOPAGE_SIGBUS; 938b3d6663SArnd Bergmann 948b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 958b3d6663SArnd Bergmann unsigned long offset = address - vma->vm_start; 968b3d6663SArnd Bergmann offset += vma->vm_pgoff << PAGE_SHIFT; 978b3d6663SArnd Bergmann 988b3d6663SArnd Bergmann spu_acquire(ctx); 998b3d6663SArnd Bergmann 1008b3d6663SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) 1018b3d6663SArnd Bergmann page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); 1028b3d6663SArnd Bergmann else 1038b3d6663SArnd Bergmann page = pfn_to_page((ctx->spu->local_store_phys + offset) 1048b3d6663SArnd Bergmann >> PAGE_SHIFT); 1058b3d6663SArnd Bergmann 1068b3d6663SArnd Bergmann spu_release(ctx); 1078b3d6663SArnd Bergmann 1088b3d6663SArnd Bergmann if (type) 1098b3d6663SArnd Bergmann *type = VM_FAULT_MINOR; 1108b3d6663SArnd Bergmann 111d88cfffaSArnd Bergmann page_cache_get(page); 1128b3d6663SArnd Bergmann return page; 1138b3d6663SArnd Bergmann } 1148b3d6663SArnd Bergmann 1158b3d6663SArnd Bergmann static struct vm_operations_struct spufs_mem_mmap_vmops = { 1168b3d6663SArnd Bergmann .nopage = spufs_mem_mmap_nopage, 1178b3d6663SArnd Bergmann }; 1188b3d6663SArnd Bergmann 11967207b96SArnd Bergmann static int 12067207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 12167207b96SArnd Bergmann { 1228b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 1238b3d6663SArnd Bergmann return -EINVAL; 12467207b96SArnd Bergmann 1258b3d6663SArnd Bergmann /* FIXME: */ 12667207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) 12767207b96SArnd Bergmann | _PAGE_NO_CACHE); 1288b3d6663SArnd Bergmann 1298b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 13067207b96SArnd Bergmann return 0; 13167207b96SArnd Bergmann } 1328b3d6663SArnd Bergmann #endif 13367207b96SArnd Bergmann 13467207b96SArnd Bergmann static struct file_operations spufs_mem_fops = { 13567207b96SArnd Bergmann .open = spufs_mem_open, 13667207b96SArnd Bergmann .read = spufs_mem_read, 13767207b96SArnd Bergmann .write = spufs_mem_write, 1388b3d6663SArnd Bergmann .llseek = generic_file_llseek, 1398b3d6663SArnd Bergmann #ifdef CONFIG_SPARSEMEM 14067207b96SArnd Bergmann .mmap = spufs_mem_mmap, 1418b3d6663SArnd Bergmann #endif 1428b3d6663SArnd Bergmann }; 1438b3d6663SArnd Bergmann 1448b3d6663SArnd Bergmann static int 1458b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 1468b3d6663SArnd Bergmann { 1478b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1488b3d6663SArnd Bergmann file->private_data = i->i_ctx; 1498b3d6663SArnd Bergmann return 0; 1508b3d6663SArnd Bergmann } 1518b3d6663SArnd Bergmann 1528b3d6663SArnd Bergmann static ssize_t 1538b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 1548b3d6663SArnd Bergmann size_t size, loff_t *pos) 1558b3d6663SArnd Bergmann { 1568b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 1578b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1588b3d6663SArnd Bergmann int ret; 1598b3d6663SArnd Bergmann 1608b3d6663SArnd Bergmann spu_acquire_saved(ctx); 1618b3d6663SArnd Bergmann 1628b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 1638b3d6663SArnd Bergmann lscsa->gprs, sizeof lscsa->gprs); 1648b3d6663SArnd Bergmann 1658b3d6663SArnd Bergmann spu_release(ctx); 1668b3d6663SArnd Bergmann return ret; 1678b3d6663SArnd Bergmann } 1688b3d6663SArnd Bergmann 1698b3d6663SArnd Bergmann static ssize_t 1708b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 1718b3d6663SArnd Bergmann size_t size, loff_t *pos) 1728b3d6663SArnd Bergmann { 1738b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 1748b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1758b3d6663SArnd Bergmann int ret; 1768b3d6663SArnd Bergmann 1778b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); 1788b3d6663SArnd Bergmann if (size <= 0) 1798b3d6663SArnd Bergmann return -EFBIG; 1808b3d6663SArnd Bergmann *pos += size; 1818b3d6663SArnd Bergmann 1828b3d6663SArnd Bergmann spu_acquire_saved(ctx); 1838b3d6663SArnd Bergmann 1848b3d6663SArnd Bergmann ret = copy_from_user(lscsa->gprs + *pos - size, 1858b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 1868b3d6663SArnd Bergmann 1878b3d6663SArnd Bergmann spu_release(ctx); 1888b3d6663SArnd Bergmann return ret; 1898b3d6663SArnd Bergmann } 1908b3d6663SArnd Bergmann 1918b3d6663SArnd Bergmann static struct file_operations spufs_regs_fops = { 1928b3d6663SArnd Bergmann .open = spufs_regs_open, 1938b3d6663SArnd Bergmann .read = spufs_regs_read, 1948b3d6663SArnd Bergmann .write = spufs_regs_write, 1958b3d6663SArnd Bergmann .llseek = generic_file_llseek, 1968b3d6663SArnd Bergmann }; 1978b3d6663SArnd Bergmann 1988b3d6663SArnd Bergmann static ssize_t 1998b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 2008b3d6663SArnd Bergmann size_t size, loff_t * pos) 2018b3d6663SArnd Bergmann { 2028b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 2038b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 2048b3d6663SArnd Bergmann int ret; 2058b3d6663SArnd Bergmann 2068b3d6663SArnd Bergmann spu_acquire_saved(ctx); 2078b3d6663SArnd Bergmann 2088b3d6663SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 2098b3d6663SArnd Bergmann &lscsa->fpcr, sizeof(lscsa->fpcr)); 2108b3d6663SArnd Bergmann 2118b3d6663SArnd Bergmann spu_release(ctx); 2128b3d6663SArnd Bergmann return ret; 2138b3d6663SArnd Bergmann } 2148b3d6663SArnd Bergmann 2158b3d6663SArnd Bergmann static ssize_t 2168b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 2178b3d6663SArnd Bergmann size_t size, loff_t * pos) 2188b3d6663SArnd Bergmann { 2198b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 2208b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 2218b3d6663SArnd Bergmann int ret; 2228b3d6663SArnd Bergmann 2238b3d6663SArnd Bergmann size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); 2248b3d6663SArnd Bergmann if (size <= 0) 2258b3d6663SArnd Bergmann return -EFBIG; 2268b3d6663SArnd Bergmann *pos += size; 2278b3d6663SArnd Bergmann 2288b3d6663SArnd Bergmann spu_acquire_saved(ctx); 2298b3d6663SArnd Bergmann 2308b3d6663SArnd Bergmann ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 2318b3d6663SArnd Bergmann buffer, size) ? -EFAULT : size; 2328b3d6663SArnd Bergmann 2338b3d6663SArnd Bergmann spu_release(ctx); 2348b3d6663SArnd Bergmann return ret; 2358b3d6663SArnd Bergmann } 2368b3d6663SArnd Bergmann 2378b3d6663SArnd Bergmann static struct file_operations spufs_fpcr_fops = { 2388b3d6663SArnd Bergmann .open = spufs_regs_open, 2398b3d6663SArnd Bergmann .read = spufs_fpcr_read, 2408b3d6663SArnd Bergmann .write = spufs_fpcr_write, 24167207b96SArnd Bergmann .llseek = generic_file_llseek, 24267207b96SArnd Bergmann }; 24367207b96SArnd Bergmann 24467207b96SArnd Bergmann /* generic open function for all pipe-like files */ 24567207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 24667207b96SArnd Bergmann { 24767207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 24867207b96SArnd Bergmann file->private_data = i->i_ctx; 24967207b96SArnd Bergmann 25067207b96SArnd Bergmann return nonseekable_open(inode, file); 25167207b96SArnd Bergmann } 25267207b96SArnd Bergmann 25367207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 25467207b96SArnd Bergmann size_t len, loff_t *pos) 25567207b96SArnd Bergmann { 2568b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 25767207b96SArnd Bergmann u32 mbox_data; 2588b3d6663SArnd Bergmann int ret; 25967207b96SArnd Bergmann 26067207b96SArnd Bergmann if (len < 4) 26167207b96SArnd Bergmann return -EINVAL; 26267207b96SArnd Bergmann 2638b3d6663SArnd Bergmann spu_acquire(ctx); 2648b3d6663SArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 2658b3d6663SArnd Bergmann spu_release(ctx); 26667207b96SArnd Bergmann 2678b3d6663SArnd Bergmann if (!ret) 2688b3d6663SArnd Bergmann return -EAGAIN; 26967207b96SArnd Bergmann 27067207b96SArnd Bergmann if (copy_to_user(buf, &mbox_data, sizeof mbox_data)) 27167207b96SArnd Bergmann return -EFAULT; 27267207b96SArnd Bergmann 27367207b96SArnd Bergmann return 4; 27467207b96SArnd Bergmann } 27567207b96SArnd Bergmann 27667207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = { 27767207b96SArnd Bergmann .open = spufs_pipe_open, 27867207b96SArnd Bergmann .read = spufs_mbox_read, 27967207b96SArnd Bergmann }; 28067207b96SArnd Bergmann 28167207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 28267207b96SArnd Bergmann size_t len, loff_t *pos) 28367207b96SArnd Bergmann { 2848b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 28567207b96SArnd Bergmann u32 mbox_stat; 28667207b96SArnd Bergmann 28767207b96SArnd Bergmann if (len < 4) 28867207b96SArnd Bergmann return -EINVAL; 28967207b96SArnd Bergmann 2908b3d6663SArnd Bergmann spu_acquire(ctx); 2918b3d6663SArnd Bergmann 2928b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 2938b3d6663SArnd Bergmann 2948b3d6663SArnd Bergmann spu_release(ctx); 29567207b96SArnd Bergmann 29667207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 29767207b96SArnd Bergmann return -EFAULT; 29867207b96SArnd Bergmann 29967207b96SArnd Bergmann return 4; 30067207b96SArnd Bergmann } 30167207b96SArnd Bergmann 30267207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = { 30367207b96SArnd Bergmann .open = spufs_pipe_open, 30467207b96SArnd Bergmann .read = spufs_mbox_stat_read, 30567207b96SArnd Bergmann }; 30667207b96SArnd Bergmann 3078b3d6663SArnd Bergmann /* 3088b3d6663SArnd Bergmann * spufs_wait 3098b3d6663SArnd Bergmann * Same as wait_event_interruptible(), except that here 3108b3d6663SArnd Bergmann * we need to call spu_release(ctx) before sleeping, and 3118b3d6663SArnd Bergmann * then spu_acquire(ctx) when awoken. 3128b3d6663SArnd Bergmann */ 3138b3d6663SArnd Bergmann 3148b3d6663SArnd Bergmann #define spufs_wait(wq, condition) \ 3158b3d6663SArnd Bergmann ({ \ 3168b3d6663SArnd Bergmann int __ret = 0; \ 3178b3d6663SArnd Bergmann DEFINE_WAIT(__wait); \ 3188b3d6663SArnd Bergmann for (;;) { \ 3198b3d6663SArnd Bergmann prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ 3208b3d6663SArnd Bergmann if (condition) \ 3218b3d6663SArnd Bergmann break; \ 3228b3d6663SArnd Bergmann if (!signal_pending(current)) { \ 3238b3d6663SArnd Bergmann spu_release(ctx); \ 3248b3d6663SArnd Bergmann schedule(); \ 3258b3d6663SArnd Bergmann spu_acquire(ctx); \ 3268b3d6663SArnd Bergmann continue; \ 3278b3d6663SArnd Bergmann } \ 3288b3d6663SArnd Bergmann __ret = -ERESTARTSYS; \ 3298b3d6663SArnd Bergmann break; \ 3308b3d6663SArnd Bergmann } \ 3318b3d6663SArnd Bergmann finish_wait(&(wq), &__wait); \ 3328b3d6663SArnd Bergmann __ret; \ 3338b3d6663SArnd Bergmann }) 3348b3d6663SArnd Bergmann 33567207b96SArnd Bergmann /* low-level ibox access function */ 3368b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 33767207b96SArnd Bergmann { 3388b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 33967207b96SArnd Bergmann } 34067207b96SArnd Bergmann 34167207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 34267207b96SArnd Bergmann { 3438b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 3448b3d6663SArnd Bergmann 3458b3d6663SArnd Bergmann return fasync_helper(fd, file, on, &ctx->ibox_fasync); 3468b3d6663SArnd Bergmann } 3478b3d6663SArnd Bergmann 3488b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 3498b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 3508b3d6663SArnd Bergmann { 3518b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 3528b3d6663SArnd Bergmann 3538b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 3548b3d6663SArnd Bergmann kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); 35567207b96SArnd Bergmann } 35667207b96SArnd Bergmann 35767207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 35867207b96SArnd Bergmann size_t len, loff_t *pos) 35967207b96SArnd Bergmann { 3608b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 36167207b96SArnd Bergmann u32 ibox_data; 36267207b96SArnd Bergmann ssize_t ret; 36367207b96SArnd Bergmann 36467207b96SArnd Bergmann if (len < 4) 36567207b96SArnd Bergmann return -EINVAL; 36667207b96SArnd Bergmann 3678b3d6663SArnd Bergmann spu_acquire(ctx); 36867207b96SArnd Bergmann 36967207b96SArnd Bergmann ret = 0; 37067207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 3718b3d6663SArnd Bergmann if (!spu_ibox_read(ctx, &ibox_data)) 37267207b96SArnd Bergmann ret = -EAGAIN; 37367207b96SArnd Bergmann } else { 3748b3d6663SArnd Bergmann ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 37567207b96SArnd Bergmann } 37667207b96SArnd Bergmann 3778b3d6663SArnd Bergmann spu_release(ctx); 3788b3d6663SArnd Bergmann 37967207b96SArnd Bergmann if (ret) 38067207b96SArnd Bergmann return ret; 38167207b96SArnd Bergmann 38267207b96SArnd Bergmann ret = 4; 38367207b96SArnd Bergmann if (copy_to_user(buf, &ibox_data, sizeof ibox_data)) 38467207b96SArnd Bergmann ret = -EFAULT; 38567207b96SArnd Bergmann 38667207b96SArnd Bergmann return ret; 38767207b96SArnd Bergmann } 38867207b96SArnd Bergmann 38967207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 39067207b96SArnd Bergmann { 3918b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 39267207b96SArnd Bergmann unsigned int mask; 39367207b96SArnd Bergmann 3948b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 39567207b96SArnd Bergmann 3963a843d7cSArnd Bergmann spu_acquire(ctx); 3973a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); 3983a843d7cSArnd Bergmann spu_release(ctx); 39967207b96SArnd Bergmann 40067207b96SArnd Bergmann return mask; 40167207b96SArnd Bergmann } 40267207b96SArnd Bergmann 40367207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = { 40467207b96SArnd Bergmann .open = spufs_pipe_open, 40567207b96SArnd Bergmann .read = spufs_ibox_read, 40667207b96SArnd Bergmann .poll = spufs_ibox_poll, 40767207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 40867207b96SArnd Bergmann }; 40967207b96SArnd Bergmann 41067207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 41167207b96SArnd Bergmann size_t len, loff_t *pos) 41267207b96SArnd Bergmann { 4138b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 41467207b96SArnd Bergmann u32 ibox_stat; 41567207b96SArnd Bergmann 41667207b96SArnd Bergmann if (len < 4) 41767207b96SArnd Bergmann return -EINVAL; 41867207b96SArnd Bergmann 4198b3d6663SArnd Bergmann spu_acquire(ctx); 4208b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 4218b3d6663SArnd Bergmann spu_release(ctx); 42267207b96SArnd Bergmann 42367207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 42467207b96SArnd Bergmann return -EFAULT; 42567207b96SArnd Bergmann 42667207b96SArnd Bergmann return 4; 42767207b96SArnd Bergmann } 42867207b96SArnd Bergmann 42967207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = { 43067207b96SArnd Bergmann .open = spufs_pipe_open, 43167207b96SArnd Bergmann .read = spufs_ibox_stat_read, 43267207b96SArnd Bergmann }; 43367207b96SArnd Bergmann 43467207b96SArnd Bergmann /* low-level mailbox write */ 4358b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 43667207b96SArnd Bergmann { 4378b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 43867207b96SArnd Bergmann } 43967207b96SArnd Bergmann 44067207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 44167207b96SArnd Bergmann { 4428b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 4438b3d6663SArnd Bergmann int ret; 4448b3d6663SArnd Bergmann 4458b3d6663SArnd Bergmann ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); 4468b3d6663SArnd Bergmann 4478b3d6663SArnd Bergmann return ret; 4488b3d6663SArnd Bergmann } 4498b3d6663SArnd Bergmann 4508b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 4518b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 4528b3d6663SArnd Bergmann { 4538b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 4548b3d6663SArnd Bergmann 4558b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 4568b3d6663SArnd Bergmann kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); 45767207b96SArnd Bergmann } 45867207b96SArnd Bergmann 45967207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 46067207b96SArnd Bergmann size_t len, loff_t *pos) 46167207b96SArnd Bergmann { 4628b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 46367207b96SArnd Bergmann u32 wbox_data; 46467207b96SArnd Bergmann int ret; 46567207b96SArnd Bergmann 46667207b96SArnd Bergmann if (len < 4) 46767207b96SArnd Bergmann return -EINVAL; 46867207b96SArnd Bergmann 46967207b96SArnd Bergmann if (copy_from_user(&wbox_data, buf, sizeof wbox_data)) 47067207b96SArnd Bergmann return -EFAULT; 47167207b96SArnd Bergmann 4728b3d6663SArnd Bergmann spu_acquire(ctx); 4738b3d6663SArnd Bergmann 47467207b96SArnd Bergmann ret = 0; 47567207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 4768b3d6663SArnd Bergmann if (!spu_wbox_write(ctx, wbox_data)) 47767207b96SArnd Bergmann ret = -EAGAIN; 47867207b96SArnd Bergmann } else { 4798b3d6663SArnd Bergmann ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 48067207b96SArnd Bergmann } 48167207b96SArnd Bergmann 4828b3d6663SArnd Bergmann spu_release(ctx); 4838b3d6663SArnd Bergmann 48467207b96SArnd Bergmann return ret ? ret : sizeof wbox_data; 48567207b96SArnd Bergmann } 48667207b96SArnd Bergmann 48767207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 48867207b96SArnd Bergmann { 4898b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 49067207b96SArnd Bergmann unsigned int mask; 49167207b96SArnd Bergmann 4928b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 49367207b96SArnd Bergmann 4943a843d7cSArnd Bergmann spu_acquire(ctx); 4953a843d7cSArnd Bergmann mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); 4963a843d7cSArnd Bergmann spu_release(ctx); 49767207b96SArnd Bergmann 49867207b96SArnd Bergmann return mask; 49967207b96SArnd Bergmann } 50067207b96SArnd Bergmann 50167207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = { 50267207b96SArnd Bergmann .open = spufs_pipe_open, 50367207b96SArnd Bergmann .write = spufs_wbox_write, 50467207b96SArnd Bergmann .poll = spufs_wbox_poll, 50567207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 50667207b96SArnd Bergmann }; 50767207b96SArnd Bergmann 50867207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 50967207b96SArnd Bergmann size_t len, loff_t *pos) 51067207b96SArnd Bergmann { 5118b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 51267207b96SArnd Bergmann u32 wbox_stat; 51367207b96SArnd Bergmann 51467207b96SArnd Bergmann if (len < 4) 51567207b96SArnd Bergmann return -EINVAL; 51667207b96SArnd Bergmann 5178b3d6663SArnd Bergmann spu_acquire(ctx); 5188b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 5198b3d6663SArnd Bergmann spu_release(ctx); 52067207b96SArnd Bergmann 52167207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 52267207b96SArnd Bergmann return -EFAULT; 52367207b96SArnd Bergmann 52467207b96SArnd Bergmann return 4; 52567207b96SArnd Bergmann } 52667207b96SArnd Bergmann 52767207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = { 52867207b96SArnd Bergmann .open = spufs_pipe_open, 52967207b96SArnd Bergmann .read = spufs_wbox_stat_read, 53067207b96SArnd Bergmann }; 53167207b96SArnd Bergmann 5325110459fSArnd Bergmann /* interrupt-level stop callback function. */ 5335110459fSArnd Bergmann void spufs_stop_callback(struct spu *spu) 5345110459fSArnd Bergmann { 5355110459fSArnd Bergmann struct spu_context *ctx = spu->ctx; 5365110459fSArnd Bergmann 5375110459fSArnd Bergmann wake_up_all(&ctx->stop_wq); 5385110459fSArnd Bergmann } 5395110459fSArnd Bergmann 5405110459fSArnd Bergmann static inline int spu_stopped(struct spu_context *ctx, u32 * stat) 5415110459fSArnd Bergmann { 5425110459fSArnd Bergmann struct spu *spu; 5435110459fSArnd Bergmann u64 pte_fault; 5445110459fSArnd Bergmann 5455110459fSArnd Bergmann *stat = ctx->ops->status_read(ctx); 5465110459fSArnd Bergmann if (ctx->state != SPU_STATE_RUNNABLE) 5475110459fSArnd Bergmann return 1; 5485110459fSArnd Bergmann spu = ctx->spu; 5495110459fSArnd Bergmann pte_fault = spu->dsisr & 5505110459fSArnd Bergmann (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); 5515110459fSArnd Bergmann return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; 5525110459fSArnd Bergmann } 5535110459fSArnd Bergmann 5545110459fSArnd Bergmann static inline int spu_run_init(struct spu_context *ctx, u32 * npc, 5555110459fSArnd Bergmann u32 * status) 5565110459fSArnd Bergmann { 5575110459fSArnd Bergmann int ret; 5585110459fSArnd Bergmann 5595110459fSArnd Bergmann if ((ret = spu_acquire_runnable(ctx)) != 0) 5605110459fSArnd Bergmann return ret; 5615110459fSArnd Bergmann ctx->ops->npc_write(ctx, *npc); 5625110459fSArnd Bergmann ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 5635110459fSArnd Bergmann return 0; 5645110459fSArnd Bergmann } 5655110459fSArnd Bergmann 5665110459fSArnd Bergmann static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, 5675110459fSArnd Bergmann u32 * status) 5685110459fSArnd Bergmann { 5695110459fSArnd Bergmann int ret = 0; 5705110459fSArnd Bergmann 5715110459fSArnd Bergmann *status = ctx->ops->status_read(ctx); 5725110459fSArnd Bergmann *npc = ctx->ops->npc_read(ctx); 5735110459fSArnd Bergmann spu_release(ctx); 5745110459fSArnd Bergmann 5755110459fSArnd Bergmann if (signal_pending(current)) 5765110459fSArnd Bergmann ret = -ERESTARTSYS; 5775110459fSArnd Bergmann if (unlikely(current->ptrace & PT_PTRACED)) { 5785110459fSArnd Bergmann if ((*status & SPU_STATUS_STOPPED_BY_STOP) 5795110459fSArnd Bergmann && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { 5805110459fSArnd Bergmann force_sig(SIGTRAP, current); 5815110459fSArnd Bergmann ret = -ERESTARTSYS; 5825110459fSArnd Bergmann } 5835110459fSArnd Bergmann } 5845110459fSArnd Bergmann return ret; 5855110459fSArnd Bergmann } 5865110459fSArnd Bergmann 5875110459fSArnd Bergmann static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, 5885110459fSArnd Bergmann u32 *status) 5895110459fSArnd Bergmann { 5905110459fSArnd Bergmann int ret; 5915110459fSArnd Bergmann 5925110459fSArnd Bergmann if ((ret = spu_run_fini(ctx, npc, status)) != 0) 5935110459fSArnd Bergmann return ret; 5945110459fSArnd Bergmann if (*status & (SPU_STATUS_STOPPED_BY_STOP | 5955110459fSArnd Bergmann SPU_STATUS_STOPPED_BY_HALT)) { 5965110459fSArnd Bergmann return *status; 5975110459fSArnd Bergmann } 5985110459fSArnd Bergmann if ((ret = spu_run_init(ctx, npc, status)) != 0) 5995110459fSArnd Bergmann return ret; 6005110459fSArnd Bergmann return 0; 6015110459fSArnd Bergmann } 6025110459fSArnd Bergmann 6035110459fSArnd Bergmann static inline int spu_process_events(struct spu_context *ctx) 6045110459fSArnd Bergmann { 6055110459fSArnd Bergmann struct spu *spu = ctx->spu; 6065110459fSArnd Bergmann u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; 6075110459fSArnd Bergmann int ret = 0; 6085110459fSArnd Bergmann 6095110459fSArnd Bergmann if (spu->dsisr & pte_fault) 6105110459fSArnd Bergmann ret = spu_irq_class_1_bottom(spu); 6115110459fSArnd Bergmann if (spu->class_0_pending) 6125110459fSArnd Bergmann ret = spu_irq_class_0_bottom(spu); 6135110459fSArnd Bergmann if (!ret && signal_pending(current)) 6145110459fSArnd Bergmann ret = -ERESTARTSYS; 6155110459fSArnd Bergmann return ret; 6165110459fSArnd Bergmann } 6175110459fSArnd Bergmann 61867207b96SArnd Bergmann long spufs_run_spu(struct file *file, struct spu_context *ctx, 61967207b96SArnd Bergmann u32 * npc, u32 * status) 62067207b96SArnd Bergmann { 62167207b96SArnd Bergmann int ret; 62267207b96SArnd Bergmann 6235110459fSArnd Bergmann if ((ret = spu_run_init(ctx, npc, status)) != 0) 6248b3d6663SArnd Bergmann return ret; 62567207b96SArnd Bergmann 6265110459fSArnd Bergmann do { 6275110459fSArnd Bergmann ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); 6285110459fSArnd Bergmann if (unlikely(ret)) 6295110459fSArnd Bergmann break; 6305110459fSArnd Bergmann if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { 6315110459fSArnd Bergmann ret = spu_reacquire_runnable(ctx, npc, status); 6325110459fSArnd Bergmann if (ret) { 6335110459fSArnd Bergmann return ret; 6345110459fSArnd Bergmann } 6355110459fSArnd Bergmann continue; 6365110459fSArnd Bergmann } 6375110459fSArnd Bergmann ret = spu_process_events(ctx); 63867207b96SArnd Bergmann 6395110459fSArnd Bergmann } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | 6405110459fSArnd Bergmann SPU_STATUS_STOPPED_BY_HALT))); 64167207b96SArnd Bergmann 6425110459fSArnd Bergmann ctx->ops->runcntl_stop(ctx); 6435110459fSArnd Bergmann ret = spu_run_fini(ctx, npc, status); 6448b3d6663SArnd Bergmann if (!ret) 6455110459fSArnd Bergmann ret = *status; 6468b3d6663SArnd Bergmann spu_yield(ctx); 6475110459fSArnd Bergmann 64867207b96SArnd Bergmann return ret; 64967207b96SArnd Bergmann } 65067207b96SArnd Bergmann 65167207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 65267207b96SArnd Bergmann size_t len, loff_t *pos) 65367207b96SArnd Bergmann { 6548b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 65567207b96SArnd Bergmann u32 data; 65667207b96SArnd Bergmann 65767207b96SArnd Bergmann if (len < 4) 65867207b96SArnd Bergmann return -EINVAL; 65967207b96SArnd Bergmann 6608b3d6663SArnd Bergmann spu_acquire(ctx); 6618b3d6663SArnd Bergmann data = ctx->ops->signal1_read(ctx); 6628b3d6663SArnd Bergmann spu_release(ctx); 6638b3d6663SArnd Bergmann 66467207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 66567207b96SArnd Bergmann return -EFAULT; 66667207b96SArnd Bergmann 66767207b96SArnd Bergmann return 4; 66867207b96SArnd Bergmann } 66967207b96SArnd Bergmann 67067207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 67167207b96SArnd Bergmann size_t len, loff_t *pos) 67267207b96SArnd Bergmann { 67367207b96SArnd Bergmann struct spu_context *ctx; 67467207b96SArnd Bergmann u32 data; 67567207b96SArnd Bergmann 67667207b96SArnd Bergmann ctx = file->private_data; 67767207b96SArnd Bergmann 67867207b96SArnd Bergmann if (len < 4) 67967207b96SArnd Bergmann return -EINVAL; 68067207b96SArnd Bergmann 68167207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 68267207b96SArnd Bergmann return -EFAULT; 68367207b96SArnd Bergmann 6848b3d6663SArnd Bergmann spu_acquire(ctx); 6858b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 6868b3d6663SArnd Bergmann spu_release(ctx); 68767207b96SArnd Bergmann 68867207b96SArnd Bergmann return 4; 68967207b96SArnd Bergmann } 69067207b96SArnd Bergmann 69167207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = { 69267207b96SArnd Bergmann .open = spufs_pipe_open, 69367207b96SArnd Bergmann .read = spufs_signal1_read, 69467207b96SArnd Bergmann .write = spufs_signal1_write, 69567207b96SArnd Bergmann }; 69667207b96SArnd Bergmann 69767207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 69867207b96SArnd Bergmann size_t len, loff_t *pos) 69967207b96SArnd Bergmann { 70067207b96SArnd Bergmann struct spu_context *ctx; 70167207b96SArnd Bergmann u32 data; 70267207b96SArnd Bergmann 70367207b96SArnd Bergmann ctx = file->private_data; 70467207b96SArnd Bergmann 70567207b96SArnd Bergmann if (len < 4) 70667207b96SArnd Bergmann return -EINVAL; 70767207b96SArnd Bergmann 7088b3d6663SArnd Bergmann spu_acquire(ctx); 7098b3d6663SArnd Bergmann data = ctx->ops->signal2_read(ctx); 7108b3d6663SArnd Bergmann spu_release(ctx); 7118b3d6663SArnd Bergmann 71267207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 71367207b96SArnd Bergmann return -EFAULT; 71467207b96SArnd Bergmann 71567207b96SArnd Bergmann return 4; 71667207b96SArnd Bergmann } 71767207b96SArnd Bergmann 71867207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 71967207b96SArnd Bergmann size_t len, loff_t *pos) 72067207b96SArnd Bergmann { 72167207b96SArnd Bergmann struct spu_context *ctx; 72267207b96SArnd Bergmann u32 data; 72367207b96SArnd Bergmann 72467207b96SArnd Bergmann ctx = file->private_data; 72567207b96SArnd Bergmann 72667207b96SArnd Bergmann if (len < 4) 72767207b96SArnd Bergmann return -EINVAL; 72867207b96SArnd Bergmann 72967207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 73067207b96SArnd Bergmann return -EFAULT; 73167207b96SArnd Bergmann 7328b3d6663SArnd Bergmann spu_acquire(ctx); 7338b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 7348b3d6663SArnd Bergmann spu_release(ctx); 73567207b96SArnd Bergmann 73667207b96SArnd Bergmann return 4; 73767207b96SArnd Bergmann } 73867207b96SArnd Bergmann 73967207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = { 74067207b96SArnd Bergmann .open = spufs_pipe_open, 74167207b96SArnd Bergmann .read = spufs_signal2_read, 74267207b96SArnd Bergmann .write = spufs_signal2_write, 74367207b96SArnd Bergmann }; 74467207b96SArnd Bergmann 74567207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val) 74667207b96SArnd Bergmann { 74767207b96SArnd Bergmann struct spu_context *ctx = data; 74867207b96SArnd Bergmann 7498b3d6663SArnd Bergmann spu_acquire(ctx); 7508b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 7518b3d6663SArnd Bergmann spu_release(ctx); 75267207b96SArnd Bergmann } 75367207b96SArnd Bergmann 75467207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data) 75567207b96SArnd Bergmann { 75667207b96SArnd Bergmann struct spu_context *ctx = data; 7578b3d6663SArnd Bergmann u64 ret; 7588b3d6663SArnd Bergmann 7598b3d6663SArnd Bergmann spu_acquire(ctx); 7608b3d6663SArnd Bergmann ret = ctx->ops->signal1_type_get(ctx); 7618b3d6663SArnd Bergmann spu_release(ctx); 7628b3d6663SArnd Bergmann 7638b3d6663SArnd Bergmann return ret; 76467207b96SArnd Bergmann } 76567207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 76667207b96SArnd Bergmann spufs_signal1_type_set, "%llu"); 76767207b96SArnd Bergmann 76867207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val) 76967207b96SArnd Bergmann { 77067207b96SArnd Bergmann struct spu_context *ctx = data; 77167207b96SArnd Bergmann 7728b3d6663SArnd Bergmann spu_acquire(ctx); 7738b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 7748b3d6663SArnd Bergmann spu_release(ctx); 77567207b96SArnd Bergmann } 77667207b96SArnd Bergmann 77767207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data) 77867207b96SArnd Bergmann { 77967207b96SArnd Bergmann struct spu_context *ctx = data; 7808b3d6663SArnd Bergmann u64 ret; 7818b3d6663SArnd Bergmann 7828b3d6663SArnd Bergmann spu_acquire(ctx); 7838b3d6663SArnd Bergmann ret = ctx->ops->signal2_type_get(ctx); 7848b3d6663SArnd Bergmann spu_release(ctx); 7858b3d6663SArnd Bergmann 7868b3d6663SArnd Bergmann return ret; 78767207b96SArnd Bergmann } 78867207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 78967207b96SArnd Bergmann spufs_signal2_type_set, "%llu"); 79067207b96SArnd Bergmann 79167207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val) 79267207b96SArnd Bergmann { 79367207b96SArnd Bergmann struct spu_context *ctx = data; 7948b3d6663SArnd Bergmann spu_acquire(ctx); 7958b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 7968b3d6663SArnd Bergmann spu_release(ctx); 79767207b96SArnd Bergmann } 79867207b96SArnd Bergmann 79967207b96SArnd Bergmann static u64 spufs_npc_get(void *data) 80067207b96SArnd Bergmann { 80167207b96SArnd Bergmann struct spu_context *ctx = data; 80267207b96SArnd Bergmann u64 ret; 8038b3d6663SArnd Bergmann spu_acquire(ctx); 8048b3d6663SArnd Bergmann ret = ctx->ops->npc_read(ctx); 8058b3d6663SArnd Bergmann spu_release(ctx); 80667207b96SArnd Bergmann return ret; 80767207b96SArnd Bergmann } 80867207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n") 80967207b96SArnd Bergmann 8108b3d6663SArnd Bergmann static void spufs_decr_set(void *data, u64 val) 8118b3d6663SArnd Bergmann { 8128b3d6663SArnd Bergmann struct spu_context *ctx = data; 8138b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 8148b3d6663SArnd Bergmann spu_acquire_saved(ctx); 8158b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 8168b3d6663SArnd Bergmann spu_release(ctx); 8178b3d6663SArnd Bergmann } 8188b3d6663SArnd Bergmann 8198b3d6663SArnd Bergmann static u64 spufs_decr_get(void *data) 8208b3d6663SArnd Bergmann { 8218b3d6663SArnd Bergmann struct spu_context *ctx = data; 8228b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 8238b3d6663SArnd Bergmann u64 ret; 8248b3d6663SArnd Bergmann spu_acquire_saved(ctx); 8258b3d6663SArnd Bergmann ret = lscsa->decr.slot[0]; 8268b3d6663SArnd Bergmann spu_release(ctx); 8278b3d6663SArnd Bergmann return ret; 8288b3d6663SArnd Bergmann } 8298b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 8308b3d6663SArnd Bergmann "%llx\n") 8318b3d6663SArnd Bergmann 8328b3d6663SArnd Bergmann static void spufs_decr_status_set(void *data, u64 val) 8338b3d6663SArnd Bergmann { 8348b3d6663SArnd Bergmann struct spu_context *ctx = data; 8358b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 8368b3d6663SArnd Bergmann spu_acquire_saved(ctx); 8378b3d6663SArnd Bergmann lscsa->decr_status.slot[0] = (u32) val; 8388b3d6663SArnd Bergmann spu_release(ctx); 8398b3d6663SArnd Bergmann } 8408b3d6663SArnd Bergmann 8418b3d6663SArnd Bergmann static u64 spufs_decr_status_get(void *data) 8428b3d6663SArnd Bergmann { 8438b3d6663SArnd Bergmann struct spu_context *ctx = data; 8448b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 8458b3d6663SArnd Bergmann u64 ret; 8468b3d6663SArnd Bergmann spu_acquire_saved(ctx); 8478b3d6663SArnd Bergmann ret = lscsa->decr_status.slot[0]; 8488b3d6663SArnd Bergmann spu_release(ctx); 8498b3d6663SArnd Bergmann return ret; 8508b3d6663SArnd Bergmann } 8518b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 8528b3d6663SArnd Bergmann spufs_decr_status_set, "%llx\n") 8538b3d6663SArnd Bergmann 8548b3d6663SArnd Bergmann static void spufs_spu_tag_mask_set(void *data, u64 val) 8558b3d6663SArnd Bergmann { 8568b3d6663SArnd Bergmann struct spu_context *ctx = data; 8578b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 8588b3d6663SArnd Bergmann spu_acquire_saved(ctx); 8598b3d6663SArnd Bergmann lscsa->tag_mask.slot[0] = (u32) val; 8608b3d6663SArnd Bergmann spu_release(ctx); 8618b3d6663SArnd Bergmann } 8628b3d6663SArnd Bergmann 8638b3d6663SArnd Bergmann static u64 spufs_spu_tag_mask_get(void *data) 8648b3d6663SArnd Bergmann { 8658b3d6663SArnd Bergmann struct spu_context *ctx = data; 8668b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 8678b3d6663SArnd Bergmann u64 ret; 8688b3d6663SArnd Bergmann spu_acquire_saved(ctx); 8698b3d6663SArnd Bergmann ret = lscsa->tag_mask.slot[0]; 8708b3d6663SArnd Bergmann spu_release(ctx); 8718b3d6663SArnd Bergmann return ret; 8728b3d6663SArnd Bergmann } 8738b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get, 8748b3d6663SArnd Bergmann spufs_spu_tag_mask_set, "%llx\n") 8758b3d6663SArnd Bergmann 8768b3d6663SArnd Bergmann static void spufs_event_mask_set(void *data, u64 val) 8778b3d6663SArnd Bergmann { 8788b3d6663SArnd Bergmann struct spu_context *ctx = data; 8798b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 8808b3d6663SArnd Bergmann spu_acquire_saved(ctx); 8818b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 8828b3d6663SArnd Bergmann spu_release(ctx); 8838b3d6663SArnd Bergmann } 8848b3d6663SArnd Bergmann 8858b3d6663SArnd Bergmann static u64 spufs_event_mask_get(void *data) 8868b3d6663SArnd Bergmann { 8878b3d6663SArnd Bergmann struct spu_context *ctx = data; 8888b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 8898b3d6663SArnd Bergmann u64 ret; 8908b3d6663SArnd Bergmann spu_acquire_saved(ctx); 8918b3d6663SArnd Bergmann ret = lscsa->event_mask.slot[0]; 8928b3d6663SArnd Bergmann spu_release(ctx); 8938b3d6663SArnd Bergmann return ret; 8948b3d6663SArnd Bergmann } 8958b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 8968b3d6663SArnd Bergmann spufs_event_mask_set, "%llx\n") 8978b3d6663SArnd Bergmann 8988b3d6663SArnd Bergmann static void spufs_srr0_set(void *data, u64 val) 8998b3d6663SArnd Bergmann { 9008b3d6663SArnd Bergmann struct spu_context *ctx = data; 9018b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 9028b3d6663SArnd Bergmann spu_acquire_saved(ctx); 9038b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 9048b3d6663SArnd Bergmann spu_release(ctx); 9058b3d6663SArnd Bergmann } 9068b3d6663SArnd Bergmann 9078b3d6663SArnd Bergmann static u64 spufs_srr0_get(void *data) 9088b3d6663SArnd Bergmann { 9098b3d6663SArnd Bergmann struct spu_context *ctx = data; 9108b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 9118b3d6663SArnd Bergmann u64 ret; 9128b3d6663SArnd Bergmann spu_acquire_saved(ctx); 9138b3d6663SArnd Bergmann ret = lscsa->srr0.slot[0]; 9148b3d6663SArnd Bergmann spu_release(ctx); 9158b3d6663SArnd Bergmann return ret; 9168b3d6663SArnd Bergmann } 9178b3d6663SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 9188b3d6663SArnd Bergmann "%llx\n") 9198b3d6663SArnd Bergmann 92067207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 92167207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 9228b3d6663SArnd Bergmann { "regs", &spufs_regs_fops, 0666, }, 92367207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 92467207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 92567207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 92667207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 92767207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 92867207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 92967207b96SArnd Bergmann { "signal1", &spufs_signal1_fops, 0666, }, 93067207b96SArnd Bergmann { "signal2", &spufs_signal2_fops, 0666, }, 93167207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 93267207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 93367207b96SArnd Bergmann { "npc", &spufs_npc_ops, 0666, }, 9348b3d6663SArnd Bergmann { "fpcr", &spufs_fpcr_fops, 0666, }, 9358b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 9368b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 9378b3d6663SArnd Bergmann { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, }, 9388b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 9398b3d6663SArnd Bergmann { "srr0", &spufs_srr0_ops, 0666, }, 94067207b96SArnd Bergmann {}, 94167207b96SArnd Bergmann }; 942