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> 274b16f8e2SPaul Gortmaker #include <linux/export.h> 28d88cfffaSArnd Bergmann #include <linux/pagemap.h> 2967207b96SArnd Bergmann #include <linux/poll.h> 305110459fSArnd Bergmann #include <linux/ptrace.h> 31cbe709c1SBenjamin Herrenschmidt #include <linux/seq_file.h> 325a0e3ad6STejun Heo #include <linux/slab.h> 3367207b96SArnd Bergmann 3467207b96SArnd Bergmann #include <asm/io.h> 35dfe1e09fSFUJITA Tomonori #include <asm/time.h> 3667207b96SArnd Bergmann #include <asm/spu.h> 37b9e3bd77SDwayne Grant McConnell #include <asm/spu_info.h> 387c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 3967207b96SArnd Bergmann 4067207b96SArnd Bergmann #include "spufs.h" 41ae142e0cSChristoph Hellwig #include "sputrace.h" 4267207b96SArnd Bergmann 4327d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 4427d5bf2aSBenjamin Herrenschmidt 45197b1a82SChristoph Hellwig /* Simple attribute files */ 46197b1a82SChristoph Hellwig struct spufs_attr { 47197b1a82SChristoph Hellwig int (*get)(void *, u64 *); 48197b1a82SChristoph Hellwig int (*set)(void *, u64); 49197b1a82SChristoph Hellwig char get_buf[24]; /* enough to store a u64 and "\n\0" */ 50197b1a82SChristoph Hellwig char set_buf[24]; 51197b1a82SChristoph Hellwig void *data; 52197b1a82SChristoph Hellwig const char *fmt; /* format for read operation */ 53197b1a82SChristoph Hellwig struct mutex mutex; /* protects access to these buffers */ 54197b1a82SChristoph Hellwig }; 55197b1a82SChristoph Hellwig 56197b1a82SChristoph Hellwig static int spufs_attr_open(struct inode *inode, struct file *file, 57197b1a82SChristoph Hellwig int (*get)(void *, u64 *), int (*set)(void *, u64), 58197b1a82SChristoph Hellwig const char *fmt) 59197b1a82SChristoph Hellwig { 60197b1a82SChristoph Hellwig struct spufs_attr *attr; 61197b1a82SChristoph Hellwig 62197b1a82SChristoph Hellwig attr = kmalloc(sizeof(*attr), GFP_KERNEL); 63197b1a82SChristoph Hellwig if (!attr) 64197b1a82SChristoph Hellwig return -ENOMEM; 65197b1a82SChristoph Hellwig 66197b1a82SChristoph Hellwig attr->get = get; 67197b1a82SChristoph Hellwig attr->set = set; 68197b1a82SChristoph Hellwig attr->data = inode->i_private; 69197b1a82SChristoph Hellwig attr->fmt = fmt; 70197b1a82SChristoph Hellwig mutex_init(&attr->mutex); 71197b1a82SChristoph Hellwig file->private_data = attr; 72197b1a82SChristoph Hellwig 73197b1a82SChristoph Hellwig return nonseekable_open(inode, file); 74197b1a82SChristoph Hellwig } 75197b1a82SChristoph Hellwig 76197b1a82SChristoph Hellwig static int spufs_attr_release(struct inode *inode, struct file *file) 77197b1a82SChristoph Hellwig { 78197b1a82SChristoph Hellwig kfree(file->private_data); 79197b1a82SChristoph Hellwig return 0; 80197b1a82SChristoph Hellwig } 81197b1a82SChristoph Hellwig 82197b1a82SChristoph Hellwig static ssize_t spufs_attr_read(struct file *file, char __user *buf, 83197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 84197b1a82SChristoph Hellwig { 85197b1a82SChristoph Hellwig struct spufs_attr *attr; 86197b1a82SChristoph Hellwig size_t size; 87197b1a82SChristoph Hellwig ssize_t ret; 88197b1a82SChristoph Hellwig 89197b1a82SChristoph Hellwig attr = file->private_data; 90197b1a82SChristoph Hellwig if (!attr->get) 91197b1a82SChristoph Hellwig return -EACCES; 92197b1a82SChristoph Hellwig 93197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 94197b1a82SChristoph Hellwig if (ret) 95197b1a82SChristoph Hellwig return ret; 96197b1a82SChristoph Hellwig 97197b1a82SChristoph Hellwig if (*ppos) { /* continued read */ 98197b1a82SChristoph Hellwig size = strlen(attr->get_buf); 99197b1a82SChristoph Hellwig } else { /* first read */ 100197b1a82SChristoph Hellwig u64 val; 101197b1a82SChristoph Hellwig ret = attr->get(attr->data, &val); 102197b1a82SChristoph Hellwig if (ret) 103197b1a82SChristoph Hellwig goto out; 104197b1a82SChristoph Hellwig 105197b1a82SChristoph Hellwig size = scnprintf(attr->get_buf, sizeof(attr->get_buf), 106197b1a82SChristoph Hellwig attr->fmt, (unsigned long long)val); 107197b1a82SChristoph Hellwig } 108197b1a82SChristoph Hellwig 109197b1a82SChristoph Hellwig ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); 110197b1a82SChristoph Hellwig out: 111197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 112197b1a82SChristoph Hellwig return ret; 113197b1a82SChristoph Hellwig } 114197b1a82SChristoph Hellwig 115197b1a82SChristoph Hellwig static ssize_t spufs_attr_write(struct file *file, const char __user *buf, 116197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 117197b1a82SChristoph Hellwig { 118197b1a82SChristoph Hellwig struct spufs_attr *attr; 119197b1a82SChristoph Hellwig u64 val; 120197b1a82SChristoph Hellwig size_t size; 121197b1a82SChristoph Hellwig ssize_t ret; 122197b1a82SChristoph Hellwig 123197b1a82SChristoph Hellwig attr = file->private_data; 124197b1a82SChristoph Hellwig if (!attr->set) 125197b1a82SChristoph Hellwig return -EACCES; 126197b1a82SChristoph Hellwig 127197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 128197b1a82SChristoph Hellwig if (ret) 129197b1a82SChristoph Hellwig return ret; 130197b1a82SChristoph Hellwig 131197b1a82SChristoph Hellwig ret = -EFAULT; 132197b1a82SChristoph Hellwig size = min(sizeof(attr->set_buf) - 1, len); 133197b1a82SChristoph Hellwig if (copy_from_user(attr->set_buf, buf, size)) 134197b1a82SChristoph Hellwig goto out; 135197b1a82SChristoph Hellwig 136197b1a82SChristoph Hellwig ret = len; /* claim we got the whole input */ 137197b1a82SChristoph Hellwig attr->set_buf[size] = '\0'; 138197b1a82SChristoph Hellwig val = simple_strtol(attr->set_buf, NULL, 0); 139197b1a82SChristoph Hellwig attr->set(attr->data, val); 140197b1a82SChristoph Hellwig out: 141197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 142197b1a82SChristoph Hellwig return ret; 143197b1a82SChristoph Hellwig } 144197b1a82SChristoph Hellwig 145197b1a82SChristoph Hellwig #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ 146197b1a82SChristoph Hellwig static int __fops ## _open(struct inode *inode, struct file *file) \ 147197b1a82SChristoph Hellwig { \ 148197b1a82SChristoph Hellwig __simple_attr_check_format(__fmt, 0ull); \ 149197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, __get, __set, __fmt); \ 150197b1a82SChristoph Hellwig } \ 151828c0950SAlexey Dobriyan static const struct file_operations __fops = { \ 152197b1a82SChristoph Hellwig .open = __fops ## _open, \ 153197b1a82SChristoph Hellwig .release = spufs_attr_release, \ 154197b1a82SChristoph Hellwig .read = spufs_attr_read, \ 155197b1a82SChristoph Hellwig .write = spufs_attr_write, \ 156fc15351dSArnd Bergmann .llseek = generic_file_llseek, \ 157197b1a82SChristoph Hellwig }; 158197b1a82SChristoph Hellwig 159cbe709c1SBenjamin Herrenschmidt 16067207b96SArnd Bergmann static int 16167207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 16267207b96SArnd Bergmann { 16367207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1646df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 16543c2bbd9SChristoph Hellwig 16647d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1676df10a82SMark Nutter file->private_data = ctx; 16843c2bbd9SChristoph Hellwig if (!i->i_openers++) 1696df10a82SMark Nutter ctx->local_store = inode->i_mapping; 17047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 17143c2bbd9SChristoph Hellwig return 0; 17243c2bbd9SChristoph Hellwig } 17343c2bbd9SChristoph Hellwig 17443c2bbd9SChristoph Hellwig static int 17543c2bbd9SChristoph Hellwig spufs_mem_release(struct inode *inode, struct file *file) 17643c2bbd9SChristoph Hellwig { 17743c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 17843c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 17943c2bbd9SChristoph Hellwig 18047d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 18143c2bbd9SChristoph Hellwig if (!--i->i_openers) 18243c2bbd9SChristoph Hellwig ctx->local_store = NULL; 18347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 18467207b96SArnd Bergmann return 0; 18567207b96SArnd Bergmann } 18667207b96SArnd Bergmann 18767207b96SArnd Bergmann static ssize_t 188bf1ab978SDwayne Grant McConnell __spufs_mem_read(struct spu_context *ctx, char __user *buffer, 189bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 190bf1ab978SDwayne Grant McConnell { 191bf1ab978SDwayne Grant McConnell char *local_store = ctx->ops->get_ls(ctx); 192bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, local_store, 193bf1ab978SDwayne Grant McConnell LS_SIZE); 194bf1ab978SDwayne Grant McConnell } 195bf1ab978SDwayne Grant McConnell 196bf1ab978SDwayne Grant McConnell static ssize_t 19767207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 19867207b96SArnd Bergmann size_t size, loff_t *pos) 19967207b96SArnd Bergmann { 200bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 201aa0ed2bdSArnd Bergmann ssize_t ret; 20267207b96SArnd Bergmann 203c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 204c9101bdbSChristoph Hellwig if (ret) 205c9101bdbSChristoph Hellwig return ret; 206bf1ab978SDwayne Grant McConnell ret = __spufs_mem_read(ctx, buffer, size, pos); 2078b3d6663SArnd Bergmann spu_release(ctx); 208c9101bdbSChristoph Hellwig 20967207b96SArnd Bergmann return ret; 21067207b96SArnd Bergmann } 21167207b96SArnd Bergmann 21267207b96SArnd Bergmann static ssize_t 21367207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 214aa0ed2bdSArnd Bergmann size_t size, loff_t *ppos) 21567207b96SArnd Bergmann { 21667207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 2178b3d6663SArnd Bergmann char *local_store; 218aa0ed2bdSArnd Bergmann loff_t pos = *ppos; 2198b3d6663SArnd Bergmann int ret; 22067207b96SArnd Bergmann 221aa0ed2bdSArnd Bergmann if (pos > LS_SIZE) 22267207b96SArnd Bergmann return -EFBIG; 2238b3d6663SArnd Bergmann 224c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 225c9101bdbSChristoph Hellwig if (ret) 226c9101bdbSChristoph Hellwig return ret; 227c9101bdbSChristoph Hellwig 2288b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 22963c3b9d7SAkinobu Mita size = simple_write_to_buffer(local_store, LS_SIZE, ppos, buffer, size); 2308b3d6663SArnd Bergmann spu_release(ctx); 231aa0ed2bdSArnd Bergmann 232aa0ed2bdSArnd Bergmann return size; 23367207b96SArnd Bergmann } 23467207b96SArnd Bergmann 235e807f02cSSouptick Joarder static vm_fault_t 23611bac800SDave Jiang spufs_mem_mmap_fault(struct vm_fault *vmf) 2378b3d6663SArnd Bergmann { 23811bac800SDave Jiang struct vm_area_struct *vma = vmf->vma; 2398b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 240b1e2270fSNick Piggin unsigned long pfn, offset; 241e807f02cSSouptick Joarder vm_fault_t ret; 242b1e2270fSNick Piggin 243b1e2270fSNick Piggin offset = vmf->pgoff << PAGE_SHIFT; 244128b8546SMasato Noguchi if (offset >= LS_SIZE) 245b1e2270fSNick Piggin return VM_FAULT_SIGBUS; 246128b8546SMasato Noguchi 247b1e2270fSNick Piggin pr_debug("spufs_mem_mmap_fault address=0x%lx, offset=0x%lx\n", 2481a29d85eSJan Kara vmf->address, offset); 249f1fa74f4SBenjamin Herrenschmidt 250c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 251b1e2270fSNick Piggin return VM_FAULT_NOPAGE; 2528b3d6663SArnd Bergmann 253ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 25464b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); 25578bde53eSBenjamin Herrenschmidt pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); 256ac91cb8dSArnd Bergmann } else { 25764b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); 25878bde53eSBenjamin Herrenschmidt pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; 259ac91cb8dSArnd Bergmann } 260e807f02cSSouptick Joarder ret = vmf_insert_pfn(vma, vmf->address, pfn); 26178bde53eSBenjamin Herrenschmidt 2628b3d6663SArnd Bergmann spu_release(ctx); 2638b3d6663SArnd Bergmann 264e807f02cSSouptick Joarder return ret; 2658b3d6663SArnd Bergmann } 2668b3d6663SArnd Bergmann 267a352894dSBenjamin Herrenschmidt static int spufs_mem_mmap_access(struct vm_area_struct *vma, 268a352894dSBenjamin Herrenschmidt unsigned long address, 269a352894dSBenjamin Herrenschmidt void *buf, int len, int write) 270a352894dSBenjamin Herrenschmidt { 271a352894dSBenjamin Herrenschmidt struct spu_context *ctx = vma->vm_file->private_data; 272a352894dSBenjamin Herrenschmidt unsigned long offset = address - vma->vm_start; 273a352894dSBenjamin Herrenschmidt char *local_store; 274a352894dSBenjamin Herrenschmidt 275a352894dSBenjamin Herrenschmidt if (write && !(vma->vm_flags & VM_WRITE)) 276a352894dSBenjamin Herrenschmidt return -EACCES; 277a352894dSBenjamin Herrenschmidt if (spu_acquire(ctx)) 278a352894dSBenjamin Herrenschmidt return -EINTR; 279a352894dSBenjamin Herrenschmidt if ((offset + len) > vma->vm_end) 280a352894dSBenjamin Herrenschmidt len = vma->vm_end - offset; 281a352894dSBenjamin Herrenschmidt local_store = ctx->ops->get_ls(ctx); 282a352894dSBenjamin Herrenschmidt if (write) 283a352894dSBenjamin Herrenschmidt memcpy_toio(local_store + offset, buf, len); 284a352894dSBenjamin Herrenschmidt else 285a352894dSBenjamin Herrenschmidt memcpy_fromio(buf, local_store + offset, len); 286a352894dSBenjamin Herrenschmidt spu_release(ctx); 287a352894dSBenjamin Herrenschmidt return len; 288a352894dSBenjamin Herrenschmidt } 28978bde53eSBenjamin Herrenschmidt 290f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mem_mmap_vmops = { 291b1e2270fSNick Piggin .fault = spufs_mem_mmap_fault, 292a352894dSBenjamin Herrenschmidt .access = spufs_mem_mmap_access, 2938b3d6663SArnd Bergmann }; 2948b3d6663SArnd Bergmann 295f1fa74f4SBenjamin Herrenschmidt static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 29667207b96SArnd Bergmann { 2978b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 2988b3d6663SArnd Bergmann return -EINVAL; 29967207b96SArnd Bergmann 30078bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 30164b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); 3028b3d6663SArnd Bergmann 3038b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 30467207b96SArnd Bergmann return 0; 30567207b96SArnd Bergmann } 30667207b96SArnd Bergmann 3075dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = { 30867207b96SArnd Bergmann .open = spufs_mem_open, 309ce92987bSChristoph Hellwig .release = spufs_mem_release, 31067207b96SArnd Bergmann .read = spufs_mem_read, 31167207b96SArnd Bergmann .write = spufs_mem_write, 3128b3d6663SArnd Bergmann .llseek = generic_file_llseek, 31367207b96SArnd Bergmann .mmap = spufs_mem_mmap, 3148b3d6663SArnd Bergmann }; 3158b3d6663SArnd Bergmann 316e807f02cSSouptick Joarder static vm_fault_t spufs_ps_fault(struct vm_fault *vmf, 31778bde53eSBenjamin Herrenschmidt unsigned long ps_offs, 31827d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 3196df10a82SMark Nutter { 32011bac800SDave Jiang struct spu_context *ctx = vmf->vma->vm_file->private_data; 321b1e2270fSNick Piggin unsigned long area, offset = vmf->pgoff << PAGE_SHIFT; 322e807f02cSSouptick Joarder int err = 0; 323e807f02cSSouptick Joarder vm_fault_t ret = VM_FAULT_NOPAGE; 3246df10a82SMark Nutter 325b1e2270fSNick Piggin spu_context_nospu_trace(spufs_ps_fault__enter, ctx); 326038200cfSChristoph Hellwig 32727d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 328b1e2270fSNick Piggin return VM_FAULT_SIGBUS; 3296df10a82SMark Nutter 33060657263SJeremy Kerr if (fatal_signal_pending(current)) 33160657263SJeremy Kerr return VM_FAULT_SIGBUS; 33260657263SJeremy Kerr 33333bfd7a7SArnd Bergmann /* 334d5883137SJeremy Kerr * Because we release the mmap_sem, the context may be destroyed while 335d5883137SJeremy Kerr * we're in spu_wait. Grab an extra reference so it isn't destroyed 336d5883137SJeremy Kerr * in the meantime. 337d5883137SJeremy Kerr */ 338d5883137SJeremy Kerr get_spu_context(ctx); 339d5883137SJeremy Kerr 340d5883137SJeremy Kerr /* 34133bfd7a7SArnd Bergmann * We have to wait for context to be loaded before we have 34233bfd7a7SArnd Bergmann * pages to hand out to the user, but we don't want to wait 34333bfd7a7SArnd Bergmann * with the mmap_sem held. 34433bfd7a7SArnd Bergmann * It is possible to drop the mmap_sem here, but then we need 345b1e2270fSNick Piggin * to return VM_FAULT_NOPAGE because the mappings may have 34633bfd7a7SArnd Bergmann * hanged. 34778bde53eSBenjamin Herrenschmidt */ 348c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 349d5883137SJeremy Kerr goto refault; 350c9101bdbSChristoph Hellwig 35133bfd7a7SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 35233bfd7a7SArnd Bergmann up_read(¤t->mm->mmap_sem); 353b1e2270fSNick Piggin spu_context_nospu_trace(spufs_ps_fault__sleep, ctx); 354e807f02cSSouptick Joarder err = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 355b1e2270fSNick Piggin spu_context_trace(spufs_ps_fault__wake, ctx, ctx->spu); 35633bfd7a7SArnd Bergmann down_read(¤t->mm->mmap_sem); 357c9101bdbSChristoph Hellwig } else { 3586df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 359e807f02cSSouptick Joarder ret = vmf_insert_pfn(vmf->vma, vmf->address, 360e807f02cSSouptick Joarder (area + offset) >> PAGE_SHIFT); 361b1e2270fSNick Piggin spu_context_trace(spufs_ps_fault__insert, ctx, ctx->spu); 362c9101bdbSChristoph Hellwig } 36333bfd7a7SArnd Bergmann 364e807f02cSSouptick Joarder if (!err) 3656df10a82SMark Nutter spu_release(ctx); 366d5883137SJeremy Kerr 367d5883137SJeremy Kerr refault: 368d5883137SJeremy Kerr put_spu_context(ctx); 369e807f02cSSouptick Joarder return ret; 3706df10a82SMark Nutter } 3716df10a82SMark Nutter 37227d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 373e807f02cSSouptick Joarder static vm_fault_t spufs_cntl_mmap_fault(struct vm_fault *vmf) 3746df10a82SMark Nutter { 37511bac800SDave Jiang return spufs_ps_fault(vmf, 0x4000, SPUFS_CNTL_MAP_SIZE); 3766df10a82SMark Nutter } 3776df10a82SMark Nutter 378f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_cntl_mmap_vmops = { 379b1e2270fSNick Piggin .fault = spufs_cntl_mmap_fault, 3806df10a82SMark Nutter }; 3816df10a82SMark Nutter 3826df10a82SMark Nutter /* 3836df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 3846df10a82SMark Nutter */ 3856df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 3866df10a82SMark Nutter { 3876df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 3886df10a82SMark Nutter return -EINVAL; 3896df10a82SMark Nutter 39078bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 39164b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 3926df10a82SMark Nutter 3936df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 3946df10a82SMark Nutter return 0; 3956df10a82SMark Nutter } 39627d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 39727d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 39827d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 3996df10a82SMark Nutter 400197b1a82SChristoph Hellwig static int spufs_cntl_get(void *data, u64 *val) 401e1dbff2bSArnd Bergmann { 402e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 403c9101bdbSChristoph Hellwig int ret; 404e1dbff2bSArnd Bergmann 405c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 406c9101bdbSChristoph Hellwig if (ret) 407c9101bdbSChristoph Hellwig return ret; 408197b1a82SChristoph Hellwig *val = ctx->ops->status_read(ctx); 409e1dbff2bSArnd Bergmann spu_release(ctx); 410e1dbff2bSArnd Bergmann 411197b1a82SChristoph Hellwig return 0; 412e1dbff2bSArnd Bergmann } 413e1dbff2bSArnd Bergmann 414197b1a82SChristoph Hellwig static int spufs_cntl_set(void *data, u64 val) 415e1dbff2bSArnd Bergmann { 416e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 417c9101bdbSChristoph Hellwig int ret; 418e1dbff2bSArnd Bergmann 419c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 420c9101bdbSChristoph Hellwig if (ret) 421c9101bdbSChristoph Hellwig return ret; 422e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 423e1dbff2bSArnd Bergmann spu_release(ctx); 424197b1a82SChristoph Hellwig 425197b1a82SChristoph Hellwig return 0; 426e1dbff2bSArnd Bergmann } 427e1dbff2bSArnd Bergmann 4286df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 4296df10a82SMark Nutter { 4306df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 4316df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 4326df10a82SMark Nutter 43347d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 4346df10a82SMark Nutter file->private_data = ctx; 43543c2bbd9SChristoph Hellwig if (!i->i_openers++) 4366df10a82SMark Nutter ctx->cntl = inode->i_mapping; 43747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 4388b88b099SChristoph Hellwig return simple_attr_open(inode, file, spufs_cntl_get, 439e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 4406df10a82SMark Nutter } 4416df10a82SMark Nutter 44243c2bbd9SChristoph Hellwig static int 44343c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file) 44443c2bbd9SChristoph Hellwig { 44543c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 44643c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 44743c2bbd9SChristoph Hellwig 44874bedc4dSChristoph Hellwig simple_attr_release(inode, file); 44943c2bbd9SChristoph Hellwig 45047d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 45143c2bbd9SChristoph Hellwig if (!--i->i_openers) 45243c2bbd9SChristoph Hellwig ctx->cntl = NULL; 45347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 45443c2bbd9SChristoph Hellwig return 0; 45543c2bbd9SChristoph Hellwig } 45643c2bbd9SChristoph Hellwig 4575dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = { 4586df10a82SMark Nutter .open = spufs_cntl_open, 45943c2bbd9SChristoph Hellwig .release = spufs_cntl_release, 4608b88b099SChristoph Hellwig .read = simple_attr_read, 4618b88b099SChristoph Hellwig .write = simple_attr_write, 462fc15351dSArnd Bergmann .llseek = generic_file_llseek, 4636df10a82SMark Nutter .mmap = spufs_cntl_mmap, 4646df10a82SMark Nutter }; 4656df10a82SMark Nutter 4668b3d6663SArnd Bergmann static int 4678b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 4688b3d6663SArnd Bergmann { 4698b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 4708b3d6663SArnd Bergmann file->private_data = i->i_ctx; 4718b3d6663SArnd Bergmann return 0; 4728b3d6663SArnd Bergmann } 4738b3d6663SArnd Bergmann 4748b3d6663SArnd Bergmann static ssize_t 475bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer, 476bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 477bf1ab978SDwayne Grant McConnell { 478bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 479bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 480bf1ab978SDwayne Grant McConnell lscsa->gprs, sizeof lscsa->gprs); 481bf1ab978SDwayne Grant McConnell } 482bf1ab978SDwayne Grant McConnell 483bf1ab978SDwayne Grant McConnell static ssize_t 4848b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 4858b3d6663SArnd Bergmann size_t size, loff_t *pos) 4868b3d6663SArnd Bergmann { 4878b3d6663SArnd Bergmann int ret; 488bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 4898b3d6663SArnd Bergmann 490f027faa2SJeremy Kerr /* pre-check for file position: if we'd return EOF, there's no point 491f027faa2SJeremy Kerr * causing a deschedule */ 492f027faa2SJeremy Kerr if (*pos >= sizeof(ctx->csa.lscsa->gprs)) 493f027faa2SJeremy Kerr return 0; 494f027faa2SJeremy Kerr 495c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 496c9101bdbSChristoph Hellwig if (ret) 497c9101bdbSChristoph Hellwig return ret; 498bf1ab978SDwayne Grant McConnell ret = __spufs_regs_read(ctx, buffer, size, pos); 49927b1ea09SChristoph Hellwig spu_release_saved(ctx); 5008b3d6663SArnd Bergmann return ret; 5018b3d6663SArnd Bergmann } 5028b3d6663SArnd Bergmann 5038b3d6663SArnd Bergmann static ssize_t 5048b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 5058b3d6663SArnd Bergmann size_t size, loff_t *pos) 5068b3d6663SArnd Bergmann { 5078b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5088b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5098b3d6663SArnd Bergmann int ret; 5108b3d6663SArnd Bergmann 511d219889bSJeremy Kerr if (*pos >= sizeof(lscsa->gprs)) 5128b3d6663SArnd Bergmann return -EFBIG; 513d219889bSJeremy Kerr 514c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 515c9101bdbSChristoph Hellwig if (ret) 516c9101bdbSChristoph Hellwig return ret; 5178b3d6663SArnd Bergmann 51863c3b9d7SAkinobu Mita size = simple_write_to_buffer(lscsa->gprs, sizeof(lscsa->gprs), pos, 51963c3b9d7SAkinobu Mita buffer, size); 5208b3d6663SArnd Bergmann 52127b1ea09SChristoph Hellwig spu_release_saved(ctx); 52263c3b9d7SAkinobu Mita return size; 5238b3d6663SArnd Bergmann } 5248b3d6663SArnd Bergmann 5255dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = { 5268b3d6663SArnd Bergmann .open = spufs_regs_open, 5278b3d6663SArnd Bergmann .read = spufs_regs_read, 5288b3d6663SArnd Bergmann .write = spufs_regs_write, 5298b3d6663SArnd Bergmann .llseek = generic_file_llseek, 5308b3d6663SArnd Bergmann }; 5318b3d6663SArnd Bergmann 5328b3d6663SArnd Bergmann static ssize_t 533bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, 534bf1ab978SDwayne Grant McConnell size_t size, loff_t * pos) 535bf1ab978SDwayne Grant McConnell { 536bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 537bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 538bf1ab978SDwayne Grant McConnell &lscsa->fpcr, sizeof(lscsa->fpcr)); 539bf1ab978SDwayne Grant McConnell } 540bf1ab978SDwayne Grant McConnell 541bf1ab978SDwayne Grant McConnell static ssize_t 5428b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 5438b3d6663SArnd Bergmann size_t size, loff_t * pos) 5448b3d6663SArnd Bergmann { 5458b3d6663SArnd Bergmann int ret; 546bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5478b3d6663SArnd Bergmann 548c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 549c9101bdbSChristoph Hellwig if (ret) 550c9101bdbSChristoph Hellwig return ret; 551bf1ab978SDwayne Grant McConnell ret = __spufs_fpcr_read(ctx, buffer, size, pos); 55227b1ea09SChristoph Hellwig spu_release_saved(ctx); 5538b3d6663SArnd Bergmann return ret; 5548b3d6663SArnd Bergmann } 5558b3d6663SArnd Bergmann 5568b3d6663SArnd Bergmann static ssize_t 5578b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 5588b3d6663SArnd Bergmann size_t size, loff_t * pos) 5598b3d6663SArnd Bergmann { 5608b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5618b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5628b3d6663SArnd Bergmann int ret; 5638b3d6663SArnd Bergmann 564d219889bSJeremy Kerr if (*pos >= sizeof(lscsa->fpcr)) 5658b3d6663SArnd Bergmann return -EFBIG; 566c9101bdbSChristoph Hellwig 567c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 568c9101bdbSChristoph Hellwig if (ret) 569c9101bdbSChristoph Hellwig return ret; 570c9101bdbSChristoph Hellwig 57163c3b9d7SAkinobu Mita size = simple_write_to_buffer(&lscsa->fpcr, sizeof(lscsa->fpcr), pos, 57263c3b9d7SAkinobu Mita buffer, size); 5738b3d6663SArnd Bergmann 57427b1ea09SChristoph Hellwig spu_release_saved(ctx); 57563c3b9d7SAkinobu Mita return size; 5768b3d6663SArnd Bergmann } 5778b3d6663SArnd Bergmann 5785dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = { 5798b3d6663SArnd Bergmann .open = spufs_regs_open, 5808b3d6663SArnd Bergmann .read = spufs_fpcr_read, 5818b3d6663SArnd Bergmann .write = spufs_fpcr_write, 58267207b96SArnd Bergmann .llseek = generic_file_llseek, 58367207b96SArnd Bergmann }; 58467207b96SArnd Bergmann 58567207b96SArnd Bergmann /* generic open function for all pipe-like files */ 58667207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 58767207b96SArnd Bergmann { 58867207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 58967207b96SArnd Bergmann file->private_data = i->i_ctx; 59067207b96SArnd Bergmann 59167207b96SArnd Bergmann return nonseekable_open(inode, file); 59267207b96SArnd Bergmann } 59367207b96SArnd Bergmann 594cdcc89bbSArnd Bergmann /* 595cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 596cdcc89bbSArnd Bergmann * one of the conditions becomes true: 597cdcc89bbSArnd Bergmann * 598cdcc89bbSArnd Bergmann * - no more data available in the mailbox 599cdcc89bbSArnd Bergmann * - end of the user provided buffer 600cdcc89bbSArnd Bergmann * - end of the mapped area 601cdcc89bbSArnd Bergmann */ 60267207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 60367207b96SArnd Bergmann size_t len, loff_t *pos) 60467207b96SArnd Bergmann { 6058b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 606cdcc89bbSArnd Bergmann u32 mbox_data, __user *udata; 607cdcc89bbSArnd Bergmann ssize_t count; 60867207b96SArnd Bergmann 60967207b96SArnd Bergmann if (len < 4) 61067207b96SArnd Bergmann return -EINVAL; 61167207b96SArnd Bergmann 612cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 61367207b96SArnd Bergmann return -EFAULT; 61467207b96SArnd Bergmann 615cdcc89bbSArnd Bergmann udata = (void __user *)buf; 616cdcc89bbSArnd Bergmann 617c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 618c9101bdbSChristoph Hellwig if (count) 619c9101bdbSChristoph Hellwig return count; 620c9101bdbSChristoph Hellwig 621274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 622cdcc89bbSArnd Bergmann int ret; 623cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 624cdcc89bbSArnd Bergmann if (ret == 0) 625cdcc89bbSArnd Bergmann break; 626cdcc89bbSArnd Bergmann 627cdcc89bbSArnd Bergmann /* 628cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 629cdcc89bbSArnd Bergmann * but still need to return the data we have 630cdcc89bbSArnd Bergmann * read successfully so far. 631cdcc89bbSArnd Bergmann */ 632cdcc89bbSArnd Bergmann ret = __put_user(mbox_data, udata); 633cdcc89bbSArnd Bergmann if (ret) { 634cdcc89bbSArnd Bergmann if (!count) 635cdcc89bbSArnd Bergmann count = -EFAULT; 636cdcc89bbSArnd Bergmann break; 637cdcc89bbSArnd Bergmann } 638cdcc89bbSArnd Bergmann } 639cdcc89bbSArnd Bergmann spu_release(ctx); 640cdcc89bbSArnd Bergmann 641cdcc89bbSArnd Bergmann if (!count) 642cdcc89bbSArnd Bergmann count = -EAGAIN; 643cdcc89bbSArnd Bergmann 644cdcc89bbSArnd Bergmann return count; 64567207b96SArnd Bergmann } 64667207b96SArnd Bergmann 6475dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = { 64867207b96SArnd Bergmann .open = spufs_pipe_open, 64967207b96SArnd Bergmann .read = spufs_mbox_read, 650fc15351dSArnd Bergmann .llseek = no_llseek, 65167207b96SArnd Bergmann }; 65267207b96SArnd Bergmann 65367207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 65467207b96SArnd Bergmann size_t len, loff_t *pos) 65567207b96SArnd Bergmann { 6568b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 657c9101bdbSChristoph Hellwig ssize_t ret; 65867207b96SArnd Bergmann u32 mbox_stat; 65967207b96SArnd Bergmann 66067207b96SArnd Bergmann if (len < 4) 66167207b96SArnd Bergmann return -EINVAL; 66267207b96SArnd Bergmann 663c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 664c9101bdbSChristoph Hellwig if (ret) 665c9101bdbSChristoph Hellwig return ret; 6668b3d6663SArnd Bergmann 6678b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 6688b3d6663SArnd Bergmann 6698b3d6663SArnd Bergmann spu_release(ctx); 67067207b96SArnd Bergmann 67167207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 67267207b96SArnd Bergmann return -EFAULT; 67367207b96SArnd Bergmann 67467207b96SArnd Bergmann return 4; 67567207b96SArnd Bergmann } 67667207b96SArnd Bergmann 6775dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = { 67867207b96SArnd Bergmann .open = spufs_pipe_open, 67967207b96SArnd Bergmann .read = spufs_mbox_stat_read, 680fc15351dSArnd Bergmann .llseek = no_llseek, 68167207b96SArnd Bergmann }; 68267207b96SArnd Bergmann 68367207b96SArnd Bergmann /* low-level ibox access function */ 6848b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 68567207b96SArnd Bergmann { 6868b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 68767207b96SArnd Bergmann } 68867207b96SArnd Bergmann 6898b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 6908b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 6918b3d6663SArnd Bergmann { 6928b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 6938b3d6663SArnd Bergmann 6947d7be3aaSAl Viro if (ctx) 6958b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 69667207b96SArnd Bergmann } 69767207b96SArnd Bergmann 698cdcc89bbSArnd Bergmann /* 699cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 700cdcc89bbSArnd Bergmann * one of the conditions becomes true: 701cdcc89bbSArnd Bergmann * 702cdcc89bbSArnd Bergmann * - no more data available in the mailbox 703cdcc89bbSArnd Bergmann * - end of the user provided buffer 704cdcc89bbSArnd Bergmann * - end of the mapped area 705cdcc89bbSArnd Bergmann * 706cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 707cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 708cdcc89bbSArnd Bergmann * read something. 709cdcc89bbSArnd Bergmann */ 71067207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 71167207b96SArnd Bergmann size_t len, loff_t *pos) 71267207b96SArnd Bergmann { 7138b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 714cdcc89bbSArnd Bergmann u32 ibox_data, __user *udata; 715cdcc89bbSArnd Bergmann ssize_t count; 71667207b96SArnd Bergmann 71767207b96SArnd Bergmann if (len < 4) 71867207b96SArnd Bergmann return -EINVAL; 71967207b96SArnd Bergmann 720cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_WRITE, buf, len)) 721cdcc89bbSArnd Bergmann return -EFAULT; 722cdcc89bbSArnd Bergmann 723cdcc89bbSArnd Bergmann udata = (void __user *)buf; 724cdcc89bbSArnd Bergmann 725c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 726c9101bdbSChristoph Hellwig if (count) 727eebead5bSChristoph Hellwig goto out; 72867207b96SArnd Bergmann 729cdcc89bbSArnd Bergmann /* wait only for the first element */ 730cdcc89bbSArnd Bergmann count = 0; 73167207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 732eebead5bSChristoph Hellwig if (!spu_ibox_read(ctx, &ibox_data)) { 733cdcc89bbSArnd Bergmann count = -EAGAIN; 734eebead5bSChristoph Hellwig goto out_unlock; 735eebead5bSChristoph Hellwig } 73667207b96SArnd Bergmann } else { 737cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 738cdcc89bbSArnd Bergmann if (count) 739cdcc89bbSArnd Bergmann goto out; 740eebead5bSChristoph Hellwig } 741cdcc89bbSArnd Bergmann 742cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 743cdcc89bbSArnd Bergmann count = __put_user(ibox_data, udata); 744cdcc89bbSArnd Bergmann if (count) 745eebead5bSChristoph Hellwig goto out_unlock; 746cdcc89bbSArnd Bergmann 747cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 748cdcc89bbSArnd Bergmann int ret; 749cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 750cdcc89bbSArnd Bergmann if (ret == 0) 751cdcc89bbSArnd Bergmann break; 752cdcc89bbSArnd Bergmann /* 753cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 754cdcc89bbSArnd Bergmann * but still need to return the data we have 755cdcc89bbSArnd Bergmann * read successfully so far. 756cdcc89bbSArnd Bergmann */ 757cdcc89bbSArnd Bergmann ret = __put_user(ibox_data, udata); 758cdcc89bbSArnd Bergmann if (ret) 759cdcc89bbSArnd Bergmann break; 76067207b96SArnd Bergmann } 76167207b96SArnd Bergmann 762eebead5bSChristoph Hellwig out_unlock: 7638b3d6663SArnd Bergmann spu_release(ctx); 764eebead5bSChristoph Hellwig out: 765cdcc89bbSArnd Bergmann return count; 76667207b96SArnd Bergmann } 76767207b96SArnd Bergmann 7688153a5eaSAl Viro static __poll_t spufs_ibox_poll(struct file *file, poll_table *wait) 76967207b96SArnd Bergmann { 7708b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 7718153a5eaSAl Viro __poll_t mask; 77267207b96SArnd Bergmann 7738b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 77467207b96SArnd Bergmann 775c9101bdbSChristoph Hellwig /* 776c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 777c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 778c9101bdbSChristoph Hellwig */ 779c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 780a9a08845SLinus Torvalds mask = ctx->ops->mbox_stat_poll(ctx, EPOLLIN | EPOLLRDNORM); 7813a843d7cSArnd Bergmann spu_release(ctx); 78267207b96SArnd Bergmann 78367207b96SArnd Bergmann return mask; 78467207b96SArnd Bergmann } 78567207b96SArnd Bergmann 7865dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = { 78767207b96SArnd Bergmann .open = spufs_pipe_open, 78867207b96SArnd Bergmann .read = spufs_ibox_read, 78967207b96SArnd Bergmann .poll = spufs_ibox_poll, 790fc15351dSArnd Bergmann .llseek = no_llseek, 79167207b96SArnd Bergmann }; 79267207b96SArnd Bergmann 79367207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 79467207b96SArnd Bergmann size_t len, loff_t *pos) 79567207b96SArnd Bergmann { 7968b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 797c9101bdbSChristoph Hellwig ssize_t ret; 79867207b96SArnd Bergmann u32 ibox_stat; 79967207b96SArnd Bergmann 80067207b96SArnd Bergmann if (len < 4) 80167207b96SArnd Bergmann return -EINVAL; 80267207b96SArnd Bergmann 803c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 804c9101bdbSChristoph Hellwig if (ret) 805c9101bdbSChristoph Hellwig return ret; 8068b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 8078b3d6663SArnd Bergmann spu_release(ctx); 80867207b96SArnd Bergmann 80967207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 81067207b96SArnd Bergmann return -EFAULT; 81167207b96SArnd Bergmann 81267207b96SArnd Bergmann return 4; 81367207b96SArnd Bergmann } 81467207b96SArnd Bergmann 8155dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = { 81667207b96SArnd Bergmann .open = spufs_pipe_open, 81767207b96SArnd Bergmann .read = spufs_ibox_stat_read, 818fc15351dSArnd Bergmann .llseek = no_llseek, 81967207b96SArnd Bergmann }; 82067207b96SArnd Bergmann 82167207b96SArnd Bergmann /* low-level mailbox write */ 8228b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 82367207b96SArnd Bergmann { 8248b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 82567207b96SArnd Bergmann } 82667207b96SArnd Bergmann 8278b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 8288b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 8298b3d6663SArnd Bergmann { 8308b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 8318b3d6663SArnd Bergmann 8327d7be3aaSAl Viro if (ctx) 8338b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 83467207b96SArnd Bergmann } 83567207b96SArnd Bergmann 836cdcc89bbSArnd Bergmann /* 837cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 838cdcc89bbSArnd Bergmann * one of the conditions becomes true: 839cdcc89bbSArnd Bergmann * 840cdcc89bbSArnd Bergmann * - the mailbox is full 841cdcc89bbSArnd Bergmann * - end of the user provided buffer 842cdcc89bbSArnd Bergmann * - end of the mapped area 843cdcc89bbSArnd Bergmann * 844cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 845027dfac6SMichael Ellerman * space is available, but return when we have been able to 846cdcc89bbSArnd Bergmann * write something. 847cdcc89bbSArnd Bergmann */ 84867207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 84967207b96SArnd Bergmann size_t len, loff_t *pos) 85067207b96SArnd Bergmann { 8518b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 852cdcc89bbSArnd Bergmann u32 wbox_data, __user *udata; 853cdcc89bbSArnd Bergmann ssize_t count; 85467207b96SArnd Bergmann 85567207b96SArnd Bergmann if (len < 4) 85667207b96SArnd Bergmann return -EINVAL; 85767207b96SArnd Bergmann 858cdcc89bbSArnd Bergmann udata = (void __user *)buf; 859cdcc89bbSArnd Bergmann if (!access_ok(VERIFY_READ, buf, len)) 860cdcc89bbSArnd Bergmann return -EFAULT; 861cdcc89bbSArnd Bergmann 862cdcc89bbSArnd Bergmann if (__get_user(wbox_data, udata)) 86367207b96SArnd Bergmann return -EFAULT; 86467207b96SArnd Bergmann 865c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 866c9101bdbSChristoph Hellwig if (count) 867eebead5bSChristoph Hellwig goto out; 8688b3d6663SArnd Bergmann 869cdcc89bbSArnd Bergmann /* 870cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 871cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 872cdcc89bbSArnd Bergmann */ 873cdcc89bbSArnd Bergmann count = 0; 87467207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 875eebead5bSChristoph Hellwig if (!spu_wbox_write(ctx, wbox_data)) { 876cdcc89bbSArnd Bergmann count = -EAGAIN; 877eebead5bSChristoph Hellwig goto out_unlock; 878eebead5bSChristoph Hellwig } 87967207b96SArnd Bergmann } else { 880cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 881cdcc89bbSArnd Bergmann if (count) 882cdcc89bbSArnd Bergmann goto out; 883eebead5bSChristoph Hellwig } 884eebead5bSChristoph Hellwig 8858b3d6663SArnd Bergmann 88696de0e25SJan Engelhardt /* write as much as possible */ 887cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 888cdcc89bbSArnd Bergmann int ret; 889cdcc89bbSArnd Bergmann ret = __get_user(wbox_data, udata); 890cdcc89bbSArnd Bergmann if (ret) 891cdcc89bbSArnd Bergmann break; 892cdcc89bbSArnd Bergmann 893cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 894cdcc89bbSArnd Bergmann if (ret == 0) 895cdcc89bbSArnd Bergmann break; 896cdcc89bbSArnd Bergmann } 897cdcc89bbSArnd Bergmann 898eebead5bSChristoph Hellwig out_unlock: 899cdcc89bbSArnd Bergmann spu_release(ctx); 900eebead5bSChristoph Hellwig out: 901cdcc89bbSArnd Bergmann return count; 90267207b96SArnd Bergmann } 90367207b96SArnd Bergmann 9048153a5eaSAl Viro static __poll_t spufs_wbox_poll(struct file *file, poll_table *wait) 90567207b96SArnd Bergmann { 9068b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 9078153a5eaSAl Viro __poll_t mask; 90867207b96SArnd Bergmann 9098b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 91067207b96SArnd Bergmann 911c9101bdbSChristoph Hellwig /* 912c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 913c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 914c9101bdbSChristoph Hellwig */ 915c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 916a9a08845SLinus Torvalds mask = ctx->ops->mbox_stat_poll(ctx, EPOLLOUT | EPOLLWRNORM); 9173a843d7cSArnd Bergmann spu_release(ctx); 91867207b96SArnd Bergmann 91967207b96SArnd Bergmann return mask; 92067207b96SArnd Bergmann } 92167207b96SArnd Bergmann 9225dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = { 92367207b96SArnd Bergmann .open = spufs_pipe_open, 92467207b96SArnd Bergmann .write = spufs_wbox_write, 92567207b96SArnd Bergmann .poll = spufs_wbox_poll, 926fc15351dSArnd Bergmann .llseek = no_llseek, 92767207b96SArnd Bergmann }; 92867207b96SArnd Bergmann 92967207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 93067207b96SArnd Bergmann size_t len, loff_t *pos) 93167207b96SArnd Bergmann { 9328b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 933c9101bdbSChristoph Hellwig ssize_t ret; 93467207b96SArnd Bergmann u32 wbox_stat; 93567207b96SArnd Bergmann 93667207b96SArnd Bergmann if (len < 4) 93767207b96SArnd Bergmann return -EINVAL; 93867207b96SArnd Bergmann 939c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 940c9101bdbSChristoph Hellwig if (ret) 941c9101bdbSChristoph Hellwig return ret; 9428b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 9438b3d6663SArnd Bergmann spu_release(ctx); 94467207b96SArnd Bergmann 94567207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 94667207b96SArnd Bergmann return -EFAULT; 94767207b96SArnd Bergmann 94867207b96SArnd Bergmann return 4; 94967207b96SArnd Bergmann } 95067207b96SArnd Bergmann 9515dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = { 95267207b96SArnd Bergmann .open = spufs_pipe_open, 95367207b96SArnd Bergmann .read = spufs_wbox_stat_read, 954fc15351dSArnd Bergmann .llseek = no_llseek, 95567207b96SArnd Bergmann }; 95667207b96SArnd Bergmann 9576df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 9586df10a82SMark Nutter { 9596df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 9606df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 96143c2bbd9SChristoph Hellwig 96247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 9636df10a82SMark Nutter file->private_data = ctx; 96443c2bbd9SChristoph Hellwig if (!i->i_openers++) 9656df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 96647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 9676df10a82SMark Nutter return nonseekable_open(inode, file); 9686df10a82SMark Nutter } 9696df10a82SMark Nutter 97043c2bbd9SChristoph Hellwig static int 97143c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file) 97243c2bbd9SChristoph Hellwig { 97343c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 97443c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 97543c2bbd9SChristoph Hellwig 97647d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 97743c2bbd9SChristoph Hellwig if (!--i->i_openers) 97843c2bbd9SChristoph Hellwig ctx->signal1 = NULL; 97947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 98043c2bbd9SChristoph Hellwig return 0; 98143c2bbd9SChristoph Hellwig } 98243c2bbd9SChristoph Hellwig 983bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 98467207b96SArnd Bergmann size_t len, loff_t *pos) 98567207b96SArnd Bergmann { 98617f88cebSDwayne Grant McConnell int ret = 0; 98767207b96SArnd Bergmann u32 data; 98867207b96SArnd Bergmann 98967207b96SArnd Bergmann if (len < 4) 99067207b96SArnd Bergmann return -EINVAL; 99167207b96SArnd Bergmann 99217f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[3]) { 99317f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[3]; 99417f88cebSDwayne Grant McConnell ret = 4; 99517f88cebSDwayne Grant McConnell } 9968b3d6663SArnd Bergmann 99717f88cebSDwayne Grant McConnell if (!ret) 99817f88cebSDwayne Grant McConnell goto out; 99917f88cebSDwayne Grant McConnell 100067207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 100167207b96SArnd Bergmann return -EFAULT; 100267207b96SArnd Bergmann 100317f88cebSDwayne Grant McConnell out: 100417f88cebSDwayne Grant McConnell return ret; 100567207b96SArnd Bergmann } 100667207b96SArnd Bergmann 1007bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 1008bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1009bf1ab978SDwayne Grant McConnell { 1010bf1ab978SDwayne Grant McConnell int ret; 1011bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1012bf1ab978SDwayne Grant McConnell 1013c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1014c9101bdbSChristoph Hellwig if (ret) 1015c9101bdbSChristoph Hellwig return ret; 1016bf1ab978SDwayne Grant McConnell ret = __spufs_signal1_read(ctx, buf, len, pos); 101727b1ea09SChristoph Hellwig spu_release_saved(ctx); 1018bf1ab978SDwayne Grant McConnell 1019bf1ab978SDwayne Grant McConnell return ret; 1020bf1ab978SDwayne Grant McConnell } 1021bf1ab978SDwayne Grant McConnell 102267207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 102367207b96SArnd Bergmann size_t len, loff_t *pos) 102467207b96SArnd Bergmann { 102567207b96SArnd Bergmann struct spu_context *ctx; 1026c9101bdbSChristoph Hellwig ssize_t ret; 102767207b96SArnd Bergmann u32 data; 102867207b96SArnd Bergmann 102967207b96SArnd Bergmann ctx = file->private_data; 103067207b96SArnd Bergmann 103167207b96SArnd Bergmann if (len < 4) 103267207b96SArnd Bergmann return -EINVAL; 103367207b96SArnd Bergmann 103467207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 103567207b96SArnd Bergmann return -EFAULT; 103667207b96SArnd Bergmann 1037c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1038c9101bdbSChristoph Hellwig if (ret) 1039c9101bdbSChristoph Hellwig return ret; 10408b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 10418b3d6663SArnd Bergmann spu_release(ctx); 104267207b96SArnd Bergmann 104367207b96SArnd Bergmann return 4; 104467207b96SArnd Bergmann } 104567207b96SArnd Bergmann 1046e807f02cSSouptick Joarder static vm_fault_t 104711bac800SDave Jiang spufs_signal1_mmap_fault(struct vm_fault *vmf) 10486df10a82SMark Nutter { 104987ff6090SJeremy Kerr #if SPUFS_SIGNAL_MAP_SIZE == 0x1000 105011bac800SDave Jiang return spufs_ps_fault(vmf, 0x14000, SPUFS_SIGNAL_MAP_SIZE); 105187ff6090SJeremy Kerr #elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 105227d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 105327d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 105427d5bf2aSBenjamin Herrenschmidt */ 105511bac800SDave Jiang return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); 105627d5bf2aSBenjamin Herrenschmidt #else 105727d5bf2aSBenjamin Herrenschmidt #error unsupported page size 105827d5bf2aSBenjamin Herrenschmidt #endif 10596df10a82SMark Nutter } 10606df10a82SMark Nutter 1061f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_signal1_mmap_vmops = { 1062b1e2270fSNick Piggin .fault = spufs_signal1_mmap_fault, 10636df10a82SMark Nutter }; 10646df10a82SMark Nutter 10656df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 10666df10a82SMark Nutter { 10676df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 10686df10a82SMark Nutter return -EINVAL; 10696df10a82SMark Nutter 107078bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 107164b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 10726df10a82SMark Nutter 10736df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 10746df10a82SMark Nutter return 0; 10756df10a82SMark Nutter } 10766df10a82SMark Nutter 10775dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = { 10786df10a82SMark Nutter .open = spufs_signal1_open, 107943c2bbd9SChristoph Hellwig .release = spufs_signal1_release, 108067207b96SArnd Bergmann .read = spufs_signal1_read, 108167207b96SArnd Bergmann .write = spufs_signal1_write, 10826df10a82SMark Nutter .mmap = spufs_signal1_mmap, 1083fc15351dSArnd Bergmann .llseek = no_llseek, 108467207b96SArnd Bergmann }; 108567207b96SArnd Bergmann 1086d054b36fSJeremy Kerr static const struct file_operations spufs_signal1_nosched_fops = { 1087d054b36fSJeremy Kerr .open = spufs_signal1_open, 1088d054b36fSJeremy Kerr .release = spufs_signal1_release, 1089d054b36fSJeremy Kerr .write = spufs_signal1_write, 1090d054b36fSJeremy Kerr .mmap = spufs_signal1_mmap, 1091fc15351dSArnd Bergmann .llseek = no_llseek, 1092d054b36fSJeremy Kerr }; 1093d054b36fSJeremy Kerr 10946df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 10956df10a82SMark Nutter { 10966df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 10976df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 109843c2bbd9SChristoph Hellwig 109947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 11006df10a82SMark Nutter file->private_data = ctx; 110143c2bbd9SChristoph Hellwig if (!i->i_openers++) 11026df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 110347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 11046df10a82SMark Nutter return nonseekable_open(inode, file); 11056df10a82SMark Nutter } 11066df10a82SMark Nutter 110743c2bbd9SChristoph Hellwig static int 110843c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file) 110943c2bbd9SChristoph Hellwig { 111043c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 111143c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 111243c2bbd9SChristoph Hellwig 111347d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 111443c2bbd9SChristoph Hellwig if (!--i->i_openers) 111543c2bbd9SChristoph Hellwig ctx->signal2 = NULL; 111647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 111743c2bbd9SChristoph Hellwig return 0; 111843c2bbd9SChristoph Hellwig } 111943c2bbd9SChristoph Hellwig 1120bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 112167207b96SArnd Bergmann size_t len, loff_t *pos) 112267207b96SArnd Bergmann { 112317f88cebSDwayne Grant McConnell int ret = 0; 112467207b96SArnd Bergmann u32 data; 112567207b96SArnd Bergmann 112667207b96SArnd Bergmann if (len < 4) 112767207b96SArnd Bergmann return -EINVAL; 112867207b96SArnd Bergmann 112917f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[4]) { 113017f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[4]; 113117f88cebSDwayne Grant McConnell ret = 4; 113217f88cebSDwayne Grant McConnell } 11338b3d6663SArnd Bergmann 113417f88cebSDwayne Grant McConnell if (!ret) 113517f88cebSDwayne Grant McConnell goto out; 113617f88cebSDwayne Grant McConnell 113767207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 113867207b96SArnd Bergmann return -EFAULT; 113967207b96SArnd Bergmann 114017f88cebSDwayne Grant McConnell out: 1141bf1ab978SDwayne Grant McConnell return ret; 1142bf1ab978SDwayne Grant McConnell } 1143bf1ab978SDwayne Grant McConnell 1144bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 1145bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1146bf1ab978SDwayne Grant McConnell { 1147bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1148bf1ab978SDwayne Grant McConnell int ret; 1149bf1ab978SDwayne Grant McConnell 1150c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1151c9101bdbSChristoph Hellwig if (ret) 1152c9101bdbSChristoph Hellwig return ret; 1153bf1ab978SDwayne Grant McConnell ret = __spufs_signal2_read(ctx, buf, len, pos); 115427b1ea09SChristoph Hellwig spu_release_saved(ctx); 1155bf1ab978SDwayne Grant McConnell 1156bf1ab978SDwayne Grant McConnell return ret; 115767207b96SArnd Bergmann } 115867207b96SArnd Bergmann 115967207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 116067207b96SArnd Bergmann size_t len, loff_t *pos) 116167207b96SArnd Bergmann { 116267207b96SArnd Bergmann struct spu_context *ctx; 1163c9101bdbSChristoph Hellwig ssize_t ret; 116467207b96SArnd Bergmann u32 data; 116567207b96SArnd Bergmann 116667207b96SArnd Bergmann ctx = file->private_data; 116767207b96SArnd Bergmann 116867207b96SArnd Bergmann if (len < 4) 116967207b96SArnd Bergmann return -EINVAL; 117067207b96SArnd Bergmann 117167207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 117267207b96SArnd Bergmann return -EFAULT; 117367207b96SArnd Bergmann 1174c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1175c9101bdbSChristoph Hellwig if (ret) 1176c9101bdbSChristoph Hellwig return ret; 11778b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 11788b3d6663SArnd Bergmann spu_release(ctx); 117967207b96SArnd Bergmann 118067207b96SArnd Bergmann return 4; 118167207b96SArnd Bergmann } 118267207b96SArnd Bergmann 118327d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1184e807f02cSSouptick Joarder static vm_fault_t 118511bac800SDave Jiang spufs_signal2_mmap_fault(struct vm_fault *vmf) 11866df10a82SMark Nutter { 118787ff6090SJeremy Kerr #if SPUFS_SIGNAL_MAP_SIZE == 0x1000 118811bac800SDave Jiang return spufs_ps_fault(vmf, 0x1c000, SPUFS_SIGNAL_MAP_SIZE); 118987ff6090SJeremy Kerr #elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 119027d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 119127d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 119227d5bf2aSBenjamin Herrenschmidt */ 119311bac800SDave Jiang return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); 119427d5bf2aSBenjamin Herrenschmidt #else 119527d5bf2aSBenjamin Herrenschmidt #error unsupported page size 119627d5bf2aSBenjamin Herrenschmidt #endif 11976df10a82SMark Nutter } 11986df10a82SMark Nutter 1199f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_signal2_mmap_vmops = { 1200b1e2270fSNick Piggin .fault = spufs_signal2_mmap_fault, 12016df10a82SMark Nutter }; 12026df10a82SMark Nutter 12036df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 12046df10a82SMark Nutter { 12056df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 12066df10a82SMark Nutter return -EINVAL; 12076df10a82SMark Nutter 120878bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 120964b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 12106df10a82SMark Nutter 12116df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 12126df10a82SMark Nutter return 0; 12136df10a82SMark Nutter } 121427d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 121527d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 121627d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 12176df10a82SMark Nutter 12185dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = { 12196df10a82SMark Nutter .open = spufs_signal2_open, 122043c2bbd9SChristoph Hellwig .release = spufs_signal2_release, 122167207b96SArnd Bergmann .read = spufs_signal2_read, 122267207b96SArnd Bergmann .write = spufs_signal2_write, 12236df10a82SMark Nutter .mmap = spufs_signal2_mmap, 1224fc15351dSArnd Bergmann .llseek = no_llseek, 122567207b96SArnd Bergmann }; 122667207b96SArnd Bergmann 1227d054b36fSJeremy Kerr static const struct file_operations spufs_signal2_nosched_fops = { 1228d054b36fSJeremy Kerr .open = spufs_signal2_open, 1229d054b36fSJeremy Kerr .release = spufs_signal2_release, 1230d054b36fSJeremy Kerr .write = spufs_signal2_write, 1231d054b36fSJeremy Kerr .mmap = spufs_signal2_mmap, 1232fc15351dSArnd Bergmann .llseek = no_llseek, 1233d054b36fSJeremy Kerr }; 1234d054b36fSJeremy Kerr 1235104f0cc2SMichael Ellerman /* 1236104f0cc2SMichael Ellerman * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the 1237104f0cc2SMichael Ellerman * work of acquiring (or not) the SPU context before calling through 1238104f0cc2SMichael Ellerman * to the actual get routine. The set routine is called directly. 1239104f0cc2SMichael Ellerman */ 1240104f0cc2SMichael Ellerman #define SPU_ATTR_NOACQUIRE 0 1241104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE 1 1242104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE_SAVED 2 1243104f0cc2SMichael Ellerman 1244104f0cc2SMichael Ellerman #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ 1245197b1a82SChristoph Hellwig static int __##__get(void *data, u64 *val) \ 1246104f0cc2SMichael Ellerman { \ 1247104f0cc2SMichael Ellerman struct spu_context *ctx = data; \ 1248c9101bdbSChristoph Hellwig int ret = 0; \ 1249104f0cc2SMichael Ellerman \ 1250104f0cc2SMichael Ellerman if (__acquire == SPU_ATTR_ACQUIRE) { \ 1251c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); \ 1252c9101bdbSChristoph Hellwig if (ret) \ 1253c9101bdbSChristoph Hellwig return ret; \ 1254197b1a82SChristoph Hellwig *val = __get(ctx); \ 1255104f0cc2SMichael Ellerman spu_release(ctx); \ 1256104f0cc2SMichael Ellerman } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ 1257c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); \ 1258c9101bdbSChristoph Hellwig if (ret) \ 1259c9101bdbSChristoph Hellwig return ret; \ 1260197b1a82SChristoph Hellwig *val = __get(ctx); \ 1261104f0cc2SMichael Ellerman spu_release_saved(ctx); \ 1262104f0cc2SMichael Ellerman } else \ 1263197b1a82SChristoph Hellwig *val = __get(ctx); \ 1264104f0cc2SMichael Ellerman \ 1265197b1a82SChristoph Hellwig return 0; \ 1266104f0cc2SMichael Ellerman } \ 1267197b1a82SChristoph Hellwig DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); 1268104f0cc2SMichael Ellerman 1269197b1a82SChristoph Hellwig static int spufs_signal1_type_set(void *data, u64 val) 127067207b96SArnd Bergmann { 127167207b96SArnd Bergmann struct spu_context *ctx = data; 1272c9101bdbSChristoph Hellwig int ret; 127367207b96SArnd Bergmann 1274c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1275c9101bdbSChristoph Hellwig if (ret) 1276c9101bdbSChristoph Hellwig return ret; 12778b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 12788b3d6663SArnd Bergmann spu_release(ctx); 1279197b1a82SChristoph Hellwig 1280197b1a82SChristoph Hellwig return 0; 128167207b96SArnd Bergmann } 128267207b96SArnd Bergmann 1283104f0cc2SMichael Ellerman static u64 spufs_signal1_type_get(struct spu_context *ctx) 1284bf1ab978SDwayne Grant McConnell { 1285bf1ab978SDwayne Grant McConnell return ctx->ops->signal1_type_get(ctx); 1286bf1ab978SDwayne Grant McConnell } 1287104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 1288af8b44e0SJeremy Kerr spufs_signal1_type_set, "%llu\n", SPU_ATTR_ACQUIRE); 1289bf1ab978SDwayne Grant McConnell 129067207b96SArnd Bergmann 1291197b1a82SChristoph Hellwig static int spufs_signal2_type_set(void *data, u64 val) 129267207b96SArnd Bergmann { 129367207b96SArnd Bergmann struct spu_context *ctx = data; 1294c9101bdbSChristoph Hellwig int ret; 129567207b96SArnd Bergmann 1296c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1297c9101bdbSChristoph Hellwig if (ret) 1298c9101bdbSChristoph Hellwig return ret; 12998b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 13008b3d6663SArnd Bergmann spu_release(ctx); 1301197b1a82SChristoph Hellwig 1302197b1a82SChristoph Hellwig return 0; 130367207b96SArnd Bergmann } 130467207b96SArnd Bergmann 1305104f0cc2SMichael Ellerman static u64 spufs_signal2_type_get(struct spu_context *ctx) 1306bf1ab978SDwayne Grant McConnell { 1307bf1ab978SDwayne Grant McConnell return ctx->ops->signal2_type_get(ctx); 1308bf1ab978SDwayne Grant McConnell } 1309104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 1310af8b44e0SJeremy Kerr spufs_signal2_type_set, "%llu\n", SPU_ATTR_ACQUIRE); 131167207b96SArnd Bergmann 131227d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1313e807f02cSSouptick Joarder static vm_fault_t 131411bac800SDave Jiang spufs_mss_mmap_fault(struct vm_fault *vmf) 1315d9379c4bSarnd@arndb.de { 131611bac800SDave Jiang return spufs_ps_fault(vmf, 0x0000, SPUFS_MSS_MAP_SIZE); 1317d9379c4bSarnd@arndb.de } 1318d9379c4bSarnd@arndb.de 1319f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mss_mmap_vmops = { 1320b1e2270fSNick Piggin .fault = spufs_mss_mmap_fault, 1321d9379c4bSarnd@arndb.de }; 1322d9379c4bSarnd@arndb.de 1323d9379c4bSarnd@arndb.de /* 1324d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 1325d9379c4bSarnd@arndb.de */ 1326d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 1327d9379c4bSarnd@arndb.de { 1328d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 1329d9379c4bSarnd@arndb.de return -EINVAL; 1330d9379c4bSarnd@arndb.de 133178bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 133264b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 1333d9379c4bSarnd@arndb.de 1334d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 1335d9379c4bSarnd@arndb.de return 0; 1336d9379c4bSarnd@arndb.de } 133727d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 133827d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 133927d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1340d9379c4bSarnd@arndb.de 1341d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 1342d9379c4bSarnd@arndb.de { 1343d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 134417e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 1345d9379c4bSarnd@arndb.de 1346d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 134743c2bbd9SChristoph Hellwig 134847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 134943c2bbd9SChristoph Hellwig if (!i->i_openers++) 135017e0e270SBenjamin Herrenschmidt ctx->mss = inode->i_mapping; 135147d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1352d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 1353d9379c4bSarnd@arndb.de } 1354d9379c4bSarnd@arndb.de 135543c2bbd9SChristoph Hellwig static int 135643c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file) 135743c2bbd9SChristoph Hellwig { 135843c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 135943c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 136043c2bbd9SChristoph Hellwig 136147d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 136243c2bbd9SChristoph Hellwig if (!--i->i_openers) 136343c2bbd9SChristoph Hellwig ctx->mss = NULL; 136447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 136543c2bbd9SChristoph Hellwig return 0; 136643c2bbd9SChristoph Hellwig } 136743c2bbd9SChristoph Hellwig 13685dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = { 1369d9379c4bSarnd@arndb.de .open = spufs_mss_open, 137043c2bbd9SChristoph Hellwig .release = spufs_mss_release, 1371d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 1372fc15351dSArnd Bergmann .llseek = no_llseek, 137327d5bf2aSBenjamin Herrenschmidt }; 137427d5bf2aSBenjamin Herrenschmidt 1375e807f02cSSouptick Joarder static vm_fault_t 137611bac800SDave Jiang spufs_psmap_mmap_fault(struct vm_fault *vmf) 137727d5bf2aSBenjamin Herrenschmidt { 137811bac800SDave Jiang return spufs_ps_fault(vmf, 0x0000, SPUFS_PS_MAP_SIZE); 137927d5bf2aSBenjamin Herrenschmidt } 138027d5bf2aSBenjamin Herrenschmidt 1381f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_psmap_mmap_vmops = { 1382b1e2270fSNick Piggin .fault = spufs_psmap_mmap_fault, 138327d5bf2aSBenjamin Herrenschmidt }; 138427d5bf2aSBenjamin Herrenschmidt 138527d5bf2aSBenjamin Herrenschmidt /* 138627d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 138727d5bf2aSBenjamin Herrenschmidt */ 138827d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 138927d5bf2aSBenjamin Herrenschmidt { 139027d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 139127d5bf2aSBenjamin Herrenschmidt return -EINVAL; 139227d5bf2aSBenjamin Herrenschmidt 139378bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 139464b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 139527d5bf2aSBenjamin Herrenschmidt 139627d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 139727d5bf2aSBenjamin Herrenschmidt return 0; 139827d5bf2aSBenjamin Herrenschmidt } 139927d5bf2aSBenjamin Herrenschmidt 140027d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 140127d5bf2aSBenjamin Herrenschmidt { 140227d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 140317e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 140427d5bf2aSBenjamin Herrenschmidt 140547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 140627d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 140743c2bbd9SChristoph Hellwig if (!i->i_openers++) 140817e0e270SBenjamin Herrenschmidt ctx->psmap = inode->i_mapping; 140947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 141027d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 141127d5bf2aSBenjamin Herrenschmidt } 141227d5bf2aSBenjamin Herrenschmidt 141343c2bbd9SChristoph Hellwig static int 141443c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file) 141543c2bbd9SChristoph Hellwig { 141643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 141743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 141843c2bbd9SChristoph Hellwig 141947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 142043c2bbd9SChristoph Hellwig if (!--i->i_openers) 142143c2bbd9SChristoph Hellwig ctx->psmap = NULL; 142247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 142343c2bbd9SChristoph Hellwig return 0; 142443c2bbd9SChristoph Hellwig } 142543c2bbd9SChristoph Hellwig 14265dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = { 142727d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 142843c2bbd9SChristoph Hellwig .release = spufs_psmap_release, 142927d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1430fc15351dSArnd Bergmann .llseek = no_llseek, 1431d9379c4bSarnd@arndb.de }; 1432d9379c4bSarnd@arndb.de 1433d9379c4bSarnd@arndb.de 143427d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1435e807f02cSSouptick Joarder static vm_fault_t 143611bac800SDave Jiang spufs_mfc_mmap_fault(struct vm_fault *vmf) 14376df10a82SMark Nutter { 143811bac800SDave Jiang return spufs_ps_fault(vmf, 0x3000, SPUFS_MFC_MAP_SIZE); 14396df10a82SMark Nutter } 14406df10a82SMark Nutter 1441f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mfc_mmap_vmops = { 1442b1e2270fSNick Piggin .fault = spufs_mfc_mmap_fault, 14436df10a82SMark Nutter }; 14446df10a82SMark Nutter 14456df10a82SMark Nutter /* 14466df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 14476df10a82SMark Nutter */ 14486df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 14496df10a82SMark Nutter { 14506df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 14516df10a82SMark Nutter return -EINVAL; 14526df10a82SMark Nutter 145378bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 145464b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 14556df10a82SMark Nutter 14566df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 14576df10a82SMark Nutter return 0; 14586df10a82SMark Nutter } 145927d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 146027d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 146127d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1462a33a7d73SArnd Bergmann 1463a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1464a33a7d73SArnd Bergmann { 1465a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1466a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1467a33a7d73SArnd Bergmann 1468a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1469a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1470a33a7d73SArnd Bergmann return -EINVAL; 1471a33a7d73SArnd Bergmann 1472a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1473a33a7d73SArnd Bergmann return -EBUSY; 1474a33a7d73SArnd Bergmann 147547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1476a33a7d73SArnd Bergmann file->private_data = ctx; 147743c2bbd9SChristoph Hellwig if (!i->i_openers++) 147817e0e270SBenjamin Herrenschmidt ctx->mfc = inode->i_mapping; 147947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1480a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1481a33a7d73SArnd Bergmann } 1482a33a7d73SArnd Bergmann 148343c2bbd9SChristoph Hellwig static int 148443c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file) 148543c2bbd9SChristoph Hellwig { 148643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 148743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 148843c2bbd9SChristoph Hellwig 148947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 149043c2bbd9SChristoph Hellwig if (!--i->i_openers) 149143c2bbd9SChristoph Hellwig ctx->mfc = NULL; 149247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 149343c2bbd9SChristoph Hellwig return 0; 149443c2bbd9SChristoph Hellwig } 149543c2bbd9SChristoph Hellwig 1496a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1497a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1498a33a7d73SArnd Bergmann { 1499a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1500a33a7d73SArnd Bergmann 15017d7be3aaSAl Viro if (ctx) 1502a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1503a33a7d73SArnd Bergmann } 1504a33a7d73SArnd Bergmann 1505a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1506a33a7d73SArnd Bergmann { 1507a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1508a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1509a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1510a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1511a33a7d73SArnd Bergmann if (*status) 1512a33a7d73SArnd Bergmann return 1; 1513a33a7d73SArnd Bergmann 1514a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1515a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1516a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1517a33a7d73SArnd Bergmann return 0; 1518a33a7d73SArnd Bergmann } 1519a33a7d73SArnd Bergmann 1520a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1521a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1522a33a7d73SArnd Bergmann { 1523a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1524a33a7d73SArnd Bergmann int ret = -EINVAL; 1525a33a7d73SArnd Bergmann u32 status; 1526a33a7d73SArnd Bergmann 1527a33a7d73SArnd Bergmann if (size != 4) 1528a33a7d73SArnd Bergmann goto out; 1529a33a7d73SArnd Bergmann 1530c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1531c9101bdbSChristoph Hellwig if (ret) 1532c9101bdbSChristoph Hellwig return ret; 1533c9101bdbSChristoph Hellwig 1534c9101bdbSChristoph Hellwig ret = -EINVAL; 1535a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1536a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1537a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1538a33a7d73SArnd Bergmann ret = -EAGAIN; 1539a33a7d73SArnd Bergmann else 1540c9101bdbSChristoph Hellwig /* XXX(hch): shouldn't we clear ret here? */ 1541a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1542a33a7d73SArnd Bergmann } else { 1543a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1544a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1545a33a7d73SArnd Bergmann if (ret) 1546a33a7d73SArnd Bergmann goto out; 1547eebead5bSChristoph Hellwig } 1548eebead5bSChristoph Hellwig spu_release(ctx); 1549a33a7d73SArnd Bergmann 1550a33a7d73SArnd Bergmann ret = 4; 1551a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1552a33a7d73SArnd Bergmann ret = -EFAULT; 1553a33a7d73SArnd Bergmann 1554a33a7d73SArnd Bergmann out: 1555a33a7d73SArnd Bergmann return ret; 1556a33a7d73SArnd Bergmann } 1557a33a7d73SArnd Bergmann 1558a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1559a33a7d73SArnd Bergmann { 15609477e455SStephen Rothwell pr_debug("queueing DMA %x %llx %x %x %x\n", cmd->lsa, 1561a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1562a33a7d73SArnd Bergmann 1563a33a7d73SArnd Bergmann switch (cmd->cmd) { 1564a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1565a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1566a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1567a33a7d73SArnd Bergmann case MFC_GET_CMD: 1568a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1569a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1570a33a7d73SArnd Bergmann break; 1571a33a7d73SArnd Bergmann default: 1572a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1573a33a7d73SArnd Bergmann return -EIO; 1574a33a7d73SArnd Bergmann } 1575a33a7d73SArnd Bergmann 1576a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 15779477e455SStephen Rothwell pr_debug("invalid DMA alignment, ea %llx lsa %x\n", 1578a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1579a33a7d73SArnd Bergmann return -EIO; 1580a33a7d73SArnd Bergmann } 1581a33a7d73SArnd Bergmann 1582a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1583a33a7d73SArnd Bergmann case 1: 1584a33a7d73SArnd Bergmann break; 1585a33a7d73SArnd Bergmann case 2: 1586a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1587a33a7d73SArnd Bergmann goto error; 1588a33a7d73SArnd Bergmann break; 1589a33a7d73SArnd Bergmann case 4: 1590a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1591a33a7d73SArnd Bergmann goto error; 1592a33a7d73SArnd Bergmann break; 1593a33a7d73SArnd Bergmann case 8: 1594a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1595a33a7d73SArnd Bergmann goto error; 1596a33a7d73SArnd Bergmann break; 1597a33a7d73SArnd Bergmann case 0: 1598a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1599a33a7d73SArnd Bergmann goto error; 1600a33a7d73SArnd Bergmann break; 1601a33a7d73SArnd Bergmann error: 1602a33a7d73SArnd Bergmann default: 1603a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1604a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1605a33a7d73SArnd Bergmann return -EIO; 1606a33a7d73SArnd Bergmann } 1607a33a7d73SArnd Bergmann 1608a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1609a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1610a33a7d73SArnd Bergmann return -EIO; 1611a33a7d73SArnd Bergmann } 1612a33a7d73SArnd Bergmann 1613a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1614a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1615a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1616a33a7d73SArnd Bergmann return -EIO; 1617a33a7d73SArnd Bergmann } 1618a33a7d73SArnd Bergmann 1619a33a7d73SArnd Bergmann if (cmd->class) { 1620a33a7d73SArnd Bergmann /* not supported in this version */ 1621a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1622a33a7d73SArnd Bergmann return -EIO; 1623a33a7d73SArnd Bergmann } 1624a33a7d73SArnd Bergmann 1625a33a7d73SArnd Bergmann return 0; 1626a33a7d73SArnd Bergmann } 1627a33a7d73SArnd Bergmann 1628a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1629a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1630a33a7d73SArnd Bergmann int *error) 1631a33a7d73SArnd Bergmann { 1632a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1633a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1634a33a7d73SArnd Bergmann /* wait for any tag group to complete 1635a33a7d73SArnd Bergmann so we have space for the new command */ 1636a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1637a33a7d73SArnd Bergmann /* try again, because the queue might be 1638a33a7d73SArnd Bergmann empty again */ 1639a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1640a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1641a33a7d73SArnd Bergmann return 0; 1642a33a7d73SArnd Bergmann } 1643a33a7d73SArnd Bergmann return 1; 1644a33a7d73SArnd Bergmann } 1645a33a7d73SArnd Bergmann 1646a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1647a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1648a33a7d73SArnd Bergmann { 1649a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1650a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1651a33a7d73SArnd Bergmann int ret = -EINVAL; 1652a33a7d73SArnd Bergmann 1653a33a7d73SArnd Bergmann if (size != sizeof cmd) 1654a33a7d73SArnd Bergmann goto out; 1655a33a7d73SArnd Bergmann 1656a33a7d73SArnd Bergmann ret = -EFAULT; 1657a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1658a33a7d73SArnd Bergmann goto out; 1659a33a7d73SArnd Bergmann 1660a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1661a33a7d73SArnd Bergmann if (ret) 1662a33a7d73SArnd Bergmann goto out; 1663a33a7d73SArnd Bergmann 1664c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1665c9101bdbSChristoph Hellwig if (ret) 1666c9101bdbSChristoph Hellwig goto out; 1667c9101bdbSChristoph Hellwig 166833bfd7a7SArnd Bergmann ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 1669577f8f10SAkinobu Mita if (ret) 1670577f8f10SAkinobu Mita goto out; 1671577f8f10SAkinobu Mita 1672a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1673a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1674a33a7d73SArnd Bergmann } else { 1675a33a7d73SArnd Bergmann int status; 1676a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1677a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1678eebead5bSChristoph Hellwig if (ret) 1679eebead5bSChristoph Hellwig goto out; 1680a33a7d73SArnd Bergmann if (status) 1681a33a7d73SArnd Bergmann ret = status; 1682a33a7d73SArnd Bergmann } 1683a33a7d73SArnd Bergmann 1684a33a7d73SArnd Bergmann if (ret) 1685933b0e35SKazunori Asayama goto out_unlock; 1686a33a7d73SArnd Bergmann 1687a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 16883692dc66SMasato Noguchi ret = size; 1689a33a7d73SArnd Bergmann 1690933b0e35SKazunori Asayama out_unlock: 1691933b0e35SKazunori Asayama spu_release(ctx); 1692a33a7d73SArnd Bergmann out: 1693a33a7d73SArnd Bergmann return ret; 1694a33a7d73SArnd Bergmann } 1695a33a7d73SArnd Bergmann 16968153a5eaSAl Viro static __poll_t spufs_mfc_poll(struct file *file,poll_table *wait) 1697a33a7d73SArnd Bergmann { 1698a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1699a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 17008153a5eaSAl Viro __poll_t mask; 1701a33a7d73SArnd Bergmann 1702933b0e35SKazunori Asayama poll_wait(file, &ctx->mfc_wq, wait); 1703933b0e35SKazunori Asayama 1704c9101bdbSChristoph Hellwig /* 1705c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 1706c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 1707c9101bdbSChristoph Hellwig */ 1708c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 1709a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1710a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1711a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1712a33a7d73SArnd Bergmann spu_release(ctx); 1713a33a7d73SArnd Bergmann 1714a33a7d73SArnd Bergmann mask = 0; 1715a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1716a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 1717a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1718a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 1719a33a7d73SArnd Bergmann 1720e48b1b45SHarvey Harrison pr_debug("%s: free %d tagstatus %d tagwait %d\n", __func__, 1721a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1722a33a7d73SArnd Bergmann 1723a33a7d73SArnd Bergmann return mask; 1724a33a7d73SArnd Bergmann } 1725a33a7d73SArnd Bergmann 172673b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1727a33a7d73SArnd Bergmann { 1728a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1729a33a7d73SArnd Bergmann int ret; 1730a33a7d73SArnd Bergmann 1731c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1732c9101bdbSChristoph Hellwig if (ret) 1733eebead5bSChristoph Hellwig goto out; 1734a33a7d73SArnd Bergmann #if 0 1735a33a7d73SArnd Bergmann /* this currently hangs */ 1736a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1737a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1738a33a7d73SArnd Bergmann if (ret) 1739a33a7d73SArnd Bergmann goto out; 1740a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1741a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1742eebead5bSChristoph Hellwig if (ret) 1743eebead5bSChristoph Hellwig goto out; 1744a33a7d73SArnd Bergmann #else 1745a33a7d73SArnd Bergmann ret = 0; 1746a33a7d73SArnd Bergmann #endif 1747a33a7d73SArnd Bergmann spu_release(ctx); 1748eebead5bSChristoph Hellwig out: 1749a33a7d73SArnd Bergmann return ret; 1750a33a7d73SArnd Bergmann } 1751a33a7d73SArnd Bergmann 175202c24a82SJosef Bacik static int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync) 1753a33a7d73SArnd Bergmann { 1754496ad9aaSAl Viro struct inode *inode = file_inode(file); 17553b49c9a1SJeff Layton int err = file_write_and_wait_range(file, start, end); 175602c24a82SJosef Bacik if (!err) { 17575955102cSAl Viro inode_lock(inode); 175802c24a82SJosef Bacik err = spufs_mfc_flush(file, NULL); 17595955102cSAl Viro inode_unlock(inode); 176002c24a82SJosef Bacik } 176102c24a82SJosef Bacik return err; 1762a33a7d73SArnd Bergmann } 1763a33a7d73SArnd Bergmann 17645dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = { 1765a33a7d73SArnd Bergmann .open = spufs_mfc_open, 176643c2bbd9SChristoph Hellwig .release = spufs_mfc_release, 1767a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1768a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1769a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1770a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1771a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 17726df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1773fc15351dSArnd Bergmann .llseek = no_llseek, 1774a33a7d73SArnd Bergmann }; 1775a33a7d73SArnd Bergmann 1776197b1a82SChristoph Hellwig static int spufs_npc_set(void *data, u64 val) 177767207b96SArnd Bergmann { 177867207b96SArnd Bergmann struct spu_context *ctx = data; 1779c9101bdbSChristoph Hellwig int ret; 1780c9101bdbSChristoph Hellwig 1781c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1782c9101bdbSChristoph Hellwig if (ret) 1783c9101bdbSChristoph Hellwig return ret; 17848b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 17858b3d6663SArnd Bergmann spu_release(ctx); 1786197b1a82SChristoph Hellwig 1787197b1a82SChristoph Hellwig return 0; 178867207b96SArnd Bergmann } 178967207b96SArnd Bergmann 1790104f0cc2SMichael Ellerman static u64 spufs_npc_get(struct spu_context *ctx) 179178810ff6SMichael Ellerman { 179278810ff6SMichael Ellerman return ctx->ops->npc_read(ctx); 179378810ff6SMichael Ellerman } 1794104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 1795104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE); 179667207b96SArnd Bergmann 1797197b1a82SChristoph Hellwig static int spufs_decr_set(void *data, u64 val) 17988b3d6663SArnd Bergmann { 17998b3d6663SArnd Bergmann struct spu_context *ctx = data; 18008b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1801c9101bdbSChristoph Hellwig int ret; 1802c9101bdbSChristoph Hellwig 1803c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1804c9101bdbSChristoph Hellwig if (ret) 1805c9101bdbSChristoph Hellwig return ret; 18068b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 180727b1ea09SChristoph Hellwig spu_release_saved(ctx); 1808197b1a82SChristoph Hellwig 1809197b1a82SChristoph Hellwig return 0; 18108b3d6663SArnd Bergmann } 18118b3d6663SArnd Bergmann 1812104f0cc2SMichael Ellerman static u64 spufs_decr_get(struct spu_context *ctx) 18138b3d6663SArnd Bergmann { 18148b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1815bf1ab978SDwayne Grant McConnell return lscsa->decr.slot[0]; 1816bf1ab978SDwayne Grant McConnell } 1817104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 1818104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); 18198b3d6663SArnd Bergmann 1820197b1a82SChristoph Hellwig static int spufs_decr_status_set(void *data, u64 val) 18218b3d6663SArnd Bergmann { 18228b3d6663SArnd Bergmann struct spu_context *ctx = data; 1823c9101bdbSChristoph Hellwig int ret; 1824c9101bdbSChristoph Hellwig 1825c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1826c9101bdbSChristoph Hellwig if (ret) 1827c9101bdbSChristoph Hellwig return ret; 1828d40a01d4SMasato Noguchi if (val) 1829d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 1830d40a01d4SMasato Noguchi else 1831d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 183227b1ea09SChristoph Hellwig spu_release_saved(ctx); 1833197b1a82SChristoph Hellwig 1834197b1a82SChristoph Hellwig return 0; 18358b3d6663SArnd Bergmann } 18368b3d6663SArnd Bergmann 1837104f0cc2SMichael Ellerman static u64 spufs_decr_status_get(struct spu_context *ctx) 18388b3d6663SArnd Bergmann { 1839d40a01d4SMasato Noguchi if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 1840d40a01d4SMasato Noguchi return SPU_DECR_STATUS_RUNNING; 1841d40a01d4SMasato Noguchi else 1842d40a01d4SMasato Noguchi return 0; 1843bf1ab978SDwayne Grant McConnell } 1844104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 1845104f0cc2SMichael Ellerman spufs_decr_status_set, "0x%llx\n", 1846104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 18478b3d6663SArnd Bergmann 1848197b1a82SChristoph Hellwig static int spufs_event_mask_set(void *data, u64 val) 18498b3d6663SArnd Bergmann { 18508b3d6663SArnd Bergmann struct spu_context *ctx = data; 18518b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1852c9101bdbSChristoph Hellwig int ret; 1853c9101bdbSChristoph Hellwig 1854c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1855c9101bdbSChristoph Hellwig if (ret) 1856c9101bdbSChristoph Hellwig return ret; 18578b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 185827b1ea09SChristoph Hellwig spu_release_saved(ctx); 1859197b1a82SChristoph Hellwig 1860197b1a82SChristoph Hellwig return 0; 18618b3d6663SArnd Bergmann } 18628b3d6663SArnd Bergmann 1863104f0cc2SMichael Ellerman static u64 spufs_event_mask_get(struct spu_context *ctx) 18648b3d6663SArnd Bergmann { 18658b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1866bf1ab978SDwayne Grant McConnell return lscsa->event_mask.slot[0]; 1867bf1ab978SDwayne Grant McConnell } 1868bf1ab978SDwayne Grant McConnell 1869104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 1870104f0cc2SMichael Ellerman spufs_event_mask_set, "0x%llx\n", 1871104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 18728b3d6663SArnd Bergmann 1873104f0cc2SMichael Ellerman static u64 spufs_event_status_get(struct spu_context *ctx) 1874b9e3bd77SDwayne Grant McConnell { 1875b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1876b9e3bd77SDwayne Grant McConnell u64 stat; 1877b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1878b9e3bd77SDwayne Grant McConnell if (stat) 1879bf1ab978SDwayne Grant McConnell return state->spu_chnldata_RW[0]; 1880bf1ab978SDwayne Grant McConnell return 0; 1881bf1ab978SDwayne Grant McConnell } 1882104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1883104f0cc2SMichael Ellerman NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 1884b9e3bd77SDwayne Grant McConnell 1885197b1a82SChristoph Hellwig static int spufs_srr0_set(void *data, u64 val) 18868b3d6663SArnd Bergmann { 18878b3d6663SArnd Bergmann struct spu_context *ctx = data; 18888b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1889c9101bdbSChristoph Hellwig int ret; 1890c9101bdbSChristoph Hellwig 1891c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1892c9101bdbSChristoph Hellwig if (ret) 1893c9101bdbSChristoph Hellwig return ret; 18948b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 189527b1ea09SChristoph Hellwig spu_release_saved(ctx); 1896197b1a82SChristoph Hellwig 1897197b1a82SChristoph Hellwig return 0; 18988b3d6663SArnd Bergmann } 18998b3d6663SArnd Bergmann 1900104f0cc2SMichael Ellerman static u64 spufs_srr0_get(struct spu_context *ctx) 19018b3d6663SArnd Bergmann { 19028b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1903104f0cc2SMichael Ellerman return lscsa->srr0.slot[0]; 19048b3d6663SArnd Bergmann } 1905104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 1906104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 19078b3d6663SArnd Bergmann 1908104f0cc2SMichael Ellerman static u64 spufs_id_get(struct spu_context *ctx) 19097b1a7014Sarnd@arndb.de { 19107b1a7014Sarnd@arndb.de u64 num; 19117b1a7014Sarnd@arndb.de 19127b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 19137b1a7014Sarnd@arndb.de num = ctx->spu->number; 19147b1a7014Sarnd@arndb.de else 19157b1a7014Sarnd@arndb.de num = (unsigned int)-1; 19167b1a7014Sarnd@arndb.de 19177b1a7014Sarnd@arndb.de return num; 19187b1a7014Sarnd@arndb.de } 1919104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", 1920104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE) 19217b1a7014Sarnd@arndb.de 1922104f0cc2SMichael Ellerman static u64 spufs_object_id_get(struct spu_context *ctx) 1923bf1ab978SDwayne Grant McConnell { 1924bf1ab978SDwayne Grant McConnell /* FIXME: Should there really be no locking here? */ 1925104f0cc2SMichael Ellerman return ctx->object_id; 1926bf1ab978SDwayne Grant McConnell } 1927bf1ab978SDwayne Grant McConnell 1928197b1a82SChristoph Hellwig static int spufs_object_id_set(void *data, u64 id) 192986767277SArnd Bergmann { 193086767277SArnd Bergmann struct spu_context *ctx = data; 193186767277SArnd Bergmann ctx->object_id = id; 1932197b1a82SChristoph Hellwig 1933197b1a82SChristoph Hellwig return 0; 193486767277SArnd Bergmann } 193586767277SArnd Bergmann 1936104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 1937104f0cc2SMichael Ellerman spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); 193886767277SArnd Bergmann 1939104f0cc2SMichael Ellerman static u64 spufs_lslr_get(struct spu_context *ctx) 1940bf1ab978SDwayne Grant McConnell { 1941bf1ab978SDwayne Grant McConnell return ctx->csa.priv2.spu_lslr_RW; 1942bf1ab978SDwayne Grant McConnell } 1943104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", 1944104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 1945b9e3bd77SDwayne Grant McConnell 1946b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 1947b9e3bd77SDwayne Grant McConnell { 1948b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 1949b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 1950b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 1951b9e3bd77SDwayne Grant McConnell return 0; 1952b9e3bd77SDwayne Grant McConnell } 1953b9e3bd77SDwayne Grant McConnell 1954cbe709c1SBenjamin Herrenschmidt static int spufs_caps_show(struct seq_file *s, void *private) 1955cbe709c1SBenjamin Herrenschmidt { 1956cbe709c1SBenjamin Herrenschmidt struct spu_context *ctx = s->private; 1957cbe709c1SBenjamin Herrenschmidt 1958cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_NOSCHED)) 1959cbe709c1SBenjamin Herrenschmidt seq_puts(s, "sched\n"); 1960cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_ISOLATE)) 1961cbe709c1SBenjamin Herrenschmidt seq_puts(s, "step\n"); 1962cbe709c1SBenjamin Herrenschmidt return 0; 1963cbe709c1SBenjamin Herrenschmidt } 1964cbe709c1SBenjamin Herrenschmidt 1965cbe709c1SBenjamin Herrenschmidt static int spufs_caps_open(struct inode *inode, struct file *file) 1966cbe709c1SBenjamin Herrenschmidt { 1967cbe709c1SBenjamin Herrenschmidt return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); 1968cbe709c1SBenjamin Herrenschmidt } 1969cbe709c1SBenjamin Herrenschmidt 1970cbe709c1SBenjamin Herrenschmidt static const struct file_operations spufs_caps_fops = { 1971cbe709c1SBenjamin Herrenschmidt .open = spufs_caps_open, 1972cbe709c1SBenjamin Herrenschmidt .read = seq_read, 1973cbe709c1SBenjamin Herrenschmidt .llseek = seq_lseek, 1974cbe709c1SBenjamin Herrenschmidt .release = single_release, 1975cbe709c1SBenjamin Herrenschmidt }; 1976cbe709c1SBenjamin Herrenschmidt 1977bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, 1978bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 1979bf1ab978SDwayne Grant McConnell { 1980bf1ab978SDwayne Grant McConnell u32 data; 1981bf1ab978SDwayne Grant McConnell 1982cbea9238SJeremy Kerr /* EOF if there's no entry in the mbox */ 1983cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0x0000ff)) 1984cbea9238SJeremy Kerr return 0; 1985cbea9238SJeremy Kerr 1986bf1ab978SDwayne Grant McConnell data = ctx->csa.prob.pu_mb_R; 1987bf1ab978SDwayne Grant McConnell 1988bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 1989bf1ab978SDwayne Grant McConnell } 1990bf1ab978SDwayne Grant McConnell 199169a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 199269a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 199369a2f00cSDwayne Grant McConnell { 1994bf1ab978SDwayne Grant McConnell int ret; 199569a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 199669a2f00cSDwayne Grant McConnell 199769a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 199869a2f00cSDwayne Grant McConnell return -EFAULT; 199969a2f00cSDwayne Grant McConnell 2000c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2001c9101bdbSChristoph Hellwig if (ret) 2002c9101bdbSChristoph Hellwig return ret; 200369a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2004bf1ab978SDwayne Grant McConnell ret = __spufs_mbox_info_read(ctx, buf, len, pos); 200569a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 200627b1ea09SChristoph Hellwig spu_release_saved(ctx); 200769a2f00cSDwayne Grant McConnell 2008bf1ab978SDwayne Grant McConnell return ret; 200969a2f00cSDwayne Grant McConnell } 201069a2f00cSDwayne Grant McConnell 20115dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = { 201269a2f00cSDwayne Grant McConnell .open = spufs_info_open, 201369a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 201469a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 201569a2f00cSDwayne Grant McConnell }; 201669a2f00cSDwayne Grant McConnell 2017bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, 2018bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2019bf1ab978SDwayne Grant McConnell { 2020bf1ab978SDwayne Grant McConnell u32 data; 2021bf1ab978SDwayne Grant McConnell 2022cbea9238SJeremy Kerr /* EOF if there's no entry in the ibox */ 2023cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) 2024cbea9238SJeremy Kerr return 0; 2025cbea9238SJeremy Kerr 2026bf1ab978SDwayne Grant McConnell data = ctx->csa.priv2.puint_mb_R; 2027bf1ab978SDwayne Grant McConnell 2028bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2029bf1ab978SDwayne Grant McConnell } 2030bf1ab978SDwayne Grant McConnell 203169a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 203269a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 203369a2f00cSDwayne Grant McConnell { 203469a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2035bf1ab978SDwayne Grant McConnell int ret; 203669a2f00cSDwayne Grant McConnell 203769a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 203869a2f00cSDwayne Grant McConnell return -EFAULT; 203969a2f00cSDwayne Grant McConnell 2040c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2041c9101bdbSChristoph Hellwig if (ret) 2042c9101bdbSChristoph Hellwig return ret; 204369a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2044bf1ab978SDwayne Grant McConnell ret = __spufs_ibox_info_read(ctx, buf, len, pos); 204569a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 204627b1ea09SChristoph Hellwig spu_release_saved(ctx); 204769a2f00cSDwayne Grant McConnell 2048bf1ab978SDwayne Grant McConnell return ret; 204969a2f00cSDwayne Grant McConnell } 205069a2f00cSDwayne Grant McConnell 20515dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = { 205269a2f00cSDwayne Grant McConnell .open = spufs_info_open, 205369a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 205469a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 205569a2f00cSDwayne Grant McConnell }; 205669a2f00cSDwayne Grant McConnell 2057bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, 2058bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2059bf1ab978SDwayne Grant McConnell { 2060bf1ab978SDwayne Grant McConnell int i, cnt; 2061bf1ab978SDwayne Grant McConnell u32 data[4]; 2062bf1ab978SDwayne Grant McConnell u32 wbox_stat; 2063bf1ab978SDwayne Grant McConnell 2064bf1ab978SDwayne Grant McConnell wbox_stat = ctx->csa.prob.mb_stat_R; 2065bf1ab978SDwayne Grant McConnell cnt = 4 - ((wbox_stat & 0x00ff00) >> 8); 2066bf1ab978SDwayne Grant McConnell for (i = 0; i < cnt; i++) { 2067bf1ab978SDwayne Grant McConnell data[i] = ctx->csa.spu_mailbox_data[i]; 2068bf1ab978SDwayne Grant McConnell } 2069bf1ab978SDwayne Grant McConnell 2070bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, 2071bf1ab978SDwayne Grant McConnell cnt * sizeof(u32)); 2072bf1ab978SDwayne Grant McConnell } 2073bf1ab978SDwayne Grant McConnell 207469a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 207569a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 207669a2f00cSDwayne Grant McConnell { 207769a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2078bf1ab978SDwayne Grant McConnell int ret; 207969a2f00cSDwayne Grant McConnell 208069a2f00cSDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 208169a2f00cSDwayne Grant McConnell return -EFAULT; 208269a2f00cSDwayne Grant McConnell 2083c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2084c9101bdbSChristoph Hellwig if (ret) 2085c9101bdbSChristoph Hellwig return ret; 208669a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2087bf1ab978SDwayne Grant McConnell ret = __spufs_wbox_info_read(ctx, buf, len, pos); 208869a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 208927b1ea09SChristoph Hellwig spu_release_saved(ctx); 209069a2f00cSDwayne Grant McConnell 2091bf1ab978SDwayne Grant McConnell return ret; 209269a2f00cSDwayne Grant McConnell } 209369a2f00cSDwayne Grant McConnell 20945dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = { 209569a2f00cSDwayne Grant McConnell .open = spufs_info_open, 209669a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 209769a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 209869a2f00cSDwayne Grant McConnell }; 209969a2f00cSDwayne Grant McConnell 2100bf1ab978SDwayne Grant McConnell static ssize_t __spufs_dma_info_read(struct spu_context *ctx, 2101bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2102b9e3bd77SDwayne Grant McConnell { 2103b9e3bd77SDwayne Grant McConnell struct spu_dma_info info; 2104b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *spuqp; 2105b9e3bd77SDwayne Grant McConnell int i; 2106b9e3bd77SDwayne Grant McConnell 2107b9e3bd77SDwayne Grant McConnell info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 2108b9e3bd77SDwayne Grant McConnell info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 2109b9e3bd77SDwayne Grant McConnell info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; 2110b9e3bd77SDwayne Grant McConnell info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 2111b9e3bd77SDwayne Grant McConnell info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 2112b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 2113b9e3bd77SDwayne Grant McConnell qp = &info.dma_info_command_data[i]; 2114b9e3bd77SDwayne Grant McConnell spuqp = &ctx->csa.priv2.spuq[i]; 2115b9e3bd77SDwayne Grant McConnell 2116b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 2117b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 2118b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 2119b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 2120b9e3bd77SDwayne Grant McConnell } 2121b9e3bd77SDwayne Grant McConnell 2122b9e3bd77SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2123b9e3bd77SDwayne Grant McConnell sizeof info); 2124b9e3bd77SDwayne Grant McConnell } 2125b9e3bd77SDwayne Grant McConnell 2126bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 2127bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2128bf1ab978SDwayne Grant McConnell { 2129bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2130bf1ab978SDwayne Grant McConnell int ret; 2131bf1ab978SDwayne Grant McConnell 2132bf1ab978SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2133bf1ab978SDwayne Grant McConnell return -EFAULT; 2134bf1ab978SDwayne Grant McConnell 2135c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2136c9101bdbSChristoph Hellwig if (ret) 2137c9101bdbSChristoph Hellwig return ret; 2138bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2139bf1ab978SDwayne Grant McConnell ret = __spufs_dma_info_read(ctx, buf, len, pos); 2140bf1ab978SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 214127b1ea09SChristoph Hellwig spu_release_saved(ctx); 2142bf1ab978SDwayne Grant McConnell 2143bf1ab978SDwayne Grant McConnell return ret; 2144bf1ab978SDwayne Grant McConnell } 2145bf1ab978SDwayne Grant McConnell 21465dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = { 2147b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2148b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 2149fc15351dSArnd Bergmann .llseek = no_llseek, 2150b9e3bd77SDwayne Grant McConnell }; 2151b9e3bd77SDwayne Grant McConnell 2152bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, 2153bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2154b9e3bd77SDwayne Grant McConnell { 2155b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 2156b9e3bd77SDwayne Grant McConnell struct mfc_cq_sr *qp, *puqp; 2157bf1ab978SDwayne Grant McConnell int ret = sizeof info; 2158b9e3bd77SDwayne Grant McConnell int i; 2159b9e3bd77SDwayne Grant McConnell 2160b9e3bd77SDwayne Grant McConnell if (len < ret) 2161b9e3bd77SDwayne Grant McConnell return -EINVAL; 2162b9e3bd77SDwayne Grant McConnell 2163b9e3bd77SDwayne Grant McConnell if (!access_ok(VERIFY_WRITE, buf, len)) 2164b9e3bd77SDwayne Grant McConnell return -EFAULT; 2165b9e3bd77SDwayne Grant McConnell 2166b9e3bd77SDwayne Grant McConnell info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 2167b9e3bd77SDwayne Grant McConnell info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 2168b9e3bd77SDwayne Grant McConnell info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 2169b9e3bd77SDwayne Grant McConnell for (i = 0; i < 8; i++) { 2170b9e3bd77SDwayne Grant McConnell qp = &info.proxydma_info_command_data[i]; 2171b9e3bd77SDwayne Grant McConnell puqp = &ctx->csa.priv2.puq[i]; 2172b9e3bd77SDwayne Grant McConnell 2173b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 2174b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 2175b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 2176b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 2177b9e3bd77SDwayne Grant McConnell } 2178bf1ab978SDwayne Grant McConnell 2179bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2180bf1ab978SDwayne Grant McConnell sizeof info); 2181bf1ab978SDwayne Grant McConnell } 2182bf1ab978SDwayne Grant McConnell 2183bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 2184bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2185bf1ab978SDwayne Grant McConnell { 2186bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 2187bf1ab978SDwayne Grant McConnell int ret; 2188bf1ab978SDwayne Grant McConnell 2189c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2190c9101bdbSChristoph Hellwig if (ret) 2191c9101bdbSChristoph Hellwig return ret; 2192bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 2193bf1ab978SDwayne Grant McConnell ret = __spufs_proxydma_info_read(ctx, buf, len, pos); 2194b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 219527b1ea09SChristoph Hellwig spu_release_saved(ctx); 2196b9e3bd77SDwayne Grant McConnell 2197b9e3bd77SDwayne Grant McConnell return ret; 2198b9e3bd77SDwayne Grant McConnell } 2199b9e3bd77SDwayne Grant McConnell 22005dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = { 2201b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2202b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 2203fc15351dSArnd Bergmann .llseek = no_llseek, 2204b9e3bd77SDwayne Grant McConnell }; 2205b9e3bd77SDwayne Grant McConnell 2206476273adSChristoph Hellwig static int spufs_show_tid(struct seq_file *s, void *private) 2207476273adSChristoph Hellwig { 2208476273adSChristoph Hellwig struct spu_context *ctx = s->private; 2209476273adSChristoph Hellwig 2210476273adSChristoph Hellwig seq_printf(s, "%d\n", ctx->tid); 2211476273adSChristoph Hellwig return 0; 2212476273adSChristoph Hellwig } 2213476273adSChristoph Hellwig 2214476273adSChristoph Hellwig static int spufs_tid_open(struct inode *inode, struct file *file) 2215476273adSChristoph Hellwig { 2216476273adSChristoph Hellwig return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); 2217476273adSChristoph Hellwig } 2218476273adSChristoph Hellwig 2219476273adSChristoph Hellwig static const struct file_operations spufs_tid_fops = { 2220476273adSChristoph Hellwig .open = spufs_tid_open, 2221476273adSChristoph Hellwig .read = seq_read, 2222476273adSChristoph Hellwig .llseek = seq_lseek, 2223476273adSChristoph Hellwig .release = single_release, 2224476273adSChristoph Hellwig }; 2225476273adSChristoph Hellwig 2226e9f8a0b6SChristoph Hellwig static const char *ctx_state_names[] = { 2227e9f8a0b6SChristoph Hellwig "user", "system", "iowait", "loaded" 2228e9f8a0b6SChristoph Hellwig }; 2229e9f8a0b6SChristoph Hellwig 2230e9f8a0b6SChristoph Hellwig static unsigned long long spufs_acct_time(struct spu_context *ctx, 223127ec41d3SAndre Detsch enum spu_utilization_state state) 2232e9f8a0b6SChristoph Hellwig { 223327ec41d3SAndre Detsch unsigned long long time = ctx->stats.times[state]; 2234e9f8a0b6SChristoph Hellwig 223527ec41d3SAndre Detsch /* 223627ec41d3SAndre Detsch * In general, utilization statistics are updated by the controlling 223727ec41d3SAndre Detsch * thread as the spu context moves through various well defined 223827ec41d3SAndre Detsch * state transitions, but if the context is lazily loaded its 223927ec41d3SAndre Detsch * utilization statistics are not updated as the controlling thread 224027ec41d3SAndre Detsch * is not tightly coupled with the execution of the spu context. We 224127ec41d3SAndre Detsch * calculate and apply the time delta from the last recorded state 224227ec41d3SAndre Detsch * of the spu context. 224327ec41d3SAndre Detsch */ 224427ec41d3SAndre Detsch if (ctx->spu && ctx->stats.util_state == state) { 2245f2dec1eaSThomas Gleixner time += ktime_get_ns() - ctx->stats.tstamp; 224627ec41d3SAndre Detsch } 2247e9f8a0b6SChristoph Hellwig 224827ec41d3SAndre Detsch return time / NSEC_PER_MSEC; 2249e9f8a0b6SChristoph Hellwig } 2250e9f8a0b6SChristoph Hellwig 2251e9f8a0b6SChristoph Hellwig static unsigned long long spufs_slb_flts(struct spu_context *ctx) 2252e9f8a0b6SChristoph Hellwig { 2253e9f8a0b6SChristoph Hellwig unsigned long long slb_flts = ctx->stats.slb_flt; 2254e9f8a0b6SChristoph Hellwig 2255e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2256e9f8a0b6SChristoph Hellwig slb_flts += (ctx->spu->stats.slb_flt - 2257e9f8a0b6SChristoph Hellwig ctx->stats.slb_flt_base); 2258e9f8a0b6SChristoph Hellwig } 2259e9f8a0b6SChristoph Hellwig 2260e9f8a0b6SChristoph Hellwig return slb_flts; 2261e9f8a0b6SChristoph Hellwig } 2262e9f8a0b6SChristoph Hellwig 2263e9f8a0b6SChristoph Hellwig static unsigned long long spufs_class2_intrs(struct spu_context *ctx) 2264e9f8a0b6SChristoph Hellwig { 2265e9f8a0b6SChristoph Hellwig unsigned long long class2_intrs = ctx->stats.class2_intr; 2266e9f8a0b6SChristoph Hellwig 2267e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2268e9f8a0b6SChristoph Hellwig class2_intrs += (ctx->spu->stats.class2_intr - 2269e9f8a0b6SChristoph Hellwig ctx->stats.class2_intr_base); 2270e9f8a0b6SChristoph Hellwig } 2271e9f8a0b6SChristoph Hellwig 2272e9f8a0b6SChristoph Hellwig return class2_intrs; 2273e9f8a0b6SChristoph Hellwig } 2274e9f8a0b6SChristoph Hellwig 2275e9f8a0b6SChristoph Hellwig 2276e9f8a0b6SChristoph Hellwig static int spufs_show_stat(struct seq_file *s, void *private) 2277e9f8a0b6SChristoph Hellwig { 2278e9f8a0b6SChristoph Hellwig struct spu_context *ctx = s->private; 2279c9101bdbSChristoph Hellwig int ret; 2280e9f8a0b6SChristoph Hellwig 2281c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 2282c9101bdbSChristoph Hellwig if (ret) 2283c9101bdbSChristoph Hellwig return ret; 2284c9101bdbSChristoph Hellwig 2285e9f8a0b6SChristoph Hellwig seq_printf(s, "%s %llu %llu %llu %llu " 2286e9f8a0b6SChristoph Hellwig "%llu %llu %llu %llu %llu %llu %llu %llu\n", 228727ec41d3SAndre Detsch ctx_state_names[ctx->stats.util_state], 228827ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_USER), 228927ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 229027ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 229127ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 2292e9f8a0b6SChristoph Hellwig ctx->stats.vol_ctx_switch, 2293e9f8a0b6SChristoph Hellwig ctx->stats.invol_ctx_switch, 2294e9f8a0b6SChristoph Hellwig spufs_slb_flts(ctx), 2295e9f8a0b6SChristoph Hellwig ctx->stats.hash_flt, 2296e9f8a0b6SChristoph Hellwig ctx->stats.min_flt, 2297e9f8a0b6SChristoph Hellwig ctx->stats.maj_flt, 2298e9f8a0b6SChristoph Hellwig spufs_class2_intrs(ctx), 2299e9f8a0b6SChristoph Hellwig ctx->stats.libassist); 2300e9f8a0b6SChristoph Hellwig spu_release(ctx); 2301e9f8a0b6SChristoph Hellwig return 0; 2302e9f8a0b6SChristoph Hellwig } 2303e9f8a0b6SChristoph Hellwig 2304e9f8a0b6SChristoph Hellwig static int spufs_stat_open(struct inode *inode, struct file *file) 2305e9f8a0b6SChristoph Hellwig { 2306e9f8a0b6SChristoph Hellwig return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); 2307e9f8a0b6SChristoph Hellwig } 2308e9f8a0b6SChristoph Hellwig 2309e9f8a0b6SChristoph Hellwig static const struct file_operations spufs_stat_fops = { 2310e9f8a0b6SChristoph Hellwig .open = spufs_stat_open, 2311e9f8a0b6SChristoph Hellwig .read = seq_read, 2312e9f8a0b6SChristoph Hellwig .llseek = seq_lseek, 2313e9f8a0b6SChristoph Hellwig .release = single_release, 2314e9f8a0b6SChristoph Hellwig }; 2315e9f8a0b6SChristoph Hellwig 23165158e9b5SChristoph Hellwig static inline int spufs_switch_log_used(struct spu_context *ctx) 23175158e9b5SChristoph Hellwig { 23185158e9b5SChristoph Hellwig return (ctx->switch_log->head - ctx->switch_log->tail) % 23195158e9b5SChristoph Hellwig SWITCH_LOG_BUFSIZE; 23205158e9b5SChristoph Hellwig } 23215158e9b5SChristoph Hellwig 23225158e9b5SChristoph Hellwig static inline int spufs_switch_log_avail(struct spu_context *ctx) 23235158e9b5SChristoph Hellwig { 23245158e9b5SChristoph Hellwig return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx); 23255158e9b5SChristoph Hellwig } 23265158e9b5SChristoph Hellwig 23275158e9b5SChristoph Hellwig static int spufs_switch_log_open(struct inode *inode, struct file *file) 23285158e9b5SChristoph Hellwig { 23295158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 2330f5ed0eb6SJeremy Kerr int rc; 23315158e9b5SChristoph Hellwig 2332f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2333f5ed0eb6SJeremy Kerr if (rc) 2334f5ed0eb6SJeremy Kerr return rc; 2335f5ed0eb6SJeremy Kerr 23365158e9b5SChristoph Hellwig if (ctx->switch_log) { 2337f5ed0eb6SJeremy Kerr rc = -EBUSY; 2338f5ed0eb6SJeremy Kerr goto out; 2339f5ed0eb6SJeremy Kerr } 2340f5ed0eb6SJeremy Kerr 2341837ef884SJeremy Kerr ctx->switch_log = kmalloc(sizeof(struct switch_log) + 23425158e9b5SChristoph Hellwig SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry), 23435158e9b5SChristoph Hellwig GFP_KERNEL); 2344f5ed0eb6SJeremy Kerr 2345f5ed0eb6SJeremy Kerr if (!ctx->switch_log) { 2346f5ed0eb6SJeremy Kerr rc = -ENOMEM; 23475158e9b5SChristoph Hellwig goto out; 23485158e9b5SChristoph Hellwig } 2349f5ed0eb6SJeremy Kerr 2350837ef884SJeremy Kerr ctx->switch_log->head = ctx->switch_log->tail = 0; 2351f5ed0eb6SJeremy Kerr init_waitqueue_head(&ctx->switch_log->wait); 2352f5ed0eb6SJeremy Kerr rc = 0; 2353f5ed0eb6SJeremy Kerr 2354f5ed0eb6SJeremy Kerr out: 2355f5ed0eb6SJeremy Kerr spu_release(ctx); 2356f5ed0eb6SJeremy Kerr return rc; 2357f5ed0eb6SJeremy Kerr } 2358f5ed0eb6SJeremy Kerr 2359f5ed0eb6SJeremy Kerr static int spufs_switch_log_release(struct inode *inode, struct file *file) 2360f5ed0eb6SJeremy Kerr { 2361f5ed0eb6SJeremy Kerr struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 2362f5ed0eb6SJeremy Kerr int rc; 2363f5ed0eb6SJeremy Kerr 2364f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2365f5ed0eb6SJeremy Kerr if (rc) 2366f5ed0eb6SJeremy Kerr return rc; 2367f5ed0eb6SJeremy Kerr 2368f5ed0eb6SJeremy Kerr kfree(ctx->switch_log); 2369f5ed0eb6SJeremy Kerr ctx->switch_log = NULL; 2370f5ed0eb6SJeremy Kerr spu_release(ctx); 23715158e9b5SChristoph Hellwig 23725158e9b5SChristoph Hellwig return 0; 23735158e9b5SChristoph Hellwig } 23745158e9b5SChristoph Hellwig 23755158e9b5SChristoph Hellwig static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) 23765158e9b5SChristoph Hellwig { 23775158e9b5SChristoph Hellwig struct switch_log_entry *p; 23785158e9b5SChristoph Hellwig 23795158e9b5SChristoph Hellwig p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE; 23805158e9b5SChristoph Hellwig 2381cef37ac1SArnd Bergmann return snprintf(tbuf, n, "%llu.%09u %d %u %u %llu\n", 2382cef37ac1SArnd Bergmann (unsigned long long) p->tstamp.tv_sec, 23835158e9b5SChristoph Hellwig (unsigned int) p->tstamp.tv_nsec, 23845158e9b5SChristoph Hellwig p->spu_id, 23855158e9b5SChristoph Hellwig (unsigned int) p->type, 23865158e9b5SChristoph Hellwig (unsigned int) p->val, 23875158e9b5SChristoph Hellwig (unsigned long long) p->timebase); 23885158e9b5SChristoph Hellwig } 23895158e9b5SChristoph Hellwig 23905158e9b5SChristoph Hellwig static ssize_t spufs_switch_log_read(struct file *file, char __user *buf, 23915158e9b5SChristoph Hellwig size_t len, loff_t *ppos) 23925158e9b5SChristoph Hellwig { 2393496ad9aaSAl Viro struct inode *inode = file_inode(file); 23945158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 23955158e9b5SChristoph Hellwig int error = 0, cnt = 0; 23965158e9b5SChristoph Hellwig 239717e37675Sroel kluin if (!buf) 23985158e9b5SChristoph Hellwig return -EINVAL; 23995158e9b5SChristoph Hellwig 2400f5ed0eb6SJeremy Kerr error = spu_acquire(ctx); 2401f5ed0eb6SJeremy Kerr if (error) 2402f5ed0eb6SJeremy Kerr return error; 2403f5ed0eb6SJeremy Kerr 24045158e9b5SChristoph Hellwig while (cnt < len) { 24055158e9b5SChristoph Hellwig char tbuf[128]; 24065158e9b5SChristoph Hellwig int width; 24075158e9b5SChristoph Hellwig 2408f5ed0eb6SJeremy Kerr if (spufs_switch_log_used(ctx) == 0) { 240914f693eeSJeremy Kerr if (cnt > 0) { 241014f693eeSJeremy Kerr /* If there's data ready to go, we can 241114f693eeSJeremy Kerr * just return straight away */ 241214f693eeSJeremy Kerr break; 241314f693eeSJeremy Kerr 241414f693eeSJeremy Kerr } else if (file->f_flags & O_NONBLOCK) { 2415f5ed0eb6SJeremy Kerr error = -EAGAIN; 24165158e9b5SChristoph Hellwig break; 241714f693eeSJeremy Kerr 2418f5ed0eb6SJeremy Kerr } else { 241914f693eeSJeremy Kerr /* spufs_wait will drop the mutex and 242014f693eeSJeremy Kerr * re-acquire, but since we're in read(), the 242114f693eeSJeremy Kerr * file cannot be _released (and so 242214f693eeSJeremy Kerr * ctx->switch_log is stable). 2423f5ed0eb6SJeremy Kerr */ 2424f5ed0eb6SJeremy Kerr error = spufs_wait(ctx->switch_log->wait, 2425f5ed0eb6SJeremy Kerr spufs_switch_log_used(ctx) > 0); 24265158e9b5SChristoph Hellwig 2427f5ed0eb6SJeremy Kerr /* On error, spufs_wait returns without the 2428f5ed0eb6SJeremy Kerr * state mutex held */ 2429f5ed0eb6SJeremy Kerr if (error) 2430f5ed0eb6SJeremy Kerr return error; 24315158e9b5SChristoph Hellwig 243214f693eeSJeremy Kerr /* We may have had entries read from underneath 243314f693eeSJeremy Kerr * us while we dropped the mutex in spufs_wait, 243414f693eeSJeremy Kerr * so re-check */ 243514f693eeSJeremy Kerr if (spufs_switch_log_used(ctx) == 0) 2436f5ed0eb6SJeremy Kerr continue; 243714f693eeSJeremy Kerr } 243814f693eeSJeremy Kerr } 2439f5ed0eb6SJeremy Kerr 24405158e9b5SChristoph Hellwig width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); 2441f5ed0eb6SJeremy Kerr if (width < len) 24425158e9b5SChristoph Hellwig ctx->switch_log->tail = 24435158e9b5SChristoph Hellwig (ctx->switch_log->tail + 1) % 24445158e9b5SChristoph Hellwig SWITCH_LOG_BUFSIZE; 2445f5ed0eb6SJeremy Kerr else 2446f5ed0eb6SJeremy Kerr /* If the record is greater than space available return 2447f5ed0eb6SJeremy Kerr * partial buffer (so far) */ 24485158e9b5SChristoph Hellwig break; 24495158e9b5SChristoph Hellwig 24505158e9b5SChristoph Hellwig error = copy_to_user(buf + cnt, tbuf, width); 24515158e9b5SChristoph Hellwig if (error) 24525158e9b5SChristoph Hellwig break; 24535158e9b5SChristoph Hellwig cnt += width; 24545158e9b5SChristoph Hellwig } 24555158e9b5SChristoph Hellwig 2456f5ed0eb6SJeremy Kerr spu_release(ctx); 2457f5ed0eb6SJeremy Kerr 24585158e9b5SChristoph Hellwig return cnt == 0 ? error : cnt; 24595158e9b5SChristoph Hellwig } 24605158e9b5SChristoph Hellwig 24618153a5eaSAl Viro static __poll_t spufs_switch_log_poll(struct file *file, poll_table *wait) 24625158e9b5SChristoph Hellwig { 2463496ad9aaSAl Viro struct inode *inode = file_inode(file); 24645158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 24658153a5eaSAl Viro __poll_t mask = 0; 2466f5ed0eb6SJeremy Kerr int rc; 24675158e9b5SChristoph Hellwig 24685158e9b5SChristoph Hellwig poll_wait(file, &ctx->switch_log->wait, wait); 24695158e9b5SChristoph Hellwig 2470f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2471f5ed0eb6SJeremy Kerr if (rc) 2472f5ed0eb6SJeremy Kerr return rc; 2473f5ed0eb6SJeremy Kerr 24745158e9b5SChristoph Hellwig if (spufs_switch_log_used(ctx) > 0) 2475a9a08845SLinus Torvalds mask |= EPOLLIN; 24765158e9b5SChristoph Hellwig 2477f5ed0eb6SJeremy Kerr spu_release(ctx); 2478f5ed0eb6SJeremy Kerr 24795158e9b5SChristoph Hellwig return mask; 24805158e9b5SChristoph Hellwig } 24815158e9b5SChristoph Hellwig 24825158e9b5SChristoph Hellwig static const struct file_operations spufs_switch_log_fops = { 24835158e9b5SChristoph Hellwig .open = spufs_switch_log_open, 24845158e9b5SChristoph Hellwig .read = spufs_switch_log_read, 24855158e9b5SChristoph Hellwig .poll = spufs_switch_log_poll, 2486f5ed0eb6SJeremy Kerr .release = spufs_switch_log_release, 2487fc15351dSArnd Bergmann .llseek = no_llseek, 24885158e9b5SChristoph Hellwig }; 24895158e9b5SChristoph Hellwig 2490f5ed0eb6SJeremy Kerr /** 2491f5ed0eb6SJeremy Kerr * Log a context switch event to a switch log reader. 2492f5ed0eb6SJeremy Kerr * 2493f5ed0eb6SJeremy Kerr * Must be called with ctx->state_mutex held. 2494f5ed0eb6SJeremy Kerr */ 24955158e9b5SChristoph Hellwig void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, 24965158e9b5SChristoph Hellwig u32 type, u32 val) 24975158e9b5SChristoph Hellwig { 24985158e9b5SChristoph Hellwig if (!ctx->switch_log) 24995158e9b5SChristoph Hellwig return; 25005158e9b5SChristoph Hellwig 25015158e9b5SChristoph Hellwig if (spufs_switch_log_avail(ctx) > 1) { 25025158e9b5SChristoph Hellwig struct switch_log_entry *p; 25035158e9b5SChristoph Hellwig 25045158e9b5SChristoph Hellwig p = ctx->switch_log->log + ctx->switch_log->head; 2505cef37ac1SArnd Bergmann ktime_get_ts64(&p->tstamp); 25065158e9b5SChristoph Hellwig p->timebase = get_tb(); 25075158e9b5SChristoph Hellwig p->spu_id = spu ? spu->number : -1; 25085158e9b5SChristoph Hellwig p->type = type; 25095158e9b5SChristoph Hellwig p->val = val; 25105158e9b5SChristoph Hellwig 25115158e9b5SChristoph Hellwig ctx->switch_log->head = 25125158e9b5SChristoph Hellwig (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE; 25135158e9b5SChristoph Hellwig } 25145158e9b5SChristoph Hellwig 25155158e9b5SChristoph Hellwig wake_up(&ctx->switch_log->wait); 25165158e9b5SChristoph Hellwig } 2517e9f8a0b6SChristoph Hellwig 251846deed69SLuke Browning static int spufs_show_ctx(struct seq_file *s, void *private) 251946deed69SLuke Browning { 252046deed69SLuke Browning struct spu_context *ctx = s->private; 252146deed69SLuke Browning u64 mfc_control_RW; 252246deed69SLuke Browning 252346deed69SLuke Browning mutex_lock(&ctx->state_mutex); 252446deed69SLuke Browning if (ctx->spu) { 252546deed69SLuke Browning struct spu *spu = ctx->spu; 252646deed69SLuke Browning struct spu_priv2 __iomem *priv2 = spu->priv2; 252746deed69SLuke Browning 252846deed69SLuke Browning spin_lock_irq(&spu->register_lock); 252946deed69SLuke Browning mfc_control_RW = in_be64(&priv2->mfc_control_RW); 253046deed69SLuke Browning spin_unlock_irq(&spu->register_lock); 253146deed69SLuke Browning } else { 253246deed69SLuke Browning struct spu_state *csa = &ctx->csa; 253346deed69SLuke Browning 253446deed69SLuke Browning mfc_control_RW = csa->priv2.mfc_control_RW; 253546deed69SLuke Browning } 253646deed69SLuke Browning 253746deed69SLuke Browning seq_printf(s, "%c flgs(%lx) sflgs(%lx) pri(%d) ts(%d) spu(%02d)" 25389477e455SStephen Rothwell " %c %llx %llx %llx %llx %x %x\n", 253946deed69SLuke Browning ctx->state == SPU_STATE_SAVED ? 'S' : 'R', 254046deed69SLuke Browning ctx->flags, 254146deed69SLuke Browning ctx->sched_flags, 254246deed69SLuke Browning ctx->prio, 254346deed69SLuke Browning ctx->time_slice, 254446deed69SLuke Browning ctx->spu ? ctx->spu->number : -1, 254546deed69SLuke Browning !list_empty(&ctx->rq) ? 'q' : ' ', 254646deed69SLuke Browning ctx->csa.class_0_pending, 254746deed69SLuke Browning ctx->csa.class_0_dar, 254846deed69SLuke Browning ctx->csa.class_1_dsisr, 254946deed69SLuke Browning mfc_control_RW, 255046deed69SLuke Browning ctx->ops->runcntl_read(ctx), 255146deed69SLuke Browning ctx->ops->status_read(ctx)); 255246deed69SLuke Browning 255346deed69SLuke Browning mutex_unlock(&ctx->state_mutex); 255446deed69SLuke Browning 255546deed69SLuke Browning return 0; 255646deed69SLuke Browning } 255746deed69SLuke Browning 255846deed69SLuke Browning static int spufs_ctx_open(struct inode *inode, struct file *file) 255946deed69SLuke Browning { 256046deed69SLuke Browning return single_open(file, spufs_show_ctx, SPUFS_I(inode)->i_ctx); 256146deed69SLuke Browning } 256246deed69SLuke Browning 256346deed69SLuke Browning static const struct file_operations spufs_ctx_fops = { 256446deed69SLuke Browning .open = spufs_ctx_open, 256546deed69SLuke Browning .read = seq_read, 256646deed69SLuke Browning .llseek = seq_lseek, 256746deed69SLuke Browning .release = single_release, 256846deed69SLuke Browning }; 256946deed69SLuke Browning 257074254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_contents[] = { 2571cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 25726f7dde81SJeremy Kerr { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, 25736f7dde81SJeremy Kerr { "regs", &spufs_regs_fops, 0666, sizeof(struct spu_reg128[128]), }, 257467207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 257567207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 257667207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 25776f7dde81SJeremy Kerr { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, 25786f7dde81SJeremy Kerr { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, 25796f7dde81SJeremy Kerr { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, 2580603c4612SJeremy Kerr { "signal1", &spufs_signal1_fops, 0666, }, 2581603c4612SJeremy Kerr { "signal2", &spufs_signal2_fops, 0666, }, 258267207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 258367207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 25846df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 25856f7dde81SJeremy Kerr { "fpcr", &spufs_fpcr_fops, 0666, sizeof(struct spu_reg128), }, 2586b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 2587b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 2588b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 2589b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 2590b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 25918b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 25928b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 25938b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 2594b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 25956f7dde81SJeremy Kerr { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, 259686767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 259786767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 25986f7dde81SJeremy Kerr { "mbox_info", &spufs_mbox_info_fops, 0444, sizeof(u32), }, 25996f7dde81SJeremy Kerr { "ibox_info", &spufs_ibox_info_fops, 0444, sizeof(u32), }, 26006f7dde81SJeremy Kerr { "wbox_info", &spufs_wbox_info_fops, 0444, sizeof(u32), }, 26016f7dde81SJeremy Kerr { "dma_info", &spufs_dma_info_fops, 0444, 26026f7dde81SJeremy Kerr sizeof(struct spu_dma_info), }, 26036f7dde81SJeremy Kerr { "proxydma_info", &spufs_proxydma_info_fops, 0444, 26046f7dde81SJeremy Kerr sizeof(struct spu_proxydma_info)}, 2605476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2606e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 26075158e9b5SChristoph Hellwig { "switch_log", &spufs_switch_log_fops, 0444 }, 260867207b96SArnd Bergmann {}, 260967207b96SArnd Bergmann }; 26105737edd1SMark Nutter 261174254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_nosched_contents[] = { 2612cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 26136f7dde81SJeremy Kerr { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, 26145737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 26155737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 26165737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 26176f7dde81SJeremy Kerr { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, 26186f7dde81SJeremy Kerr { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, 26196f7dde81SJeremy Kerr { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, 2620d054b36fSJeremy Kerr { "signal1", &spufs_signal1_nosched_fops, 0222, }, 2621d054b36fSJeremy Kerr { "signal2", &spufs_signal2_nosched_fops, 0222, }, 26225737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 26235737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 26245737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 26255737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 26265737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 26275737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 26286f7dde81SJeremy Kerr { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, 26295737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 26305737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 2631476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2632e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 26332c3e4787SJeremy Kerr {}, 26342c3e4787SJeremy Kerr }; 26352c3e4787SJeremy Kerr 263674254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_debug_contents[] = { 263746deed69SLuke Browning { ".ctx", &spufs_ctx_fops, 0444, }, 26385737edd1SMark Nutter {}, 26395737edd1SMark Nutter }; 2640bf1ab978SDwayne Grant McConnell 264174254647SJeremy Kerr const struct spufs_coredump_reader spufs_coredump_read[] = { 26424fca9c42SMichael Ellerman { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, 26434fca9c42SMichael Ellerman { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, 2644104f0cc2SMichael Ellerman { "lslr", NULL, spufs_lslr_get, 19 }, 2645104f0cc2SMichael Ellerman { "decr", NULL, spufs_decr_get, 19 }, 2646104f0cc2SMichael Ellerman { "decr_status", NULL, spufs_decr_status_get, 19 }, 26474fca9c42SMichael Ellerman { "mem", __spufs_mem_read, NULL, LS_SIZE, }, 26484fca9c42SMichael Ellerman { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, 2649104f0cc2SMichael Ellerman { "signal1_type", NULL, spufs_signal1_type_get, 19 }, 26504fca9c42SMichael Ellerman { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, 2651104f0cc2SMichael Ellerman { "signal2_type", NULL, spufs_signal2_type_get, 19 }, 2652104f0cc2SMichael Ellerman { "event_mask", NULL, spufs_event_mask_get, 19 }, 2653104f0cc2SMichael Ellerman { "event_status", NULL, spufs_event_status_get, 19 }, 26544fca9c42SMichael Ellerman { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, 26554fca9c42SMichael Ellerman { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, 26564fca9c42SMichael Ellerman { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, 26574fca9c42SMichael Ellerman { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, 26584fca9c42SMichael Ellerman { "proxydma_info", __spufs_proxydma_info_read, 26594fca9c42SMichael Ellerman NULL, sizeof(struct spu_proxydma_info)}, 2660104f0cc2SMichael Ellerman { "object-id", NULL, spufs_object_id_get, 19 }, 2661104f0cc2SMichael Ellerman { "npc", NULL, spufs_npc_get, 19 }, 2662936d5bf1SMichael Ellerman { NULL }, 2663bf1ab978SDwayne Grant McConnell }; 2664