1de6cc651SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 267207b96SArnd Bergmann /* 367207b96SArnd Bergmann * SPU file system -- file contents 467207b96SArnd Bergmann * 567207b96SArnd Bergmann * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 667207b96SArnd Bergmann * 767207b96SArnd Bergmann * Author: Arnd Bergmann <arndb@de.ibm.com> 867207b96SArnd Bergmann */ 967207b96SArnd Bergmann 10a33a7d73SArnd Bergmann #undef DEBUG 11a33a7d73SArnd Bergmann 1267207b96SArnd Bergmann #include <linux/fs.h> 1367207b96SArnd Bergmann #include <linux/ioctl.h> 144b16f8e2SPaul Gortmaker #include <linux/export.h> 15d88cfffaSArnd Bergmann #include <linux/pagemap.h> 1667207b96SArnd Bergmann #include <linux/poll.h> 175110459fSArnd Bergmann #include <linux/ptrace.h> 18cbe709c1SBenjamin Herrenschmidt #include <linux/seq_file.h> 195a0e3ad6STejun Heo #include <linux/slab.h> 2067207b96SArnd Bergmann 2167207b96SArnd Bergmann #include <asm/io.h> 22dfe1e09fSFUJITA Tomonori #include <asm/time.h> 2367207b96SArnd Bergmann #include <asm/spu.h> 24b9e3bd77SDwayne Grant McConnell #include <asm/spu_info.h> 257c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 2667207b96SArnd Bergmann 2767207b96SArnd Bergmann #include "spufs.h" 28ae142e0cSChristoph Hellwig #include "sputrace.h" 2967207b96SArnd Bergmann 3027d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 3127d5bf2aSBenjamin Herrenschmidt 32197b1a82SChristoph Hellwig /* Simple attribute files */ 33197b1a82SChristoph Hellwig struct spufs_attr { 34197b1a82SChristoph Hellwig int (*get)(void *, u64 *); 35197b1a82SChristoph Hellwig int (*set)(void *, u64); 36197b1a82SChristoph Hellwig char get_buf[24]; /* enough to store a u64 and "\n\0" */ 37197b1a82SChristoph Hellwig char set_buf[24]; 38197b1a82SChristoph Hellwig void *data; 39197b1a82SChristoph Hellwig const char *fmt; /* format for read operation */ 40197b1a82SChristoph Hellwig struct mutex mutex; /* protects access to these buffers */ 41197b1a82SChristoph Hellwig }; 42197b1a82SChristoph Hellwig 43197b1a82SChristoph Hellwig static int spufs_attr_open(struct inode *inode, struct file *file, 44197b1a82SChristoph Hellwig int (*get)(void *, u64 *), int (*set)(void *, u64), 45197b1a82SChristoph Hellwig const char *fmt) 46197b1a82SChristoph Hellwig { 47197b1a82SChristoph Hellwig struct spufs_attr *attr; 48197b1a82SChristoph Hellwig 49197b1a82SChristoph Hellwig attr = kmalloc(sizeof(*attr), GFP_KERNEL); 50197b1a82SChristoph Hellwig if (!attr) 51197b1a82SChristoph Hellwig return -ENOMEM; 52197b1a82SChristoph Hellwig 53197b1a82SChristoph Hellwig attr->get = get; 54197b1a82SChristoph Hellwig attr->set = set; 55197b1a82SChristoph Hellwig attr->data = inode->i_private; 56197b1a82SChristoph Hellwig attr->fmt = fmt; 57197b1a82SChristoph Hellwig mutex_init(&attr->mutex); 58197b1a82SChristoph Hellwig file->private_data = attr; 59197b1a82SChristoph Hellwig 60197b1a82SChristoph Hellwig return nonseekable_open(inode, file); 61197b1a82SChristoph Hellwig } 62197b1a82SChristoph Hellwig 63197b1a82SChristoph Hellwig static int spufs_attr_release(struct inode *inode, struct file *file) 64197b1a82SChristoph Hellwig { 65197b1a82SChristoph Hellwig kfree(file->private_data); 66197b1a82SChristoph Hellwig return 0; 67197b1a82SChristoph Hellwig } 68197b1a82SChristoph Hellwig 69197b1a82SChristoph Hellwig static ssize_t spufs_attr_read(struct file *file, char __user *buf, 70197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 71197b1a82SChristoph Hellwig { 72197b1a82SChristoph Hellwig struct spufs_attr *attr; 73197b1a82SChristoph Hellwig size_t size; 74197b1a82SChristoph Hellwig ssize_t ret; 75197b1a82SChristoph Hellwig 76197b1a82SChristoph Hellwig attr = file->private_data; 77197b1a82SChristoph Hellwig if (!attr->get) 78197b1a82SChristoph Hellwig return -EACCES; 79197b1a82SChristoph Hellwig 80197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 81197b1a82SChristoph Hellwig if (ret) 82197b1a82SChristoph Hellwig return ret; 83197b1a82SChristoph Hellwig 84197b1a82SChristoph Hellwig if (*ppos) { /* continued read */ 85197b1a82SChristoph Hellwig size = strlen(attr->get_buf); 86197b1a82SChristoph Hellwig } else { /* first read */ 87197b1a82SChristoph Hellwig u64 val; 88197b1a82SChristoph Hellwig ret = attr->get(attr->data, &val); 89197b1a82SChristoph Hellwig if (ret) 90197b1a82SChristoph Hellwig goto out; 91197b1a82SChristoph Hellwig 92197b1a82SChristoph Hellwig size = scnprintf(attr->get_buf, sizeof(attr->get_buf), 93197b1a82SChristoph Hellwig attr->fmt, (unsigned long long)val); 94197b1a82SChristoph Hellwig } 95197b1a82SChristoph Hellwig 96197b1a82SChristoph Hellwig ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); 97197b1a82SChristoph Hellwig out: 98197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 99197b1a82SChristoph Hellwig return ret; 100197b1a82SChristoph Hellwig } 101197b1a82SChristoph Hellwig 102197b1a82SChristoph Hellwig static ssize_t spufs_attr_write(struct file *file, const char __user *buf, 103197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 104197b1a82SChristoph Hellwig { 105197b1a82SChristoph Hellwig struct spufs_attr *attr; 106197b1a82SChristoph Hellwig u64 val; 107197b1a82SChristoph Hellwig size_t size; 108197b1a82SChristoph Hellwig ssize_t ret; 109197b1a82SChristoph Hellwig 110197b1a82SChristoph Hellwig attr = file->private_data; 111197b1a82SChristoph Hellwig if (!attr->set) 112197b1a82SChristoph Hellwig return -EACCES; 113197b1a82SChristoph Hellwig 114197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 115197b1a82SChristoph Hellwig if (ret) 116197b1a82SChristoph Hellwig return ret; 117197b1a82SChristoph Hellwig 118197b1a82SChristoph Hellwig ret = -EFAULT; 119197b1a82SChristoph Hellwig size = min(sizeof(attr->set_buf) - 1, len); 120197b1a82SChristoph Hellwig if (copy_from_user(attr->set_buf, buf, size)) 121197b1a82SChristoph Hellwig goto out; 122197b1a82SChristoph Hellwig 123197b1a82SChristoph Hellwig ret = len; /* claim we got the whole input */ 124197b1a82SChristoph Hellwig attr->set_buf[size] = '\0'; 125197b1a82SChristoph Hellwig val = simple_strtol(attr->set_buf, NULL, 0); 126197b1a82SChristoph Hellwig attr->set(attr->data, val); 127197b1a82SChristoph Hellwig out: 128197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 129197b1a82SChristoph Hellwig return ret; 130197b1a82SChristoph Hellwig } 131197b1a82SChristoph Hellwig 132197b1a82SChristoph Hellwig #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ 133197b1a82SChristoph Hellwig static int __fops ## _open(struct inode *inode, struct file *file) \ 134197b1a82SChristoph Hellwig { \ 135197b1a82SChristoph Hellwig __simple_attr_check_format(__fmt, 0ull); \ 136197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, __get, __set, __fmt); \ 137197b1a82SChristoph Hellwig } \ 138828c0950SAlexey Dobriyan static const struct file_operations __fops = { \ 139197b1a82SChristoph Hellwig .open = __fops ## _open, \ 140197b1a82SChristoph Hellwig .release = spufs_attr_release, \ 141197b1a82SChristoph Hellwig .read = spufs_attr_read, \ 142197b1a82SChristoph Hellwig .write = spufs_attr_write, \ 143fc15351dSArnd Bergmann .llseek = generic_file_llseek, \ 144197b1a82SChristoph Hellwig }; 145197b1a82SChristoph Hellwig 146cbe709c1SBenjamin Herrenschmidt 14767207b96SArnd Bergmann static int 14867207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 14967207b96SArnd Bergmann { 15067207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1516df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 15243c2bbd9SChristoph Hellwig 15347d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1546df10a82SMark Nutter file->private_data = ctx; 15543c2bbd9SChristoph Hellwig if (!i->i_openers++) 1566df10a82SMark Nutter ctx->local_store = inode->i_mapping; 15747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 15843c2bbd9SChristoph Hellwig return 0; 15943c2bbd9SChristoph Hellwig } 16043c2bbd9SChristoph Hellwig 16143c2bbd9SChristoph Hellwig static int 16243c2bbd9SChristoph Hellwig spufs_mem_release(struct inode *inode, struct file *file) 16343c2bbd9SChristoph Hellwig { 16443c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 16543c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 16643c2bbd9SChristoph Hellwig 16747d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 16843c2bbd9SChristoph Hellwig if (!--i->i_openers) 16943c2bbd9SChristoph Hellwig ctx->local_store = NULL; 17047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 17167207b96SArnd Bergmann return 0; 17267207b96SArnd Bergmann } 17367207b96SArnd Bergmann 17467207b96SArnd Bergmann static ssize_t 175bf1ab978SDwayne Grant McConnell __spufs_mem_read(struct spu_context *ctx, char __user *buffer, 176bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 177bf1ab978SDwayne Grant McConnell { 178bf1ab978SDwayne Grant McConnell char *local_store = ctx->ops->get_ls(ctx); 179bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, local_store, 180bf1ab978SDwayne Grant McConnell LS_SIZE); 181bf1ab978SDwayne Grant McConnell } 182bf1ab978SDwayne Grant McConnell 183bf1ab978SDwayne Grant McConnell static ssize_t 18467207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 18567207b96SArnd Bergmann size_t size, loff_t *pos) 18667207b96SArnd Bergmann { 187bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 188aa0ed2bdSArnd Bergmann ssize_t ret; 18967207b96SArnd Bergmann 190c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 191c9101bdbSChristoph Hellwig if (ret) 192c9101bdbSChristoph Hellwig return ret; 193bf1ab978SDwayne Grant McConnell ret = __spufs_mem_read(ctx, buffer, size, pos); 1948b3d6663SArnd Bergmann spu_release(ctx); 195c9101bdbSChristoph Hellwig 19667207b96SArnd Bergmann return ret; 19767207b96SArnd Bergmann } 19867207b96SArnd Bergmann 19967207b96SArnd Bergmann static ssize_t 20067207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 201aa0ed2bdSArnd Bergmann size_t size, loff_t *ppos) 20267207b96SArnd Bergmann { 20367207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 2048b3d6663SArnd Bergmann char *local_store; 205aa0ed2bdSArnd Bergmann loff_t pos = *ppos; 2068b3d6663SArnd Bergmann int ret; 20767207b96SArnd Bergmann 208aa0ed2bdSArnd Bergmann if (pos > LS_SIZE) 20967207b96SArnd Bergmann return -EFBIG; 2108b3d6663SArnd Bergmann 211c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 212c9101bdbSChristoph Hellwig if (ret) 213c9101bdbSChristoph Hellwig return ret; 214c9101bdbSChristoph Hellwig 2158b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 21663c3b9d7SAkinobu Mita size = simple_write_to_buffer(local_store, LS_SIZE, ppos, buffer, size); 2178b3d6663SArnd Bergmann spu_release(ctx); 218aa0ed2bdSArnd Bergmann 219aa0ed2bdSArnd Bergmann return size; 22067207b96SArnd Bergmann } 22167207b96SArnd Bergmann 222e807f02cSSouptick Joarder static vm_fault_t 22311bac800SDave Jiang spufs_mem_mmap_fault(struct vm_fault *vmf) 2248b3d6663SArnd Bergmann { 22511bac800SDave Jiang struct vm_area_struct *vma = vmf->vma; 2268b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 227b1e2270fSNick Piggin unsigned long pfn, offset; 228e807f02cSSouptick Joarder vm_fault_t ret; 229b1e2270fSNick Piggin 230b1e2270fSNick Piggin offset = vmf->pgoff << PAGE_SHIFT; 231128b8546SMasato Noguchi if (offset >= LS_SIZE) 232b1e2270fSNick Piggin return VM_FAULT_SIGBUS; 233128b8546SMasato Noguchi 234b1e2270fSNick Piggin pr_debug("spufs_mem_mmap_fault address=0x%lx, offset=0x%lx\n", 2351a29d85eSJan Kara vmf->address, offset); 236f1fa74f4SBenjamin Herrenschmidt 237c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 238b1e2270fSNick Piggin return VM_FAULT_NOPAGE; 2398b3d6663SArnd Bergmann 240ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 24164b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); 24278bde53eSBenjamin Herrenschmidt pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); 243ac91cb8dSArnd Bergmann } else { 24464b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); 24578bde53eSBenjamin Herrenschmidt pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; 246ac91cb8dSArnd Bergmann } 247e807f02cSSouptick Joarder ret = vmf_insert_pfn(vma, vmf->address, pfn); 24878bde53eSBenjamin Herrenschmidt 2498b3d6663SArnd Bergmann spu_release(ctx); 2508b3d6663SArnd Bergmann 251e807f02cSSouptick Joarder return ret; 2528b3d6663SArnd Bergmann } 2538b3d6663SArnd Bergmann 254a352894dSBenjamin Herrenschmidt static int spufs_mem_mmap_access(struct vm_area_struct *vma, 255a352894dSBenjamin Herrenschmidt unsigned long address, 256a352894dSBenjamin Herrenschmidt void *buf, int len, int write) 257a352894dSBenjamin Herrenschmidt { 258a352894dSBenjamin Herrenschmidt struct spu_context *ctx = vma->vm_file->private_data; 259a352894dSBenjamin Herrenschmidt unsigned long offset = address - vma->vm_start; 260a352894dSBenjamin Herrenschmidt char *local_store; 261a352894dSBenjamin Herrenschmidt 262a352894dSBenjamin Herrenschmidt if (write && !(vma->vm_flags & VM_WRITE)) 263a352894dSBenjamin Herrenschmidt return -EACCES; 264a352894dSBenjamin Herrenschmidt if (spu_acquire(ctx)) 265a352894dSBenjamin Herrenschmidt return -EINTR; 266a352894dSBenjamin Herrenschmidt if ((offset + len) > vma->vm_end) 267a352894dSBenjamin Herrenschmidt len = vma->vm_end - offset; 268a352894dSBenjamin Herrenschmidt local_store = ctx->ops->get_ls(ctx); 269a352894dSBenjamin Herrenschmidt if (write) 270a352894dSBenjamin Herrenschmidt memcpy_toio(local_store + offset, buf, len); 271a352894dSBenjamin Herrenschmidt else 272a352894dSBenjamin Herrenschmidt memcpy_fromio(buf, local_store + offset, len); 273a352894dSBenjamin Herrenschmidt spu_release(ctx); 274a352894dSBenjamin Herrenschmidt return len; 275a352894dSBenjamin Herrenschmidt } 27678bde53eSBenjamin Herrenschmidt 277f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mem_mmap_vmops = { 278b1e2270fSNick Piggin .fault = spufs_mem_mmap_fault, 279a352894dSBenjamin Herrenschmidt .access = spufs_mem_mmap_access, 2808b3d6663SArnd Bergmann }; 2818b3d6663SArnd Bergmann 282f1fa74f4SBenjamin Herrenschmidt static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 28367207b96SArnd Bergmann { 2848b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 2858b3d6663SArnd Bergmann return -EINVAL; 28667207b96SArnd Bergmann 28778bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 28864b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); 2898b3d6663SArnd Bergmann 2908b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 29167207b96SArnd Bergmann return 0; 29267207b96SArnd Bergmann } 29367207b96SArnd Bergmann 2945dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = { 29567207b96SArnd Bergmann .open = spufs_mem_open, 296ce92987bSChristoph Hellwig .release = spufs_mem_release, 29767207b96SArnd Bergmann .read = spufs_mem_read, 29867207b96SArnd Bergmann .write = spufs_mem_write, 2998b3d6663SArnd Bergmann .llseek = generic_file_llseek, 30067207b96SArnd Bergmann .mmap = spufs_mem_mmap, 3018b3d6663SArnd Bergmann }; 3028b3d6663SArnd Bergmann 303e807f02cSSouptick Joarder static vm_fault_t spufs_ps_fault(struct vm_fault *vmf, 30478bde53eSBenjamin Herrenschmidt unsigned long ps_offs, 30527d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 3066df10a82SMark Nutter { 30711bac800SDave Jiang struct spu_context *ctx = vmf->vma->vm_file->private_data; 308b1e2270fSNick Piggin unsigned long area, offset = vmf->pgoff << PAGE_SHIFT; 309e807f02cSSouptick Joarder int err = 0; 310e807f02cSSouptick Joarder vm_fault_t ret = VM_FAULT_NOPAGE; 3116df10a82SMark Nutter 312b1e2270fSNick Piggin spu_context_nospu_trace(spufs_ps_fault__enter, ctx); 313038200cfSChristoph Hellwig 31427d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 315b1e2270fSNick Piggin return VM_FAULT_SIGBUS; 3166df10a82SMark Nutter 31760657263SJeremy Kerr if (fatal_signal_pending(current)) 31860657263SJeremy Kerr return VM_FAULT_SIGBUS; 31960657263SJeremy Kerr 32033bfd7a7SArnd Bergmann /* 321d5883137SJeremy Kerr * Because we release the mmap_sem, the context may be destroyed while 322d5883137SJeremy Kerr * we're in spu_wait. Grab an extra reference so it isn't destroyed 323d5883137SJeremy Kerr * in the meantime. 324d5883137SJeremy Kerr */ 325d5883137SJeremy Kerr get_spu_context(ctx); 326d5883137SJeremy Kerr 327d5883137SJeremy Kerr /* 32833bfd7a7SArnd Bergmann * We have to wait for context to be loaded before we have 32933bfd7a7SArnd Bergmann * pages to hand out to the user, but we don't want to wait 33033bfd7a7SArnd Bergmann * with the mmap_sem held. 33133bfd7a7SArnd Bergmann * It is possible to drop the mmap_sem here, but then we need 332b1e2270fSNick Piggin * to return VM_FAULT_NOPAGE because the mappings may have 33333bfd7a7SArnd Bergmann * hanged. 33478bde53eSBenjamin Herrenschmidt */ 335c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 336d5883137SJeremy Kerr goto refault; 337c9101bdbSChristoph Hellwig 33833bfd7a7SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 33933bfd7a7SArnd Bergmann up_read(¤t->mm->mmap_sem); 340b1e2270fSNick Piggin spu_context_nospu_trace(spufs_ps_fault__sleep, ctx); 341e807f02cSSouptick Joarder err = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 342b1e2270fSNick Piggin spu_context_trace(spufs_ps_fault__wake, ctx, ctx->spu); 34333bfd7a7SArnd Bergmann down_read(¤t->mm->mmap_sem); 344c9101bdbSChristoph Hellwig } else { 3456df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 346e807f02cSSouptick Joarder ret = vmf_insert_pfn(vmf->vma, vmf->address, 347e807f02cSSouptick Joarder (area + offset) >> PAGE_SHIFT); 348b1e2270fSNick Piggin spu_context_trace(spufs_ps_fault__insert, ctx, ctx->spu); 349c9101bdbSChristoph Hellwig } 35033bfd7a7SArnd Bergmann 351e807f02cSSouptick Joarder if (!err) 3526df10a82SMark Nutter spu_release(ctx); 353d5883137SJeremy Kerr 354d5883137SJeremy Kerr refault: 355d5883137SJeremy Kerr put_spu_context(ctx); 356e807f02cSSouptick Joarder return ret; 3576df10a82SMark Nutter } 3586df10a82SMark Nutter 35927d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 360e807f02cSSouptick Joarder static vm_fault_t spufs_cntl_mmap_fault(struct vm_fault *vmf) 3616df10a82SMark Nutter { 36211bac800SDave Jiang return spufs_ps_fault(vmf, 0x4000, SPUFS_CNTL_MAP_SIZE); 3636df10a82SMark Nutter } 3646df10a82SMark Nutter 365f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_cntl_mmap_vmops = { 366b1e2270fSNick Piggin .fault = spufs_cntl_mmap_fault, 3676df10a82SMark Nutter }; 3686df10a82SMark Nutter 3696df10a82SMark Nutter /* 3706df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 3716df10a82SMark Nutter */ 3726df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 3736df10a82SMark Nutter { 3746df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 3756df10a82SMark Nutter return -EINVAL; 3766df10a82SMark Nutter 37778bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 37864b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 3796df10a82SMark Nutter 3806df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 3816df10a82SMark Nutter return 0; 3826df10a82SMark Nutter } 38327d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 38427d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 38527d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 3866df10a82SMark Nutter 387197b1a82SChristoph Hellwig static int spufs_cntl_get(void *data, u64 *val) 388e1dbff2bSArnd Bergmann { 389e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 390c9101bdbSChristoph Hellwig int ret; 391e1dbff2bSArnd Bergmann 392c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 393c9101bdbSChristoph Hellwig if (ret) 394c9101bdbSChristoph Hellwig return ret; 395197b1a82SChristoph Hellwig *val = ctx->ops->status_read(ctx); 396e1dbff2bSArnd Bergmann spu_release(ctx); 397e1dbff2bSArnd Bergmann 398197b1a82SChristoph Hellwig return 0; 399e1dbff2bSArnd Bergmann } 400e1dbff2bSArnd Bergmann 401197b1a82SChristoph Hellwig static int spufs_cntl_set(void *data, u64 val) 402e1dbff2bSArnd Bergmann { 403e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 404c9101bdbSChristoph Hellwig int ret; 405e1dbff2bSArnd Bergmann 406c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 407c9101bdbSChristoph Hellwig if (ret) 408c9101bdbSChristoph Hellwig return ret; 409e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 410e1dbff2bSArnd Bergmann spu_release(ctx); 411197b1a82SChristoph Hellwig 412197b1a82SChristoph Hellwig return 0; 413e1dbff2bSArnd Bergmann } 414e1dbff2bSArnd Bergmann 4156df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 4166df10a82SMark Nutter { 4176df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 4186df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 4196df10a82SMark Nutter 42047d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 4216df10a82SMark Nutter file->private_data = ctx; 42243c2bbd9SChristoph Hellwig if (!i->i_openers++) 4236df10a82SMark Nutter ctx->cntl = inode->i_mapping; 42447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 4258b88b099SChristoph Hellwig return simple_attr_open(inode, file, spufs_cntl_get, 426e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 4276df10a82SMark Nutter } 4286df10a82SMark Nutter 42943c2bbd9SChristoph Hellwig static int 43043c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file) 43143c2bbd9SChristoph Hellwig { 43243c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 43343c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 43443c2bbd9SChristoph Hellwig 43574bedc4dSChristoph Hellwig simple_attr_release(inode, file); 43643c2bbd9SChristoph Hellwig 43747d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 43843c2bbd9SChristoph Hellwig if (!--i->i_openers) 43943c2bbd9SChristoph Hellwig ctx->cntl = NULL; 44047d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 44143c2bbd9SChristoph Hellwig return 0; 44243c2bbd9SChristoph Hellwig } 44343c2bbd9SChristoph Hellwig 4445dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = { 4456df10a82SMark Nutter .open = spufs_cntl_open, 44643c2bbd9SChristoph Hellwig .release = spufs_cntl_release, 4478b88b099SChristoph Hellwig .read = simple_attr_read, 4488b88b099SChristoph Hellwig .write = simple_attr_write, 449658829dfSGeliang Tang .llseek = no_llseek, 4506df10a82SMark Nutter .mmap = spufs_cntl_mmap, 4516df10a82SMark Nutter }; 4526df10a82SMark Nutter 4538b3d6663SArnd Bergmann static int 4548b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 4558b3d6663SArnd Bergmann { 4568b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 4578b3d6663SArnd Bergmann file->private_data = i->i_ctx; 4588b3d6663SArnd Bergmann return 0; 4598b3d6663SArnd Bergmann } 4608b3d6663SArnd Bergmann 4618b3d6663SArnd Bergmann static ssize_t 462bf1ab978SDwayne Grant McConnell __spufs_regs_read(struct spu_context *ctx, char __user *buffer, 463bf1ab978SDwayne Grant McConnell size_t size, loff_t *pos) 464bf1ab978SDwayne Grant McConnell { 465bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 466bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 467bf1ab978SDwayne Grant McConnell lscsa->gprs, sizeof lscsa->gprs); 468bf1ab978SDwayne Grant McConnell } 469bf1ab978SDwayne Grant McConnell 470bf1ab978SDwayne Grant McConnell static ssize_t 4718b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 4728b3d6663SArnd Bergmann size_t size, loff_t *pos) 4738b3d6663SArnd Bergmann { 4748b3d6663SArnd Bergmann int ret; 475bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 4768b3d6663SArnd Bergmann 477f027faa2SJeremy Kerr /* pre-check for file position: if we'd return EOF, there's no point 478f027faa2SJeremy Kerr * causing a deschedule */ 479f027faa2SJeremy Kerr if (*pos >= sizeof(ctx->csa.lscsa->gprs)) 480f027faa2SJeremy Kerr return 0; 481f027faa2SJeremy Kerr 482c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 483c9101bdbSChristoph Hellwig if (ret) 484c9101bdbSChristoph Hellwig return ret; 485bf1ab978SDwayne Grant McConnell ret = __spufs_regs_read(ctx, buffer, size, pos); 48627b1ea09SChristoph Hellwig spu_release_saved(ctx); 4878b3d6663SArnd Bergmann return ret; 4888b3d6663SArnd Bergmann } 4898b3d6663SArnd Bergmann 4908b3d6663SArnd Bergmann static ssize_t 4918b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 4928b3d6663SArnd Bergmann size_t size, loff_t *pos) 4938b3d6663SArnd Bergmann { 4948b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 4958b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 4968b3d6663SArnd Bergmann int ret; 4978b3d6663SArnd Bergmann 498d219889bSJeremy Kerr if (*pos >= sizeof(lscsa->gprs)) 4998b3d6663SArnd Bergmann return -EFBIG; 500d219889bSJeremy Kerr 501c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 502c9101bdbSChristoph Hellwig if (ret) 503c9101bdbSChristoph Hellwig return ret; 5048b3d6663SArnd Bergmann 50563c3b9d7SAkinobu Mita size = simple_write_to_buffer(lscsa->gprs, sizeof(lscsa->gprs), pos, 50663c3b9d7SAkinobu Mita buffer, size); 5078b3d6663SArnd Bergmann 50827b1ea09SChristoph Hellwig spu_release_saved(ctx); 50963c3b9d7SAkinobu Mita return size; 5108b3d6663SArnd Bergmann } 5118b3d6663SArnd Bergmann 5125dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = { 5138b3d6663SArnd Bergmann .open = spufs_regs_open, 5148b3d6663SArnd Bergmann .read = spufs_regs_read, 5158b3d6663SArnd Bergmann .write = spufs_regs_write, 5168b3d6663SArnd Bergmann .llseek = generic_file_llseek, 5178b3d6663SArnd Bergmann }; 5188b3d6663SArnd Bergmann 5198b3d6663SArnd Bergmann static ssize_t 520bf1ab978SDwayne Grant McConnell __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, 521bf1ab978SDwayne Grant McConnell size_t size, loff_t * pos) 522bf1ab978SDwayne Grant McConnell { 523bf1ab978SDwayne Grant McConnell struct spu_lscsa *lscsa = ctx->csa.lscsa; 524bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buffer, size, pos, 525bf1ab978SDwayne Grant McConnell &lscsa->fpcr, sizeof(lscsa->fpcr)); 526bf1ab978SDwayne Grant McConnell } 527bf1ab978SDwayne Grant McConnell 528bf1ab978SDwayne Grant McConnell static ssize_t 5298b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 5308b3d6663SArnd Bergmann size_t size, loff_t * pos) 5318b3d6663SArnd Bergmann { 5328b3d6663SArnd Bergmann int ret; 533bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5348b3d6663SArnd Bergmann 535c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 536c9101bdbSChristoph Hellwig if (ret) 537c9101bdbSChristoph Hellwig return ret; 538bf1ab978SDwayne Grant McConnell ret = __spufs_fpcr_read(ctx, buffer, size, pos); 53927b1ea09SChristoph Hellwig spu_release_saved(ctx); 5408b3d6663SArnd Bergmann return ret; 5418b3d6663SArnd Bergmann } 5428b3d6663SArnd Bergmann 5438b3d6663SArnd Bergmann static ssize_t 5448b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 5458b3d6663SArnd Bergmann size_t size, loff_t * pos) 5468b3d6663SArnd Bergmann { 5478b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5488b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5498b3d6663SArnd Bergmann int ret; 5508b3d6663SArnd Bergmann 551d219889bSJeremy Kerr if (*pos >= sizeof(lscsa->fpcr)) 5528b3d6663SArnd Bergmann return -EFBIG; 553c9101bdbSChristoph Hellwig 554c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 555c9101bdbSChristoph Hellwig if (ret) 556c9101bdbSChristoph Hellwig return ret; 557c9101bdbSChristoph Hellwig 55863c3b9d7SAkinobu Mita size = simple_write_to_buffer(&lscsa->fpcr, sizeof(lscsa->fpcr), pos, 55963c3b9d7SAkinobu Mita buffer, size); 5608b3d6663SArnd Bergmann 56127b1ea09SChristoph Hellwig spu_release_saved(ctx); 56263c3b9d7SAkinobu Mita return size; 5638b3d6663SArnd Bergmann } 5648b3d6663SArnd Bergmann 5655dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = { 5668b3d6663SArnd Bergmann .open = spufs_regs_open, 5678b3d6663SArnd Bergmann .read = spufs_fpcr_read, 5688b3d6663SArnd Bergmann .write = spufs_fpcr_write, 56967207b96SArnd Bergmann .llseek = generic_file_llseek, 57067207b96SArnd Bergmann }; 57167207b96SArnd Bergmann 57267207b96SArnd Bergmann /* generic open function for all pipe-like files */ 57367207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 57467207b96SArnd Bergmann { 57567207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 57667207b96SArnd Bergmann file->private_data = i->i_ctx; 57767207b96SArnd Bergmann 578c5bf68feSKirill Smelkov return stream_open(inode, file); 57967207b96SArnd Bergmann } 58067207b96SArnd Bergmann 581cdcc89bbSArnd Bergmann /* 582cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 583cdcc89bbSArnd Bergmann * one of the conditions becomes true: 584cdcc89bbSArnd Bergmann * 585cdcc89bbSArnd Bergmann * - no more data available in the mailbox 586cdcc89bbSArnd Bergmann * - end of the user provided buffer 587cdcc89bbSArnd Bergmann * - end of the mapped area 588cdcc89bbSArnd Bergmann */ 58967207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 59067207b96SArnd Bergmann size_t len, loff_t *pos) 59167207b96SArnd Bergmann { 5928b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5936904d3d0SChristoph Hellwig u32 mbox_data, __user *udata = (void __user *)buf; 594cdcc89bbSArnd Bergmann ssize_t count; 59567207b96SArnd Bergmann 59667207b96SArnd Bergmann if (len < 4) 59767207b96SArnd Bergmann return -EINVAL; 59867207b96SArnd Bergmann 599c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 600c9101bdbSChristoph Hellwig if (count) 601c9101bdbSChristoph Hellwig return count; 602c9101bdbSChristoph Hellwig 603274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 604cdcc89bbSArnd Bergmann int ret; 605cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 606cdcc89bbSArnd Bergmann if (ret == 0) 607cdcc89bbSArnd Bergmann break; 608cdcc89bbSArnd Bergmann 609cdcc89bbSArnd Bergmann /* 610cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 611cdcc89bbSArnd Bergmann * but still need to return the data we have 612cdcc89bbSArnd Bergmann * read successfully so far. 613cdcc89bbSArnd Bergmann */ 6146904d3d0SChristoph Hellwig ret = put_user(mbox_data, udata); 615cdcc89bbSArnd Bergmann if (ret) { 616cdcc89bbSArnd Bergmann if (!count) 617cdcc89bbSArnd Bergmann count = -EFAULT; 618cdcc89bbSArnd Bergmann break; 619cdcc89bbSArnd Bergmann } 620cdcc89bbSArnd Bergmann } 621cdcc89bbSArnd Bergmann spu_release(ctx); 622cdcc89bbSArnd Bergmann 623cdcc89bbSArnd Bergmann if (!count) 624cdcc89bbSArnd Bergmann count = -EAGAIN; 625cdcc89bbSArnd Bergmann 626cdcc89bbSArnd Bergmann return count; 62767207b96SArnd Bergmann } 62867207b96SArnd Bergmann 6295dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = { 63067207b96SArnd Bergmann .open = spufs_pipe_open, 63167207b96SArnd Bergmann .read = spufs_mbox_read, 632fc15351dSArnd Bergmann .llseek = no_llseek, 63367207b96SArnd Bergmann }; 63467207b96SArnd Bergmann 63567207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 63667207b96SArnd Bergmann size_t len, loff_t *pos) 63767207b96SArnd Bergmann { 6388b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 639c9101bdbSChristoph Hellwig ssize_t ret; 64067207b96SArnd Bergmann u32 mbox_stat; 64167207b96SArnd Bergmann 64267207b96SArnd Bergmann if (len < 4) 64367207b96SArnd Bergmann return -EINVAL; 64467207b96SArnd Bergmann 645c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 646c9101bdbSChristoph Hellwig if (ret) 647c9101bdbSChristoph Hellwig return ret; 6488b3d6663SArnd Bergmann 6498b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 6508b3d6663SArnd Bergmann 6518b3d6663SArnd Bergmann spu_release(ctx); 65267207b96SArnd Bergmann 65367207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 65467207b96SArnd Bergmann return -EFAULT; 65567207b96SArnd Bergmann 65667207b96SArnd Bergmann return 4; 65767207b96SArnd Bergmann } 65867207b96SArnd Bergmann 6595dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = { 66067207b96SArnd Bergmann .open = spufs_pipe_open, 66167207b96SArnd Bergmann .read = spufs_mbox_stat_read, 662fc15351dSArnd Bergmann .llseek = no_llseek, 66367207b96SArnd Bergmann }; 66467207b96SArnd Bergmann 66567207b96SArnd Bergmann /* low-level ibox access function */ 6668b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 66767207b96SArnd Bergmann { 6688b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 66967207b96SArnd Bergmann } 67067207b96SArnd Bergmann 6718b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 6728b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 6738b3d6663SArnd Bergmann { 6748b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 6758b3d6663SArnd Bergmann 6767d7be3aaSAl Viro if (ctx) 6778b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 67867207b96SArnd Bergmann } 67967207b96SArnd Bergmann 680cdcc89bbSArnd Bergmann /* 681cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 682cdcc89bbSArnd Bergmann * one of the conditions becomes true: 683cdcc89bbSArnd Bergmann * 684cdcc89bbSArnd Bergmann * - no more data available in the mailbox 685cdcc89bbSArnd Bergmann * - end of the user provided buffer 686cdcc89bbSArnd Bergmann * - end of the mapped area 687cdcc89bbSArnd Bergmann * 688cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 689cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 690cdcc89bbSArnd Bergmann * read something. 691cdcc89bbSArnd Bergmann */ 69267207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 69367207b96SArnd Bergmann size_t len, loff_t *pos) 69467207b96SArnd Bergmann { 6958b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 6966904d3d0SChristoph Hellwig u32 ibox_data, __user *udata = (void __user *)buf; 697cdcc89bbSArnd Bergmann ssize_t count; 69867207b96SArnd Bergmann 69967207b96SArnd Bergmann if (len < 4) 70067207b96SArnd Bergmann return -EINVAL; 70167207b96SArnd Bergmann 702c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 703c9101bdbSChristoph Hellwig if (count) 704eebead5bSChristoph Hellwig goto out; 70567207b96SArnd Bergmann 706cdcc89bbSArnd Bergmann /* wait only for the first element */ 707cdcc89bbSArnd Bergmann count = 0; 70867207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 709eebead5bSChristoph Hellwig if (!spu_ibox_read(ctx, &ibox_data)) { 710cdcc89bbSArnd Bergmann count = -EAGAIN; 711eebead5bSChristoph Hellwig goto out_unlock; 712eebead5bSChristoph Hellwig } 71367207b96SArnd Bergmann } else { 714cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 715cdcc89bbSArnd Bergmann if (count) 716cdcc89bbSArnd Bergmann goto out; 717eebead5bSChristoph Hellwig } 718cdcc89bbSArnd Bergmann 719cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 7206904d3d0SChristoph Hellwig count = put_user(ibox_data, udata); 721cdcc89bbSArnd Bergmann if (count) 722eebead5bSChristoph Hellwig goto out_unlock; 723cdcc89bbSArnd Bergmann 724cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 725cdcc89bbSArnd Bergmann int ret; 726cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 727cdcc89bbSArnd Bergmann if (ret == 0) 728cdcc89bbSArnd Bergmann break; 729cdcc89bbSArnd Bergmann /* 730cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 731cdcc89bbSArnd Bergmann * but still need to return the data we have 732cdcc89bbSArnd Bergmann * read successfully so far. 733cdcc89bbSArnd Bergmann */ 7346904d3d0SChristoph Hellwig ret = put_user(ibox_data, udata); 735cdcc89bbSArnd Bergmann if (ret) 736cdcc89bbSArnd Bergmann break; 73767207b96SArnd Bergmann } 73867207b96SArnd Bergmann 739eebead5bSChristoph Hellwig out_unlock: 7408b3d6663SArnd Bergmann spu_release(ctx); 741eebead5bSChristoph Hellwig out: 742cdcc89bbSArnd Bergmann return count; 74367207b96SArnd Bergmann } 74467207b96SArnd Bergmann 7458153a5eaSAl Viro static __poll_t spufs_ibox_poll(struct file *file, poll_table *wait) 74667207b96SArnd Bergmann { 7478b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 7488153a5eaSAl Viro __poll_t mask; 74967207b96SArnd Bergmann 7508b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 75167207b96SArnd Bergmann 752c9101bdbSChristoph Hellwig /* 753c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 754c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 755c9101bdbSChristoph Hellwig */ 756c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 757a9a08845SLinus Torvalds mask = ctx->ops->mbox_stat_poll(ctx, EPOLLIN | EPOLLRDNORM); 7583a843d7cSArnd Bergmann spu_release(ctx); 75967207b96SArnd Bergmann 76067207b96SArnd Bergmann return mask; 76167207b96SArnd Bergmann } 76267207b96SArnd Bergmann 7635dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = { 76467207b96SArnd Bergmann .open = spufs_pipe_open, 76567207b96SArnd Bergmann .read = spufs_ibox_read, 76667207b96SArnd Bergmann .poll = spufs_ibox_poll, 767fc15351dSArnd Bergmann .llseek = no_llseek, 76867207b96SArnd Bergmann }; 76967207b96SArnd Bergmann 77067207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 77167207b96SArnd Bergmann size_t len, loff_t *pos) 77267207b96SArnd Bergmann { 7738b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 774c9101bdbSChristoph Hellwig ssize_t ret; 77567207b96SArnd Bergmann u32 ibox_stat; 77667207b96SArnd Bergmann 77767207b96SArnd Bergmann if (len < 4) 77867207b96SArnd Bergmann return -EINVAL; 77967207b96SArnd Bergmann 780c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 781c9101bdbSChristoph Hellwig if (ret) 782c9101bdbSChristoph Hellwig return ret; 7838b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 7848b3d6663SArnd Bergmann spu_release(ctx); 78567207b96SArnd Bergmann 78667207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 78767207b96SArnd Bergmann return -EFAULT; 78867207b96SArnd Bergmann 78967207b96SArnd Bergmann return 4; 79067207b96SArnd Bergmann } 79167207b96SArnd Bergmann 7925dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = { 79367207b96SArnd Bergmann .open = spufs_pipe_open, 79467207b96SArnd Bergmann .read = spufs_ibox_stat_read, 795fc15351dSArnd Bergmann .llseek = no_llseek, 79667207b96SArnd Bergmann }; 79767207b96SArnd Bergmann 79867207b96SArnd Bergmann /* low-level mailbox write */ 7998b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 80067207b96SArnd Bergmann { 8018b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 80267207b96SArnd Bergmann } 80367207b96SArnd Bergmann 8048b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 8058b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 8068b3d6663SArnd Bergmann { 8078b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 8088b3d6663SArnd Bergmann 8097d7be3aaSAl Viro if (ctx) 8108b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 81167207b96SArnd Bergmann } 81267207b96SArnd Bergmann 813cdcc89bbSArnd Bergmann /* 814cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 815cdcc89bbSArnd Bergmann * one of the conditions becomes true: 816cdcc89bbSArnd Bergmann * 817cdcc89bbSArnd Bergmann * - the mailbox is full 818cdcc89bbSArnd Bergmann * - end of the user provided buffer 819cdcc89bbSArnd Bergmann * - end of the mapped area 820cdcc89bbSArnd Bergmann * 821cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 822027dfac6SMichael Ellerman * space is available, but return when we have been able to 823cdcc89bbSArnd Bergmann * write something. 824cdcc89bbSArnd Bergmann */ 82567207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 82667207b96SArnd Bergmann size_t len, loff_t *pos) 82767207b96SArnd Bergmann { 8288b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 8296904d3d0SChristoph Hellwig u32 wbox_data, __user *udata = (void __user *)buf; 830cdcc89bbSArnd Bergmann ssize_t count; 83167207b96SArnd Bergmann 83267207b96SArnd Bergmann if (len < 4) 83367207b96SArnd Bergmann return -EINVAL; 83467207b96SArnd Bergmann 8356904d3d0SChristoph Hellwig if (get_user(wbox_data, udata)) 83667207b96SArnd Bergmann return -EFAULT; 83767207b96SArnd Bergmann 838c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 839c9101bdbSChristoph Hellwig if (count) 840eebead5bSChristoph Hellwig goto out; 8418b3d6663SArnd Bergmann 842cdcc89bbSArnd Bergmann /* 843cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 844cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 845cdcc89bbSArnd Bergmann */ 846cdcc89bbSArnd Bergmann count = 0; 84767207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 848eebead5bSChristoph Hellwig if (!spu_wbox_write(ctx, wbox_data)) { 849cdcc89bbSArnd Bergmann count = -EAGAIN; 850eebead5bSChristoph Hellwig goto out_unlock; 851eebead5bSChristoph Hellwig } 85267207b96SArnd Bergmann } else { 853cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 854cdcc89bbSArnd Bergmann if (count) 855cdcc89bbSArnd Bergmann goto out; 856eebead5bSChristoph Hellwig } 857eebead5bSChristoph Hellwig 8588b3d6663SArnd Bergmann 85996de0e25SJan Engelhardt /* write as much as possible */ 860cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 861cdcc89bbSArnd Bergmann int ret; 8626904d3d0SChristoph Hellwig ret = get_user(wbox_data, udata); 863cdcc89bbSArnd Bergmann if (ret) 864cdcc89bbSArnd Bergmann break; 865cdcc89bbSArnd Bergmann 866cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 867cdcc89bbSArnd Bergmann if (ret == 0) 868cdcc89bbSArnd Bergmann break; 869cdcc89bbSArnd Bergmann } 870cdcc89bbSArnd Bergmann 871eebead5bSChristoph Hellwig out_unlock: 872cdcc89bbSArnd Bergmann spu_release(ctx); 873eebead5bSChristoph Hellwig out: 874cdcc89bbSArnd Bergmann return count; 87567207b96SArnd Bergmann } 87667207b96SArnd Bergmann 8778153a5eaSAl Viro static __poll_t spufs_wbox_poll(struct file *file, poll_table *wait) 87867207b96SArnd Bergmann { 8798b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 8808153a5eaSAl Viro __poll_t mask; 88167207b96SArnd Bergmann 8828b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 88367207b96SArnd Bergmann 884c9101bdbSChristoph Hellwig /* 885c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 886c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 887c9101bdbSChristoph Hellwig */ 888c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 889a9a08845SLinus Torvalds mask = ctx->ops->mbox_stat_poll(ctx, EPOLLOUT | EPOLLWRNORM); 8903a843d7cSArnd Bergmann spu_release(ctx); 89167207b96SArnd Bergmann 89267207b96SArnd Bergmann return mask; 89367207b96SArnd Bergmann } 89467207b96SArnd Bergmann 8955dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = { 89667207b96SArnd Bergmann .open = spufs_pipe_open, 89767207b96SArnd Bergmann .write = spufs_wbox_write, 89867207b96SArnd Bergmann .poll = spufs_wbox_poll, 899fc15351dSArnd Bergmann .llseek = no_llseek, 90067207b96SArnd Bergmann }; 90167207b96SArnd Bergmann 90267207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 90367207b96SArnd Bergmann size_t len, loff_t *pos) 90467207b96SArnd Bergmann { 9058b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 906c9101bdbSChristoph Hellwig ssize_t ret; 90767207b96SArnd Bergmann u32 wbox_stat; 90867207b96SArnd Bergmann 90967207b96SArnd Bergmann if (len < 4) 91067207b96SArnd Bergmann return -EINVAL; 91167207b96SArnd Bergmann 912c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 913c9101bdbSChristoph Hellwig if (ret) 914c9101bdbSChristoph Hellwig return ret; 9158b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 9168b3d6663SArnd Bergmann spu_release(ctx); 91767207b96SArnd Bergmann 91867207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 91967207b96SArnd Bergmann return -EFAULT; 92067207b96SArnd Bergmann 92167207b96SArnd Bergmann return 4; 92267207b96SArnd Bergmann } 92367207b96SArnd Bergmann 9245dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = { 92567207b96SArnd Bergmann .open = spufs_pipe_open, 92667207b96SArnd Bergmann .read = spufs_wbox_stat_read, 927fc15351dSArnd Bergmann .llseek = no_llseek, 92867207b96SArnd Bergmann }; 92967207b96SArnd Bergmann 9306df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 9316df10a82SMark Nutter { 9326df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 9336df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 93443c2bbd9SChristoph Hellwig 93547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 9366df10a82SMark Nutter file->private_data = ctx; 93743c2bbd9SChristoph Hellwig if (!i->i_openers++) 9386df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 93947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 9406df10a82SMark Nutter return nonseekable_open(inode, file); 9416df10a82SMark Nutter } 9426df10a82SMark Nutter 94343c2bbd9SChristoph Hellwig static int 94443c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file) 94543c2bbd9SChristoph Hellwig { 94643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 94743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 94843c2bbd9SChristoph Hellwig 94947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 95043c2bbd9SChristoph Hellwig if (!--i->i_openers) 95143c2bbd9SChristoph Hellwig ctx->signal1 = NULL; 95247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 95343c2bbd9SChristoph Hellwig return 0; 95443c2bbd9SChristoph Hellwig } 95543c2bbd9SChristoph Hellwig 956bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 95767207b96SArnd Bergmann size_t len, loff_t *pos) 95867207b96SArnd Bergmann { 95917f88cebSDwayne Grant McConnell int ret = 0; 96067207b96SArnd Bergmann u32 data; 96167207b96SArnd Bergmann 96267207b96SArnd Bergmann if (len < 4) 96367207b96SArnd Bergmann return -EINVAL; 96467207b96SArnd Bergmann 96517f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[3]) { 96617f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[3]; 96717f88cebSDwayne Grant McConnell ret = 4; 96817f88cebSDwayne Grant McConnell } 9698b3d6663SArnd Bergmann 97017f88cebSDwayne Grant McConnell if (!ret) 97117f88cebSDwayne Grant McConnell goto out; 97217f88cebSDwayne Grant McConnell 97367207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 97467207b96SArnd Bergmann return -EFAULT; 97567207b96SArnd Bergmann 97617f88cebSDwayne Grant McConnell out: 97717f88cebSDwayne Grant McConnell return ret; 97867207b96SArnd Bergmann } 97967207b96SArnd Bergmann 980bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 981bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 982bf1ab978SDwayne Grant McConnell { 983bf1ab978SDwayne Grant McConnell int ret; 984bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 985bf1ab978SDwayne Grant McConnell 986c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 987c9101bdbSChristoph Hellwig if (ret) 988c9101bdbSChristoph Hellwig return ret; 989bf1ab978SDwayne Grant McConnell ret = __spufs_signal1_read(ctx, buf, len, pos); 99027b1ea09SChristoph Hellwig spu_release_saved(ctx); 991bf1ab978SDwayne Grant McConnell 992bf1ab978SDwayne Grant McConnell return ret; 993bf1ab978SDwayne Grant McConnell } 994bf1ab978SDwayne Grant McConnell 99567207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 99667207b96SArnd Bergmann size_t len, loff_t *pos) 99767207b96SArnd Bergmann { 99867207b96SArnd Bergmann struct spu_context *ctx; 999c9101bdbSChristoph Hellwig ssize_t ret; 100067207b96SArnd Bergmann u32 data; 100167207b96SArnd Bergmann 100267207b96SArnd Bergmann ctx = file->private_data; 100367207b96SArnd Bergmann 100467207b96SArnd Bergmann if (len < 4) 100567207b96SArnd Bergmann return -EINVAL; 100667207b96SArnd Bergmann 100767207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 100867207b96SArnd Bergmann return -EFAULT; 100967207b96SArnd Bergmann 1010c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1011c9101bdbSChristoph Hellwig if (ret) 1012c9101bdbSChristoph Hellwig return ret; 10138b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 10148b3d6663SArnd Bergmann spu_release(ctx); 101567207b96SArnd Bergmann 101667207b96SArnd Bergmann return 4; 101767207b96SArnd Bergmann } 101867207b96SArnd Bergmann 1019e807f02cSSouptick Joarder static vm_fault_t 102011bac800SDave Jiang spufs_signal1_mmap_fault(struct vm_fault *vmf) 10216df10a82SMark Nutter { 102287ff6090SJeremy Kerr #if SPUFS_SIGNAL_MAP_SIZE == 0x1000 102311bac800SDave Jiang return spufs_ps_fault(vmf, 0x14000, SPUFS_SIGNAL_MAP_SIZE); 102487ff6090SJeremy Kerr #elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 102527d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 102627d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 102727d5bf2aSBenjamin Herrenschmidt */ 102811bac800SDave Jiang return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); 102927d5bf2aSBenjamin Herrenschmidt #else 103027d5bf2aSBenjamin Herrenschmidt #error unsupported page size 103127d5bf2aSBenjamin Herrenschmidt #endif 10326df10a82SMark Nutter } 10336df10a82SMark Nutter 1034f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_signal1_mmap_vmops = { 1035b1e2270fSNick Piggin .fault = spufs_signal1_mmap_fault, 10366df10a82SMark Nutter }; 10376df10a82SMark Nutter 10386df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 10396df10a82SMark Nutter { 10406df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 10416df10a82SMark Nutter return -EINVAL; 10426df10a82SMark Nutter 104378bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 104464b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 10456df10a82SMark Nutter 10466df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 10476df10a82SMark Nutter return 0; 10486df10a82SMark Nutter } 10496df10a82SMark Nutter 10505dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = { 10516df10a82SMark Nutter .open = spufs_signal1_open, 105243c2bbd9SChristoph Hellwig .release = spufs_signal1_release, 105367207b96SArnd Bergmann .read = spufs_signal1_read, 105467207b96SArnd Bergmann .write = spufs_signal1_write, 10556df10a82SMark Nutter .mmap = spufs_signal1_mmap, 1056fc15351dSArnd Bergmann .llseek = no_llseek, 105767207b96SArnd Bergmann }; 105867207b96SArnd Bergmann 1059d054b36fSJeremy Kerr static const struct file_operations spufs_signal1_nosched_fops = { 1060d054b36fSJeremy Kerr .open = spufs_signal1_open, 1061d054b36fSJeremy Kerr .release = spufs_signal1_release, 1062d054b36fSJeremy Kerr .write = spufs_signal1_write, 1063d054b36fSJeremy Kerr .mmap = spufs_signal1_mmap, 1064fc15351dSArnd Bergmann .llseek = no_llseek, 1065d054b36fSJeremy Kerr }; 1066d054b36fSJeremy Kerr 10676df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 10686df10a82SMark Nutter { 10696df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 10706df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 107143c2bbd9SChristoph Hellwig 107247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 10736df10a82SMark Nutter file->private_data = ctx; 107443c2bbd9SChristoph Hellwig if (!i->i_openers++) 10756df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 107647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 10776df10a82SMark Nutter return nonseekable_open(inode, file); 10786df10a82SMark Nutter } 10796df10a82SMark Nutter 108043c2bbd9SChristoph Hellwig static int 108143c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file) 108243c2bbd9SChristoph Hellwig { 108343c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 108443c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 108543c2bbd9SChristoph Hellwig 108647d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 108743c2bbd9SChristoph Hellwig if (!--i->i_openers) 108843c2bbd9SChristoph Hellwig ctx->signal2 = NULL; 108947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 109043c2bbd9SChristoph Hellwig return 0; 109143c2bbd9SChristoph Hellwig } 109243c2bbd9SChristoph Hellwig 1093bf1ab978SDwayne Grant McConnell static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 109467207b96SArnd Bergmann size_t len, loff_t *pos) 109567207b96SArnd Bergmann { 109617f88cebSDwayne Grant McConnell int ret = 0; 109767207b96SArnd Bergmann u32 data; 109867207b96SArnd Bergmann 109967207b96SArnd Bergmann if (len < 4) 110067207b96SArnd Bergmann return -EINVAL; 110167207b96SArnd Bergmann 110217f88cebSDwayne Grant McConnell if (ctx->csa.spu_chnlcnt_RW[4]) { 110317f88cebSDwayne Grant McConnell data = ctx->csa.spu_chnldata_RW[4]; 110417f88cebSDwayne Grant McConnell ret = 4; 110517f88cebSDwayne Grant McConnell } 11068b3d6663SArnd Bergmann 110717f88cebSDwayne Grant McConnell if (!ret) 110817f88cebSDwayne Grant McConnell goto out; 110917f88cebSDwayne Grant McConnell 111067207b96SArnd Bergmann if (copy_to_user(buf, &data, 4)) 111167207b96SArnd Bergmann return -EFAULT; 111267207b96SArnd Bergmann 111317f88cebSDwayne Grant McConnell out: 1114bf1ab978SDwayne Grant McConnell return ret; 1115bf1ab978SDwayne Grant McConnell } 1116bf1ab978SDwayne Grant McConnell 1117bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 1118bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1119bf1ab978SDwayne Grant McConnell { 1120bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1121bf1ab978SDwayne Grant McConnell int ret; 1122bf1ab978SDwayne Grant McConnell 1123c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1124c9101bdbSChristoph Hellwig if (ret) 1125c9101bdbSChristoph Hellwig return ret; 1126bf1ab978SDwayne Grant McConnell ret = __spufs_signal2_read(ctx, buf, len, pos); 112727b1ea09SChristoph Hellwig spu_release_saved(ctx); 1128bf1ab978SDwayne Grant McConnell 1129bf1ab978SDwayne Grant McConnell return ret; 113067207b96SArnd Bergmann } 113167207b96SArnd Bergmann 113267207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 113367207b96SArnd Bergmann size_t len, loff_t *pos) 113467207b96SArnd Bergmann { 113567207b96SArnd Bergmann struct spu_context *ctx; 1136c9101bdbSChristoph Hellwig ssize_t ret; 113767207b96SArnd Bergmann u32 data; 113867207b96SArnd Bergmann 113967207b96SArnd Bergmann ctx = file->private_data; 114067207b96SArnd Bergmann 114167207b96SArnd Bergmann if (len < 4) 114267207b96SArnd Bergmann return -EINVAL; 114367207b96SArnd Bergmann 114467207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 114567207b96SArnd Bergmann return -EFAULT; 114667207b96SArnd Bergmann 1147c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1148c9101bdbSChristoph Hellwig if (ret) 1149c9101bdbSChristoph Hellwig return ret; 11508b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 11518b3d6663SArnd Bergmann spu_release(ctx); 115267207b96SArnd Bergmann 115367207b96SArnd Bergmann return 4; 115467207b96SArnd Bergmann } 115567207b96SArnd Bergmann 115627d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1157e807f02cSSouptick Joarder static vm_fault_t 115811bac800SDave Jiang spufs_signal2_mmap_fault(struct vm_fault *vmf) 11596df10a82SMark Nutter { 116087ff6090SJeremy Kerr #if SPUFS_SIGNAL_MAP_SIZE == 0x1000 116111bac800SDave Jiang return spufs_ps_fault(vmf, 0x1c000, SPUFS_SIGNAL_MAP_SIZE); 116287ff6090SJeremy Kerr #elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 116327d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 116427d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 116527d5bf2aSBenjamin Herrenschmidt */ 116611bac800SDave Jiang return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); 116727d5bf2aSBenjamin Herrenschmidt #else 116827d5bf2aSBenjamin Herrenschmidt #error unsupported page size 116927d5bf2aSBenjamin Herrenschmidt #endif 11706df10a82SMark Nutter } 11716df10a82SMark Nutter 1172f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_signal2_mmap_vmops = { 1173b1e2270fSNick Piggin .fault = spufs_signal2_mmap_fault, 11746df10a82SMark Nutter }; 11756df10a82SMark Nutter 11766df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 11776df10a82SMark Nutter { 11786df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 11796df10a82SMark Nutter return -EINVAL; 11806df10a82SMark Nutter 118178bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 118264b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 11836df10a82SMark Nutter 11846df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 11856df10a82SMark Nutter return 0; 11866df10a82SMark Nutter } 118727d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 118827d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 118927d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 11906df10a82SMark Nutter 11915dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = { 11926df10a82SMark Nutter .open = spufs_signal2_open, 119343c2bbd9SChristoph Hellwig .release = spufs_signal2_release, 119467207b96SArnd Bergmann .read = spufs_signal2_read, 119567207b96SArnd Bergmann .write = spufs_signal2_write, 11966df10a82SMark Nutter .mmap = spufs_signal2_mmap, 1197fc15351dSArnd Bergmann .llseek = no_llseek, 119867207b96SArnd Bergmann }; 119967207b96SArnd Bergmann 1200d054b36fSJeremy Kerr static const struct file_operations spufs_signal2_nosched_fops = { 1201d054b36fSJeremy Kerr .open = spufs_signal2_open, 1202d054b36fSJeremy Kerr .release = spufs_signal2_release, 1203d054b36fSJeremy Kerr .write = spufs_signal2_write, 1204d054b36fSJeremy Kerr .mmap = spufs_signal2_mmap, 1205fc15351dSArnd Bergmann .llseek = no_llseek, 1206d054b36fSJeremy Kerr }; 1207d054b36fSJeremy Kerr 1208104f0cc2SMichael Ellerman /* 1209104f0cc2SMichael Ellerman * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the 1210104f0cc2SMichael Ellerman * work of acquiring (or not) the SPU context before calling through 1211104f0cc2SMichael Ellerman * to the actual get routine. The set routine is called directly. 1212104f0cc2SMichael Ellerman */ 1213104f0cc2SMichael Ellerman #define SPU_ATTR_NOACQUIRE 0 1214104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE 1 1215104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE_SAVED 2 1216104f0cc2SMichael Ellerman 1217104f0cc2SMichael Ellerman #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ 1218197b1a82SChristoph Hellwig static int __##__get(void *data, u64 *val) \ 1219104f0cc2SMichael Ellerman { \ 1220104f0cc2SMichael Ellerman struct spu_context *ctx = data; \ 1221c9101bdbSChristoph Hellwig int ret = 0; \ 1222104f0cc2SMichael Ellerman \ 1223104f0cc2SMichael Ellerman if (__acquire == SPU_ATTR_ACQUIRE) { \ 1224c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); \ 1225c9101bdbSChristoph Hellwig if (ret) \ 1226c9101bdbSChristoph Hellwig return ret; \ 1227197b1a82SChristoph Hellwig *val = __get(ctx); \ 1228104f0cc2SMichael Ellerman spu_release(ctx); \ 1229104f0cc2SMichael Ellerman } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ 1230c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); \ 1231c9101bdbSChristoph Hellwig if (ret) \ 1232c9101bdbSChristoph Hellwig return ret; \ 1233197b1a82SChristoph Hellwig *val = __get(ctx); \ 1234104f0cc2SMichael Ellerman spu_release_saved(ctx); \ 1235104f0cc2SMichael Ellerman } else \ 1236197b1a82SChristoph Hellwig *val = __get(ctx); \ 1237104f0cc2SMichael Ellerman \ 1238197b1a82SChristoph Hellwig return 0; \ 1239104f0cc2SMichael Ellerman } \ 1240197b1a82SChristoph Hellwig DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); 1241104f0cc2SMichael Ellerman 1242197b1a82SChristoph Hellwig static int spufs_signal1_type_set(void *data, u64 val) 124367207b96SArnd Bergmann { 124467207b96SArnd Bergmann struct spu_context *ctx = data; 1245c9101bdbSChristoph Hellwig int ret; 124667207b96SArnd Bergmann 1247c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1248c9101bdbSChristoph Hellwig if (ret) 1249c9101bdbSChristoph Hellwig return ret; 12508b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 12518b3d6663SArnd Bergmann spu_release(ctx); 1252197b1a82SChristoph Hellwig 1253197b1a82SChristoph Hellwig return 0; 125467207b96SArnd Bergmann } 125567207b96SArnd Bergmann 1256104f0cc2SMichael Ellerman static u64 spufs_signal1_type_get(struct spu_context *ctx) 1257bf1ab978SDwayne Grant McConnell { 1258bf1ab978SDwayne Grant McConnell return ctx->ops->signal1_type_get(ctx); 1259bf1ab978SDwayne Grant McConnell } 1260104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 1261af8b44e0SJeremy Kerr spufs_signal1_type_set, "%llu\n", SPU_ATTR_ACQUIRE); 1262bf1ab978SDwayne Grant McConnell 126367207b96SArnd Bergmann 1264197b1a82SChristoph Hellwig static int spufs_signal2_type_set(void *data, u64 val) 126567207b96SArnd Bergmann { 126667207b96SArnd Bergmann struct spu_context *ctx = data; 1267c9101bdbSChristoph Hellwig int ret; 126867207b96SArnd Bergmann 1269c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1270c9101bdbSChristoph Hellwig if (ret) 1271c9101bdbSChristoph Hellwig return ret; 12728b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 12738b3d6663SArnd Bergmann spu_release(ctx); 1274197b1a82SChristoph Hellwig 1275197b1a82SChristoph Hellwig return 0; 127667207b96SArnd Bergmann } 127767207b96SArnd Bergmann 1278104f0cc2SMichael Ellerman static u64 spufs_signal2_type_get(struct spu_context *ctx) 1279bf1ab978SDwayne Grant McConnell { 1280bf1ab978SDwayne Grant McConnell return ctx->ops->signal2_type_get(ctx); 1281bf1ab978SDwayne Grant McConnell } 1282104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 1283af8b44e0SJeremy Kerr spufs_signal2_type_set, "%llu\n", SPU_ATTR_ACQUIRE); 128467207b96SArnd Bergmann 128527d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1286e807f02cSSouptick Joarder static vm_fault_t 128711bac800SDave Jiang spufs_mss_mmap_fault(struct vm_fault *vmf) 1288d9379c4bSarnd@arndb.de { 128911bac800SDave Jiang return spufs_ps_fault(vmf, 0x0000, SPUFS_MSS_MAP_SIZE); 1290d9379c4bSarnd@arndb.de } 1291d9379c4bSarnd@arndb.de 1292f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mss_mmap_vmops = { 1293b1e2270fSNick Piggin .fault = spufs_mss_mmap_fault, 1294d9379c4bSarnd@arndb.de }; 1295d9379c4bSarnd@arndb.de 1296d9379c4bSarnd@arndb.de /* 1297d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 1298d9379c4bSarnd@arndb.de */ 1299d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 1300d9379c4bSarnd@arndb.de { 1301d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 1302d9379c4bSarnd@arndb.de return -EINVAL; 1303d9379c4bSarnd@arndb.de 130478bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 130564b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 1306d9379c4bSarnd@arndb.de 1307d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 1308d9379c4bSarnd@arndb.de return 0; 1309d9379c4bSarnd@arndb.de } 131027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 131127d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 131227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1313d9379c4bSarnd@arndb.de 1314d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 1315d9379c4bSarnd@arndb.de { 1316d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 131717e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 1318d9379c4bSarnd@arndb.de 1319d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 132043c2bbd9SChristoph Hellwig 132147d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 132243c2bbd9SChristoph Hellwig if (!i->i_openers++) 132317e0e270SBenjamin Herrenschmidt ctx->mss = inode->i_mapping; 132447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1325d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 1326d9379c4bSarnd@arndb.de } 1327d9379c4bSarnd@arndb.de 132843c2bbd9SChristoph Hellwig static int 132943c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file) 133043c2bbd9SChristoph Hellwig { 133143c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 133243c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 133343c2bbd9SChristoph Hellwig 133447d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 133543c2bbd9SChristoph Hellwig if (!--i->i_openers) 133643c2bbd9SChristoph Hellwig ctx->mss = NULL; 133747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 133843c2bbd9SChristoph Hellwig return 0; 133943c2bbd9SChristoph Hellwig } 134043c2bbd9SChristoph Hellwig 13415dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = { 1342d9379c4bSarnd@arndb.de .open = spufs_mss_open, 134343c2bbd9SChristoph Hellwig .release = spufs_mss_release, 1344d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 1345fc15351dSArnd Bergmann .llseek = no_llseek, 134627d5bf2aSBenjamin Herrenschmidt }; 134727d5bf2aSBenjamin Herrenschmidt 1348e807f02cSSouptick Joarder static vm_fault_t 134911bac800SDave Jiang spufs_psmap_mmap_fault(struct vm_fault *vmf) 135027d5bf2aSBenjamin Herrenschmidt { 135111bac800SDave Jiang return spufs_ps_fault(vmf, 0x0000, SPUFS_PS_MAP_SIZE); 135227d5bf2aSBenjamin Herrenschmidt } 135327d5bf2aSBenjamin Herrenschmidt 1354f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_psmap_mmap_vmops = { 1355b1e2270fSNick Piggin .fault = spufs_psmap_mmap_fault, 135627d5bf2aSBenjamin Herrenschmidt }; 135727d5bf2aSBenjamin Herrenschmidt 135827d5bf2aSBenjamin Herrenschmidt /* 135927d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 136027d5bf2aSBenjamin Herrenschmidt */ 136127d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 136227d5bf2aSBenjamin Herrenschmidt { 136327d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 136427d5bf2aSBenjamin Herrenschmidt return -EINVAL; 136527d5bf2aSBenjamin Herrenschmidt 136678bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 136764b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 136827d5bf2aSBenjamin Herrenschmidt 136927d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 137027d5bf2aSBenjamin Herrenschmidt return 0; 137127d5bf2aSBenjamin Herrenschmidt } 137227d5bf2aSBenjamin Herrenschmidt 137327d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 137427d5bf2aSBenjamin Herrenschmidt { 137527d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 137617e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 137727d5bf2aSBenjamin Herrenschmidt 137847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 137927d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 138043c2bbd9SChristoph Hellwig if (!i->i_openers++) 138117e0e270SBenjamin Herrenschmidt ctx->psmap = inode->i_mapping; 138247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 138327d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 138427d5bf2aSBenjamin Herrenschmidt } 138527d5bf2aSBenjamin Herrenschmidt 138643c2bbd9SChristoph Hellwig static int 138743c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file) 138843c2bbd9SChristoph Hellwig { 138943c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 139043c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 139143c2bbd9SChristoph Hellwig 139247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 139343c2bbd9SChristoph Hellwig if (!--i->i_openers) 139443c2bbd9SChristoph Hellwig ctx->psmap = NULL; 139547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 139643c2bbd9SChristoph Hellwig return 0; 139743c2bbd9SChristoph Hellwig } 139843c2bbd9SChristoph Hellwig 13995dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = { 140027d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 140143c2bbd9SChristoph Hellwig .release = spufs_psmap_release, 140227d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1403fc15351dSArnd Bergmann .llseek = no_llseek, 1404d9379c4bSarnd@arndb.de }; 1405d9379c4bSarnd@arndb.de 1406d9379c4bSarnd@arndb.de 140727d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1408e807f02cSSouptick Joarder static vm_fault_t 140911bac800SDave Jiang spufs_mfc_mmap_fault(struct vm_fault *vmf) 14106df10a82SMark Nutter { 141111bac800SDave Jiang return spufs_ps_fault(vmf, 0x3000, SPUFS_MFC_MAP_SIZE); 14126df10a82SMark Nutter } 14136df10a82SMark Nutter 1414f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mfc_mmap_vmops = { 1415b1e2270fSNick Piggin .fault = spufs_mfc_mmap_fault, 14166df10a82SMark Nutter }; 14176df10a82SMark Nutter 14186df10a82SMark Nutter /* 14196df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 14206df10a82SMark Nutter */ 14216df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 14226df10a82SMark Nutter { 14236df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 14246df10a82SMark Nutter return -EINVAL; 14256df10a82SMark Nutter 142678bde53eSBenjamin Herrenschmidt vma->vm_flags |= VM_IO | VM_PFNMAP; 142764b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 14286df10a82SMark Nutter 14296df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 14306df10a82SMark Nutter return 0; 14316df10a82SMark Nutter } 143227d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 143327d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 143427d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1435a33a7d73SArnd Bergmann 1436a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1437a33a7d73SArnd Bergmann { 1438a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1439a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1440a33a7d73SArnd Bergmann 1441a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1442a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1443a33a7d73SArnd Bergmann return -EINVAL; 1444a33a7d73SArnd Bergmann 1445a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1446a33a7d73SArnd Bergmann return -EBUSY; 1447a33a7d73SArnd Bergmann 144847d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1449a33a7d73SArnd Bergmann file->private_data = ctx; 145043c2bbd9SChristoph Hellwig if (!i->i_openers++) 145117e0e270SBenjamin Herrenschmidt ctx->mfc = inode->i_mapping; 145247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1453a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1454a33a7d73SArnd Bergmann } 1455a33a7d73SArnd Bergmann 145643c2bbd9SChristoph Hellwig static int 145743c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file) 145843c2bbd9SChristoph Hellwig { 145943c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 146043c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 146143c2bbd9SChristoph Hellwig 146247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 146343c2bbd9SChristoph Hellwig if (!--i->i_openers) 146443c2bbd9SChristoph Hellwig ctx->mfc = NULL; 146547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 146643c2bbd9SChristoph Hellwig return 0; 146743c2bbd9SChristoph Hellwig } 146843c2bbd9SChristoph Hellwig 1469a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1470a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1471a33a7d73SArnd Bergmann { 1472a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1473a33a7d73SArnd Bergmann 14747d7be3aaSAl Viro if (ctx) 1475a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1476a33a7d73SArnd Bergmann } 1477a33a7d73SArnd Bergmann 1478a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1479a33a7d73SArnd Bergmann { 1480a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1481a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1482a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1483a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1484a33a7d73SArnd Bergmann if (*status) 1485a33a7d73SArnd Bergmann return 1; 1486a33a7d73SArnd Bergmann 1487a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1488a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1489a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1490a33a7d73SArnd Bergmann return 0; 1491a33a7d73SArnd Bergmann } 1492a33a7d73SArnd Bergmann 1493a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1494a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1495a33a7d73SArnd Bergmann { 1496a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1497a33a7d73SArnd Bergmann int ret = -EINVAL; 1498a33a7d73SArnd Bergmann u32 status; 1499a33a7d73SArnd Bergmann 1500a33a7d73SArnd Bergmann if (size != 4) 1501a33a7d73SArnd Bergmann goto out; 1502a33a7d73SArnd Bergmann 1503c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1504c9101bdbSChristoph Hellwig if (ret) 1505c9101bdbSChristoph Hellwig return ret; 1506c9101bdbSChristoph Hellwig 1507c9101bdbSChristoph Hellwig ret = -EINVAL; 1508a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1509a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1510a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1511a33a7d73SArnd Bergmann ret = -EAGAIN; 1512a33a7d73SArnd Bergmann else 1513c9101bdbSChristoph Hellwig /* XXX(hch): shouldn't we clear ret here? */ 1514a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1515a33a7d73SArnd Bergmann } else { 1516a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1517a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1518a33a7d73SArnd Bergmann if (ret) 1519a33a7d73SArnd Bergmann goto out; 1520eebead5bSChristoph Hellwig } 1521eebead5bSChristoph Hellwig spu_release(ctx); 1522a33a7d73SArnd Bergmann 1523a33a7d73SArnd Bergmann ret = 4; 1524a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1525a33a7d73SArnd Bergmann ret = -EFAULT; 1526a33a7d73SArnd Bergmann 1527a33a7d73SArnd Bergmann out: 1528a33a7d73SArnd Bergmann return ret; 1529a33a7d73SArnd Bergmann } 1530a33a7d73SArnd Bergmann 1531a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1532a33a7d73SArnd Bergmann { 15339477e455SStephen Rothwell pr_debug("queueing DMA %x %llx %x %x %x\n", cmd->lsa, 1534a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1535a33a7d73SArnd Bergmann 1536a33a7d73SArnd Bergmann switch (cmd->cmd) { 1537a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1538a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1539a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1540a33a7d73SArnd Bergmann case MFC_GET_CMD: 1541a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1542a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1543a33a7d73SArnd Bergmann break; 1544a33a7d73SArnd Bergmann default: 1545a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1546a33a7d73SArnd Bergmann return -EIO; 1547a33a7d73SArnd Bergmann } 1548a33a7d73SArnd Bergmann 1549a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 15509477e455SStephen Rothwell pr_debug("invalid DMA alignment, ea %llx lsa %x\n", 1551a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1552a33a7d73SArnd Bergmann return -EIO; 1553a33a7d73SArnd Bergmann } 1554a33a7d73SArnd Bergmann 1555a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1556a33a7d73SArnd Bergmann case 1: 1557a33a7d73SArnd Bergmann break; 1558a33a7d73SArnd Bergmann case 2: 1559a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1560a33a7d73SArnd Bergmann goto error; 1561a33a7d73SArnd Bergmann break; 1562a33a7d73SArnd Bergmann case 4: 1563a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1564a33a7d73SArnd Bergmann goto error; 1565a33a7d73SArnd Bergmann break; 1566a33a7d73SArnd Bergmann case 8: 1567a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1568a33a7d73SArnd Bergmann goto error; 1569a33a7d73SArnd Bergmann break; 1570a33a7d73SArnd Bergmann case 0: 1571a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1572a33a7d73SArnd Bergmann goto error; 1573a33a7d73SArnd Bergmann break; 1574a33a7d73SArnd Bergmann error: 1575a33a7d73SArnd Bergmann default: 1576a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1577a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1578a33a7d73SArnd Bergmann return -EIO; 1579a33a7d73SArnd Bergmann } 1580a33a7d73SArnd Bergmann 1581a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1582a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1583a33a7d73SArnd Bergmann return -EIO; 1584a33a7d73SArnd Bergmann } 1585a33a7d73SArnd Bergmann 1586a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1587a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1588a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1589a33a7d73SArnd Bergmann return -EIO; 1590a33a7d73SArnd Bergmann } 1591a33a7d73SArnd Bergmann 1592a33a7d73SArnd Bergmann if (cmd->class) { 1593a33a7d73SArnd Bergmann /* not supported in this version */ 1594a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1595a33a7d73SArnd Bergmann return -EIO; 1596a33a7d73SArnd Bergmann } 1597a33a7d73SArnd Bergmann 1598a33a7d73SArnd Bergmann return 0; 1599a33a7d73SArnd Bergmann } 1600a33a7d73SArnd Bergmann 1601a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1602a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1603a33a7d73SArnd Bergmann int *error) 1604a33a7d73SArnd Bergmann { 1605a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1606a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1607a33a7d73SArnd Bergmann /* wait for any tag group to complete 1608a33a7d73SArnd Bergmann so we have space for the new command */ 1609a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1610a33a7d73SArnd Bergmann /* try again, because the queue might be 1611a33a7d73SArnd Bergmann empty again */ 1612a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1613a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1614a33a7d73SArnd Bergmann return 0; 1615a33a7d73SArnd Bergmann } 1616a33a7d73SArnd Bergmann return 1; 1617a33a7d73SArnd Bergmann } 1618a33a7d73SArnd Bergmann 1619a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1620a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1621a33a7d73SArnd Bergmann { 1622a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1623a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1624a33a7d73SArnd Bergmann int ret = -EINVAL; 1625a33a7d73SArnd Bergmann 1626a33a7d73SArnd Bergmann if (size != sizeof cmd) 1627a33a7d73SArnd Bergmann goto out; 1628a33a7d73SArnd Bergmann 1629a33a7d73SArnd Bergmann ret = -EFAULT; 1630a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1631a33a7d73SArnd Bergmann goto out; 1632a33a7d73SArnd Bergmann 1633a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1634a33a7d73SArnd Bergmann if (ret) 1635a33a7d73SArnd Bergmann goto out; 1636a33a7d73SArnd Bergmann 1637c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1638c9101bdbSChristoph Hellwig if (ret) 1639c9101bdbSChristoph Hellwig goto out; 1640c9101bdbSChristoph Hellwig 164133bfd7a7SArnd Bergmann ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 1642577f8f10SAkinobu Mita if (ret) 1643577f8f10SAkinobu Mita goto out; 1644577f8f10SAkinobu Mita 1645a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1646a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1647a33a7d73SArnd Bergmann } else { 1648a33a7d73SArnd Bergmann int status; 1649a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1650a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1651eebead5bSChristoph Hellwig if (ret) 1652eebead5bSChristoph Hellwig goto out; 1653a33a7d73SArnd Bergmann if (status) 1654a33a7d73SArnd Bergmann ret = status; 1655a33a7d73SArnd Bergmann } 1656a33a7d73SArnd Bergmann 1657a33a7d73SArnd Bergmann if (ret) 1658933b0e35SKazunori Asayama goto out_unlock; 1659a33a7d73SArnd Bergmann 1660a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 16613692dc66SMasato Noguchi ret = size; 1662a33a7d73SArnd Bergmann 1663933b0e35SKazunori Asayama out_unlock: 1664933b0e35SKazunori Asayama spu_release(ctx); 1665a33a7d73SArnd Bergmann out: 1666a33a7d73SArnd Bergmann return ret; 1667a33a7d73SArnd Bergmann } 1668a33a7d73SArnd Bergmann 16698153a5eaSAl Viro static __poll_t spufs_mfc_poll(struct file *file,poll_table *wait) 1670a33a7d73SArnd Bergmann { 1671a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1672a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 16738153a5eaSAl Viro __poll_t mask; 1674a33a7d73SArnd Bergmann 1675933b0e35SKazunori Asayama poll_wait(file, &ctx->mfc_wq, wait); 1676933b0e35SKazunori Asayama 1677c9101bdbSChristoph Hellwig /* 1678c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 1679c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 1680c9101bdbSChristoph Hellwig */ 1681c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 1682a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1683a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1684a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1685a33a7d73SArnd Bergmann spu_release(ctx); 1686a33a7d73SArnd Bergmann 1687a33a7d73SArnd Bergmann mask = 0; 1688a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1689a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 1690a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1691a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 1692a33a7d73SArnd Bergmann 1693e48b1b45SHarvey Harrison pr_debug("%s: free %d tagstatus %d tagwait %d\n", __func__, 1694a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1695a33a7d73SArnd Bergmann 1696a33a7d73SArnd Bergmann return mask; 1697a33a7d73SArnd Bergmann } 1698a33a7d73SArnd Bergmann 169973b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1700a33a7d73SArnd Bergmann { 1701a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1702a33a7d73SArnd Bergmann int ret; 1703a33a7d73SArnd Bergmann 1704c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1705c9101bdbSChristoph Hellwig if (ret) 1706eebead5bSChristoph Hellwig goto out; 1707a33a7d73SArnd Bergmann #if 0 1708a33a7d73SArnd Bergmann /* this currently hangs */ 1709a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1710a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); 1711a33a7d73SArnd Bergmann if (ret) 1712a33a7d73SArnd Bergmann goto out; 1713a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1714a33a7d73SArnd Bergmann ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); 1715eebead5bSChristoph Hellwig if (ret) 1716eebead5bSChristoph Hellwig goto out; 1717a33a7d73SArnd Bergmann #else 1718a33a7d73SArnd Bergmann ret = 0; 1719a33a7d73SArnd Bergmann #endif 1720a33a7d73SArnd Bergmann spu_release(ctx); 1721eebead5bSChristoph Hellwig out: 1722a33a7d73SArnd Bergmann return ret; 1723a33a7d73SArnd Bergmann } 1724a33a7d73SArnd Bergmann 172502c24a82SJosef Bacik static int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync) 1726a33a7d73SArnd Bergmann { 1727496ad9aaSAl Viro struct inode *inode = file_inode(file); 17283b49c9a1SJeff Layton int err = file_write_and_wait_range(file, start, end); 172902c24a82SJosef Bacik if (!err) { 17305955102cSAl Viro inode_lock(inode); 173102c24a82SJosef Bacik err = spufs_mfc_flush(file, NULL); 17325955102cSAl Viro inode_unlock(inode); 173302c24a82SJosef Bacik } 173402c24a82SJosef Bacik return err; 1735a33a7d73SArnd Bergmann } 1736a33a7d73SArnd Bergmann 17375dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = { 1738a33a7d73SArnd Bergmann .open = spufs_mfc_open, 173943c2bbd9SChristoph Hellwig .release = spufs_mfc_release, 1740a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1741a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1742a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1743a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1744a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 17456df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1746fc15351dSArnd Bergmann .llseek = no_llseek, 1747a33a7d73SArnd Bergmann }; 1748a33a7d73SArnd Bergmann 1749197b1a82SChristoph Hellwig static int spufs_npc_set(void *data, u64 val) 175067207b96SArnd Bergmann { 175167207b96SArnd Bergmann struct spu_context *ctx = data; 1752c9101bdbSChristoph Hellwig int ret; 1753c9101bdbSChristoph Hellwig 1754c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1755c9101bdbSChristoph Hellwig if (ret) 1756c9101bdbSChristoph Hellwig return ret; 17578b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 17588b3d6663SArnd Bergmann spu_release(ctx); 1759197b1a82SChristoph Hellwig 1760197b1a82SChristoph Hellwig return 0; 176167207b96SArnd Bergmann } 176267207b96SArnd Bergmann 1763104f0cc2SMichael Ellerman static u64 spufs_npc_get(struct spu_context *ctx) 176478810ff6SMichael Ellerman { 176578810ff6SMichael Ellerman return ctx->ops->npc_read(ctx); 176678810ff6SMichael Ellerman } 1767104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 1768104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE); 176967207b96SArnd Bergmann 1770197b1a82SChristoph Hellwig static int spufs_decr_set(void *data, u64 val) 17718b3d6663SArnd Bergmann { 17728b3d6663SArnd Bergmann struct spu_context *ctx = data; 17738b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1774c9101bdbSChristoph Hellwig int ret; 1775c9101bdbSChristoph Hellwig 1776c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1777c9101bdbSChristoph Hellwig if (ret) 1778c9101bdbSChristoph Hellwig return ret; 17798b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 178027b1ea09SChristoph Hellwig spu_release_saved(ctx); 1781197b1a82SChristoph Hellwig 1782197b1a82SChristoph Hellwig return 0; 17838b3d6663SArnd Bergmann } 17848b3d6663SArnd Bergmann 1785104f0cc2SMichael Ellerman static u64 spufs_decr_get(struct spu_context *ctx) 17868b3d6663SArnd Bergmann { 17878b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1788bf1ab978SDwayne Grant McConnell return lscsa->decr.slot[0]; 1789bf1ab978SDwayne Grant McConnell } 1790104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 1791104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); 17928b3d6663SArnd Bergmann 1793197b1a82SChristoph Hellwig static int spufs_decr_status_set(void *data, u64 val) 17948b3d6663SArnd Bergmann { 17958b3d6663SArnd Bergmann struct spu_context *ctx = data; 1796c9101bdbSChristoph Hellwig int ret; 1797c9101bdbSChristoph Hellwig 1798c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1799c9101bdbSChristoph Hellwig if (ret) 1800c9101bdbSChristoph Hellwig return ret; 1801d40a01d4SMasato Noguchi if (val) 1802d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 1803d40a01d4SMasato Noguchi else 1804d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 180527b1ea09SChristoph Hellwig spu_release_saved(ctx); 1806197b1a82SChristoph Hellwig 1807197b1a82SChristoph Hellwig return 0; 18088b3d6663SArnd Bergmann } 18098b3d6663SArnd Bergmann 1810104f0cc2SMichael Ellerman static u64 spufs_decr_status_get(struct spu_context *ctx) 18118b3d6663SArnd Bergmann { 1812d40a01d4SMasato Noguchi if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 1813d40a01d4SMasato Noguchi return SPU_DECR_STATUS_RUNNING; 1814d40a01d4SMasato Noguchi else 1815d40a01d4SMasato Noguchi return 0; 1816bf1ab978SDwayne Grant McConnell } 1817104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 1818104f0cc2SMichael Ellerman spufs_decr_status_set, "0x%llx\n", 1819104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 18208b3d6663SArnd Bergmann 1821197b1a82SChristoph Hellwig static int spufs_event_mask_set(void *data, u64 val) 18228b3d6663SArnd Bergmann { 18238b3d6663SArnd Bergmann struct spu_context *ctx = data; 18248b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1825c9101bdbSChristoph Hellwig int ret; 1826c9101bdbSChristoph Hellwig 1827c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1828c9101bdbSChristoph Hellwig if (ret) 1829c9101bdbSChristoph Hellwig return ret; 18308b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 183127b1ea09SChristoph Hellwig spu_release_saved(ctx); 1832197b1a82SChristoph Hellwig 1833197b1a82SChristoph Hellwig return 0; 18348b3d6663SArnd Bergmann } 18358b3d6663SArnd Bergmann 1836104f0cc2SMichael Ellerman static u64 spufs_event_mask_get(struct spu_context *ctx) 18378b3d6663SArnd Bergmann { 18388b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1839bf1ab978SDwayne Grant McConnell return lscsa->event_mask.slot[0]; 1840bf1ab978SDwayne Grant McConnell } 1841bf1ab978SDwayne Grant McConnell 1842104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 1843104f0cc2SMichael Ellerman spufs_event_mask_set, "0x%llx\n", 1844104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 18458b3d6663SArnd Bergmann 1846104f0cc2SMichael Ellerman static u64 spufs_event_status_get(struct spu_context *ctx) 1847b9e3bd77SDwayne Grant McConnell { 1848b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1849b9e3bd77SDwayne Grant McConnell u64 stat; 1850b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1851b9e3bd77SDwayne Grant McConnell if (stat) 1852bf1ab978SDwayne Grant McConnell return state->spu_chnldata_RW[0]; 1853bf1ab978SDwayne Grant McConnell return 0; 1854bf1ab978SDwayne Grant McConnell } 1855104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1856104f0cc2SMichael Ellerman NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 1857b9e3bd77SDwayne Grant McConnell 1858197b1a82SChristoph Hellwig static int spufs_srr0_set(void *data, u64 val) 18598b3d6663SArnd Bergmann { 18608b3d6663SArnd Bergmann struct spu_context *ctx = data; 18618b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1862c9101bdbSChristoph Hellwig int ret; 1863c9101bdbSChristoph Hellwig 1864c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1865c9101bdbSChristoph Hellwig if (ret) 1866c9101bdbSChristoph Hellwig return ret; 18678b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 186827b1ea09SChristoph Hellwig spu_release_saved(ctx); 1869197b1a82SChristoph Hellwig 1870197b1a82SChristoph Hellwig return 0; 18718b3d6663SArnd Bergmann } 18728b3d6663SArnd Bergmann 1873104f0cc2SMichael Ellerman static u64 spufs_srr0_get(struct spu_context *ctx) 18748b3d6663SArnd Bergmann { 18758b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1876104f0cc2SMichael Ellerman return lscsa->srr0.slot[0]; 18778b3d6663SArnd Bergmann } 1878104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 1879104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 18808b3d6663SArnd Bergmann 1881104f0cc2SMichael Ellerman static u64 spufs_id_get(struct spu_context *ctx) 18827b1a7014Sarnd@arndb.de { 18837b1a7014Sarnd@arndb.de u64 num; 18847b1a7014Sarnd@arndb.de 18857b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 18867b1a7014Sarnd@arndb.de num = ctx->spu->number; 18877b1a7014Sarnd@arndb.de else 18887b1a7014Sarnd@arndb.de num = (unsigned int)-1; 18897b1a7014Sarnd@arndb.de 18907b1a7014Sarnd@arndb.de return num; 18917b1a7014Sarnd@arndb.de } 1892104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", 1893104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE) 18947b1a7014Sarnd@arndb.de 1895104f0cc2SMichael Ellerman static u64 spufs_object_id_get(struct spu_context *ctx) 1896bf1ab978SDwayne Grant McConnell { 1897bf1ab978SDwayne Grant McConnell /* FIXME: Should there really be no locking here? */ 1898104f0cc2SMichael Ellerman return ctx->object_id; 1899bf1ab978SDwayne Grant McConnell } 1900bf1ab978SDwayne Grant McConnell 1901197b1a82SChristoph Hellwig static int spufs_object_id_set(void *data, u64 id) 190286767277SArnd Bergmann { 190386767277SArnd Bergmann struct spu_context *ctx = data; 190486767277SArnd Bergmann ctx->object_id = id; 1905197b1a82SChristoph Hellwig 1906197b1a82SChristoph Hellwig return 0; 190786767277SArnd Bergmann } 190886767277SArnd Bergmann 1909104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 1910104f0cc2SMichael Ellerman spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); 191186767277SArnd Bergmann 1912104f0cc2SMichael Ellerman static u64 spufs_lslr_get(struct spu_context *ctx) 1913bf1ab978SDwayne Grant McConnell { 1914bf1ab978SDwayne Grant McConnell return ctx->csa.priv2.spu_lslr_RW; 1915bf1ab978SDwayne Grant McConnell } 1916104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", 1917104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 1918b9e3bd77SDwayne Grant McConnell 1919b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 1920b9e3bd77SDwayne Grant McConnell { 1921b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 1922b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 1923b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 1924b9e3bd77SDwayne Grant McConnell return 0; 1925b9e3bd77SDwayne Grant McConnell } 1926b9e3bd77SDwayne Grant McConnell 1927cbe709c1SBenjamin Herrenschmidt static int spufs_caps_show(struct seq_file *s, void *private) 1928cbe709c1SBenjamin Herrenschmidt { 1929cbe709c1SBenjamin Herrenschmidt struct spu_context *ctx = s->private; 1930cbe709c1SBenjamin Herrenschmidt 1931cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_NOSCHED)) 1932cbe709c1SBenjamin Herrenschmidt seq_puts(s, "sched\n"); 1933cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_ISOLATE)) 1934cbe709c1SBenjamin Herrenschmidt seq_puts(s, "step\n"); 1935cbe709c1SBenjamin Herrenschmidt return 0; 1936cbe709c1SBenjamin Herrenschmidt } 1937cbe709c1SBenjamin Herrenschmidt 1938cbe709c1SBenjamin Herrenschmidt static int spufs_caps_open(struct inode *inode, struct file *file) 1939cbe709c1SBenjamin Herrenschmidt { 1940cbe709c1SBenjamin Herrenschmidt return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); 1941cbe709c1SBenjamin Herrenschmidt } 1942cbe709c1SBenjamin Herrenschmidt 1943cbe709c1SBenjamin Herrenschmidt static const struct file_operations spufs_caps_fops = { 1944cbe709c1SBenjamin Herrenschmidt .open = spufs_caps_open, 1945cbe709c1SBenjamin Herrenschmidt .read = seq_read, 1946cbe709c1SBenjamin Herrenschmidt .llseek = seq_lseek, 1947cbe709c1SBenjamin Herrenschmidt .release = single_release, 1948cbe709c1SBenjamin Herrenschmidt }; 1949cbe709c1SBenjamin Herrenschmidt 1950bf1ab978SDwayne Grant McConnell static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, 1951bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 1952bf1ab978SDwayne Grant McConnell { 1953bf1ab978SDwayne Grant McConnell u32 data; 1954bf1ab978SDwayne Grant McConnell 1955cbea9238SJeremy Kerr /* EOF if there's no entry in the mbox */ 1956cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0x0000ff)) 1957cbea9238SJeremy Kerr return 0; 1958cbea9238SJeremy Kerr 1959bf1ab978SDwayne Grant McConnell data = ctx->csa.prob.pu_mb_R; 1960bf1ab978SDwayne Grant McConnell 1961bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 1962bf1ab978SDwayne Grant McConnell } 1963bf1ab978SDwayne Grant McConnell 196469a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 196569a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 196669a2f00cSDwayne Grant McConnell { 196769a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 196888413a6bSJeremy Kerr u32 stat, data; 196988413a6bSJeremy Kerr int ret; 197069a2f00cSDwayne Grant McConnell 1971c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1972c9101bdbSChristoph Hellwig if (ret) 1973c9101bdbSChristoph Hellwig return ret; 197469a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 197588413a6bSJeremy Kerr stat = ctx->csa.prob.mb_stat_R; 197688413a6bSJeremy Kerr data = ctx->csa.prob.pu_mb_R; 197769a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 197827b1ea09SChristoph Hellwig spu_release_saved(ctx); 197969a2f00cSDwayne Grant McConnell 198088413a6bSJeremy Kerr /* EOF if there's no entry in the mbox */ 198188413a6bSJeremy Kerr if (!(stat & 0x0000ff)) 198288413a6bSJeremy Kerr return 0; 198388413a6bSJeremy Kerr 198488413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &data, sizeof(data)); 198569a2f00cSDwayne Grant McConnell } 198669a2f00cSDwayne Grant McConnell 19875dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = { 198869a2f00cSDwayne Grant McConnell .open = spufs_info_open, 198969a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 199069a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 199169a2f00cSDwayne Grant McConnell }; 199269a2f00cSDwayne Grant McConnell 1993bf1ab978SDwayne Grant McConnell static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, 1994bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 1995bf1ab978SDwayne Grant McConnell { 1996bf1ab978SDwayne Grant McConnell u32 data; 1997bf1ab978SDwayne Grant McConnell 1998cbea9238SJeremy Kerr /* EOF if there's no entry in the ibox */ 1999cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) 2000cbea9238SJeremy Kerr return 0; 2001cbea9238SJeremy Kerr 2002bf1ab978SDwayne Grant McConnell data = ctx->csa.priv2.puint_mb_R; 2003bf1ab978SDwayne Grant McConnell 2004bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, sizeof data); 2005bf1ab978SDwayne Grant McConnell } 2006bf1ab978SDwayne Grant McConnell 200769a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 200869a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 200969a2f00cSDwayne Grant McConnell { 201069a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 201188413a6bSJeremy Kerr u32 stat, data; 2012bf1ab978SDwayne Grant McConnell int ret; 201369a2f00cSDwayne Grant McConnell 2014c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2015c9101bdbSChristoph Hellwig if (ret) 2016c9101bdbSChristoph Hellwig return ret; 201769a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 201888413a6bSJeremy Kerr stat = ctx->csa.prob.mb_stat_R; 201988413a6bSJeremy Kerr data = ctx->csa.priv2.puint_mb_R; 202069a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 202127b1ea09SChristoph Hellwig spu_release_saved(ctx); 202269a2f00cSDwayne Grant McConnell 202388413a6bSJeremy Kerr /* EOF if there's no entry in the ibox */ 202488413a6bSJeremy Kerr if (!(stat & 0xff0000)) 202588413a6bSJeremy Kerr return 0; 202688413a6bSJeremy Kerr 202788413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &data, sizeof(data)); 202869a2f00cSDwayne Grant McConnell } 202969a2f00cSDwayne Grant McConnell 20305dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = { 203169a2f00cSDwayne Grant McConnell .open = spufs_info_open, 203269a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 203369a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 203469a2f00cSDwayne Grant McConnell }; 203569a2f00cSDwayne Grant McConnell 203688413a6bSJeremy Kerr static size_t spufs_wbox_info_cnt(struct spu_context *ctx) 203788413a6bSJeremy Kerr { 203888413a6bSJeremy Kerr return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32); 203988413a6bSJeremy Kerr } 204088413a6bSJeremy Kerr 2041bf1ab978SDwayne Grant McConnell static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, 2042bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2043bf1ab978SDwayne Grant McConnell { 2044bf1ab978SDwayne Grant McConnell int i, cnt; 2045bf1ab978SDwayne Grant McConnell u32 data[4]; 2046bf1ab978SDwayne Grant McConnell u32 wbox_stat; 2047bf1ab978SDwayne Grant McConnell 2048bf1ab978SDwayne Grant McConnell wbox_stat = ctx->csa.prob.mb_stat_R; 204988413a6bSJeremy Kerr cnt = spufs_wbox_info_cnt(ctx); 2050bf1ab978SDwayne Grant McConnell for (i = 0; i < cnt; i++) { 2051bf1ab978SDwayne Grant McConnell data[i] = ctx->csa.spu_mailbox_data[i]; 2052bf1ab978SDwayne Grant McConnell } 2053bf1ab978SDwayne Grant McConnell 2054bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &data, 2055bf1ab978SDwayne Grant McConnell cnt * sizeof(u32)); 2056bf1ab978SDwayne Grant McConnell } 2057bf1ab978SDwayne Grant McConnell 205869a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 205969a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 206069a2f00cSDwayne Grant McConnell { 206169a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 206288413a6bSJeremy Kerr u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)]; 206388413a6bSJeremy Kerr int ret, count; 206469a2f00cSDwayne Grant McConnell 2065c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2066c9101bdbSChristoph Hellwig if (ret) 2067c9101bdbSChristoph Hellwig return ret; 206869a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 206988413a6bSJeremy Kerr count = spufs_wbox_info_cnt(ctx); 207088413a6bSJeremy Kerr memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data)); 207169a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 207227b1ea09SChristoph Hellwig spu_release_saved(ctx); 207369a2f00cSDwayne Grant McConnell 207488413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &data, 207588413a6bSJeremy Kerr count * sizeof(u32)); 207669a2f00cSDwayne Grant McConnell } 207769a2f00cSDwayne Grant McConnell 20785dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = { 207969a2f00cSDwayne Grant McConnell .open = spufs_info_open, 208069a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 208169a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 208269a2f00cSDwayne Grant McConnell }; 208369a2f00cSDwayne Grant McConnell 208488413a6bSJeremy Kerr static void spufs_get_dma_info(struct spu_context *ctx, 208588413a6bSJeremy Kerr struct spu_dma_info *info) 2086b9e3bd77SDwayne Grant McConnell { 2087b9e3bd77SDwayne Grant McConnell int i; 2088b9e3bd77SDwayne Grant McConnell 208988413a6bSJeremy Kerr info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 209088413a6bSJeremy Kerr info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 209188413a6bSJeremy Kerr info->dma_info_status = ctx->csa.spu_chnldata_RW[24]; 209288413a6bSJeremy Kerr info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 209388413a6bSJeremy Kerr info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 2094b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 209588413a6bSJeremy Kerr struct mfc_cq_sr *qp = &info->dma_info_command_data[i]; 209688413a6bSJeremy Kerr struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i]; 2097b9e3bd77SDwayne Grant McConnell 2098b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 2099b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 2100b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 2101b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 2102b9e3bd77SDwayne Grant McConnell } 210388413a6bSJeremy Kerr } 210488413a6bSJeremy Kerr 210588413a6bSJeremy Kerr static ssize_t __spufs_dma_info_read(struct spu_context *ctx, 210688413a6bSJeremy Kerr char __user *buf, size_t len, loff_t *pos) 210788413a6bSJeremy Kerr { 210888413a6bSJeremy Kerr struct spu_dma_info info; 210988413a6bSJeremy Kerr 211088413a6bSJeremy Kerr spufs_get_dma_info(ctx, &info); 2111b9e3bd77SDwayne Grant McConnell 2112b9e3bd77SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2113b9e3bd77SDwayne Grant McConnell sizeof info); 2114b9e3bd77SDwayne Grant McConnell } 2115b9e3bd77SDwayne Grant McConnell 2116bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 2117bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2118bf1ab978SDwayne Grant McConnell { 2119bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 212088413a6bSJeremy Kerr struct spu_dma_info info; 2121bf1ab978SDwayne Grant McConnell int ret; 2122bf1ab978SDwayne Grant McConnell 2123c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2124c9101bdbSChristoph Hellwig if (ret) 2125c9101bdbSChristoph Hellwig return ret; 2126bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 212788413a6bSJeremy Kerr spufs_get_dma_info(ctx, &info); 2128bf1ab978SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 212927b1ea09SChristoph Hellwig spu_release_saved(ctx); 2130bf1ab978SDwayne Grant McConnell 213188413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &info, 213288413a6bSJeremy Kerr sizeof(info)); 2133bf1ab978SDwayne Grant McConnell } 2134bf1ab978SDwayne Grant McConnell 21355dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = { 2136b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2137b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 2138fc15351dSArnd Bergmann .llseek = no_llseek, 2139b9e3bd77SDwayne Grant McConnell }; 2140b9e3bd77SDwayne Grant McConnell 214188413a6bSJeremy Kerr static void spufs_get_proxydma_info(struct spu_context *ctx, 214288413a6bSJeremy Kerr struct spu_proxydma_info *info) 214388413a6bSJeremy Kerr { 214488413a6bSJeremy Kerr int i; 214588413a6bSJeremy Kerr 214688413a6bSJeremy Kerr info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 214788413a6bSJeremy Kerr info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 214888413a6bSJeremy Kerr info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 214988413a6bSJeremy Kerr 215088413a6bSJeremy Kerr for (i = 0; i < 8; i++) { 215188413a6bSJeremy Kerr struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i]; 215288413a6bSJeremy Kerr struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i]; 215388413a6bSJeremy Kerr 215488413a6bSJeremy Kerr qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 215588413a6bSJeremy Kerr qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 215688413a6bSJeremy Kerr qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 215788413a6bSJeremy Kerr qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 215888413a6bSJeremy Kerr } 215988413a6bSJeremy Kerr } 216088413a6bSJeremy Kerr 2161bf1ab978SDwayne Grant McConnell static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, 2162bf1ab978SDwayne Grant McConnell char __user *buf, size_t len, loff_t *pos) 2163b9e3bd77SDwayne Grant McConnell { 2164b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 2165bf1ab978SDwayne Grant McConnell int ret = sizeof info; 2166b9e3bd77SDwayne Grant McConnell 2167b9e3bd77SDwayne Grant McConnell if (len < ret) 2168b9e3bd77SDwayne Grant McConnell return -EINVAL; 2169b9e3bd77SDwayne Grant McConnell 217096d4f267SLinus Torvalds if (!access_ok(buf, len)) 2171b9e3bd77SDwayne Grant McConnell return -EFAULT; 2172b9e3bd77SDwayne Grant McConnell 217388413a6bSJeremy Kerr spufs_get_proxydma_info(ctx, &info); 2174bf1ab978SDwayne Grant McConnell 2175bf1ab978SDwayne Grant McConnell return simple_read_from_buffer(buf, len, pos, &info, 2176bf1ab978SDwayne Grant McConnell sizeof info); 2177bf1ab978SDwayne Grant McConnell } 2178bf1ab978SDwayne Grant McConnell 2179bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 2180bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2181bf1ab978SDwayne Grant McConnell { 2182bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 218388413a6bSJeremy Kerr struct spu_proxydma_info info; 2184bf1ab978SDwayne Grant McConnell int ret; 2185bf1ab978SDwayne Grant McConnell 2186c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2187c9101bdbSChristoph Hellwig if (ret) 2188c9101bdbSChristoph Hellwig return ret; 2189bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 219088413a6bSJeremy Kerr spufs_get_proxydma_info(ctx, &info); 2191b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 219227b1ea09SChristoph Hellwig spu_release_saved(ctx); 2193b9e3bd77SDwayne Grant McConnell 219488413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &info, 219588413a6bSJeremy Kerr sizeof(info)); 2196b9e3bd77SDwayne Grant McConnell } 2197b9e3bd77SDwayne Grant McConnell 21985dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = { 2199b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2200b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 2201fc15351dSArnd Bergmann .llseek = no_llseek, 2202b9e3bd77SDwayne Grant McConnell }; 2203b9e3bd77SDwayne Grant McConnell 2204476273adSChristoph Hellwig static int spufs_show_tid(struct seq_file *s, void *private) 2205476273adSChristoph Hellwig { 2206476273adSChristoph Hellwig struct spu_context *ctx = s->private; 2207476273adSChristoph Hellwig 2208476273adSChristoph Hellwig seq_printf(s, "%d\n", ctx->tid); 2209476273adSChristoph Hellwig return 0; 2210476273adSChristoph Hellwig } 2211476273adSChristoph Hellwig 2212476273adSChristoph Hellwig static int spufs_tid_open(struct inode *inode, struct file *file) 2213476273adSChristoph Hellwig { 2214476273adSChristoph Hellwig return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); 2215476273adSChristoph Hellwig } 2216476273adSChristoph Hellwig 2217476273adSChristoph Hellwig static const struct file_operations spufs_tid_fops = { 2218476273adSChristoph Hellwig .open = spufs_tid_open, 2219476273adSChristoph Hellwig .read = seq_read, 2220476273adSChristoph Hellwig .llseek = seq_lseek, 2221476273adSChristoph Hellwig .release = single_release, 2222476273adSChristoph Hellwig }; 2223476273adSChristoph Hellwig 2224e9f8a0b6SChristoph Hellwig static const char *ctx_state_names[] = { 2225e9f8a0b6SChristoph Hellwig "user", "system", "iowait", "loaded" 2226e9f8a0b6SChristoph Hellwig }; 2227e9f8a0b6SChristoph Hellwig 2228e9f8a0b6SChristoph Hellwig static unsigned long long spufs_acct_time(struct spu_context *ctx, 222927ec41d3SAndre Detsch enum spu_utilization_state state) 2230e9f8a0b6SChristoph Hellwig { 223127ec41d3SAndre Detsch unsigned long long time = ctx->stats.times[state]; 2232e9f8a0b6SChristoph Hellwig 223327ec41d3SAndre Detsch /* 223427ec41d3SAndre Detsch * In general, utilization statistics are updated by the controlling 223527ec41d3SAndre Detsch * thread as the spu context moves through various well defined 223627ec41d3SAndre Detsch * state transitions, but if the context is lazily loaded its 223727ec41d3SAndre Detsch * utilization statistics are not updated as the controlling thread 223827ec41d3SAndre Detsch * is not tightly coupled with the execution of the spu context. We 223927ec41d3SAndre Detsch * calculate and apply the time delta from the last recorded state 224027ec41d3SAndre Detsch * of the spu context. 224127ec41d3SAndre Detsch */ 224227ec41d3SAndre Detsch if (ctx->spu && ctx->stats.util_state == state) { 2243f2dec1eaSThomas Gleixner time += ktime_get_ns() - ctx->stats.tstamp; 224427ec41d3SAndre Detsch } 2245e9f8a0b6SChristoph Hellwig 224627ec41d3SAndre Detsch return time / NSEC_PER_MSEC; 2247e9f8a0b6SChristoph Hellwig } 2248e9f8a0b6SChristoph Hellwig 2249e9f8a0b6SChristoph Hellwig static unsigned long long spufs_slb_flts(struct spu_context *ctx) 2250e9f8a0b6SChristoph Hellwig { 2251e9f8a0b6SChristoph Hellwig unsigned long long slb_flts = ctx->stats.slb_flt; 2252e9f8a0b6SChristoph Hellwig 2253e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2254e9f8a0b6SChristoph Hellwig slb_flts += (ctx->spu->stats.slb_flt - 2255e9f8a0b6SChristoph Hellwig ctx->stats.slb_flt_base); 2256e9f8a0b6SChristoph Hellwig } 2257e9f8a0b6SChristoph Hellwig 2258e9f8a0b6SChristoph Hellwig return slb_flts; 2259e9f8a0b6SChristoph Hellwig } 2260e9f8a0b6SChristoph Hellwig 2261e9f8a0b6SChristoph Hellwig static unsigned long long spufs_class2_intrs(struct spu_context *ctx) 2262e9f8a0b6SChristoph Hellwig { 2263e9f8a0b6SChristoph Hellwig unsigned long long class2_intrs = ctx->stats.class2_intr; 2264e9f8a0b6SChristoph Hellwig 2265e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2266e9f8a0b6SChristoph Hellwig class2_intrs += (ctx->spu->stats.class2_intr - 2267e9f8a0b6SChristoph Hellwig ctx->stats.class2_intr_base); 2268e9f8a0b6SChristoph Hellwig } 2269e9f8a0b6SChristoph Hellwig 2270e9f8a0b6SChristoph Hellwig return class2_intrs; 2271e9f8a0b6SChristoph Hellwig } 2272e9f8a0b6SChristoph Hellwig 2273e9f8a0b6SChristoph Hellwig 2274e9f8a0b6SChristoph Hellwig static int spufs_show_stat(struct seq_file *s, void *private) 2275e9f8a0b6SChristoph Hellwig { 2276e9f8a0b6SChristoph Hellwig struct spu_context *ctx = s->private; 2277c9101bdbSChristoph Hellwig int ret; 2278e9f8a0b6SChristoph Hellwig 2279c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 2280c9101bdbSChristoph Hellwig if (ret) 2281c9101bdbSChristoph Hellwig return ret; 2282c9101bdbSChristoph Hellwig 2283e9f8a0b6SChristoph Hellwig seq_printf(s, "%s %llu %llu %llu %llu " 2284e9f8a0b6SChristoph Hellwig "%llu %llu %llu %llu %llu %llu %llu %llu\n", 228527ec41d3SAndre Detsch ctx_state_names[ctx->stats.util_state], 228627ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_USER), 228727ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 228827ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 228927ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 2290e9f8a0b6SChristoph Hellwig ctx->stats.vol_ctx_switch, 2291e9f8a0b6SChristoph Hellwig ctx->stats.invol_ctx_switch, 2292e9f8a0b6SChristoph Hellwig spufs_slb_flts(ctx), 2293e9f8a0b6SChristoph Hellwig ctx->stats.hash_flt, 2294e9f8a0b6SChristoph Hellwig ctx->stats.min_flt, 2295e9f8a0b6SChristoph Hellwig ctx->stats.maj_flt, 2296e9f8a0b6SChristoph Hellwig spufs_class2_intrs(ctx), 2297e9f8a0b6SChristoph Hellwig ctx->stats.libassist); 2298e9f8a0b6SChristoph Hellwig spu_release(ctx); 2299e9f8a0b6SChristoph Hellwig return 0; 2300e9f8a0b6SChristoph Hellwig } 2301e9f8a0b6SChristoph Hellwig 2302e9f8a0b6SChristoph Hellwig static int spufs_stat_open(struct inode *inode, struct file *file) 2303e9f8a0b6SChristoph Hellwig { 2304e9f8a0b6SChristoph Hellwig return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); 2305e9f8a0b6SChristoph Hellwig } 2306e9f8a0b6SChristoph Hellwig 2307e9f8a0b6SChristoph Hellwig static const struct file_operations spufs_stat_fops = { 2308e9f8a0b6SChristoph Hellwig .open = spufs_stat_open, 2309e9f8a0b6SChristoph Hellwig .read = seq_read, 2310e9f8a0b6SChristoph Hellwig .llseek = seq_lseek, 2311e9f8a0b6SChristoph Hellwig .release = single_release, 2312e9f8a0b6SChristoph Hellwig }; 2313e9f8a0b6SChristoph Hellwig 23145158e9b5SChristoph Hellwig static inline int spufs_switch_log_used(struct spu_context *ctx) 23155158e9b5SChristoph Hellwig { 23165158e9b5SChristoph Hellwig return (ctx->switch_log->head - ctx->switch_log->tail) % 23175158e9b5SChristoph Hellwig SWITCH_LOG_BUFSIZE; 23185158e9b5SChristoph Hellwig } 23195158e9b5SChristoph Hellwig 23205158e9b5SChristoph Hellwig static inline int spufs_switch_log_avail(struct spu_context *ctx) 23215158e9b5SChristoph Hellwig { 23225158e9b5SChristoph Hellwig return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx); 23235158e9b5SChristoph Hellwig } 23245158e9b5SChristoph Hellwig 23255158e9b5SChristoph Hellwig static int spufs_switch_log_open(struct inode *inode, struct file *file) 23265158e9b5SChristoph Hellwig { 23275158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 2328f5ed0eb6SJeremy Kerr int rc; 23295158e9b5SChristoph Hellwig 2330f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2331f5ed0eb6SJeremy Kerr if (rc) 2332f5ed0eb6SJeremy Kerr return rc; 2333f5ed0eb6SJeremy Kerr 23345158e9b5SChristoph Hellwig if (ctx->switch_log) { 2335f5ed0eb6SJeremy Kerr rc = -EBUSY; 2336f5ed0eb6SJeremy Kerr goto out; 2337f5ed0eb6SJeremy Kerr } 2338f5ed0eb6SJeremy Kerr 233900def713SGustavo A. R. Silva ctx->switch_log = kmalloc(struct_size(ctx->switch_log, log, 234000def713SGustavo A. R. Silva SWITCH_LOG_BUFSIZE), GFP_KERNEL); 2341f5ed0eb6SJeremy Kerr 2342f5ed0eb6SJeremy Kerr if (!ctx->switch_log) { 2343f5ed0eb6SJeremy Kerr rc = -ENOMEM; 23445158e9b5SChristoph Hellwig goto out; 23455158e9b5SChristoph Hellwig } 2346f5ed0eb6SJeremy Kerr 2347837ef884SJeremy Kerr ctx->switch_log->head = ctx->switch_log->tail = 0; 2348f5ed0eb6SJeremy Kerr init_waitqueue_head(&ctx->switch_log->wait); 2349f5ed0eb6SJeremy Kerr rc = 0; 2350f5ed0eb6SJeremy Kerr 2351f5ed0eb6SJeremy Kerr out: 2352f5ed0eb6SJeremy Kerr spu_release(ctx); 2353f5ed0eb6SJeremy Kerr return rc; 2354f5ed0eb6SJeremy Kerr } 2355f5ed0eb6SJeremy Kerr 2356f5ed0eb6SJeremy Kerr static int spufs_switch_log_release(struct inode *inode, struct file *file) 2357f5ed0eb6SJeremy Kerr { 2358f5ed0eb6SJeremy Kerr struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 2359f5ed0eb6SJeremy Kerr int rc; 2360f5ed0eb6SJeremy Kerr 2361f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2362f5ed0eb6SJeremy Kerr if (rc) 2363f5ed0eb6SJeremy Kerr return rc; 2364f5ed0eb6SJeremy Kerr 2365f5ed0eb6SJeremy Kerr kfree(ctx->switch_log); 2366f5ed0eb6SJeremy Kerr ctx->switch_log = NULL; 2367f5ed0eb6SJeremy Kerr spu_release(ctx); 23685158e9b5SChristoph Hellwig 23695158e9b5SChristoph Hellwig return 0; 23705158e9b5SChristoph Hellwig } 23715158e9b5SChristoph Hellwig 23725158e9b5SChristoph Hellwig static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) 23735158e9b5SChristoph Hellwig { 23745158e9b5SChristoph Hellwig struct switch_log_entry *p; 23755158e9b5SChristoph Hellwig 23765158e9b5SChristoph Hellwig p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE; 23775158e9b5SChristoph Hellwig 2378cef37ac1SArnd Bergmann return snprintf(tbuf, n, "%llu.%09u %d %u %u %llu\n", 2379cef37ac1SArnd Bergmann (unsigned long long) p->tstamp.tv_sec, 23805158e9b5SChristoph Hellwig (unsigned int) p->tstamp.tv_nsec, 23815158e9b5SChristoph Hellwig p->spu_id, 23825158e9b5SChristoph Hellwig (unsigned int) p->type, 23835158e9b5SChristoph Hellwig (unsigned int) p->val, 23845158e9b5SChristoph Hellwig (unsigned long long) p->timebase); 23855158e9b5SChristoph Hellwig } 23865158e9b5SChristoph Hellwig 23875158e9b5SChristoph Hellwig static ssize_t spufs_switch_log_read(struct file *file, char __user *buf, 23885158e9b5SChristoph Hellwig size_t len, loff_t *ppos) 23895158e9b5SChristoph Hellwig { 2390496ad9aaSAl Viro struct inode *inode = file_inode(file); 23915158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 23925158e9b5SChristoph Hellwig int error = 0, cnt = 0; 23935158e9b5SChristoph Hellwig 239417e37675Sroel kluin if (!buf) 23955158e9b5SChristoph Hellwig return -EINVAL; 23965158e9b5SChristoph Hellwig 2397f5ed0eb6SJeremy Kerr error = spu_acquire(ctx); 2398f5ed0eb6SJeremy Kerr if (error) 2399f5ed0eb6SJeremy Kerr return error; 2400f5ed0eb6SJeremy Kerr 24015158e9b5SChristoph Hellwig while (cnt < len) { 24025158e9b5SChristoph Hellwig char tbuf[128]; 24035158e9b5SChristoph Hellwig int width; 24045158e9b5SChristoph Hellwig 2405f5ed0eb6SJeremy Kerr if (spufs_switch_log_used(ctx) == 0) { 240614f693eeSJeremy Kerr if (cnt > 0) { 240714f693eeSJeremy Kerr /* If there's data ready to go, we can 240814f693eeSJeremy Kerr * just return straight away */ 240914f693eeSJeremy Kerr break; 241014f693eeSJeremy Kerr 241114f693eeSJeremy Kerr } else if (file->f_flags & O_NONBLOCK) { 2412f5ed0eb6SJeremy Kerr error = -EAGAIN; 24135158e9b5SChristoph Hellwig break; 241414f693eeSJeremy Kerr 2415f5ed0eb6SJeremy Kerr } else { 241614f693eeSJeremy Kerr /* spufs_wait will drop the mutex and 241714f693eeSJeremy Kerr * re-acquire, but since we're in read(), the 241814f693eeSJeremy Kerr * file cannot be _released (and so 241914f693eeSJeremy Kerr * ctx->switch_log is stable). 2420f5ed0eb6SJeremy Kerr */ 2421f5ed0eb6SJeremy Kerr error = spufs_wait(ctx->switch_log->wait, 2422f5ed0eb6SJeremy Kerr spufs_switch_log_used(ctx) > 0); 24235158e9b5SChristoph Hellwig 2424f5ed0eb6SJeremy Kerr /* On error, spufs_wait returns without the 2425f5ed0eb6SJeremy Kerr * state mutex held */ 2426f5ed0eb6SJeremy Kerr if (error) 2427f5ed0eb6SJeremy Kerr return error; 24285158e9b5SChristoph Hellwig 242914f693eeSJeremy Kerr /* We may have had entries read from underneath 243014f693eeSJeremy Kerr * us while we dropped the mutex in spufs_wait, 243114f693eeSJeremy Kerr * so re-check */ 243214f693eeSJeremy Kerr if (spufs_switch_log_used(ctx) == 0) 2433f5ed0eb6SJeremy Kerr continue; 243414f693eeSJeremy Kerr } 243514f693eeSJeremy Kerr } 2436f5ed0eb6SJeremy Kerr 24375158e9b5SChristoph Hellwig width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); 2438f5ed0eb6SJeremy Kerr if (width < len) 24395158e9b5SChristoph Hellwig ctx->switch_log->tail = 24405158e9b5SChristoph Hellwig (ctx->switch_log->tail + 1) % 24415158e9b5SChristoph Hellwig SWITCH_LOG_BUFSIZE; 2442f5ed0eb6SJeremy Kerr else 2443f5ed0eb6SJeremy Kerr /* If the record is greater than space available return 2444f5ed0eb6SJeremy Kerr * partial buffer (so far) */ 24455158e9b5SChristoph Hellwig break; 24465158e9b5SChristoph Hellwig 24475158e9b5SChristoph Hellwig error = copy_to_user(buf + cnt, tbuf, width); 24485158e9b5SChristoph Hellwig if (error) 24495158e9b5SChristoph Hellwig break; 24505158e9b5SChristoph Hellwig cnt += width; 24515158e9b5SChristoph Hellwig } 24525158e9b5SChristoph Hellwig 2453f5ed0eb6SJeremy Kerr spu_release(ctx); 2454f5ed0eb6SJeremy Kerr 24555158e9b5SChristoph Hellwig return cnt == 0 ? error : cnt; 24565158e9b5SChristoph Hellwig } 24575158e9b5SChristoph Hellwig 24588153a5eaSAl Viro static __poll_t spufs_switch_log_poll(struct file *file, poll_table *wait) 24595158e9b5SChristoph Hellwig { 2460496ad9aaSAl Viro struct inode *inode = file_inode(file); 24615158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 24628153a5eaSAl Viro __poll_t mask = 0; 2463f5ed0eb6SJeremy Kerr int rc; 24645158e9b5SChristoph Hellwig 24655158e9b5SChristoph Hellwig poll_wait(file, &ctx->switch_log->wait, wait); 24665158e9b5SChristoph Hellwig 2467f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2468f5ed0eb6SJeremy Kerr if (rc) 2469f5ed0eb6SJeremy Kerr return rc; 2470f5ed0eb6SJeremy Kerr 24715158e9b5SChristoph Hellwig if (spufs_switch_log_used(ctx) > 0) 2472a9a08845SLinus Torvalds mask |= EPOLLIN; 24735158e9b5SChristoph Hellwig 2474f5ed0eb6SJeremy Kerr spu_release(ctx); 2475f5ed0eb6SJeremy Kerr 24765158e9b5SChristoph Hellwig return mask; 24775158e9b5SChristoph Hellwig } 24785158e9b5SChristoph Hellwig 24795158e9b5SChristoph Hellwig static const struct file_operations spufs_switch_log_fops = { 24805158e9b5SChristoph Hellwig .open = spufs_switch_log_open, 24815158e9b5SChristoph Hellwig .read = spufs_switch_log_read, 24825158e9b5SChristoph Hellwig .poll = spufs_switch_log_poll, 2483f5ed0eb6SJeremy Kerr .release = spufs_switch_log_release, 2484fc15351dSArnd Bergmann .llseek = no_llseek, 24855158e9b5SChristoph Hellwig }; 24865158e9b5SChristoph Hellwig 2487f5ed0eb6SJeremy Kerr /** 2488f5ed0eb6SJeremy Kerr * Log a context switch event to a switch log reader. 2489f5ed0eb6SJeremy Kerr * 2490f5ed0eb6SJeremy Kerr * Must be called with ctx->state_mutex held. 2491f5ed0eb6SJeremy Kerr */ 24925158e9b5SChristoph Hellwig void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, 24935158e9b5SChristoph Hellwig u32 type, u32 val) 24945158e9b5SChristoph Hellwig { 24955158e9b5SChristoph Hellwig if (!ctx->switch_log) 24965158e9b5SChristoph Hellwig return; 24975158e9b5SChristoph Hellwig 24985158e9b5SChristoph Hellwig if (spufs_switch_log_avail(ctx) > 1) { 24995158e9b5SChristoph Hellwig struct switch_log_entry *p; 25005158e9b5SChristoph Hellwig 25015158e9b5SChristoph Hellwig p = ctx->switch_log->log + ctx->switch_log->head; 2502cef37ac1SArnd Bergmann ktime_get_ts64(&p->tstamp); 25035158e9b5SChristoph Hellwig p->timebase = get_tb(); 25045158e9b5SChristoph Hellwig p->spu_id = spu ? spu->number : -1; 25055158e9b5SChristoph Hellwig p->type = type; 25065158e9b5SChristoph Hellwig p->val = val; 25075158e9b5SChristoph Hellwig 25085158e9b5SChristoph Hellwig ctx->switch_log->head = 25095158e9b5SChristoph Hellwig (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE; 25105158e9b5SChristoph Hellwig } 25115158e9b5SChristoph Hellwig 25125158e9b5SChristoph Hellwig wake_up(&ctx->switch_log->wait); 25135158e9b5SChristoph Hellwig } 2514e9f8a0b6SChristoph Hellwig 251546deed69SLuke Browning static int spufs_show_ctx(struct seq_file *s, void *private) 251646deed69SLuke Browning { 251746deed69SLuke Browning struct spu_context *ctx = s->private; 251846deed69SLuke Browning u64 mfc_control_RW; 251946deed69SLuke Browning 252046deed69SLuke Browning mutex_lock(&ctx->state_mutex); 252146deed69SLuke Browning if (ctx->spu) { 252246deed69SLuke Browning struct spu *spu = ctx->spu; 252346deed69SLuke Browning struct spu_priv2 __iomem *priv2 = spu->priv2; 252446deed69SLuke Browning 252546deed69SLuke Browning spin_lock_irq(&spu->register_lock); 252646deed69SLuke Browning mfc_control_RW = in_be64(&priv2->mfc_control_RW); 252746deed69SLuke Browning spin_unlock_irq(&spu->register_lock); 252846deed69SLuke Browning } else { 252946deed69SLuke Browning struct spu_state *csa = &ctx->csa; 253046deed69SLuke Browning 253146deed69SLuke Browning mfc_control_RW = csa->priv2.mfc_control_RW; 253246deed69SLuke Browning } 253346deed69SLuke Browning 253446deed69SLuke Browning seq_printf(s, "%c flgs(%lx) sflgs(%lx) pri(%d) ts(%d) spu(%02d)" 25359477e455SStephen Rothwell " %c %llx %llx %llx %llx %x %x\n", 253646deed69SLuke Browning ctx->state == SPU_STATE_SAVED ? 'S' : 'R', 253746deed69SLuke Browning ctx->flags, 253846deed69SLuke Browning ctx->sched_flags, 253946deed69SLuke Browning ctx->prio, 254046deed69SLuke Browning ctx->time_slice, 254146deed69SLuke Browning ctx->spu ? ctx->spu->number : -1, 254246deed69SLuke Browning !list_empty(&ctx->rq) ? 'q' : ' ', 254346deed69SLuke Browning ctx->csa.class_0_pending, 254446deed69SLuke Browning ctx->csa.class_0_dar, 254546deed69SLuke Browning ctx->csa.class_1_dsisr, 254646deed69SLuke Browning mfc_control_RW, 254746deed69SLuke Browning ctx->ops->runcntl_read(ctx), 254846deed69SLuke Browning ctx->ops->status_read(ctx)); 254946deed69SLuke Browning 255046deed69SLuke Browning mutex_unlock(&ctx->state_mutex); 255146deed69SLuke Browning 255246deed69SLuke Browning return 0; 255346deed69SLuke Browning } 255446deed69SLuke Browning 255546deed69SLuke Browning static int spufs_ctx_open(struct inode *inode, struct file *file) 255646deed69SLuke Browning { 255746deed69SLuke Browning return single_open(file, spufs_show_ctx, SPUFS_I(inode)->i_ctx); 255846deed69SLuke Browning } 255946deed69SLuke Browning 256046deed69SLuke Browning static const struct file_operations spufs_ctx_fops = { 256146deed69SLuke Browning .open = spufs_ctx_open, 256246deed69SLuke Browning .read = seq_read, 256346deed69SLuke Browning .llseek = seq_lseek, 256446deed69SLuke Browning .release = single_release, 256546deed69SLuke Browning }; 256646deed69SLuke Browning 256774254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_contents[] = { 2568cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 25696f7dde81SJeremy Kerr { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, 25706f7dde81SJeremy Kerr { "regs", &spufs_regs_fops, 0666, sizeof(struct spu_reg128[128]), }, 257167207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 257267207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 257367207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 25746f7dde81SJeremy Kerr { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, 25756f7dde81SJeremy Kerr { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, 25766f7dde81SJeremy Kerr { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, 2577603c4612SJeremy Kerr { "signal1", &spufs_signal1_fops, 0666, }, 2578603c4612SJeremy Kerr { "signal2", &spufs_signal2_fops, 0666, }, 257967207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 258067207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 25816df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 25826f7dde81SJeremy Kerr { "fpcr", &spufs_fpcr_fops, 0666, sizeof(struct spu_reg128), }, 2583b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 2584b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 2585b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 2586b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 2587b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 25888b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 25898b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 25908b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 2591b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 25926f7dde81SJeremy Kerr { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, 259386767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 259486767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 25956f7dde81SJeremy Kerr { "mbox_info", &spufs_mbox_info_fops, 0444, sizeof(u32), }, 25966f7dde81SJeremy Kerr { "ibox_info", &spufs_ibox_info_fops, 0444, sizeof(u32), }, 25976f7dde81SJeremy Kerr { "wbox_info", &spufs_wbox_info_fops, 0444, sizeof(u32), }, 25986f7dde81SJeremy Kerr { "dma_info", &spufs_dma_info_fops, 0444, 25996f7dde81SJeremy Kerr sizeof(struct spu_dma_info), }, 26006f7dde81SJeremy Kerr { "proxydma_info", &spufs_proxydma_info_fops, 0444, 26016f7dde81SJeremy Kerr sizeof(struct spu_proxydma_info)}, 2602476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2603e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 26045158e9b5SChristoph Hellwig { "switch_log", &spufs_switch_log_fops, 0444 }, 260567207b96SArnd Bergmann {}, 260667207b96SArnd Bergmann }; 26075737edd1SMark Nutter 260874254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_nosched_contents[] = { 2609cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 26106f7dde81SJeremy Kerr { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, 26115737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 26125737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 26135737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 26146f7dde81SJeremy Kerr { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, 26156f7dde81SJeremy Kerr { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, 26166f7dde81SJeremy Kerr { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, 2617d054b36fSJeremy Kerr { "signal1", &spufs_signal1_nosched_fops, 0222, }, 2618d054b36fSJeremy Kerr { "signal2", &spufs_signal2_nosched_fops, 0222, }, 26195737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 26205737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 26215737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 26225737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 26235737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 26245737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 26256f7dde81SJeremy Kerr { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, 26265737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 26275737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 2628476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2629e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 26302c3e4787SJeremy Kerr {}, 26312c3e4787SJeremy Kerr }; 26322c3e4787SJeremy Kerr 263374254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_debug_contents[] = { 263446deed69SLuke Browning { ".ctx", &spufs_ctx_fops, 0444, }, 26355737edd1SMark Nutter {}, 26365737edd1SMark Nutter }; 2637bf1ab978SDwayne Grant McConnell 263874254647SJeremy Kerr const struct spufs_coredump_reader spufs_coredump_read[] = { 26394fca9c42SMichael Ellerman { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, 26404fca9c42SMichael Ellerman { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, 2641104f0cc2SMichael Ellerman { "lslr", NULL, spufs_lslr_get, 19 }, 2642104f0cc2SMichael Ellerman { "decr", NULL, spufs_decr_get, 19 }, 2643104f0cc2SMichael Ellerman { "decr_status", NULL, spufs_decr_status_get, 19 }, 26444fca9c42SMichael Ellerman { "mem", __spufs_mem_read, NULL, LS_SIZE, }, 26454fca9c42SMichael Ellerman { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, 2646104f0cc2SMichael Ellerman { "signal1_type", NULL, spufs_signal1_type_get, 19 }, 26474fca9c42SMichael Ellerman { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, 2648104f0cc2SMichael Ellerman { "signal2_type", NULL, spufs_signal2_type_get, 19 }, 2649104f0cc2SMichael Ellerman { "event_mask", NULL, spufs_event_mask_get, 19 }, 2650104f0cc2SMichael Ellerman { "event_status", NULL, spufs_event_status_get, 19 }, 26514fca9c42SMichael Ellerman { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, 26524fca9c42SMichael Ellerman { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, 26534fca9c42SMichael Ellerman { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, 26544fca9c42SMichael Ellerman { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, 26554fca9c42SMichael Ellerman { "proxydma_info", __spufs_proxydma_info_read, 26564fca9c42SMichael Ellerman NULL, sizeof(struct spu_proxydma_info)}, 2657104f0cc2SMichael Ellerman { "object-id", NULL, spufs_object_id_get, 19 }, 2658104f0cc2SMichael Ellerman { "npc", NULL, spufs_npc_get, 19 }, 2659936d5bf1SMichael Ellerman { NULL }, 2660bf1ab978SDwayne Grant McConnell }; 2661