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> 2667207b96SArnd Bergmann #include <linux/poll.h> 2767207b96SArnd Bergmann 2867207b96SArnd Bergmann #include <asm/io.h> 2967207b96SArnd Bergmann #include <asm/semaphore.h> 3067207b96SArnd Bergmann #include <asm/spu.h> 3167207b96SArnd Bergmann #include <asm/uaccess.h> 3267207b96SArnd Bergmann 3367207b96SArnd Bergmann #include "spufs.h" 3467207b96SArnd Bergmann 3567207b96SArnd Bergmann static int 3667207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 3767207b96SArnd Bergmann { 3867207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 3967207b96SArnd Bergmann file->private_data = i->i_ctx; 4067207b96SArnd Bergmann return 0; 4167207b96SArnd Bergmann } 4267207b96SArnd Bergmann 4367207b96SArnd Bergmann static ssize_t 4467207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 4567207b96SArnd Bergmann size_t size, loff_t *pos) 4667207b96SArnd Bergmann { 4767207b96SArnd Bergmann struct spu *spu; 4867207b96SArnd Bergmann struct spu_context *ctx; 4967207b96SArnd Bergmann int ret; 5067207b96SArnd Bergmann 5167207b96SArnd Bergmann ctx = file->private_data; 5267207b96SArnd Bergmann spu = ctx->spu; 5367207b96SArnd Bergmann 5467207b96SArnd Bergmann down_read(&ctx->backing_sema); 5567207b96SArnd Bergmann if (spu->number & 0/*1*/) { 5667207b96SArnd Bergmann ret = generic_file_read(file, buffer, size, pos); 5767207b96SArnd Bergmann goto out; 5867207b96SArnd Bergmann } 5967207b96SArnd Bergmann 6067207b96SArnd Bergmann ret = simple_read_from_buffer(buffer, size, pos, 6167207b96SArnd Bergmann spu->local_store, LS_SIZE); 6267207b96SArnd Bergmann out: 6367207b96SArnd Bergmann up_read(&ctx->backing_sema); 6467207b96SArnd Bergmann return ret; 6567207b96SArnd Bergmann } 6667207b96SArnd Bergmann 6767207b96SArnd Bergmann static ssize_t 6867207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 6967207b96SArnd Bergmann size_t size, loff_t *pos) 7067207b96SArnd Bergmann { 7167207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 7267207b96SArnd Bergmann struct spu *spu = ctx->spu; 7367207b96SArnd Bergmann 7467207b96SArnd Bergmann if (spu->number & 0) //1) 7567207b96SArnd Bergmann return generic_file_write(file, buffer, size, pos); 7667207b96SArnd Bergmann 7767207b96SArnd Bergmann size = min_t(ssize_t, LS_SIZE - *pos, size); 7867207b96SArnd Bergmann if (size <= 0) 7967207b96SArnd Bergmann return -EFBIG; 8067207b96SArnd Bergmann *pos += size; 8167207b96SArnd Bergmann return copy_from_user(spu->local_store + *pos - size, 8267207b96SArnd Bergmann buffer, size) ? -EFAULT : size; 8367207b96SArnd Bergmann } 8467207b96SArnd Bergmann 8567207b96SArnd Bergmann static int 8667207b96SArnd Bergmann spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 8767207b96SArnd Bergmann { 8867207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 8967207b96SArnd Bergmann struct spu *spu = ctx->spu; 9067207b96SArnd Bergmann unsigned long pfn; 9167207b96SArnd Bergmann 9267207b96SArnd Bergmann if (spu->number & 0) //1) 9367207b96SArnd Bergmann return generic_file_mmap(file, vma); 9467207b96SArnd Bergmann 9567207b96SArnd Bergmann vma->vm_flags |= VM_RESERVED; 9667207b96SArnd Bergmann vma->vm_page_prot = __pgprot(pgprot_val (vma->vm_page_prot) 9767207b96SArnd Bergmann | _PAGE_NO_CACHE); 9867207b96SArnd Bergmann pfn = spu->local_store_phys >> PAGE_SHIFT; 9967207b96SArnd Bergmann /* 10067207b96SArnd Bergmann * This will work for actual SPUs, but not for vmalloc memory: 10167207b96SArnd Bergmann */ 10267207b96SArnd Bergmann if (remap_pfn_range(vma, vma->vm_start, pfn, 10367207b96SArnd Bergmann vma->vm_end-vma->vm_start, vma->vm_page_prot)) 10467207b96SArnd Bergmann return -EAGAIN; 10567207b96SArnd Bergmann return 0; 10667207b96SArnd Bergmann } 10767207b96SArnd Bergmann 10867207b96SArnd Bergmann static struct file_operations spufs_mem_fops = { 10967207b96SArnd Bergmann .open = spufs_mem_open, 11067207b96SArnd Bergmann .read = spufs_mem_read, 11167207b96SArnd Bergmann .write = spufs_mem_write, 11267207b96SArnd Bergmann .mmap = spufs_mem_mmap, 11367207b96SArnd Bergmann .llseek = generic_file_llseek, 11467207b96SArnd Bergmann }; 11567207b96SArnd Bergmann 11667207b96SArnd Bergmann /* generic open function for all pipe-like files */ 11767207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 11867207b96SArnd Bergmann { 11967207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 12067207b96SArnd Bergmann file->private_data = i->i_ctx; 12167207b96SArnd Bergmann 12267207b96SArnd Bergmann return nonseekable_open(inode, file); 12367207b96SArnd Bergmann } 12467207b96SArnd Bergmann 12567207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 12667207b96SArnd Bergmann size_t len, loff_t *pos) 12767207b96SArnd Bergmann { 12867207b96SArnd Bergmann struct spu_context *ctx; 12967207b96SArnd Bergmann struct spu_problem __iomem *prob; 13067207b96SArnd Bergmann u32 mbox_stat; 13167207b96SArnd Bergmann u32 mbox_data; 13267207b96SArnd Bergmann 13367207b96SArnd Bergmann if (len < 4) 13467207b96SArnd Bergmann return -EINVAL; 13567207b96SArnd Bergmann 13667207b96SArnd Bergmann ctx = file->private_data; 13767207b96SArnd Bergmann prob = ctx->spu->problem; 13867207b96SArnd Bergmann mbox_stat = in_be32(&prob->mb_stat_R); 13967207b96SArnd Bergmann if (!(mbox_stat & 0x0000ff)) 14067207b96SArnd Bergmann return -EAGAIN; 14167207b96SArnd Bergmann 14267207b96SArnd Bergmann mbox_data = in_be32(&prob->pu_mb_R); 14367207b96SArnd Bergmann 14467207b96SArnd Bergmann if (copy_to_user(buf, &mbox_data, sizeof mbox_data)) 14567207b96SArnd Bergmann return -EFAULT; 14667207b96SArnd Bergmann 14767207b96SArnd Bergmann return 4; 14867207b96SArnd Bergmann } 14967207b96SArnd Bergmann 15067207b96SArnd Bergmann static struct file_operations spufs_mbox_fops = { 15167207b96SArnd Bergmann .open = spufs_pipe_open, 15267207b96SArnd Bergmann .read = spufs_mbox_read, 15367207b96SArnd Bergmann }; 15467207b96SArnd Bergmann 15567207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 15667207b96SArnd Bergmann size_t len, loff_t *pos) 15767207b96SArnd Bergmann { 15867207b96SArnd Bergmann struct spu_context *ctx; 15967207b96SArnd Bergmann u32 mbox_stat; 16067207b96SArnd Bergmann 16167207b96SArnd Bergmann if (len < 4) 16267207b96SArnd Bergmann return -EINVAL; 16367207b96SArnd Bergmann 16467207b96SArnd Bergmann ctx = file->private_data; 16567207b96SArnd Bergmann mbox_stat = in_be32(&ctx->spu->problem->mb_stat_R) & 0xff; 16667207b96SArnd Bergmann 16767207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 16867207b96SArnd Bergmann return -EFAULT; 16967207b96SArnd Bergmann 17067207b96SArnd Bergmann return 4; 17167207b96SArnd Bergmann } 17267207b96SArnd Bergmann 17367207b96SArnd Bergmann static struct file_operations spufs_mbox_stat_fops = { 17467207b96SArnd Bergmann .open = spufs_pipe_open, 17567207b96SArnd Bergmann .read = spufs_mbox_stat_read, 17667207b96SArnd Bergmann }; 17767207b96SArnd Bergmann 17867207b96SArnd Bergmann /* low-level ibox access function */ 17967207b96SArnd Bergmann size_t spu_ibox_read(struct spu *spu, u32 *data) 18067207b96SArnd Bergmann { 18167207b96SArnd Bergmann int ret; 18267207b96SArnd Bergmann 18367207b96SArnd Bergmann spin_lock_irq(&spu->register_lock); 18467207b96SArnd Bergmann 18567207b96SArnd Bergmann if (in_be32(&spu->problem->mb_stat_R) & 0xff0000) { 18667207b96SArnd Bergmann /* read the first available word */ 18767207b96SArnd Bergmann *data = in_be64(&spu->priv2->puint_mb_R); 18867207b96SArnd Bergmann ret = 4; 18967207b96SArnd Bergmann } else { 19067207b96SArnd Bergmann /* make sure we get woken up by the interrupt */ 19167207b96SArnd Bergmann out_be64(&spu->priv1->int_mask_class2_RW, 19267207b96SArnd Bergmann in_be64(&spu->priv1->int_mask_class2_RW) | 0x1); 19367207b96SArnd Bergmann ret = 0; 19467207b96SArnd Bergmann } 19567207b96SArnd Bergmann 19667207b96SArnd Bergmann spin_unlock_irq(&spu->register_lock); 19767207b96SArnd Bergmann return ret; 19867207b96SArnd Bergmann } 19967207b96SArnd Bergmann EXPORT_SYMBOL(spu_ibox_read); 20067207b96SArnd Bergmann 20167207b96SArnd Bergmann static int spufs_ibox_fasync(int fd, struct file *file, int on) 20267207b96SArnd Bergmann { 20367207b96SArnd Bergmann struct spu_context *ctx; 20467207b96SArnd Bergmann ctx = file->private_data; 20567207b96SArnd Bergmann return fasync_helper(fd, file, on, &ctx->spu->ibox_fasync); 20667207b96SArnd Bergmann } 20767207b96SArnd Bergmann 20867207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 20967207b96SArnd Bergmann size_t len, loff_t *pos) 21067207b96SArnd Bergmann { 21167207b96SArnd Bergmann struct spu_context *ctx; 21267207b96SArnd Bergmann u32 ibox_data; 21367207b96SArnd Bergmann ssize_t ret; 21467207b96SArnd Bergmann 21567207b96SArnd Bergmann if (len < 4) 21667207b96SArnd Bergmann return -EINVAL; 21767207b96SArnd Bergmann 21867207b96SArnd Bergmann ctx = file->private_data; 21967207b96SArnd Bergmann 22067207b96SArnd Bergmann ret = 0; 22167207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 22267207b96SArnd Bergmann if (!spu_ibox_read(ctx->spu, &ibox_data)) 22367207b96SArnd Bergmann ret = -EAGAIN; 22467207b96SArnd Bergmann } else { 22567207b96SArnd Bergmann ret = wait_event_interruptible(ctx->spu->ibox_wq, 22667207b96SArnd Bergmann spu_ibox_read(ctx->spu, &ibox_data)); 22767207b96SArnd Bergmann } 22867207b96SArnd Bergmann 22967207b96SArnd Bergmann if (ret) 23067207b96SArnd Bergmann return ret; 23167207b96SArnd Bergmann 23267207b96SArnd Bergmann ret = 4; 23367207b96SArnd Bergmann if (copy_to_user(buf, &ibox_data, sizeof ibox_data)) 23467207b96SArnd Bergmann ret = -EFAULT; 23567207b96SArnd Bergmann 23667207b96SArnd Bergmann return ret; 23767207b96SArnd Bergmann } 23867207b96SArnd Bergmann 23967207b96SArnd Bergmann static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 24067207b96SArnd Bergmann { 24167207b96SArnd Bergmann struct spu_context *ctx; 24267207b96SArnd Bergmann struct spu_problem __iomem *prob; 24367207b96SArnd Bergmann u32 mbox_stat; 24467207b96SArnd Bergmann unsigned int mask; 24567207b96SArnd Bergmann 24667207b96SArnd Bergmann ctx = file->private_data; 24767207b96SArnd Bergmann prob = ctx->spu->problem; 24867207b96SArnd Bergmann mbox_stat = in_be32(&prob->mb_stat_R); 24967207b96SArnd Bergmann 25067207b96SArnd Bergmann poll_wait(file, &ctx->spu->ibox_wq, wait); 25167207b96SArnd Bergmann 25267207b96SArnd Bergmann mask = 0; 25367207b96SArnd Bergmann if (mbox_stat & 0xff0000) 25467207b96SArnd Bergmann mask |= POLLIN | POLLRDNORM; 25567207b96SArnd Bergmann 25667207b96SArnd Bergmann return mask; 25767207b96SArnd Bergmann } 25867207b96SArnd Bergmann 25967207b96SArnd Bergmann static struct file_operations spufs_ibox_fops = { 26067207b96SArnd Bergmann .open = spufs_pipe_open, 26167207b96SArnd Bergmann .read = spufs_ibox_read, 26267207b96SArnd Bergmann .poll = spufs_ibox_poll, 26367207b96SArnd Bergmann .fasync = spufs_ibox_fasync, 26467207b96SArnd Bergmann }; 26567207b96SArnd Bergmann 26667207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 26767207b96SArnd Bergmann size_t len, loff_t *pos) 26867207b96SArnd Bergmann { 26967207b96SArnd Bergmann struct spu_context *ctx; 27067207b96SArnd Bergmann u32 ibox_stat; 27167207b96SArnd Bergmann 27267207b96SArnd Bergmann if (len < 4) 27367207b96SArnd Bergmann return -EINVAL; 27467207b96SArnd Bergmann 27567207b96SArnd Bergmann ctx = file->private_data; 27667207b96SArnd Bergmann ibox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 16) & 0xff; 27767207b96SArnd Bergmann 27867207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 27967207b96SArnd Bergmann return -EFAULT; 28067207b96SArnd Bergmann 28167207b96SArnd Bergmann return 4; 28267207b96SArnd Bergmann } 28367207b96SArnd Bergmann 28467207b96SArnd Bergmann static struct file_operations spufs_ibox_stat_fops = { 28567207b96SArnd Bergmann .open = spufs_pipe_open, 28667207b96SArnd Bergmann .read = spufs_ibox_stat_read, 28767207b96SArnd Bergmann }; 28867207b96SArnd Bergmann 28967207b96SArnd Bergmann /* low-level mailbox write */ 29067207b96SArnd Bergmann size_t spu_wbox_write(struct spu *spu, u32 data) 29167207b96SArnd Bergmann { 29267207b96SArnd Bergmann int ret; 29367207b96SArnd Bergmann 29467207b96SArnd Bergmann spin_lock_irq(&spu->register_lock); 29567207b96SArnd Bergmann 29667207b96SArnd Bergmann if (in_be32(&spu->problem->mb_stat_R) & 0x00ff00) { 29767207b96SArnd Bergmann /* we have space to write wbox_data to */ 29867207b96SArnd Bergmann out_be32(&spu->problem->spu_mb_W, data); 29967207b96SArnd Bergmann ret = 4; 30067207b96SArnd Bergmann } else { 30167207b96SArnd Bergmann /* make sure we get woken up by the interrupt when space 30267207b96SArnd Bergmann becomes available */ 30367207b96SArnd Bergmann out_be64(&spu->priv1->int_mask_class2_RW, 30467207b96SArnd Bergmann in_be64(&spu->priv1->int_mask_class2_RW) | 0x10); 30567207b96SArnd Bergmann ret = 0; 30667207b96SArnd Bergmann } 30767207b96SArnd Bergmann 30867207b96SArnd Bergmann spin_unlock_irq(&spu->register_lock); 30967207b96SArnd Bergmann return ret; 31067207b96SArnd Bergmann } 31167207b96SArnd Bergmann EXPORT_SYMBOL(spu_wbox_write); 31267207b96SArnd Bergmann 31367207b96SArnd Bergmann static int spufs_wbox_fasync(int fd, struct file *file, int on) 31467207b96SArnd Bergmann { 31567207b96SArnd Bergmann struct spu_context *ctx; 31667207b96SArnd Bergmann ctx = file->private_data; 31767207b96SArnd Bergmann return fasync_helper(fd, file, on, &ctx->spu->wbox_fasync); 31867207b96SArnd Bergmann } 31967207b96SArnd Bergmann 32067207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 32167207b96SArnd Bergmann size_t len, loff_t *pos) 32267207b96SArnd Bergmann { 32367207b96SArnd Bergmann struct spu_context *ctx; 32467207b96SArnd Bergmann u32 wbox_data; 32567207b96SArnd Bergmann int ret; 32667207b96SArnd Bergmann 32767207b96SArnd Bergmann if (len < 4) 32867207b96SArnd Bergmann return -EINVAL; 32967207b96SArnd Bergmann 33067207b96SArnd Bergmann ctx = file->private_data; 33167207b96SArnd Bergmann 33267207b96SArnd Bergmann if (copy_from_user(&wbox_data, buf, sizeof wbox_data)) 33367207b96SArnd Bergmann return -EFAULT; 33467207b96SArnd Bergmann 33567207b96SArnd Bergmann ret = 0; 33667207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 33767207b96SArnd Bergmann if (!spu_wbox_write(ctx->spu, wbox_data)) 33867207b96SArnd Bergmann ret = -EAGAIN; 33967207b96SArnd Bergmann } else { 34067207b96SArnd Bergmann ret = wait_event_interruptible(ctx->spu->wbox_wq, 34167207b96SArnd Bergmann spu_wbox_write(ctx->spu, wbox_data)); 34267207b96SArnd Bergmann } 34367207b96SArnd Bergmann 34467207b96SArnd Bergmann return ret ? ret : sizeof wbox_data; 34567207b96SArnd Bergmann } 34667207b96SArnd Bergmann 34767207b96SArnd Bergmann static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 34867207b96SArnd Bergmann { 34967207b96SArnd Bergmann struct spu_context *ctx; 35067207b96SArnd Bergmann struct spu_problem __iomem *prob; 35167207b96SArnd Bergmann u32 mbox_stat; 35267207b96SArnd Bergmann unsigned int mask; 35367207b96SArnd Bergmann 35467207b96SArnd Bergmann ctx = file->private_data; 35567207b96SArnd Bergmann prob = ctx->spu->problem; 35667207b96SArnd Bergmann mbox_stat = in_be32(&prob->mb_stat_R); 35767207b96SArnd Bergmann 35867207b96SArnd Bergmann poll_wait(file, &ctx->spu->wbox_wq, wait); 35967207b96SArnd Bergmann 36067207b96SArnd Bergmann mask = 0; 36167207b96SArnd Bergmann if (mbox_stat & 0x00ff00) 36267207b96SArnd Bergmann mask = POLLOUT | POLLWRNORM; 36367207b96SArnd Bergmann 36467207b96SArnd Bergmann return mask; 36567207b96SArnd Bergmann } 36667207b96SArnd Bergmann 36767207b96SArnd Bergmann static struct file_operations spufs_wbox_fops = { 36867207b96SArnd Bergmann .open = spufs_pipe_open, 36967207b96SArnd Bergmann .write = spufs_wbox_write, 37067207b96SArnd Bergmann .poll = spufs_wbox_poll, 37167207b96SArnd Bergmann .fasync = spufs_wbox_fasync, 37267207b96SArnd Bergmann }; 37367207b96SArnd Bergmann 37467207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 37567207b96SArnd Bergmann size_t len, loff_t *pos) 37667207b96SArnd Bergmann { 37767207b96SArnd Bergmann struct spu_context *ctx; 37867207b96SArnd Bergmann u32 wbox_stat; 37967207b96SArnd Bergmann 38067207b96SArnd Bergmann if (len < 4) 38167207b96SArnd Bergmann return -EINVAL; 38267207b96SArnd Bergmann 38367207b96SArnd Bergmann ctx = file->private_data; 38467207b96SArnd Bergmann wbox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 8) & 0xff; 38567207b96SArnd Bergmann 38667207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 38767207b96SArnd Bergmann return -EFAULT; 38867207b96SArnd Bergmann 38967207b96SArnd Bergmann return 4; 39067207b96SArnd Bergmann } 39167207b96SArnd Bergmann 39267207b96SArnd Bergmann static struct file_operations spufs_wbox_stat_fops = { 39367207b96SArnd Bergmann .open = spufs_pipe_open, 39467207b96SArnd Bergmann .read = spufs_wbox_stat_read, 39567207b96SArnd Bergmann }; 39667207b96SArnd Bergmann 39767207b96SArnd Bergmann long spufs_run_spu(struct file *file, struct spu_context *ctx, 39867207b96SArnd Bergmann u32 *npc, u32 *status) 39967207b96SArnd Bergmann { 40067207b96SArnd Bergmann struct spu_problem __iomem *prob; 40167207b96SArnd Bergmann int ret; 40267207b96SArnd Bergmann 40367207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 40467207b96SArnd Bergmann ret = -EAGAIN; 40567207b96SArnd Bergmann if (!down_write_trylock(&ctx->backing_sema)) 40667207b96SArnd Bergmann goto out; 40767207b96SArnd Bergmann } else { 40867207b96SArnd Bergmann down_write(&ctx->backing_sema); 40967207b96SArnd Bergmann } 41067207b96SArnd Bergmann 41167207b96SArnd Bergmann prob = ctx->spu->problem; 41267207b96SArnd Bergmann out_be32(&prob->spu_npc_RW, *npc); 41367207b96SArnd Bergmann 41467207b96SArnd Bergmann ret = spu_run(ctx->spu); 41567207b96SArnd Bergmann 41667207b96SArnd Bergmann *status = in_be32(&prob->spu_status_R); 41767207b96SArnd Bergmann *npc = in_be32(&prob->spu_npc_RW); 41867207b96SArnd Bergmann 41967207b96SArnd Bergmann up_write(&ctx->backing_sema); 42067207b96SArnd Bergmann 42167207b96SArnd Bergmann out: 42267207b96SArnd Bergmann return ret; 42367207b96SArnd Bergmann } 42467207b96SArnd Bergmann 42567207b96SArnd Bergmann static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 42667207b96SArnd Bergmann size_t len, loff_t *pos) 42767207b96SArnd Bergmann { 42867207b96SArnd Bergmann struct spu_context *ctx; 42967207b96SArnd Bergmann struct spu_problem *prob; 43067207b96SArnd Bergmann u32 data; 43167207b96SArnd Bergmann 43267207b96SArnd Bergmann ctx = file->private_data; 43367207b96SArnd Bergmann prob = ctx->spu->problem; 43467207b96SArnd Bergmann 43567207b96SArnd Bergmann if (len < 4) 43667207b96SArnd Bergmann return -EINVAL; 43767207b96SArnd Bergmann 43867207b96SArnd Bergmann data = in_be32(&prob->signal_notify1); 43967207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 44067207b96SArnd Bergmann return -EFAULT; 44167207b96SArnd Bergmann 44267207b96SArnd Bergmann return 4; 44367207b96SArnd Bergmann } 44467207b96SArnd Bergmann 44567207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 44667207b96SArnd Bergmann size_t len, loff_t *pos) 44767207b96SArnd Bergmann { 44867207b96SArnd Bergmann struct spu_context *ctx; 44967207b96SArnd Bergmann struct spu_problem *prob; 45067207b96SArnd Bergmann u32 data; 45167207b96SArnd Bergmann 45267207b96SArnd Bergmann ctx = file->private_data; 45367207b96SArnd Bergmann prob = ctx->spu->problem; 45467207b96SArnd Bergmann 45567207b96SArnd Bergmann if (len < 4) 45667207b96SArnd Bergmann return -EINVAL; 45767207b96SArnd Bergmann 45867207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 45967207b96SArnd Bergmann return -EFAULT; 46067207b96SArnd Bergmann 46167207b96SArnd Bergmann out_be32(&prob->signal_notify1, data); 46267207b96SArnd Bergmann 46367207b96SArnd Bergmann return 4; 46467207b96SArnd Bergmann } 46567207b96SArnd Bergmann 46667207b96SArnd Bergmann static struct file_operations spufs_signal1_fops = { 46767207b96SArnd Bergmann .open = spufs_pipe_open, 46867207b96SArnd Bergmann .read = spufs_signal1_read, 46967207b96SArnd Bergmann .write = spufs_signal1_write, 47067207b96SArnd Bergmann }; 47167207b96SArnd Bergmann 47267207b96SArnd Bergmann static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 47367207b96SArnd Bergmann size_t len, loff_t *pos) 47467207b96SArnd Bergmann { 47567207b96SArnd Bergmann struct spu_context *ctx; 47667207b96SArnd Bergmann struct spu_problem *prob; 47767207b96SArnd Bergmann u32 data; 47867207b96SArnd Bergmann 47967207b96SArnd Bergmann ctx = file->private_data; 48067207b96SArnd Bergmann prob = ctx->spu->problem; 48167207b96SArnd Bergmann 48267207b96SArnd Bergmann if (len < 4) 48367207b96SArnd Bergmann return -EINVAL; 48467207b96SArnd Bergmann 48567207b96SArnd Bergmann data = in_be32(&prob->signal_notify2); 48667207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 48767207b96SArnd Bergmann return -EFAULT; 48867207b96SArnd Bergmann 48967207b96SArnd Bergmann return 4; 49067207b96SArnd Bergmann } 49167207b96SArnd Bergmann 49267207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 49367207b96SArnd Bergmann size_t len, loff_t *pos) 49467207b96SArnd Bergmann { 49567207b96SArnd Bergmann struct spu_context *ctx; 49667207b96SArnd Bergmann struct spu_problem *prob; 49767207b96SArnd Bergmann u32 data; 49867207b96SArnd Bergmann 49967207b96SArnd Bergmann ctx = file->private_data; 50067207b96SArnd Bergmann prob = ctx->spu->problem; 50167207b96SArnd Bergmann 50267207b96SArnd Bergmann if (len < 4) 50367207b96SArnd Bergmann return -EINVAL; 50467207b96SArnd Bergmann 50567207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 50667207b96SArnd Bergmann return -EFAULT; 50767207b96SArnd Bergmann 50867207b96SArnd Bergmann out_be32(&prob->signal_notify2, data); 50967207b96SArnd Bergmann 51067207b96SArnd Bergmann return 4; 51167207b96SArnd Bergmann } 51267207b96SArnd Bergmann 51367207b96SArnd Bergmann static struct file_operations spufs_signal2_fops = { 51467207b96SArnd Bergmann .open = spufs_pipe_open, 51567207b96SArnd Bergmann .read = spufs_signal2_read, 51667207b96SArnd Bergmann .write = spufs_signal2_write, 51767207b96SArnd Bergmann }; 51867207b96SArnd Bergmann 51967207b96SArnd Bergmann static void spufs_signal1_type_set(void *data, u64 val) 52067207b96SArnd Bergmann { 52167207b96SArnd Bergmann struct spu_context *ctx = data; 52267207b96SArnd Bergmann struct spu_priv2 *priv2 = ctx->spu->priv2; 52367207b96SArnd Bergmann u64 tmp; 52467207b96SArnd Bergmann 52567207b96SArnd Bergmann spin_lock_irq(&ctx->spu->register_lock); 52667207b96SArnd Bergmann tmp = in_be64(&priv2->spu_cfg_RW); 52767207b96SArnd Bergmann if (val) 52867207b96SArnd Bergmann tmp |= 1; 52967207b96SArnd Bergmann else 53067207b96SArnd Bergmann tmp &= ~1; 53167207b96SArnd Bergmann out_be64(&priv2->spu_cfg_RW, tmp); 53267207b96SArnd Bergmann spin_unlock_irq(&ctx->spu->register_lock); 53367207b96SArnd Bergmann } 53467207b96SArnd Bergmann 53567207b96SArnd Bergmann static u64 spufs_signal1_type_get(void *data) 53667207b96SArnd Bergmann { 53767207b96SArnd Bergmann struct spu_context *ctx = data; 53867207b96SArnd Bergmann return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0; 53967207b96SArnd Bergmann } 54067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 54167207b96SArnd Bergmann spufs_signal1_type_set, "%llu"); 54267207b96SArnd Bergmann 54367207b96SArnd Bergmann static void spufs_signal2_type_set(void *data, u64 val) 54467207b96SArnd Bergmann { 54567207b96SArnd Bergmann struct spu_context *ctx = data; 54667207b96SArnd Bergmann struct spu_priv2 *priv2 = ctx->spu->priv2; 54767207b96SArnd Bergmann u64 tmp; 54867207b96SArnd Bergmann 54967207b96SArnd Bergmann spin_lock_irq(&ctx->spu->register_lock); 55067207b96SArnd Bergmann tmp = in_be64(&priv2->spu_cfg_RW); 55167207b96SArnd Bergmann if (val) 55267207b96SArnd Bergmann tmp |= 2; 55367207b96SArnd Bergmann else 55467207b96SArnd Bergmann tmp &= ~2; 55567207b96SArnd Bergmann out_be64(&priv2->spu_cfg_RW, tmp); 55667207b96SArnd Bergmann spin_unlock_irq(&ctx->spu->register_lock); 55767207b96SArnd Bergmann } 55867207b96SArnd Bergmann 55967207b96SArnd Bergmann static u64 spufs_signal2_type_get(void *data) 56067207b96SArnd Bergmann { 56167207b96SArnd Bergmann struct spu_context *ctx = data; 56267207b96SArnd Bergmann return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0; 56367207b96SArnd Bergmann } 56467207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 56567207b96SArnd Bergmann spufs_signal2_type_set, "%llu"); 56667207b96SArnd Bergmann 56767207b96SArnd Bergmann static void spufs_npc_set(void *data, u64 val) 56867207b96SArnd Bergmann { 56967207b96SArnd Bergmann struct spu_context *ctx = data; 57067207b96SArnd Bergmann out_be32(&ctx->spu->problem->spu_npc_RW, val); 57167207b96SArnd Bergmann } 57267207b96SArnd Bergmann 57367207b96SArnd Bergmann static u64 spufs_npc_get(void *data) 57467207b96SArnd Bergmann { 57567207b96SArnd Bergmann struct spu_context *ctx = data; 57667207b96SArnd Bergmann u64 ret; 57767207b96SArnd Bergmann ret = in_be32(&ctx->spu->problem->spu_npc_RW); 57867207b96SArnd Bergmann return ret; 57967207b96SArnd Bergmann } 58067207b96SArnd Bergmann DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n") 58167207b96SArnd Bergmann 58267207b96SArnd Bergmann struct tree_descr spufs_dir_contents[] = { 58367207b96SArnd Bergmann { "mem", &spufs_mem_fops, 0666, }, 58467207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 58567207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 58667207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 58767207b96SArnd Bergmann { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 58867207b96SArnd Bergmann { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 58967207b96SArnd Bergmann { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 59067207b96SArnd Bergmann { "signal1", &spufs_signal1_fops, 0666, }, 59167207b96SArnd Bergmann { "signal2", &spufs_signal2_fops, 0666, }, 59267207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 59367207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 59467207b96SArnd Bergmann { "npc", &spufs_npc_ops, 0666, }, 59567207b96SArnd Bergmann {}, 59667207b96SArnd Bergmann }; 597