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 125456ffdeSChristoph Hellwig #include <linux/coredump.h> 1367207b96SArnd Bergmann #include <linux/fs.h> 1467207b96SArnd Bergmann #include <linux/ioctl.h> 154b16f8e2SPaul Gortmaker #include <linux/export.h> 16d88cfffaSArnd Bergmann #include <linux/pagemap.h> 1767207b96SArnd Bergmann #include <linux/poll.h> 185110459fSArnd Bergmann #include <linux/ptrace.h> 19cbe709c1SBenjamin Herrenschmidt #include <linux/seq_file.h> 205a0e3ad6STejun Heo #include <linux/slab.h> 2167207b96SArnd Bergmann 2267207b96SArnd Bergmann #include <asm/io.h> 23dfe1e09fSFUJITA Tomonori #include <asm/time.h> 2467207b96SArnd Bergmann #include <asm/spu.h> 25b9e3bd77SDwayne Grant McConnell #include <asm/spu_info.h> 267c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 2767207b96SArnd Bergmann 2867207b96SArnd Bergmann #include "spufs.h" 29ae142e0cSChristoph Hellwig #include "sputrace.h" 3067207b96SArnd Bergmann 3127d5bf2aSBenjamin Herrenschmidt #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) 3227d5bf2aSBenjamin Herrenschmidt 33197b1a82SChristoph Hellwig /* Simple attribute files */ 34197b1a82SChristoph Hellwig struct spufs_attr { 35197b1a82SChristoph Hellwig int (*get)(void *, u64 *); 36197b1a82SChristoph Hellwig int (*set)(void *, u64); 37197b1a82SChristoph Hellwig char get_buf[24]; /* enough to store a u64 and "\n\0" */ 38197b1a82SChristoph Hellwig char set_buf[24]; 39197b1a82SChristoph Hellwig void *data; 40197b1a82SChristoph Hellwig const char *fmt; /* format for read operation */ 41197b1a82SChristoph Hellwig struct mutex mutex; /* protects access to these buffers */ 42197b1a82SChristoph Hellwig }; 43197b1a82SChristoph Hellwig 44197b1a82SChristoph Hellwig static int spufs_attr_open(struct inode *inode, struct file *file, 45197b1a82SChristoph Hellwig int (*get)(void *, u64 *), int (*set)(void *, u64), 46197b1a82SChristoph Hellwig const char *fmt) 47197b1a82SChristoph Hellwig { 48197b1a82SChristoph Hellwig struct spufs_attr *attr; 49197b1a82SChristoph Hellwig 50197b1a82SChristoph Hellwig attr = kmalloc(sizeof(*attr), GFP_KERNEL); 51197b1a82SChristoph Hellwig if (!attr) 52197b1a82SChristoph Hellwig return -ENOMEM; 53197b1a82SChristoph Hellwig 54197b1a82SChristoph Hellwig attr->get = get; 55197b1a82SChristoph Hellwig attr->set = set; 56197b1a82SChristoph Hellwig attr->data = inode->i_private; 57197b1a82SChristoph Hellwig attr->fmt = fmt; 58197b1a82SChristoph Hellwig mutex_init(&attr->mutex); 59197b1a82SChristoph Hellwig file->private_data = attr; 60197b1a82SChristoph Hellwig 61197b1a82SChristoph Hellwig return nonseekable_open(inode, file); 62197b1a82SChristoph Hellwig } 63197b1a82SChristoph Hellwig 64197b1a82SChristoph Hellwig static int spufs_attr_release(struct inode *inode, struct file *file) 65197b1a82SChristoph Hellwig { 66197b1a82SChristoph Hellwig kfree(file->private_data); 67197b1a82SChristoph Hellwig return 0; 68197b1a82SChristoph Hellwig } 69197b1a82SChristoph Hellwig 70197b1a82SChristoph Hellwig static ssize_t spufs_attr_read(struct file *file, char __user *buf, 71197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 72197b1a82SChristoph Hellwig { 73197b1a82SChristoph Hellwig struct spufs_attr *attr; 74197b1a82SChristoph Hellwig size_t size; 75197b1a82SChristoph Hellwig ssize_t ret; 76197b1a82SChristoph Hellwig 77197b1a82SChristoph Hellwig attr = file->private_data; 78197b1a82SChristoph Hellwig if (!attr->get) 79197b1a82SChristoph Hellwig return -EACCES; 80197b1a82SChristoph Hellwig 81197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 82197b1a82SChristoph Hellwig if (ret) 83197b1a82SChristoph Hellwig return ret; 84197b1a82SChristoph Hellwig 85197b1a82SChristoph Hellwig if (*ppos) { /* continued read */ 86197b1a82SChristoph Hellwig size = strlen(attr->get_buf); 87197b1a82SChristoph Hellwig } else { /* first read */ 88197b1a82SChristoph Hellwig u64 val; 89197b1a82SChristoph Hellwig ret = attr->get(attr->data, &val); 90197b1a82SChristoph Hellwig if (ret) 91197b1a82SChristoph Hellwig goto out; 92197b1a82SChristoph Hellwig 93197b1a82SChristoph Hellwig size = scnprintf(attr->get_buf, sizeof(attr->get_buf), 94197b1a82SChristoph Hellwig attr->fmt, (unsigned long long)val); 95197b1a82SChristoph Hellwig } 96197b1a82SChristoph Hellwig 97197b1a82SChristoph Hellwig ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); 98197b1a82SChristoph Hellwig out: 99197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 100197b1a82SChristoph Hellwig return ret; 101197b1a82SChristoph Hellwig } 102197b1a82SChristoph Hellwig 103197b1a82SChristoph Hellwig static ssize_t spufs_attr_write(struct file *file, const char __user *buf, 104197b1a82SChristoph Hellwig size_t len, loff_t *ppos) 105197b1a82SChristoph Hellwig { 106197b1a82SChristoph Hellwig struct spufs_attr *attr; 107197b1a82SChristoph Hellwig u64 val; 108197b1a82SChristoph Hellwig size_t size; 109197b1a82SChristoph Hellwig ssize_t ret; 110197b1a82SChristoph Hellwig 111197b1a82SChristoph Hellwig attr = file->private_data; 112197b1a82SChristoph Hellwig if (!attr->set) 113197b1a82SChristoph Hellwig return -EACCES; 114197b1a82SChristoph Hellwig 115197b1a82SChristoph Hellwig ret = mutex_lock_interruptible(&attr->mutex); 116197b1a82SChristoph Hellwig if (ret) 117197b1a82SChristoph Hellwig return ret; 118197b1a82SChristoph Hellwig 119197b1a82SChristoph Hellwig ret = -EFAULT; 120197b1a82SChristoph Hellwig size = min(sizeof(attr->set_buf) - 1, len); 121197b1a82SChristoph Hellwig if (copy_from_user(attr->set_buf, buf, size)) 122197b1a82SChristoph Hellwig goto out; 123197b1a82SChristoph Hellwig 124197b1a82SChristoph Hellwig ret = len; /* claim we got the whole input */ 125197b1a82SChristoph Hellwig attr->set_buf[size] = '\0'; 126197b1a82SChristoph Hellwig val = simple_strtol(attr->set_buf, NULL, 0); 127197b1a82SChristoph Hellwig attr->set(attr->data, val); 128197b1a82SChristoph Hellwig out: 129197b1a82SChristoph Hellwig mutex_unlock(&attr->mutex); 130197b1a82SChristoph Hellwig return ret; 131197b1a82SChristoph Hellwig } 132197b1a82SChristoph Hellwig 1335456ffdeSChristoph Hellwig static ssize_t spufs_dump_emit(struct coredump_params *cprm, void *buf, 1345456ffdeSChristoph Hellwig size_t size) 1355456ffdeSChristoph Hellwig { 1365456ffdeSChristoph Hellwig if (!dump_emit(cprm, buf, size)) 1375456ffdeSChristoph Hellwig return -EIO; 1385456ffdeSChristoph Hellwig return size; 1395456ffdeSChristoph Hellwig } 1405456ffdeSChristoph Hellwig 141197b1a82SChristoph Hellwig #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ 142197b1a82SChristoph Hellwig static int __fops ## _open(struct inode *inode, struct file *file) \ 143197b1a82SChristoph Hellwig { \ 144197b1a82SChristoph Hellwig __simple_attr_check_format(__fmt, 0ull); \ 145197b1a82SChristoph Hellwig return spufs_attr_open(inode, file, __get, __set, __fmt); \ 146197b1a82SChristoph Hellwig } \ 147828c0950SAlexey Dobriyan static const struct file_operations __fops = { \ 148197b1a82SChristoph Hellwig .open = __fops ## _open, \ 149197b1a82SChristoph Hellwig .release = spufs_attr_release, \ 150197b1a82SChristoph Hellwig .read = spufs_attr_read, \ 151197b1a82SChristoph Hellwig .write = spufs_attr_write, \ 152fc15351dSArnd Bergmann .llseek = generic_file_llseek, \ 153197b1a82SChristoph Hellwig }; 154197b1a82SChristoph Hellwig 155cbe709c1SBenjamin Herrenschmidt 15667207b96SArnd Bergmann static int 15767207b96SArnd Bergmann spufs_mem_open(struct inode *inode, struct file *file) 15867207b96SArnd Bergmann { 15967207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1606df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 16143c2bbd9SChristoph Hellwig 16247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1636df10a82SMark Nutter file->private_data = ctx; 16443c2bbd9SChristoph Hellwig if (!i->i_openers++) 1656df10a82SMark Nutter ctx->local_store = inode->i_mapping; 16647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 16743c2bbd9SChristoph Hellwig return 0; 16843c2bbd9SChristoph Hellwig } 16943c2bbd9SChristoph Hellwig 17043c2bbd9SChristoph Hellwig static int 17143c2bbd9SChristoph Hellwig spufs_mem_release(struct inode *inode, struct file *file) 17243c2bbd9SChristoph Hellwig { 17343c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 17443c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 17543c2bbd9SChristoph Hellwig 17647d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 17743c2bbd9SChristoph Hellwig if (!--i->i_openers) 17843c2bbd9SChristoph Hellwig ctx->local_store = NULL; 17947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 18067207b96SArnd Bergmann return 0; 18167207b96SArnd Bergmann } 18267207b96SArnd Bergmann 18367207b96SArnd Bergmann static ssize_t 1845456ffdeSChristoph Hellwig spufs_mem_dump(struct spu_context *ctx, struct coredump_params *cprm) 185bf1ab978SDwayne Grant McConnell { 1865456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, ctx->ops->get_ls(ctx), LS_SIZE); 187bf1ab978SDwayne Grant McConnell } 188bf1ab978SDwayne Grant McConnell 189bf1ab978SDwayne Grant McConnell static ssize_t 19067207b96SArnd Bergmann spufs_mem_read(struct file *file, char __user *buffer, 19167207b96SArnd Bergmann size_t size, loff_t *pos) 19267207b96SArnd Bergmann { 193bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 194aa0ed2bdSArnd Bergmann ssize_t ret; 19567207b96SArnd Bergmann 196c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 197c9101bdbSChristoph Hellwig if (ret) 198c9101bdbSChristoph Hellwig return ret; 1995456ffdeSChristoph Hellwig ret = simple_read_from_buffer(buffer, size, pos, ctx->ops->get_ls(ctx), 2005456ffdeSChristoph Hellwig LS_SIZE); 2018b3d6663SArnd Bergmann spu_release(ctx); 202c9101bdbSChristoph Hellwig 20367207b96SArnd Bergmann return ret; 20467207b96SArnd Bergmann } 20567207b96SArnd Bergmann 20667207b96SArnd Bergmann static ssize_t 20767207b96SArnd Bergmann spufs_mem_write(struct file *file, const char __user *buffer, 208aa0ed2bdSArnd Bergmann size_t size, loff_t *ppos) 20967207b96SArnd Bergmann { 21067207b96SArnd Bergmann struct spu_context *ctx = file->private_data; 2118b3d6663SArnd Bergmann char *local_store; 212aa0ed2bdSArnd Bergmann loff_t pos = *ppos; 2138b3d6663SArnd Bergmann int ret; 21467207b96SArnd Bergmann 215aa0ed2bdSArnd Bergmann if (pos > LS_SIZE) 21667207b96SArnd Bergmann return -EFBIG; 2178b3d6663SArnd Bergmann 218c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 219c9101bdbSChristoph Hellwig if (ret) 220c9101bdbSChristoph Hellwig return ret; 221c9101bdbSChristoph Hellwig 2228b3d6663SArnd Bergmann local_store = ctx->ops->get_ls(ctx); 22363c3b9d7SAkinobu Mita size = simple_write_to_buffer(local_store, LS_SIZE, ppos, buffer, size); 2248b3d6663SArnd Bergmann spu_release(ctx); 225aa0ed2bdSArnd Bergmann 226aa0ed2bdSArnd Bergmann return size; 22767207b96SArnd Bergmann } 22867207b96SArnd Bergmann 229e807f02cSSouptick Joarder static vm_fault_t 23011bac800SDave Jiang spufs_mem_mmap_fault(struct vm_fault *vmf) 2318b3d6663SArnd Bergmann { 23211bac800SDave Jiang struct vm_area_struct *vma = vmf->vma; 2338b3d6663SArnd Bergmann struct spu_context *ctx = vma->vm_file->private_data; 234b1e2270fSNick Piggin unsigned long pfn, offset; 235e807f02cSSouptick Joarder vm_fault_t ret; 236b1e2270fSNick Piggin 237b1e2270fSNick Piggin offset = vmf->pgoff << PAGE_SHIFT; 238128b8546SMasato Noguchi if (offset >= LS_SIZE) 239b1e2270fSNick Piggin return VM_FAULT_SIGBUS; 240128b8546SMasato Noguchi 241b1e2270fSNick Piggin pr_debug("spufs_mem_mmap_fault address=0x%lx, offset=0x%lx\n", 2421a29d85eSJan Kara vmf->address, offset); 243f1fa74f4SBenjamin Herrenschmidt 244c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 245b1e2270fSNick Piggin return VM_FAULT_NOPAGE; 2468b3d6663SArnd Bergmann 247ac91cb8dSArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 24864b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); 24978bde53eSBenjamin Herrenschmidt pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); 250ac91cb8dSArnd Bergmann } else { 25164b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); 25278bde53eSBenjamin Herrenschmidt pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; 253ac91cb8dSArnd Bergmann } 254e807f02cSSouptick Joarder ret = vmf_insert_pfn(vma, vmf->address, pfn); 25578bde53eSBenjamin Herrenschmidt 2568b3d6663SArnd Bergmann spu_release(ctx); 2578b3d6663SArnd Bergmann 258e807f02cSSouptick Joarder return ret; 2598b3d6663SArnd Bergmann } 2608b3d6663SArnd Bergmann 261a352894dSBenjamin Herrenschmidt static int spufs_mem_mmap_access(struct vm_area_struct *vma, 262a352894dSBenjamin Herrenschmidt unsigned long address, 263a352894dSBenjamin Herrenschmidt void *buf, int len, int write) 264a352894dSBenjamin Herrenschmidt { 265a352894dSBenjamin Herrenschmidt struct spu_context *ctx = vma->vm_file->private_data; 266a352894dSBenjamin Herrenschmidt unsigned long offset = address - vma->vm_start; 267a352894dSBenjamin Herrenschmidt char *local_store; 268a352894dSBenjamin Herrenschmidt 269a352894dSBenjamin Herrenschmidt if (write && !(vma->vm_flags & VM_WRITE)) 270a352894dSBenjamin Herrenschmidt return -EACCES; 271a352894dSBenjamin Herrenschmidt if (spu_acquire(ctx)) 272a352894dSBenjamin Herrenschmidt return -EINTR; 273a352894dSBenjamin Herrenschmidt if ((offset + len) > vma->vm_end) 274a352894dSBenjamin Herrenschmidt len = vma->vm_end - offset; 275a352894dSBenjamin Herrenschmidt local_store = ctx->ops->get_ls(ctx); 276a352894dSBenjamin Herrenschmidt if (write) 277a352894dSBenjamin Herrenschmidt memcpy_toio(local_store + offset, buf, len); 278a352894dSBenjamin Herrenschmidt else 279a352894dSBenjamin Herrenschmidt memcpy_fromio(buf, local_store + offset, len); 280a352894dSBenjamin Herrenschmidt spu_release(ctx); 281a352894dSBenjamin Herrenschmidt return len; 282a352894dSBenjamin Herrenschmidt } 28378bde53eSBenjamin Herrenschmidt 284f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mem_mmap_vmops = { 285b1e2270fSNick Piggin .fault = spufs_mem_mmap_fault, 286a352894dSBenjamin Herrenschmidt .access = spufs_mem_mmap_access, 2878b3d6663SArnd Bergmann }; 2888b3d6663SArnd Bergmann 289f1fa74f4SBenjamin Herrenschmidt static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 29067207b96SArnd Bergmann { 2918b3d6663SArnd Bergmann if (!(vma->vm_flags & VM_SHARED)) 2928b3d6663SArnd Bergmann return -EINVAL; 29367207b96SArnd Bergmann 2941c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP); 29564b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); 2968b3d6663SArnd Bergmann 2978b3d6663SArnd Bergmann vma->vm_ops = &spufs_mem_mmap_vmops; 29867207b96SArnd Bergmann return 0; 29967207b96SArnd Bergmann } 30067207b96SArnd Bergmann 3015dfe4c96SArjan van de Ven static const struct file_operations spufs_mem_fops = { 30267207b96SArnd Bergmann .open = spufs_mem_open, 303ce92987bSChristoph Hellwig .release = spufs_mem_release, 30467207b96SArnd Bergmann .read = spufs_mem_read, 30567207b96SArnd Bergmann .write = spufs_mem_write, 3068b3d6663SArnd Bergmann .llseek = generic_file_llseek, 30767207b96SArnd Bergmann .mmap = spufs_mem_mmap, 3088b3d6663SArnd Bergmann }; 3098b3d6663SArnd Bergmann 310e807f02cSSouptick Joarder static vm_fault_t spufs_ps_fault(struct vm_fault *vmf, 31178bde53eSBenjamin Herrenschmidt unsigned long ps_offs, 31227d5bf2aSBenjamin Herrenschmidt unsigned long ps_size) 3136df10a82SMark Nutter { 31411bac800SDave Jiang struct spu_context *ctx = vmf->vma->vm_file->private_data; 315b1e2270fSNick Piggin unsigned long area, offset = vmf->pgoff << PAGE_SHIFT; 316e807f02cSSouptick Joarder int err = 0; 317e807f02cSSouptick Joarder vm_fault_t ret = VM_FAULT_NOPAGE; 3186df10a82SMark Nutter 319b1e2270fSNick Piggin spu_context_nospu_trace(spufs_ps_fault__enter, ctx); 320038200cfSChristoph Hellwig 32127d5bf2aSBenjamin Herrenschmidt if (offset >= ps_size) 322b1e2270fSNick Piggin return VM_FAULT_SIGBUS; 3236df10a82SMark Nutter 32460657263SJeremy Kerr if (fatal_signal_pending(current)) 32560657263SJeremy Kerr return VM_FAULT_SIGBUS; 32660657263SJeremy Kerr 32733bfd7a7SArnd Bergmann /* 328c1e8d7c6SMichel Lespinasse * Because we release the mmap_lock, the context may be destroyed while 329d5883137SJeremy Kerr * we're in spu_wait. Grab an extra reference so it isn't destroyed 330d5883137SJeremy Kerr * in the meantime. 331d5883137SJeremy Kerr */ 332d5883137SJeremy Kerr get_spu_context(ctx); 333d5883137SJeremy Kerr 334d5883137SJeremy Kerr /* 33533bfd7a7SArnd Bergmann * We have to wait for context to be loaded before we have 33633bfd7a7SArnd Bergmann * pages to hand out to the user, but we don't want to wait 337c1e8d7c6SMichel Lespinasse * with the mmap_lock held. 338c1e8d7c6SMichel Lespinasse * It is possible to drop the mmap_lock here, but then we need 339b1e2270fSNick Piggin * to return VM_FAULT_NOPAGE because the mappings may have 34033bfd7a7SArnd Bergmann * hanged. 34178bde53eSBenjamin Herrenschmidt */ 342c9101bdbSChristoph Hellwig if (spu_acquire(ctx)) 343d5883137SJeremy Kerr goto refault; 344c9101bdbSChristoph Hellwig 34533bfd7a7SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 346d8ed45c5SMichel Lespinasse mmap_read_unlock(current->mm); 347b1e2270fSNick Piggin spu_context_nospu_trace(spufs_ps_fault__sleep, ctx); 348e807f02cSSouptick Joarder err = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 349b1e2270fSNick Piggin spu_context_trace(spufs_ps_fault__wake, ctx, ctx->spu); 350d8ed45c5SMichel Lespinasse mmap_read_lock(current->mm); 351c9101bdbSChristoph Hellwig } else { 3526df10a82SMark Nutter area = ctx->spu->problem_phys + ps_offs; 353e807f02cSSouptick Joarder ret = vmf_insert_pfn(vmf->vma, vmf->address, 354e807f02cSSouptick Joarder (area + offset) >> PAGE_SHIFT); 355b1e2270fSNick Piggin spu_context_trace(spufs_ps_fault__insert, ctx, ctx->spu); 356c9101bdbSChristoph Hellwig } 35733bfd7a7SArnd Bergmann 358e807f02cSSouptick Joarder if (!err) 3596df10a82SMark Nutter spu_release(ctx); 360d5883137SJeremy Kerr 361d5883137SJeremy Kerr refault: 362d5883137SJeremy Kerr put_spu_context(ctx); 363e807f02cSSouptick Joarder return ret; 3646df10a82SMark Nutter } 3656df10a82SMark Nutter 36627d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 367e807f02cSSouptick Joarder static vm_fault_t spufs_cntl_mmap_fault(struct vm_fault *vmf) 3686df10a82SMark Nutter { 36911bac800SDave Jiang return spufs_ps_fault(vmf, 0x4000, SPUFS_CNTL_MAP_SIZE); 3706df10a82SMark Nutter } 3716df10a82SMark Nutter 372f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_cntl_mmap_vmops = { 373b1e2270fSNick Piggin .fault = spufs_cntl_mmap_fault, 3746df10a82SMark Nutter }; 3756df10a82SMark Nutter 3766df10a82SMark Nutter /* 3776df10a82SMark Nutter * mmap support for problem state control area [0x4000 - 0x4fff]. 3786df10a82SMark Nutter */ 3796df10a82SMark Nutter static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) 3806df10a82SMark Nutter { 3816df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 3826df10a82SMark Nutter return -EINVAL; 3836df10a82SMark Nutter 3841c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP); 38564b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 3866df10a82SMark Nutter 3876df10a82SMark Nutter vma->vm_ops = &spufs_cntl_mmap_vmops; 3886df10a82SMark Nutter return 0; 3896df10a82SMark Nutter } 39027d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 39127d5bf2aSBenjamin Herrenschmidt #define spufs_cntl_mmap NULL 39227d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 3936df10a82SMark Nutter 394197b1a82SChristoph Hellwig static int spufs_cntl_get(void *data, u64 *val) 395e1dbff2bSArnd Bergmann { 396e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 397c9101bdbSChristoph Hellwig int ret; 398e1dbff2bSArnd Bergmann 399c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 400c9101bdbSChristoph Hellwig if (ret) 401c9101bdbSChristoph Hellwig return ret; 402197b1a82SChristoph Hellwig *val = ctx->ops->status_read(ctx); 403e1dbff2bSArnd Bergmann spu_release(ctx); 404e1dbff2bSArnd Bergmann 405197b1a82SChristoph Hellwig return 0; 406e1dbff2bSArnd Bergmann } 407e1dbff2bSArnd Bergmann 408197b1a82SChristoph Hellwig static int spufs_cntl_set(void *data, u64 val) 409e1dbff2bSArnd Bergmann { 410e1dbff2bSArnd Bergmann struct spu_context *ctx = data; 411c9101bdbSChristoph Hellwig int ret; 412e1dbff2bSArnd Bergmann 413c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 414c9101bdbSChristoph Hellwig if (ret) 415c9101bdbSChristoph Hellwig return ret; 416e1dbff2bSArnd Bergmann ctx->ops->runcntl_write(ctx, val); 417e1dbff2bSArnd Bergmann spu_release(ctx); 418197b1a82SChristoph Hellwig 419197b1a82SChristoph Hellwig return 0; 420e1dbff2bSArnd Bergmann } 421e1dbff2bSArnd Bergmann 4226df10a82SMark Nutter static int spufs_cntl_open(struct inode *inode, struct file *file) 4236df10a82SMark Nutter { 4246df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 4256df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 4266df10a82SMark Nutter 42747d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 4286df10a82SMark Nutter file->private_data = ctx; 42943c2bbd9SChristoph Hellwig if (!i->i_openers++) 4306df10a82SMark Nutter ctx->cntl = inode->i_mapping; 43147d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 4328b88b099SChristoph Hellwig return simple_attr_open(inode, file, spufs_cntl_get, 433e1dbff2bSArnd Bergmann spufs_cntl_set, "0x%08lx"); 4346df10a82SMark Nutter } 4356df10a82SMark Nutter 43643c2bbd9SChristoph Hellwig static int 43743c2bbd9SChristoph Hellwig spufs_cntl_release(struct inode *inode, struct file *file) 43843c2bbd9SChristoph Hellwig { 43943c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 44043c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 44143c2bbd9SChristoph Hellwig 44274bedc4dSChristoph Hellwig simple_attr_release(inode, file); 44343c2bbd9SChristoph Hellwig 44447d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 44543c2bbd9SChristoph Hellwig if (!--i->i_openers) 44643c2bbd9SChristoph Hellwig ctx->cntl = NULL; 44747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 44843c2bbd9SChristoph Hellwig return 0; 44943c2bbd9SChristoph Hellwig } 45043c2bbd9SChristoph Hellwig 4515dfe4c96SArjan van de Ven static const struct file_operations spufs_cntl_fops = { 4526df10a82SMark Nutter .open = spufs_cntl_open, 45343c2bbd9SChristoph Hellwig .release = spufs_cntl_release, 4548b88b099SChristoph Hellwig .read = simple_attr_read, 4558b88b099SChristoph Hellwig .write = simple_attr_write, 456658829dfSGeliang Tang .llseek = no_llseek, 4576df10a82SMark Nutter .mmap = spufs_cntl_mmap, 4586df10a82SMark Nutter }; 4596df10a82SMark Nutter 4608b3d6663SArnd Bergmann static int 4618b3d6663SArnd Bergmann spufs_regs_open(struct inode *inode, struct file *file) 4628b3d6663SArnd Bergmann { 4638b3d6663SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 4648b3d6663SArnd Bergmann file->private_data = i->i_ctx; 4658b3d6663SArnd Bergmann return 0; 4668b3d6663SArnd Bergmann } 4678b3d6663SArnd Bergmann 4688b3d6663SArnd Bergmann static ssize_t 4695456ffdeSChristoph Hellwig spufs_regs_dump(struct spu_context *ctx, struct coredump_params *cprm) 470bf1ab978SDwayne Grant McConnell { 4715456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, ctx->csa.lscsa->gprs, 4725456ffdeSChristoph Hellwig sizeof(ctx->csa.lscsa->gprs)); 473bf1ab978SDwayne Grant McConnell } 474bf1ab978SDwayne Grant McConnell 475bf1ab978SDwayne Grant McConnell static ssize_t 4768b3d6663SArnd Bergmann spufs_regs_read(struct file *file, char __user *buffer, 4778b3d6663SArnd Bergmann size_t size, loff_t *pos) 4788b3d6663SArnd Bergmann { 4798b3d6663SArnd Bergmann int ret; 480bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 4818b3d6663SArnd Bergmann 482f027faa2SJeremy Kerr /* pre-check for file position: if we'd return EOF, there's no point 483f027faa2SJeremy Kerr * causing a deschedule */ 484f027faa2SJeremy Kerr if (*pos >= sizeof(ctx->csa.lscsa->gprs)) 485f027faa2SJeremy Kerr return 0; 486f027faa2SJeremy Kerr 487c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 488c9101bdbSChristoph Hellwig if (ret) 489c9101bdbSChristoph Hellwig return ret; 4905456ffdeSChristoph Hellwig ret = simple_read_from_buffer(buffer, size, pos, ctx->csa.lscsa->gprs, 4915456ffdeSChristoph Hellwig sizeof(ctx->csa.lscsa->gprs)); 49227b1ea09SChristoph Hellwig spu_release_saved(ctx); 4938b3d6663SArnd Bergmann return ret; 4948b3d6663SArnd Bergmann } 4958b3d6663SArnd Bergmann 4968b3d6663SArnd Bergmann static ssize_t 4978b3d6663SArnd Bergmann spufs_regs_write(struct file *file, const char __user *buffer, 4988b3d6663SArnd Bergmann size_t size, loff_t *pos) 4998b3d6663SArnd Bergmann { 5008b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5018b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5028b3d6663SArnd Bergmann int ret; 5038b3d6663SArnd Bergmann 504d219889bSJeremy Kerr if (*pos >= sizeof(lscsa->gprs)) 5058b3d6663SArnd Bergmann return -EFBIG; 506d219889bSJeremy Kerr 507c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 508c9101bdbSChristoph Hellwig if (ret) 509c9101bdbSChristoph Hellwig return ret; 5108b3d6663SArnd Bergmann 51163c3b9d7SAkinobu Mita size = simple_write_to_buffer(lscsa->gprs, sizeof(lscsa->gprs), pos, 51263c3b9d7SAkinobu Mita buffer, size); 5138b3d6663SArnd Bergmann 51427b1ea09SChristoph Hellwig spu_release_saved(ctx); 51563c3b9d7SAkinobu Mita return size; 5168b3d6663SArnd Bergmann } 5178b3d6663SArnd Bergmann 5185dfe4c96SArjan van de Ven static const struct file_operations spufs_regs_fops = { 5198b3d6663SArnd Bergmann .open = spufs_regs_open, 5208b3d6663SArnd Bergmann .read = spufs_regs_read, 5218b3d6663SArnd Bergmann .write = spufs_regs_write, 5228b3d6663SArnd Bergmann .llseek = generic_file_llseek, 5238b3d6663SArnd Bergmann }; 5248b3d6663SArnd Bergmann 5258b3d6663SArnd Bergmann static ssize_t 5265456ffdeSChristoph Hellwig spufs_fpcr_dump(struct spu_context *ctx, struct coredump_params *cprm) 527bf1ab978SDwayne Grant McConnell { 5285456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, &ctx->csa.lscsa->fpcr, 5295456ffdeSChristoph Hellwig sizeof(ctx->csa.lscsa->fpcr)); 530bf1ab978SDwayne Grant McConnell } 531bf1ab978SDwayne Grant McConnell 532bf1ab978SDwayne Grant McConnell static ssize_t 5338b3d6663SArnd Bergmann spufs_fpcr_read(struct file *file, char __user * buffer, 5348b3d6663SArnd Bergmann size_t size, loff_t * pos) 5358b3d6663SArnd Bergmann { 5368b3d6663SArnd Bergmann int ret; 537bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 5388b3d6663SArnd Bergmann 539c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 540c9101bdbSChristoph Hellwig if (ret) 541c9101bdbSChristoph Hellwig return ret; 5425456ffdeSChristoph Hellwig ret = simple_read_from_buffer(buffer, size, pos, &ctx->csa.lscsa->fpcr, 5435456ffdeSChristoph Hellwig sizeof(ctx->csa.lscsa->fpcr)); 54427b1ea09SChristoph Hellwig spu_release_saved(ctx); 5458b3d6663SArnd Bergmann return ret; 5468b3d6663SArnd Bergmann } 5478b3d6663SArnd Bergmann 5488b3d6663SArnd Bergmann static ssize_t 5498b3d6663SArnd Bergmann spufs_fpcr_write(struct file *file, const char __user * buffer, 5508b3d6663SArnd Bergmann size_t size, loff_t * pos) 5518b3d6663SArnd Bergmann { 5528b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5538b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 5548b3d6663SArnd Bergmann int ret; 5558b3d6663SArnd Bergmann 556d219889bSJeremy Kerr if (*pos >= sizeof(lscsa->fpcr)) 5578b3d6663SArnd Bergmann return -EFBIG; 558c9101bdbSChristoph Hellwig 559c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 560c9101bdbSChristoph Hellwig if (ret) 561c9101bdbSChristoph Hellwig return ret; 562c9101bdbSChristoph Hellwig 56363c3b9d7SAkinobu Mita size = simple_write_to_buffer(&lscsa->fpcr, sizeof(lscsa->fpcr), pos, 56463c3b9d7SAkinobu Mita buffer, size); 5658b3d6663SArnd Bergmann 56627b1ea09SChristoph Hellwig spu_release_saved(ctx); 56763c3b9d7SAkinobu Mita return size; 5688b3d6663SArnd Bergmann } 5698b3d6663SArnd Bergmann 5705dfe4c96SArjan van de Ven static const struct file_operations spufs_fpcr_fops = { 5718b3d6663SArnd Bergmann .open = spufs_regs_open, 5728b3d6663SArnd Bergmann .read = spufs_fpcr_read, 5738b3d6663SArnd Bergmann .write = spufs_fpcr_write, 57467207b96SArnd Bergmann .llseek = generic_file_llseek, 57567207b96SArnd Bergmann }; 57667207b96SArnd Bergmann 57767207b96SArnd Bergmann /* generic open function for all pipe-like files */ 57867207b96SArnd Bergmann static int spufs_pipe_open(struct inode *inode, struct file *file) 57967207b96SArnd Bergmann { 58067207b96SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 58167207b96SArnd Bergmann file->private_data = i->i_ctx; 58267207b96SArnd Bergmann 583c5bf68feSKirill Smelkov return stream_open(inode, file); 58467207b96SArnd Bergmann } 58567207b96SArnd Bergmann 586cdcc89bbSArnd Bergmann /* 587cdcc89bbSArnd Bergmann * Read as many bytes from the mailbox as possible, until 588cdcc89bbSArnd Bergmann * one of the conditions becomes true: 589cdcc89bbSArnd Bergmann * 590cdcc89bbSArnd Bergmann * - no more data available in the mailbox 591cdcc89bbSArnd Bergmann * - end of the user provided buffer 592cdcc89bbSArnd Bergmann * - end of the mapped area 593cdcc89bbSArnd Bergmann */ 59467207b96SArnd Bergmann static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 59567207b96SArnd Bergmann size_t len, loff_t *pos) 59667207b96SArnd Bergmann { 5978b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 5986904d3d0SChristoph Hellwig u32 mbox_data, __user *udata = (void __user *)buf; 599cdcc89bbSArnd Bergmann ssize_t count; 60067207b96SArnd Bergmann 60167207b96SArnd Bergmann if (len < 4) 60267207b96SArnd Bergmann return -EINVAL; 60367207b96SArnd Bergmann 604c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 605c9101bdbSChristoph Hellwig if (count) 606c9101bdbSChristoph Hellwig return count; 607c9101bdbSChristoph Hellwig 608274cef5eSArnd Bergmann for (count = 0; (count + 4) <= len; count += 4, udata++) { 609cdcc89bbSArnd Bergmann int ret; 610cdcc89bbSArnd Bergmann ret = ctx->ops->mbox_read(ctx, &mbox_data); 611cdcc89bbSArnd Bergmann if (ret == 0) 612cdcc89bbSArnd Bergmann break; 613cdcc89bbSArnd Bergmann 614cdcc89bbSArnd Bergmann /* 615cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 616cdcc89bbSArnd Bergmann * but still need to return the data we have 617cdcc89bbSArnd Bergmann * read successfully so far. 618cdcc89bbSArnd Bergmann */ 6196904d3d0SChristoph Hellwig ret = put_user(mbox_data, udata); 620cdcc89bbSArnd Bergmann if (ret) { 621cdcc89bbSArnd Bergmann if (!count) 622cdcc89bbSArnd Bergmann count = -EFAULT; 623cdcc89bbSArnd Bergmann break; 624cdcc89bbSArnd Bergmann } 625cdcc89bbSArnd Bergmann } 626cdcc89bbSArnd Bergmann spu_release(ctx); 627cdcc89bbSArnd Bergmann 628cdcc89bbSArnd Bergmann if (!count) 629cdcc89bbSArnd Bergmann count = -EAGAIN; 630cdcc89bbSArnd Bergmann 631cdcc89bbSArnd Bergmann return count; 63267207b96SArnd Bergmann } 63367207b96SArnd Bergmann 6345dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_fops = { 63567207b96SArnd Bergmann .open = spufs_pipe_open, 63667207b96SArnd Bergmann .read = spufs_mbox_read, 637fc15351dSArnd Bergmann .llseek = no_llseek, 63867207b96SArnd Bergmann }; 63967207b96SArnd Bergmann 64067207b96SArnd Bergmann static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 64167207b96SArnd Bergmann size_t len, loff_t *pos) 64267207b96SArnd Bergmann { 6438b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 644c9101bdbSChristoph Hellwig ssize_t ret; 64567207b96SArnd Bergmann u32 mbox_stat; 64667207b96SArnd Bergmann 64767207b96SArnd Bergmann if (len < 4) 64867207b96SArnd Bergmann return -EINVAL; 64967207b96SArnd Bergmann 650c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 651c9101bdbSChristoph Hellwig if (ret) 652c9101bdbSChristoph Hellwig return ret; 6538b3d6663SArnd Bergmann 6548b3d6663SArnd Bergmann mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; 6558b3d6663SArnd Bergmann 6568b3d6663SArnd Bergmann spu_release(ctx); 65767207b96SArnd Bergmann 65867207b96SArnd Bergmann if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 65967207b96SArnd Bergmann return -EFAULT; 66067207b96SArnd Bergmann 66167207b96SArnd Bergmann return 4; 66267207b96SArnd Bergmann } 66367207b96SArnd Bergmann 6645dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_stat_fops = { 66567207b96SArnd Bergmann .open = spufs_pipe_open, 66667207b96SArnd Bergmann .read = spufs_mbox_stat_read, 667fc15351dSArnd Bergmann .llseek = no_llseek, 66867207b96SArnd Bergmann }; 66967207b96SArnd Bergmann 67067207b96SArnd Bergmann /* low-level ibox access function */ 6718b3d6663SArnd Bergmann size_t spu_ibox_read(struct spu_context *ctx, u32 *data) 67267207b96SArnd Bergmann { 6738b3d6663SArnd Bergmann return ctx->ops->ibox_read(ctx, data); 67467207b96SArnd Bergmann } 67567207b96SArnd Bergmann 6768b3d6663SArnd Bergmann /* interrupt-level ibox callback function. */ 6778b3d6663SArnd Bergmann void spufs_ibox_callback(struct spu *spu) 6788b3d6663SArnd Bergmann { 6798b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 6808b3d6663SArnd Bergmann 6817d7be3aaSAl Viro if (ctx) 6828b3d6663SArnd Bergmann wake_up_all(&ctx->ibox_wq); 68367207b96SArnd Bergmann } 68467207b96SArnd Bergmann 685cdcc89bbSArnd Bergmann /* 686cdcc89bbSArnd Bergmann * Read as many bytes from the interrupt mailbox as possible, until 687cdcc89bbSArnd Bergmann * one of the conditions becomes true: 688cdcc89bbSArnd Bergmann * 689cdcc89bbSArnd Bergmann * - no more data available in the mailbox 690cdcc89bbSArnd Bergmann * - end of the user provided buffer 691cdcc89bbSArnd Bergmann * - end of the mapped area 692cdcc89bbSArnd Bergmann * 693cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 694cdcc89bbSArnd Bergmann * any data is available, but return when we have been able to 695cdcc89bbSArnd Bergmann * read something. 696cdcc89bbSArnd Bergmann */ 69767207b96SArnd Bergmann static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 69867207b96SArnd Bergmann size_t len, loff_t *pos) 69967207b96SArnd Bergmann { 7008b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 7016904d3d0SChristoph Hellwig u32 ibox_data, __user *udata = (void __user *)buf; 702cdcc89bbSArnd Bergmann ssize_t count; 70367207b96SArnd Bergmann 70467207b96SArnd Bergmann if (len < 4) 70567207b96SArnd Bergmann return -EINVAL; 70667207b96SArnd Bergmann 707c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 708c9101bdbSChristoph Hellwig if (count) 709eebead5bSChristoph Hellwig goto out; 71067207b96SArnd Bergmann 711cdcc89bbSArnd Bergmann /* wait only for the first element */ 712cdcc89bbSArnd Bergmann count = 0; 71367207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 714eebead5bSChristoph Hellwig if (!spu_ibox_read(ctx, &ibox_data)) { 715cdcc89bbSArnd Bergmann count = -EAGAIN; 716eebead5bSChristoph Hellwig goto out_unlock; 717eebead5bSChristoph Hellwig } 71867207b96SArnd Bergmann } else { 719cdcc89bbSArnd Bergmann count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); 720cdcc89bbSArnd Bergmann if (count) 721cdcc89bbSArnd Bergmann goto out; 722eebead5bSChristoph Hellwig } 723cdcc89bbSArnd Bergmann 724cdcc89bbSArnd Bergmann /* if we can't write at all, return -EFAULT */ 7256904d3d0SChristoph Hellwig count = put_user(ibox_data, udata); 726cdcc89bbSArnd Bergmann if (count) 727eebead5bSChristoph Hellwig goto out_unlock; 728cdcc89bbSArnd Bergmann 729cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 730cdcc89bbSArnd Bergmann int ret; 731cdcc89bbSArnd Bergmann ret = ctx->ops->ibox_read(ctx, &ibox_data); 732cdcc89bbSArnd Bergmann if (ret == 0) 733cdcc89bbSArnd Bergmann break; 734cdcc89bbSArnd Bergmann /* 735cdcc89bbSArnd Bergmann * at the end of the mapped area, we can fault 736cdcc89bbSArnd Bergmann * but still need to return the data we have 737cdcc89bbSArnd Bergmann * read successfully so far. 738cdcc89bbSArnd Bergmann */ 7396904d3d0SChristoph Hellwig ret = put_user(ibox_data, udata); 740cdcc89bbSArnd Bergmann if (ret) 741cdcc89bbSArnd Bergmann break; 74267207b96SArnd Bergmann } 74367207b96SArnd Bergmann 744eebead5bSChristoph Hellwig out_unlock: 7458b3d6663SArnd Bergmann spu_release(ctx); 746eebead5bSChristoph Hellwig out: 747cdcc89bbSArnd Bergmann return count; 74867207b96SArnd Bergmann } 74967207b96SArnd Bergmann 7508153a5eaSAl Viro static __poll_t spufs_ibox_poll(struct file *file, poll_table *wait) 75167207b96SArnd Bergmann { 7528b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 7538153a5eaSAl Viro __poll_t mask; 75467207b96SArnd Bergmann 7558b3d6663SArnd Bergmann poll_wait(file, &ctx->ibox_wq, wait); 75667207b96SArnd Bergmann 757c9101bdbSChristoph Hellwig /* 758c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 759c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 760c9101bdbSChristoph Hellwig */ 761c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 762a9a08845SLinus Torvalds mask = ctx->ops->mbox_stat_poll(ctx, EPOLLIN | EPOLLRDNORM); 7633a843d7cSArnd Bergmann spu_release(ctx); 76467207b96SArnd Bergmann 76567207b96SArnd Bergmann return mask; 76667207b96SArnd Bergmann } 76767207b96SArnd Bergmann 7685dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_fops = { 76967207b96SArnd Bergmann .open = spufs_pipe_open, 77067207b96SArnd Bergmann .read = spufs_ibox_read, 77167207b96SArnd Bergmann .poll = spufs_ibox_poll, 772fc15351dSArnd Bergmann .llseek = no_llseek, 77367207b96SArnd Bergmann }; 77467207b96SArnd Bergmann 77567207b96SArnd Bergmann static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 77667207b96SArnd Bergmann size_t len, loff_t *pos) 77767207b96SArnd Bergmann { 7788b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 779c9101bdbSChristoph Hellwig ssize_t ret; 78067207b96SArnd Bergmann u32 ibox_stat; 78167207b96SArnd Bergmann 78267207b96SArnd Bergmann if (len < 4) 78367207b96SArnd Bergmann return -EINVAL; 78467207b96SArnd Bergmann 785c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 786c9101bdbSChristoph Hellwig if (ret) 787c9101bdbSChristoph Hellwig return ret; 7888b3d6663SArnd Bergmann ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; 7898b3d6663SArnd Bergmann spu_release(ctx); 79067207b96SArnd Bergmann 79167207b96SArnd Bergmann if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 79267207b96SArnd Bergmann return -EFAULT; 79367207b96SArnd Bergmann 79467207b96SArnd Bergmann return 4; 79567207b96SArnd Bergmann } 79667207b96SArnd Bergmann 7975dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_stat_fops = { 79867207b96SArnd Bergmann .open = spufs_pipe_open, 79967207b96SArnd Bergmann .read = spufs_ibox_stat_read, 800fc15351dSArnd Bergmann .llseek = no_llseek, 80167207b96SArnd Bergmann }; 80267207b96SArnd Bergmann 80367207b96SArnd Bergmann /* low-level mailbox write */ 8048b3d6663SArnd Bergmann size_t spu_wbox_write(struct spu_context *ctx, u32 data) 80567207b96SArnd Bergmann { 8068b3d6663SArnd Bergmann return ctx->ops->wbox_write(ctx, data); 80767207b96SArnd Bergmann } 80867207b96SArnd Bergmann 8098b3d6663SArnd Bergmann /* interrupt-level wbox callback function. */ 8108b3d6663SArnd Bergmann void spufs_wbox_callback(struct spu *spu) 8118b3d6663SArnd Bergmann { 8128b3d6663SArnd Bergmann struct spu_context *ctx = spu->ctx; 8138b3d6663SArnd Bergmann 8147d7be3aaSAl Viro if (ctx) 8158b3d6663SArnd Bergmann wake_up_all(&ctx->wbox_wq); 81667207b96SArnd Bergmann } 81767207b96SArnd Bergmann 818cdcc89bbSArnd Bergmann /* 819cdcc89bbSArnd Bergmann * Write as many bytes to the interrupt mailbox as possible, until 820cdcc89bbSArnd Bergmann * one of the conditions becomes true: 821cdcc89bbSArnd Bergmann * 822cdcc89bbSArnd Bergmann * - the mailbox is full 823cdcc89bbSArnd Bergmann * - end of the user provided buffer 824cdcc89bbSArnd Bergmann * - end of the mapped area 825cdcc89bbSArnd Bergmann * 826cdcc89bbSArnd Bergmann * If the file is opened without O_NONBLOCK, we wait here until 827027dfac6SMichael Ellerman * space is available, but return when we have been able to 828cdcc89bbSArnd Bergmann * write something. 829cdcc89bbSArnd Bergmann */ 83067207b96SArnd Bergmann static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 83167207b96SArnd Bergmann size_t len, loff_t *pos) 83267207b96SArnd Bergmann { 8338b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 8346904d3d0SChristoph Hellwig u32 wbox_data, __user *udata = (void __user *)buf; 835cdcc89bbSArnd Bergmann ssize_t count; 83667207b96SArnd Bergmann 83767207b96SArnd Bergmann if (len < 4) 83867207b96SArnd Bergmann return -EINVAL; 83967207b96SArnd Bergmann 8406904d3d0SChristoph Hellwig if (get_user(wbox_data, udata)) 84167207b96SArnd Bergmann return -EFAULT; 84267207b96SArnd Bergmann 843c9101bdbSChristoph Hellwig count = spu_acquire(ctx); 844c9101bdbSChristoph Hellwig if (count) 845eebead5bSChristoph Hellwig goto out; 8468b3d6663SArnd Bergmann 847cdcc89bbSArnd Bergmann /* 848cdcc89bbSArnd Bergmann * make sure we can at least write one element, by waiting 849cdcc89bbSArnd Bergmann * in case of !O_NONBLOCK 850cdcc89bbSArnd Bergmann */ 851cdcc89bbSArnd Bergmann count = 0; 85267207b96SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 853eebead5bSChristoph Hellwig if (!spu_wbox_write(ctx, wbox_data)) { 854cdcc89bbSArnd Bergmann count = -EAGAIN; 855eebead5bSChristoph Hellwig goto out_unlock; 856eebead5bSChristoph Hellwig } 85767207b96SArnd Bergmann } else { 858cdcc89bbSArnd Bergmann count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); 859cdcc89bbSArnd Bergmann if (count) 860cdcc89bbSArnd Bergmann goto out; 861eebead5bSChristoph Hellwig } 862eebead5bSChristoph Hellwig 8638b3d6663SArnd Bergmann 86496de0e25SJan Engelhardt /* write as much as possible */ 865cdcc89bbSArnd Bergmann for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { 866cdcc89bbSArnd Bergmann int ret; 8676904d3d0SChristoph Hellwig ret = get_user(wbox_data, udata); 868cdcc89bbSArnd Bergmann if (ret) 869cdcc89bbSArnd Bergmann break; 870cdcc89bbSArnd Bergmann 871cdcc89bbSArnd Bergmann ret = spu_wbox_write(ctx, wbox_data); 872cdcc89bbSArnd Bergmann if (ret == 0) 873cdcc89bbSArnd Bergmann break; 874cdcc89bbSArnd Bergmann } 875cdcc89bbSArnd Bergmann 876eebead5bSChristoph Hellwig out_unlock: 877cdcc89bbSArnd Bergmann spu_release(ctx); 878eebead5bSChristoph Hellwig out: 879cdcc89bbSArnd Bergmann return count; 88067207b96SArnd Bergmann } 88167207b96SArnd Bergmann 8828153a5eaSAl Viro static __poll_t spufs_wbox_poll(struct file *file, poll_table *wait) 88367207b96SArnd Bergmann { 8848b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 8858153a5eaSAl Viro __poll_t mask; 88667207b96SArnd Bergmann 8878b3d6663SArnd Bergmann poll_wait(file, &ctx->wbox_wq, wait); 88867207b96SArnd Bergmann 889c9101bdbSChristoph Hellwig /* 890c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 891c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 892c9101bdbSChristoph Hellwig */ 893c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 894a9a08845SLinus Torvalds mask = ctx->ops->mbox_stat_poll(ctx, EPOLLOUT | EPOLLWRNORM); 8953a843d7cSArnd Bergmann spu_release(ctx); 89667207b96SArnd Bergmann 89767207b96SArnd Bergmann return mask; 89867207b96SArnd Bergmann } 89967207b96SArnd Bergmann 9005dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_fops = { 90167207b96SArnd Bergmann .open = spufs_pipe_open, 90267207b96SArnd Bergmann .write = spufs_wbox_write, 90367207b96SArnd Bergmann .poll = spufs_wbox_poll, 904fc15351dSArnd Bergmann .llseek = no_llseek, 90567207b96SArnd Bergmann }; 90667207b96SArnd Bergmann 90767207b96SArnd Bergmann static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 90867207b96SArnd Bergmann size_t len, loff_t *pos) 90967207b96SArnd Bergmann { 9108b3d6663SArnd Bergmann struct spu_context *ctx = file->private_data; 911c9101bdbSChristoph Hellwig ssize_t ret; 91267207b96SArnd Bergmann u32 wbox_stat; 91367207b96SArnd Bergmann 91467207b96SArnd Bergmann if (len < 4) 91567207b96SArnd Bergmann return -EINVAL; 91667207b96SArnd Bergmann 917c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 918c9101bdbSChristoph Hellwig if (ret) 919c9101bdbSChristoph Hellwig return ret; 9208b3d6663SArnd Bergmann wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; 9218b3d6663SArnd Bergmann spu_release(ctx); 92267207b96SArnd Bergmann 92367207b96SArnd Bergmann if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 92467207b96SArnd Bergmann return -EFAULT; 92567207b96SArnd Bergmann 92667207b96SArnd Bergmann return 4; 92767207b96SArnd Bergmann } 92867207b96SArnd Bergmann 9295dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_stat_fops = { 93067207b96SArnd Bergmann .open = spufs_pipe_open, 93167207b96SArnd Bergmann .read = spufs_wbox_stat_read, 932fc15351dSArnd Bergmann .llseek = no_llseek, 93367207b96SArnd Bergmann }; 93467207b96SArnd Bergmann 9356df10a82SMark Nutter static int spufs_signal1_open(struct inode *inode, struct file *file) 9366df10a82SMark Nutter { 9376df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 9386df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 93943c2bbd9SChristoph Hellwig 94047d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 9416df10a82SMark Nutter file->private_data = ctx; 94243c2bbd9SChristoph Hellwig if (!i->i_openers++) 9436df10a82SMark Nutter ctx->signal1 = inode->i_mapping; 94447d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 9456df10a82SMark Nutter return nonseekable_open(inode, file); 9466df10a82SMark Nutter } 9476df10a82SMark Nutter 94843c2bbd9SChristoph Hellwig static int 94943c2bbd9SChristoph Hellwig spufs_signal1_release(struct inode *inode, struct file *file) 95043c2bbd9SChristoph Hellwig { 95143c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 95243c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 95343c2bbd9SChristoph Hellwig 95447d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 95543c2bbd9SChristoph Hellwig if (!--i->i_openers) 95643c2bbd9SChristoph Hellwig ctx->signal1 = NULL; 95747d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 95843c2bbd9SChristoph Hellwig return 0; 95943c2bbd9SChristoph Hellwig } 96043c2bbd9SChristoph Hellwig 9615456ffdeSChristoph Hellwig static ssize_t spufs_signal1_dump(struct spu_context *ctx, 9625456ffdeSChristoph Hellwig struct coredump_params *cprm) 96367207b96SArnd Bergmann { 9645456ffdeSChristoph Hellwig if (!ctx->csa.spu_chnlcnt_RW[3]) 9655456ffdeSChristoph Hellwig return 0; 9665456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[3], 9675456ffdeSChristoph Hellwig sizeof(ctx->csa.spu_chnldata_RW[3])); 96817f88cebSDwayne Grant McConnell } 9698b3d6663SArnd Bergmann 9705456ffdeSChristoph Hellwig static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, 9715456ffdeSChristoph Hellwig size_t len) 9725456ffdeSChristoph Hellwig { 9735456ffdeSChristoph Hellwig if (len < sizeof(ctx->csa.spu_chnldata_RW[3])) 9745456ffdeSChristoph Hellwig return -EINVAL; 9755456ffdeSChristoph Hellwig if (!ctx->csa.spu_chnlcnt_RW[3]) 9765456ffdeSChristoph Hellwig return 0; 9775456ffdeSChristoph Hellwig if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[3], 9785456ffdeSChristoph Hellwig sizeof(ctx->csa.spu_chnldata_RW[3]))) 97967207b96SArnd Bergmann return -EFAULT; 9805456ffdeSChristoph Hellwig return sizeof(ctx->csa.spu_chnldata_RW[3]); 98167207b96SArnd Bergmann } 98267207b96SArnd Bergmann 983bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 984bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 985bf1ab978SDwayne Grant McConnell { 986bf1ab978SDwayne Grant McConnell int ret; 987bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 988bf1ab978SDwayne Grant McConnell 989c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 990c9101bdbSChristoph Hellwig if (ret) 991c9101bdbSChristoph Hellwig return ret; 9925456ffdeSChristoph Hellwig ret = __spufs_signal1_read(ctx, buf, len); 99327b1ea09SChristoph Hellwig spu_release_saved(ctx); 994bf1ab978SDwayne Grant McConnell 995bf1ab978SDwayne Grant McConnell return ret; 996bf1ab978SDwayne Grant McConnell } 997bf1ab978SDwayne Grant McConnell 99867207b96SArnd Bergmann static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, 99967207b96SArnd Bergmann size_t len, loff_t *pos) 100067207b96SArnd Bergmann { 100167207b96SArnd Bergmann struct spu_context *ctx; 1002c9101bdbSChristoph Hellwig ssize_t ret; 100367207b96SArnd Bergmann u32 data; 100467207b96SArnd Bergmann 100567207b96SArnd Bergmann ctx = file->private_data; 100667207b96SArnd Bergmann 100767207b96SArnd Bergmann if (len < 4) 100867207b96SArnd Bergmann return -EINVAL; 100967207b96SArnd Bergmann 101067207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 101167207b96SArnd Bergmann return -EFAULT; 101267207b96SArnd Bergmann 1013c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1014c9101bdbSChristoph Hellwig if (ret) 1015c9101bdbSChristoph Hellwig return ret; 10168b3d6663SArnd Bergmann ctx->ops->signal1_write(ctx, data); 10178b3d6663SArnd Bergmann spu_release(ctx); 101867207b96SArnd Bergmann 101967207b96SArnd Bergmann return 4; 102067207b96SArnd Bergmann } 102167207b96SArnd Bergmann 1022e807f02cSSouptick Joarder static vm_fault_t 102311bac800SDave Jiang spufs_signal1_mmap_fault(struct vm_fault *vmf) 10246df10a82SMark Nutter { 102587ff6090SJeremy Kerr #if SPUFS_SIGNAL_MAP_SIZE == 0x1000 102611bac800SDave Jiang return spufs_ps_fault(vmf, 0x14000, SPUFS_SIGNAL_MAP_SIZE); 102787ff6090SJeremy Kerr #elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 102827d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 102927d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 103027d5bf2aSBenjamin Herrenschmidt */ 103111bac800SDave Jiang return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); 103227d5bf2aSBenjamin Herrenschmidt #else 103327d5bf2aSBenjamin Herrenschmidt #error unsupported page size 103427d5bf2aSBenjamin Herrenschmidt #endif 10356df10a82SMark Nutter } 10366df10a82SMark Nutter 1037f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_signal1_mmap_vmops = { 1038b1e2270fSNick Piggin .fault = spufs_signal1_mmap_fault, 10396df10a82SMark Nutter }; 10406df10a82SMark Nutter 10416df10a82SMark Nutter static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) 10426df10a82SMark Nutter { 10436df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 10446df10a82SMark Nutter return -EINVAL; 10456df10a82SMark Nutter 10461c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP); 104764b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 10486df10a82SMark Nutter 10496df10a82SMark Nutter vma->vm_ops = &spufs_signal1_mmap_vmops; 10506df10a82SMark Nutter return 0; 10516df10a82SMark Nutter } 10526df10a82SMark Nutter 10535dfe4c96SArjan van de Ven static const struct file_operations spufs_signal1_fops = { 10546df10a82SMark Nutter .open = spufs_signal1_open, 105543c2bbd9SChristoph Hellwig .release = spufs_signal1_release, 105667207b96SArnd Bergmann .read = spufs_signal1_read, 105767207b96SArnd Bergmann .write = spufs_signal1_write, 10586df10a82SMark Nutter .mmap = spufs_signal1_mmap, 1059fc15351dSArnd Bergmann .llseek = no_llseek, 106067207b96SArnd Bergmann }; 106167207b96SArnd Bergmann 1062d054b36fSJeremy Kerr static const struct file_operations spufs_signal1_nosched_fops = { 1063d054b36fSJeremy Kerr .open = spufs_signal1_open, 1064d054b36fSJeremy Kerr .release = spufs_signal1_release, 1065d054b36fSJeremy Kerr .write = spufs_signal1_write, 1066d054b36fSJeremy Kerr .mmap = spufs_signal1_mmap, 1067fc15351dSArnd Bergmann .llseek = no_llseek, 1068d054b36fSJeremy Kerr }; 1069d054b36fSJeremy Kerr 10706df10a82SMark Nutter static int spufs_signal2_open(struct inode *inode, struct file *file) 10716df10a82SMark Nutter { 10726df10a82SMark Nutter struct spufs_inode_info *i = SPUFS_I(inode); 10736df10a82SMark Nutter struct spu_context *ctx = i->i_ctx; 107443c2bbd9SChristoph Hellwig 107547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 10766df10a82SMark Nutter file->private_data = ctx; 107743c2bbd9SChristoph Hellwig if (!i->i_openers++) 10786df10a82SMark Nutter ctx->signal2 = inode->i_mapping; 107947d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 10806df10a82SMark Nutter return nonseekable_open(inode, file); 10816df10a82SMark Nutter } 10826df10a82SMark Nutter 108343c2bbd9SChristoph Hellwig static int 108443c2bbd9SChristoph Hellwig spufs_signal2_release(struct inode *inode, struct file *file) 108543c2bbd9SChristoph Hellwig { 108643c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 108743c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 108843c2bbd9SChristoph Hellwig 108947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 109043c2bbd9SChristoph Hellwig if (!--i->i_openers) 109143c2bbd9SChristoph Hellwig ctx->signal2 = NULL; 109247d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 109343c2bbd9SChristoph Hellwig return 0; 109443c2bbd9SChristoph Hellwig } 109543c2bbd9SChristoph Hellwig 10965456ffdeSChristoph Hellwig static ssize_t spufs_signal2_dump(struct spu_context *ctx, 10975456ffdeSChristoph Hellwig struct coredump_params *cprm) 109867207b96SArnd Bergmann { 10995456ffdeSChristoph Hellwig if (!ctx->csa.spu_chnlcnt_RW[4]) 11005456ffdeSChristoph Hellwig return 0; 11015456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[4], 11025456ffdeSChristoph Hellwig sizeof(ctx->csa.spu_chnldata_RW[4])); 110317f88cebSDwayne Grant McConnell } 11048b3d6663SArnd Bergmann 11055456ffdeSChristoph Hellwig static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, 11065456ffdeSChristoph Hellwig size_t len) 11075456ffdeSChristoph Hellwig { 11085456ffdeSChristoph Hellwig if (len < sizeof(ctx->csa.spu_chnldata_RW[4])) 11095456ffdeSChristoph Hellwig return -EINVAL; 11105456ffdeSChristoph Hellwig if (!ctx->csa.spu_chnlcnt_RW[4]) 11115456ffdeSChristoph Hellwig return 0; 11125456ffdeSChristoph Hellwig if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[4], 11135456ffdeSChristoph Hellwig sizeof(ctx->csa.spu_chnldata_RW[4]))) 111467207b96SArnd Bergmann return -EFAULT; 11155456ffdeSChristoph Hellwig return sizeof(ctx->csa.spu_chnldata_RW[4]); 1116bf1ab978SDwayne Grant McConnell } 1117bf1ab978SDwayne Grant McConnell 1118bf1ab978SDwayne Grant McConnell static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 1119bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 1120bf1ab978SDwayne Grant McConnell { 1121bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 1122bf1ab978SDwayne Grant McConnell int ret; 1123bf1ab978SDwayne Grant McConnell 1124c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1125c9101bdbSChristoph Hellwig if (ret) 1126c9101bdbSChristoph Hellwig return ret; 11275456ffdeSChristoph Hellwig ret = __spufs_signal2_read(ctx, buf, len); 112827b1ea09SChristoph Hellwig spu_release_saved(ctx); 1129bf1ab978SDwayne Grant McConnell 1130bf1ab978SDwayne Grant McConnell return ret; 113167207b96SArnd Bergmann } 113267207b96SArnd Bergmann 113367207b96SArnd Bergmann static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, 113467207b96SArnd Bergmann size_t len, loff_t *pos) 113567207b96SArnd Bergmann { 113667207b96SArnd Bergmann struct spu_context *ctx; 1137c9101bdbSChristoph Hellwig ssize_t ret; 113867207b96SArnd Bergmann u32 data; 113967207b96SArnd Bergmann 114067207b96SArnd Bergmann ctx = file->private_data; 114167207b96SArnd Bergmann 114267207b96SArnd Bergmann if (len < 4) 114367207b96SArnd Bergmann return -EINVAL; 114467207b96SArnd Bergmann 114567207b96SArnd Bergmann if (copy_from_user(&data, buf, 4)) 114667207b96SArnd Bergmann return -EFAULT; 114767207b96SArnd Bergmann 1148c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1149c9101bdbSChristoph Hellwig if (ret) 1150c9101bdbSChristoph Hellwig return ret; 11518b3d6663SArnd Bergmann ctx->ops->signal2_write(ctx, data); 11528b3d6663SArnd Bergmann spu_release(ctx); 115367207b96SArnd Bergmann 115467207b96SArnd Bergmann return 4; 115567207b96SArnd Bergmann } 115667207b96SArnd Bergmann 115727d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1158e807f02cSSouptick Joarder static vm_fault_t 115911bac800SDave Jiang spufs_signal2_mmap_fault(struct vm_fault *vmf) 11606df10a82SMark Nutter { 116187ff6090SJeremy Kerr #if SPUFS_SIGNAL_MAP_SIZE == 0x1000 116211bac800SDave Jiang return spufs_ps_fault(vmf, 0x1c000, SPUFS_SIGNAL_MAP_SIZE); 116387ff6090SJeremy Kerr #elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 116427d5bf2aSBenjamin Herrenschmidt /* For 64k pages, both signal1 and signal2 can be used to mmap the whole 116527d5bf2aSBenjamin Herrenschmidt * signal 1 and 2 area 116627d5bf2aSBenjamin Herrenschmidt */ 116711bac800SDave Jiang return spufs_ps_fault(vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); 116827d5bf2aSBenjamin Herrenschmidt #else 116927d5bf2aSBenjamin Herrenschmidt #error unsupported page size 117027d5bf2aSBenjamin Herrenschmidt #endif 11716df10a82SMark Nutter } 11726df10a82SMark Nutter 1173f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_signal2_mmap_vmops = { 1174b1e2270fSNick Piggin .fault = spufs_signal2_mmap_fault, 11756df10a82SMark Nutter }; 11766df10a82SMark Nutter 11776df10a82SMark Nutter static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) 11786df10a82SMark Nutter { 11796df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 11806df10a82SMark Nutter return -EINVAL; 11816df10a82SMark Nutter 11821c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP); 118364b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 11846df10a82SMark Nutter 11856df10a82SMark Nutter vma->vm_ops = &spufs_signal2_mmap_vmops; 11866df10a82SMark Nutter return 0; 11876df10a82SMark Nutter } 118827d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 118927d5bf2aSBenjamin Herrenschmidt #define spufs_signal2_mmap NULL 119027d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 11916df10a82SMark Nutter 11925dfe4c96SArjan van de Ven static const struct file_operations spufs_signal2_fops = { 11936df10a82SMark Nutter .open = spufs_signal2_open, 119443c2bbd9SChristoph Hellwig .release = spufs_signal2_release, 119567207b96SArnd Bergmann .read = spufs_signal2_read, 119667207b96SArnd Bergmann .write = spufs_signal2_write, 11976df10a82SMark Nutter .mmap = spufs_signal2_mmap, 1198fc15351dSArnd Bergmann .llseek = no_llseek, 119967207b96SArnd Bergmann }; 120067207b96SArnd Bergmann 1201d054b36fSJeremy Kerr static const struct file_operations spufs_signal2_nosched_fops = { 1202d054b36fSJeremy Kerr .open = spufs_signal2_open, 1203d054b36fSJeremy Kerr .release = spufs_signal2_release, 1204d054b36fSJeremy Kerr .write = spufs_signal2_write, 1205d054b36fSJeremy Kerr .mmap = spufs_signal2_mmap, 1206fc15351dSArnd Bergmann .llseek = no_llseek, 1207d054b36fSJeremy Kerr }; 1208d054b36fSJeremy Kerr 1209104f0cc2SMichael Ellerman /* 1210104f0cc2SMichael Ellerman * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the 1211104f0cc2SMichael Ellerman * work of acquiring (or not) the SPU context before calling through 1212104f0cc2SMichael Ellerman * to the actual get routine. The set routine is called directly. 1213104f0cc2SMichael Ellerman */ 1214104f0cc2SMichael Ellerman #define SPU_ATTR_NOACQUIRE 0 1215104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE 1 1216104f0cc2SMichael Ellerman #define SPU_ATTR_ACQUIRE_SAVED 2 1217104f0cc2SMichael Ellerman 1218104f0cc2SMichael Ellerman #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ 1219197b1a82SChristoph Hellwig static int __##__get(void *data, u64 *val) \ 1220104f0cc2SMichael Ellerman { \ 1221104f0cc2SMichael Ellerman struct spu_context *ctx = data; \ 1222c9101bdbSChristoph Hellwig int ret = 0; \ 1223104f0cc2SMichael Ellerman \ 1224104f0cc2SMichael Ellerman if (__acquire == SPU_ATTR_ACQUIRE) { \ 1225c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); \ 1226c9101bdbSChristoph Hellwig if (ret) \ 1227c9101bdbSChristoph Hellwig return ret; \ 1228197b1a82SChristoph Hellwig *val = __get(ctx); \ 1229104f0cc2SMichael Ellerman spu_release(ctx); \ 1230104f0cc2SMichael Ellerman } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ 1231c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); \ 1232c9101bdbSChristoph Hellwig if (ret) \ 1233c9101bdbSChristoph Hellwig return ret; \ 1234197b1a82SChristoph Hellwig *val = __get(ctx); \ 1235104f0cc2SMichael Ellerman spu_release_saved(ctx); \ 1236104f0cc2SMichael Ellerman } else \ 1237197b1a82SChristoph Hellwig *val = __get(ctx); \ 1238104f0cc2SMichael Ellerman \ 1239197b1a82SChristoph Hellwig return 0; \ 1240104f0cc2SMichael Ellerman } \ 1241197b1a82SChristoph Hellwig DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); 1242104f0cc2SMichael Ellerman 1243197b1a82SChristoph Hellwig static int spufs_signal1_type_set(void *data, u64 val) 124467207b96SArnd Bergmann { 124567207b96SArnd Bergmann struct spu_context *ctx = data; 1246c9101bdbSChristoph Hellwig int ret; 124767207b96SArnd Bergmann 1248c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1249c9101bdbSChristoph Hellwig if (ret) 1250c9101bdbSChristoph Hellwig return ret; 12518b3d6663SArnd Bergmann ctx->ops->signal1_type_set(ctx, val); 12528b3d6663SArnd Bergmann spu_release(ctx); 1253197b1a82SChristoph Hellwig 1254197b1a82SChristoph Hellwig return 0; 125567207b96SArnd Bergmann } 125667207b96SArnd Bergmann 1257104f0cc2SMichael Ellerman static u64 spufs_signal1_type_get(struct spu_context *ctx) 1258bf1ab978SDwayne Grant McConnell { 1259bf1ab978SDwayne Grant McConnell return ctx->ops->signal1_type_get(ctx); 1260bf1ab978SDwayne Grant McConnell } 1261104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 1262af8b44e0SJeremy Kerr spufs_signal1_type_set, "%llu\n", SPU_ATTR_ACQUIRE); 1263bf1ab978SDwayne Grant McConnell 126467207b96SArnd Bergmann 1265197b1a82SChristoph Hellwig static int spufs_signal2_type_set(void *data, u64 val) 126667207b96SArnd Bergmann { 126767207b96SArnd Bergmann struct spu_context *ctx = data; 1268c9101bdbSChristoph Hellwig int ret; 126967207b96SArnd Bergmann 1270c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1271c9101bdbSChristoph Hellwig if (ret) 1272c9101bdbSChristoph Hellwig return ret; 12738b3d6663SArnd Bergmann ctx->ops->signal2_type_set(ctx, val); 12748b3d6663SArnd Bergmann spu_release(ctx); 1275197b1a82SChristoph Hellwig 1276197b1a82SChristoph Hellwig return 0; 127767207b96SArnd Bergmann } 127867207b96SArnd Bergmann 1279104f0cc2SMichael Ellerman static u64 spufs_signal2_type_get(struct spu_context *ctx) 1280bf1ab978SDwayne Grant McConnell { 1281bf1ab978SDwayne Grant McConnell return ctx->ops->signal2_type_get(ctx); 1282bf1ab978SDwayne Grant McConnell } 1283104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 1284af8b44e0SJeremy Kerr spufs_signal2_type_set, "%llu\n", SPU_ATTR_ACQUIRE); 128567207b96SArnd Bergmann 128627d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1287e807f02cSSouptick Joarder static vm_fault_t 128811bac800SDave Jiang spufs_mss_mmap_fault(struct vm_fault *vmf) 1289d9379c4bSarnd@arndb.de { 129011bac800SDave Jiang return spufs_ps_fault(vmf, 0x0000, SPUFS_MSS_MAP_SIZE); 1291d9379c4bSarnd@arndb.de } 1292d9379c4bSarnd@arndb.de 1293f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mss_mmap_vmops = { 1294b1e2270fSNick Piggin .fault = spufs_mss_mmap_fault, 1295d9379c4bSarnd@arndb.de }; 1296d9379c4bSarnd@arndb.de 1297d9379c4bSarnd@arndb.de /* 1298d9379c4bSarnd@arndb.de * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 1299d9379c4bSarnd@arndb.de */ 1300d9379c4bSarnd@arndb.de static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 1301d9379c4bSarnd@arndb.de { 1302d9379c4bSarnd@arndb.de if (!(vma->vm_flags & VM_SHARED)) 1303d9379c4bSarnd@arndb.de return -EINVAL; 1304d9379c4bSarnd@arndb.de 13051c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP); 130664b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 1307d9379c4bSarnd@arndb.de 1308d9379c4bSarnd@arndb.de vma->vm_ops = &spufs_mss_mmap_vmops; 1309d9379c4bSarnd@arndb.de return 0; 1310d9379c4bSarnd@arndb.de } 131127d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 131227d5bf2aSBenjamin Herrenschmidt #define spufs_mss_mmap NULL 131327d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1314d9379c4bSarnd@arndb.de 1315d9379c4bSarnd@arndb.de static int spufs_mss_open(struct inode *inode, struct file *file) 1316d9379c4bSarnd@arndb.de { 1317d9379c4bSarnd@arndb.de struct spufs_inode_info *i = SPUFS_I(inode); 131817e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 1319d9379c4bSarnd@arndb.de 1320d9379c4bSarnd@arndb.de file->private_data = i->i_ctx; 132143c2bbd9SChristoph Hellwig 132247d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 132343c2bbd9SChristoph Hellwig if (!i->i_openers++) 132417e0e270SBenjamin Herrenschmidt ctx->mss = inode->i_mapping; 132547d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1326d9379c4bSarnd@arndb.de return nonseekable_open(inode, file); 1327d9379c4bSarnd@arndb.de } 1328d9379c4bSarnd@arndb.de 132943c2bbd9SChristoph Hellwig static int 133043c2bbd9SChristoph Hellwig spufs_mss_release(struct inode *inode, struct file *file) 133143c2bbd9SChristoph Hellwig { 133243c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 133343c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 133443c2bbd9SChristoph Hellwig 133547d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 133643c2bbd9SChristoph Hellwig if (!--i->i_openers) 133743c2bbd9SChristoph Hellwig ctx->mss = NULL; 133847d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 133943c2bbd9SChristoph Hellwig return 0; 134043c2bbd9SChristoph Hellwig } 134143c2bbd9SChristoph Hellwig 13425dfe4c96SArjan van de Ven static const struct file_operations spufs_mss_fops = { 1343d9379c4bSarnd@arndb.de .open = spufs_mss_open, 134443c2bbd9SChristoph Hellwig .release = spufs_mss_release, 1345d9379c4bSarnd@arndb.de .mmap = spufs_mss_mmap, 1346fc15351dSArnd Bergmann .llseek = no_llseek, 134727d5bf2aSBenjamin Herrenschmidt }; 134827d5bf2aSBenjamin Herrenschmidt 1349e807f02cSSouptick Joarder static vm_fault_t 135011bac800SDave Jiang spufs_psmap_mmap_fault(struct vm_fault *vmf) 135127d5bf2aSBenjamin Herrenschmidt { 135211bac800SDave Jiang return spufs_ps_fault(vmf, 0x0000, SPUFS_PS_MAP_SIZE); 135327d5bf2aSBenjamin Herrenschmidt } 135427d5bf2aSBenjamin Herrenschmidt 1355f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_psmap_mmap_vmops = { 1356b1e2270fSNick Piggin .fault = spufs_psmap_mmap_fault, 135727d5bf2aSBenjamin Herrenschmidt }; 135827d5bf2aSBenjamin Herrenschmidt 135927d5bf2aSBenjamin Herrenschmidt /* 136027d5bf2aSBenjamin Herrenschmidt * mmap support for full problem state area [0x00000 - 0x1ffff]. 136127d5bf2aSBenjamin Herrenschmidt */ 136227d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 136327d5bf2aSBenjamin Herrenschmidt { 136427d5bf2aSBenjamin Herrenschmidt if (!(vma->vm_flags & VM_SHARED)) 136527d5bf2aSBenjamin Herrenschmidt return -EINVAL; 136627d5bf2aSBenjamin Herrenschmidt 13671c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP); 136864b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 136927d5bf2aSBenjamin Herrenschmidt 137027d5bf2aSBenjamin Herrenschmidt vma->vm_ops = &spufs_psmap_mmap_vmops; 137127d5bf2aSBenjamin Herrenschmidt return 0; 137227d5bf2aSBenjamin Herrenschmidt } 137327d5bf2aSBenjamin Herrenschmidt 137427d5bf2aSBenjamin Herrenschmidt static int spufs_psmap_open(struct inode *inode, struct file *file) 137527d5bf2aSBenjamin Herrenschmidt { 137627d5bf2aSBenjamin Herrenschmidt struct spufs_inode_info *i = SPUFS_I(inode); 137717e0e270SBenjamin Herrenschmidt struct spu_context *ctx = i->i_ctx; 137827d5bf2aSBenjamin Herrenschmidt 137947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 138027d5bf2aSBenjamin Herrenschmidt file->private_data = i->i_ctx; 138143c2bbd9SChristoph Hellwig if (!i->i_openers++) 138217e0e270SBenjamin Herrenschmidt ctx->psmap = inode->i_mapping; 138347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 138427d5bf2aSBenjamin Herrenschmidt return nonseekable_open(inode, file); 138527d5bf2aSBenjamin Herrenschmidt } 138627d5bf2aSBenjamin Herrenschmidt 138743c2bbd9SChristoph Hellwig static int 138843c2bbd9SChristoph Hellwig spufs_psmap_release(struct inode *inode, struct file *file) 138943c2bbd9SChristoph Hellwig { 139043c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 139143c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 139243c2bbd9SChristoph Hellwig 139347d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 139443c2bbd9SChristoph Hellwig if (!--i->i_openers) 139543c2bbd9SChristoph Hellwig ctx->psmap = NULL; 139647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 139743c2bbd9SChristoph Hellwig return 0; 139843c2bbd9SChristoph Hellwig } 139943c2bbd9SChristoph Hellwig 14005dfe4c96SArjan van de Ven static const struct file_operations spufs_psmap_fops = { 140127d5bf2aSBenjamin Herrenschmidt .open = spufs_psmap_open, 140243c2bbd9SChristoph Hellwig .release = spufs_psmap_release, 140327d5bf2aSBenjamin Herrenschmidt .mmap = spufs_psmap_mmap, 1404fc15351dSArnd Bergmann .llseek = no_llseek, 1405d9379c4bSarnd@arndb.de }; 1406d9379c4bSarnd@arndb.de 1407d9379c4bSarnd@arndb.de 140827d5bf2aSBenjamin Herrenschmidt #if SPUFS_MMAP_4K 1409e807f02cSSouptick Joarder static vm_fault_t 141011bac800SDave Jiang spufs_mfc_mmap_fault(struct vm_fault *vmf) 14116df10a82SMark Nutter { 141211bac800SDave Jiang return spufs_ps_fault(vmf, 0x3000, SPUFS_MFC_MAP_SIZE); 14136df10a82SMark Nutter } 14146df10a82SMark Nutter 1415f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct spufs_mfc_mmap_vmops = { 1416b1e2270fSNick Piggin .fault = spufs_mfc_mmap_fault, 14176df10a82SMark Nutter }; 14186df10a82SMark Nutter 14196df10a82SMark Nutter /* 14206df10a82SMark Nutter * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. 14216df10a82SMark Nutter */ 14226df10a82SMark Nutter static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) 14236df10a82SMark Nutter { 14246df10a82SMark Nutter if (!(vma->vm_flags & VM_SHARED)) 14256df10a82SMark Nutter return -EINVAL; 14266df10a82SMark Nutter 14271c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP); 142864b3d0e8SBenjamin Herrenschmidt vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 14296df10a82SMark Nutter 14306df10a82SMark Nutter vma->vm_ops = &spufs_mfc_mmap_vmops; 14316df10a82SMark Nutter return 0; 14326df10a82SMark Nutter } 143327d5bf2aSBenjamin Herrenschmidt #else /* SPUFS_MMAP_4K */ 143427d5bf2aSBenjamin Herrenschmidt #define spufs_mfc_mmap NULL 143527d5bf2aSBenjamin Herrenschmidt #endif /* !SPUFS_MMAP_4K */ 1436a33a7d73SArnd Bergmann 1437a33a7d73SArnd Bergmann static int spufs_mfc_open(struct inode *inode, struct file *file) 1438a33a7d73SArnd Bergmann { 1439a33a7d73SArnd Bergmann struct spufs_inode_info *i = SPUFS_I(inode); 1440a33a7d73SArnd Bergmann struct spu_context *ctx = i->i_ctx; 1441a33a7d73SArnd Bergmann 1442a33a7d73SArnd Bergmann /* we don't want to deal with DMA into other processes */ 1443a33a7d73SArnd Bergmann if (ctx->owner != current->mm) 1444a33a7d73SArnd Bergmann return -EINVAL; 1445a33a7d73SArnd Bergmann 1446a33a7d73SArnd Bergmann if (atomic_read(&inode->i_count) != 1) 1447a33a7d73SArnd Bergmann return -EBUSY; 1448a33a7d73SArnd Bergmann 144947d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 1450a33a7d73SArnd Bergmann file->private_data = ctx; 145143c2bbd9SChristoph Hellwig if (!i->i_openers++) 145217e0e270SBenjamin Herrenschmidt ctx->mfc = inode->i_mapping; 145347d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 1454a33a7d73SArnd Bergmann return nonseekable_open(inode, file); 1455a33a7d73SArnd Bergmann } 1456a33a7d73SArnd Bergmann 145743c2bbd9SChristoph Hellwig static int 145843c2bbd9SChristoph Hellwig spufs_mfc_release(struct inode *inode, struct file *file) 145943c2bbd9SChristoph Hellwig { 146043c2bbd9SChristoph Hellwig struct spufs_inode_info *i = SPUFS_I(inode); 146143c2bbd9SChristoph Hellwig struct spu_context *ctx = i->i_ctx; 146243c2bbd9SChristoph Hellwig 146347d3a5faSChristoph Hellwig mutex_lock(&ctx->mapping_lock); 146443c2bbd9SChristoph Hellwig if (!--i->i_openers) 146543c2bbd9SChristoph Hellwig ctx->mfc = NULL; 146647d3a5faSChristoph Hellwig mutex_unlock(&ctx->mapping_lock); 146743c2bbd9SChristoph Hellwig return 0; 146843c2bbd9SChristoph Hellwig } 146943c2bbd9SChristoph Hellwig 1470a33a7d73SArnd Bergmann /* interrupt-level mfc callback function. */ 1471a33a7d73SArnd Bergmann void spufs_mfc_callback(struct spu *spu) 1472a33a7d73SArnd Bergmann { 1473a33a7d73SArnd Bergmann struct spu_context *ctx = spu->ctx; 1474a33a7d73SArnd Bergmann 14757d7be3aaSAl Viro if (ctx) 1476a33a7d73SArnd Bergmann wake_up_all(&ctx->mfc_wq); 1477a33a7d73SArnd Bergmann } 1478a33a7d73SArnd Bergmann 1479a33a7d73SArnd Bergmann static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) 1480a33a7d73SArnd Bergmann { 1481a33a7d73SArnd Bergmann /* See if there is one tag group is complete */ 1482a33a7d73SArnd Bergmann /* FIXME we need locking around tagwait */ 1483a33a7d73SArnd Bergmann *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; 1484a33a7d73SArnd Bergmann ctx->tagwait &= ~*status; 1485a33a7d73SArnd Bergmann if (*status) 1486a33a7d73SArnd Bergmann return 1; 1487a33a7d73SArnd Bergmann 1488a33a7d73SArnd Bergmann /* enable interrupt waiting for any tag group, 1489a33a7d73SArnd Bergmann may silently fail if interrupts are already enabled */ 1490a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1491a33a7d73SArnd Bergmann return 0; 1492a33a7d73SArnd Bergmann } 1493a33a7d73SArnd Bergmann 1494a33a7d73SArnd Bergmann static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, 1495a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1496a33a7d73SArnd Bergmann { 1497a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1498a33a7d73SArnd Bergmann int ret = -EINVAL; 1499a33a7d73SArnd Bergmann u32 status; 1500a33a7d73SArnd Bergmann 1501a33a7d73SArnd Bergmann if (size != 4) 1502a33a7d73SArnd Bergmann goto out; 1503a33a7d73SArnd Bergmann 1504c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1505c9101bdbSChristoph Hellwig if (ret) 1506c9101bdbSChristoph Hellwig return ret; 1507c9101bdbSChristoph Hellwig 1508c9101bdbSChristoph Hellwig ret = -EINVAL; 1509a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1510a33a7d73SArnd Bergmann status = ctx->ops->read_mfc_tagstatus(ctx); 1511a33a7d73SArnd Bergmann if (!(status & ctx->tagwait)) 1512a33a7d73SArnd Bergmann ret = -EAGAIN; 1513a33a7d73SArnd Bergmann else 1514c9101bdbSChristoph Hellwig /* XXX(hch): shouldn't we clear ret here? */ 1515a33a7d73SArnd Bergmann ctx->tagwait &= ~status; 1516a33a7d73SArnd Bergmann } else { 1517a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1518a33a7d73SArnd Bergmann spufs_read_mfc_tagstatus(ctx, &status)); 1519a33a7d73SArnd Bergmann if (ret) 1520a33a7d73SArnd Bergmann goto out; 1521eebead5bSChristoph Hellwig } 1522eebead5bSChristoph Hellwig spu_release(ctx); 1523a33a7d73SArnd Bergmann 1524a33a7d73SArnd Bergmann ret = 4; 1525a33a7d73SArnd Bergmann if (copy_to_user(buffer, &status, 4)) 1526a33a7d73SArnd Bergmann ret = -EFAULT; 1527a33a7d73SArnd Bergmann 1528a33a7d73SArnd Bergmann out: 1529a33a7d73SArnd Bergmann return ret; 1530a33a7d73SArnd Bergmann } 1531a33a7d73SArnd Bergmann 1532a33a7d73SArnd Bergmann static int spufs_check_valid_dma(struct mfc_dma_command *cmd) 1533a33a7d73SArnd Bergmann { 15349477e455SStephen Rothwell pr_debug("queueing DMA %x %llx %x %x %x\n", cmd->lsa, 1535a33a7d73SArnd Bergmann cmd->ea, cmd->size, cmd->tag, cmd->cmd); 1536a33a7d73SArnd Bergmann 1537a33a7d73SArnd Bergmann switch (cmd->cmd) { 1538a33a7d73SArnd Bergmann case MFC_PUT_CMD: 1539a33a7d73SArnd Bergmann case MFC_PUTF_CMD: 1540a33a7d73SArnd Bergmann case MFC_PUTB_CMD: 1541a33a7d73SArnd Bergmann case MFC_GET_CMD: 1542a33a7d73SArnd Bergmann case MFC_GETF_CMD: 1543a33a7d73SArnd Bergmann case MFC_GETB_CMD: 1544a33a7d73SArnd Bergmann break; 1545a33a7d73SArnd Bergmann default: 1546a33a7d73SArnd Bergmann pr_debug("invalid DMA opcode %x\n", cmd->cmd); 1547a33a7d73SArnd Bergmann return -EIO; 1548a33a7d73SArnd Bergmann } 1549a33a7d73SArnd Bergmann 1550a33a7d73SArnd Bergmann if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { 15519477e455SStephen Rothwell pr_debug("invalid DMA alignment, ea %llx lsa %x\n", 1552a33a7d73SArnd Bergmann cmd->ea, cmd->lsa); 1553a33a7d73SArnd Bergmann return -EIO; 1554a33a7d73SArnd Bergmann } 1555a33a7d73SArnd Bergmann 1556a33a7d73SArnd Bergmann switch (cmd->size & 0xf) { 1557a33a7d73SArnd Bergmann case 1: 1558a33a7d73SArnd Bergmann break; 1559a33a7d73SArnd Bergmann case 2: 1560a33a7d73SArnd Bergmann if (cmd->lsa & 1) 1561a33a7d73SArnd Bergmann goto error; 1562a33a7d73SArnd Bergmann break; 1563a33a7d73SArnd Bergmann case 4: 1564a33a7d73SArnd Bergmann if (cmd->lsa & 3) 1565a33a7d73SArnd Bergmann goto error; 1566a33a7d73SArnd Bergmann break; 1567a33a7d73SArnd Bergmann case 8: 1568a33a7d73SArnd Bergmann if (cmd->lsa & 7) 1569a33a7d73SArnd Bergmann goto error; 1570a33a7d73SArnd Bergmann break; 1571a33a7d73SArnd Bergmann case 0: 1572a33a7d73SArnd Bergmann if (cmd->lsa & 15) 1573a33a7d73SArnd Bergmann goto error; 1574a33a7d73SArnd Bergmann break; 1575a33a7d73SArnd Bergmann error: 1576a33a7d73SArnd Bergmann default: 1577a33a7d73SArnd Bergmann pr_debug("invalid DMA alignment %x for size %x\n", 1578a33a7d73SArnd Bergmann cmd->lsa & 0xf, cmd->size); 1579a33a7d73SArnd Bergmann return -EIO; 1580a33a7d73SArnd Bergmann } 1581a33a7d73SArnd Bergmann 1582a33a7d73SArnd Bergmann if (cmd->size > 16 * 1024) { 1583a33a7d73SArnd Bergmann pr_debug("invalid DMA size %x\n", cmd->size); 1584a33a7d73SArnd Bergmann return -EIO; 1585a33a7d73SArnd Bergmann } 1586a33a7d73SArnd Bergmann 1587a33a7d73SArnd Bergmann if (cmd->tag & 0xfff0) { 1588a33a7d73SArnd Bergmann /* we reserve the higher tag numbers for kernel use */ 1589a33a7d73SArnd Bergmann pr_debug("invalid DMA tag\n"); 1590a33a7d73SArnd Bergmann return -EIO; 1591a33a7d73SArnd Bergmann } 1592a33a7d73SArnd Bergmann 1593a33a7d73SArnd Bergmann if (cmd->class) { 1594a33a7d73SArnd Bergmann /* not supported in this version */ 1595a33a7d73SArnd Bergmann pr_debug("invalid DMA class\n"); 1596a33a7d73SArnd Bergmann return -EIO; 1597a33a7d73SArnd Bergmann } 1598a33a7d73SArnd Bergmann 1599a33a7d73SArnd Bergmann return 0; 1600a33a7d73SArnd Bergmann } 1601a33a7d73SArnd Bergmann 1602a33a7d73SArnd Bergmann static int spu_send_mfc_command(struct spu_context *ctx, 1603a33a7d73SArnd Bergmann struct mfc_dma_command cmd, 1604a33a7d73SArnd Bergmann int *error) 1605a33a7d73SArnd Bergmann { 1606a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1607a33a7d73SArnd Bergmann if (*error == -EAGAIN) { 1608a33a7d73SArnd Bergmann /* wait for any tag group to complete 1609a33a7d73SArnd Bergmann so we have space for the new command */ 1610a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); 1611a33a7d73SArnd Bergmann /* try again, because the queue might be 1612a33a7d73SArnd Bergmann empty again */ 1613a33a7d73SArnd Bergmann *error = ctx->ops->send_mfc_command(ctx, &cmd); 1614a33a7d73SArnd Bergmann if (*error == -EAGAIN) 1615a33a7d73SArnd Bergmann return 0; 1616a33a7d73SArnd Bergmann } 1617a33a7d73SArnd Bergmann return 1; 1618a33a7d73SArnd Bergmann } 1619a33a7d73SArnd Bergmann 1620a33a7d73SArnd Bergmann static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, 1621a33a7d73SArnd Bergmann size_t size, loff_t *pos) 1622a33a7d73SArnd Bergmann { 1623a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1624a33a7d73SArnd Bergmann struct mfc_dma_command cmd; 1625a33a7d73SArnd Bergmann int ret = -EINVAL; 1626a33a7d73SArnd Bergmann 1627a33a7d73SArnd Bergmann if (size != sizeof cmd) 1628a33a7d73SArnd Bergmann goto out; 1629a33a7d73SArnd Bergmann 1630a33a7d73SArnd Bergmann ret = -EFAULT; 1631a33a7d73SArnd Bergmann if (copy_from_user(&cmd, buffer, sizeof cmd)) 1632a33a7d73SArnd Bergmann goto out; 1633a33a7d73SArnd Bergmann 1634a33a7d73SArnd Bergmann ret = spufs_check_valid_dma(&cmd); 1635a33a7d73SArnd Bergmann if (ret) 1636a33a7d73SArnd Bergmann goto out; 1637a33a7d73SArnd Bergmann 1638c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1639c9101bdbSChristoph Hellwig if (ret) 1640c9101bdbSChristoph Hellwig goto out; 1641c9101bdbSChristoph Hellwig 164233bfd7a7SArnd Bergmann ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); 1643577f8f10SAkinobu Mita if (ret) 1644577f8f10SAkinobu Mita goto out; 1645577f8f10SAkinobu Mita 1646a33a7d73SArnd Bergmann if (file->f_flags & O_NONBLOCK) { 1647a33a7d73SArnd Bergmann ret = ctx->ops->send_mfc_command(ctx, &cmd); 1648a33a7d73SArnd Bergmann } else { 1649a33a7d73SArnd Bergmann int status; 1650a33a7d73SArnd Bergmann ret = spufs_wait(ctx->mfc_wq, 1651a33a7d73SArnd Bergmann spu_send_mfc_command(ctx, cmd, &status)); 1652eebead5bSChristoph Hellwig if (ret) 1653eebead5bSChristoph Hellwig goto out; 1654a33a7d73SArnd Bergmann if (status) 1655a33a7d73SArnd Bergmann ret = status; 1656a33a7d73SArnd Bergmann } 1657a33a7d73SArnd Bergmann 1658a33a7d73SArnd Bergmann if (ret) 1659933b0e35SKazunori Asayama goto out_unlock; 1660a33a7d73SArnd Bergmann 1661a33a7d73SArnd Bergmann ctx->tagwait |= 1 << cmd.tag; 16623692dc66SMasato Noguchi ret = size; 1663a33a7d73SArnd Bergmann 1664933b0e35SKazunori Asayama out_unlock: 1665933b0e35SKazunori Asayama spu_release(ctx); 1666a33a7d73SArnd Bergmann out: 1667a33a7d73SArnd Bergmann return ret; 1668a33a7d73SArnd Bergmann } 1669a33a7d73SArnd Bergmann 16708153a5eaSAl Viro static __poll_t spufs_mfc_poll(struct file *file,poll_table *wait) 1671a33a7d73SArnd Bergmann { 1672a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1673a33a7d73SArnd Bergmann u32 free_elements, tagstatus; 16748153a5eaSAl Viro __poll_t mask; 1675a33a7d73SArnd Bergmann 1676933b0e35SKazunori Asayama poll_wait(file, &ctx->mfc_wq, wait); 1677933b0e35SKazunori Asayama 1678c9101bdbSChristoph Hellwig /* 1679c9101bdbSChristoph Hellwig * For now keep this uninterruptible and also ignore the rule 1680c9101bdbSChristoph Hellwig * that poll should not sleep. Will be fixed later. 1681c9101bdbSChristoph Hellwig */ 1682c9101bdbSChristoph Hellwig mutex_lock(&ctx->state_mutex); 1683a33a7d73SArnd Bergmann ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); 1684a33a7d73SArnd Bergmann free_elements = ctx->ops->get_mfc_free_elements(ctx); 1685a33a7d73SArnd Bergmann tagstatus = ctx->ops->read_mfc_tagstatus(ctx); 1686a33a7d73SArnd Bergmann spu_release(ctx); 1687a33a7d73SArnd Bergmann 1688a33a7d73SArnd Bergmann mask = 0; 1689a33a7d73SArnd Bergmann if (free_elements & 0xffff) 1690a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 1691a33a7d73SArnd Bergmann if (tagstatus & ctx->tagwait) 1692a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 1693a33a7d73SArnd Bergmann 1694e48b1b45SHarvey Harrison pr_debug("%s: free %d tagstatus %d tagwait %d\n", __func__, 1695a33a7d73SArnd Bergmann free_elements, tagstatus, ctx->tagwait); 1696a33a7d73SArnd Bergmann 1697a33a7d73SArnd Bergmann return mask; 1698a33a7d73SArnd Bergmann } 1699a33a7d73SArnd Bergmann 170073b6af8aSAl Viro static int spufs_mfc_flush(struct file *file, fl_owner_t id) 1701a33a7d73SArnd Bergmann { 1702a33a7d73SArnd Bergmann struct spu_context *ctx = file->private_data; 1703a33a7d73SArnd Bergmann int ret; 1704a33a7d73SArnd Bergmann 1705c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1706c9101bdbSChristoph Hellwig if (ret) 1707a33a7d73SArnd Bergmann return ret; 1708*66d8e646SKunwu Chan 1709*66d8e646SKunwu Chan spu_release(ctx); 1710*66d8e646SKunwu Chan 1711*66d8e646SKunwu Chan return 0; 1712a33a7d73SArnd Bergmann } 1713a33a7d73SArnd Bergmann 171402c24a82SJosef Bacik static int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync) 1715a33a7d73SArnd Bergmann { 1716496ad9aaSAl Viro struct inode *inode = file_inode(file); 17173b49c9a1SJeff Layton int err = file_write_and_wait_range(file, start, end); 171802c24a82SJosef Bacik if (!err) { 17195955102cSAl Viro inode_lock(inode); 172002c24a82SJosef Bacik err = spufs_mfc_flush(file, NULL); 17215955102cSAl Viro inode_unlock(inode); 172202c24a82SJosef Bacik } 172302c24a82SJosef Bacik return err; 1724a33a7d73SArnd Bergmann } 1725a33a7d73SArnd Bergmann 17265dfe4c96SArjan van de Ven static const struct file_operations spufs_mfc_fops = { 1727a33a7d73SArnd Bergmann .open = spufs_mfc_open, 172843c2bbd9SChristoph Hellwig .release = spufs_mfc_release, 1729a33a7d73SArnd Bergmann .read = spufs_mfc_read, 1730a33a7d73SArnd Bergmann .write = spufs_mfc_write, 1731a33a7d73SArnd Bergmann .poll = spufs_mfc_poll, 1732a33a7d73SArnd Bergmann .flush = spufs_mfc_flush, 1733a33a7d73SArnd Bergmann .fsync = spufs_mfc_fsync, 17346df10a82SMark Nutter .mmap = spufs_mfc_mmap, 1735fc15351dSArnd Bergmann .llseek = no_llseek, 1736a33a7d73SArnd Bergmann }; 1737a33a7d73SArnd Bergmann 1738197b1a82SChristoph Hellwig static int spufs_npc_set(void *data, u64 val) 173967207b96SArnd Bergmann { 174067207b96SArnd Bergmann struct spu_context *ctx = data; 1741c9101bdbSChristoph Hellwig int ret; 1742c9101bdbSChristoph Hellwig 1743c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 1744c9101bdbSChristoph Hellwig if (ret) 1745c9101bdbSChristoph Hellwig return ret; 17468b3d6663SArnd Bergmann ctx->ops->npc_write(ctx, val); 17478b3d6663SArnd Bergmann spu_release(ctx); 1748197b1a82SChristoph Hellwig 1749197b1a82SChristoph Hellwig return 0; 175067207b96SArnd Bergmann } 175167207b96SArnd Bergmann 1752104f0cc2SMichael Ellerman static u64 spufs_npc_get(struct spu_context *ctx) 175378810ff6SMichael Ellerman { 175478810ff6SMichael Ellerman return ctx->ops->npc_read(ctx); 175578810ff6SMichael Ellerman } 1756104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, 1757104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE); 175867207b96SArnd Bergmann 1759197b1a82SChristoph Hellwig static int spufs_decr_set(void *data, u64 val) 17608b3d6663SArnd Bergmann { 17618b3d6663SArnd Bergmann struct spu_context *ctx = data; 17628b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1763c9101bdbSChristoph Hellwig int ret; 1764c9101bdbSChristoph Hellwig 1765c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1766c9101bdbSChristoph Hellwig if (ret) 1767c9101bdbSChristoph Hellwig return ret; 17688b3d6663SArnd Bergmann lscsa->decr.slot[0] = (u32) val; 176927b1ea09SChristoph Hellwig spu_release_saved(ctx); 1770197b1a82SChristoph Hellwig 1771197b1a82SChristoph Hellwig return 0; 17728b3d6663SArnd Bergmann } 17738b3d6663SArnd Bergmann 1774104f0cc2SMichael Ellerman static u64 spufs_decr_get(struct spu_context *ctx) 17758b3d6663SArnd Bergmann { 17768b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1777bf1ab978SDwayne Grant McConnell return lscsa->decr.slot[0]; 1778bf1ab978SDwayne Grant McConnell } 1779104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, 1780104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); 17818b3d6663SArnd Bergmann 1782197b1a82SChristoph Hellwig static int spufs_decr_status_set(void *data, u64 val) 17838b3d6663SArnd Bergmann { 17848b3d6663SArnd Bergmann struct spu_context *ctx = data; 1785c9101bdbSChristoph Hellwig int ret; 1786c9101bdbSChristoph Hellwig 1787c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1788c9101bdbSChristoph Hellwig if (ret) 1789c9101bdbSChristoph Hellwig return ret; 1790d40a01d4SMasato Noguchi if (val) 1791d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 1792d40a01d4SMasato Noguchi else 1793d40a01d4SMasato Noguchi ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 179427b1ea09SChristoph Hellwig spu_release_saved(ctx); 1795197b1a82SChristoph Hellwig 1796197b1a82SChristoph Hellwig return 0; 17978b3d6663SArnd Bergmann } 17988b3d6663SArnd Bergmann 1799104f0cc2SMichael Ellerman static u64 spufs_decr_status_get(struct spu_context *ctx) 18008b3d6663SArnd Bergmann { 1801d40a01d4SMasato Noguchi if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 1802d40a01d4SMasato Noguchi return SPU_DECR_STATUS_RUNNING; 1803d40a01d4SMasato Noguchi else 1804d40a01d4SMasato Noguchi return 0; 1805bf1ab978SDwayne Grant McConnell } 1806104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, 1807104f0cc2SMichael Ellerman spufs_decr_status_set, "0x%llx\n", 1808104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 18098b3d6663SArnd Bergmann 1810197b1a82SChristoph Hellwig static int spufs_event_mask_set(void *data, u64 val) 18118b3d6663SArnd Bergmann { 18128b3d6663SArnd Bergmann struct spu_context *ctx = data; 18138b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1814c9101bdbSChristoph Hellwig int ret; 1815c9101bdbSChristoph Hellwig 1816c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1817c9101bdbSChristoph Hellwig if (ret) 1818c9101bdbSChristoph Hellwig return ret; 18198b3d6663SArnd Bergmann lscsa->event_mask.slot[0] = (u32) val; 182027b1ea09SChristoph Hellwig spu_release_saved(ctx); 1821197b1a82SChristoph Hellwig 1822197b1a82SChristoph Hellwig return 0; 18238b3d6663SArnd Bergmann } 18248b3d6663SArnd Bergmann 1825104f0cc2SMichael Ellerman static u64 spufs_event_mask_get(struct spu_context *ctx) 18268b3d6663SArnd Bergmann { 18278b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1828bf1ab978SDwayne Grant McConnell return lscsa->event_mask.slot[0]; 1829bf1ab978SDwayne Grant McConnell } 1830bf1ab978SDwayne Grant McConnell 1831104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, 1832104f0cc2SMichael Ellerman spufs_event_mask_set, "0x%llx\n", 1833104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 18348b3d6663SArnd Bergmann 1835104f0cc2SMichael Ellerman static u64 spufs_event_status_get(struct spu_context *ctx) 1836b9e3bd77SDwayne Grant McConnell { 1837b9e3bd77SDwayne Grant McConnell struct spu_state *state = &ctx->csa; 1838b9e3bd77SDwayne Grant McConnell u64 stat; 1839b9e3bd77SDwayne Grant McConnell stat = state->spu_chnlcnt_RW[0]; 1840b9e3bd77SDwayne Grant McConnell if (stat) 1841bf1ab978SDwayne Grant McConnell return state->spu_chnldata_RW[0]; 1842bf1ab978SDwayne Grant McConnell return 0; 1843bf1ab978SDwayne Grant McConnell } 1844104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, 1845104f0cc2SMichael Ellerman NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 1846b9e3bd77SDwayne Grant McConnell 1847197b1a82SChristoph Hellwig static int spufs_srr0_set(void *data, u64 val) 18488b3d6663SArnd Bergmann { 18498b3d6663SArnd Bergmann struct spu_context *ctx = data; 18508b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1851c9101bdbSChristoph Hellwig int ret; 1852c9101bdbSChristoph Hellwig 1853c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1854c9101bdbSChristoph Hellwig if (ret) 1855c9101bdbSChristoph Hellwig return ret; 18568b3d6663SArnd Bergmann lscsa->srr0.slot[0] = (u32) val; 185727b1ea09SChristoph Hellwig spu_release_saved(ctx); 1858197b1a82SChristoph Hellwig 1859197b1a82SChristoph Hellwig return 0; 18608b3d6663SArnd Bergmann } 18618b3d6663SArnd Bergmann 1862104f0cc2SMichael Ellerman static u64 spufs_srr0_get(struct spu_context *ctx) 18638b3d6663SArnd Bergmann { 18648b3d6663SArnd Bergmann struct spu_lscsa *lscsa = ctx->csa.lscsa; 1865104f0cc2SMichael Ellerman return lscsa->srr0.slot[0]; 18668b3d6663SArnd Bergmann } 1867104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, 1868104f0cc2SMichael Ellerman "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) 18698b3d6663SArnd Bergmann 1870104f0cc2SMichael Ellerman static u64 spufs_id_get(struct spu_context *ctx) 18717b1a7014Sarnd@arndb.de { 18727b1a7014Sarnd@arndb.de u64 num; 18737b1a7014Sarnd@arndb.de 18747b1a7014Sarnd@arndb.de if (ctx->state == SPU_STATE_RUNNABLE) 18757b1a7014Sarnd@arndb.de num = ctx->spu->number; 18767b1a7014Sarnd@arndb.de else 18777b1a7014Sarnd@arndb.de num = (unsigned int)-1; 18787b1a7014Sarnd@arndb.de 18797b1a7014Sarnd@arndb.de return num; 18807b1a7014Sarnd@arndb.de } 1881104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", 1882104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE) 18837b1a7014Sarnd@arndb.de 1884104f0cc2SMichael Ellerman static u64 spufs_object_id_get(struct spu_context *ctx) 1885bf1ab978SDwayne Grant McConnell { 1886bf1ab978SDwayne Grant McConnell /* FIXME: Should there really be no locking here? */ 1887104f0cc2SMichael Ellerman return ctx->object_id; 1888bf1ab978SDwayne Grant McConnell } 1889bf1ab978SDwayne Grant McConnell 1890197b1a82SChristoph Hellwig static int spufs_object_id_set(void *data, u64 id) 189186767277SArnd Bergmann { 189286767277SArnd Bergmann struct spu_context *ctx = data; 189386767277SArnd Bergmann ctx->object_id = id; 1894197b1a82SChristoph Hellwig 1895197b1a82SChristoph Hellwig return 0; 189686767277SArnd Bergmann } 189786767277SArnd Bergmann 1898104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, 1899104f0cc2SMichael Ellerman spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); 190086767277SArnd Bergmann 1901104f0cc2SMichael Ellerman static u64 spufs_lslr_get(struct spu_context *ctx) 1902bf1ab978SDwayne Grant McConnell { 1903bf1ab978SDwayne Grant McConnell return ctx->csa.priv2.spu_lslr_RW; 1904bf1ab978SDwayne Grant McConnell } 1905104f0cc2SMichael Ellerman DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", 1906104f0cc2SMichael Ellerman SPU_ATTR_ACQUIRE_SAVED); 1907b9e3bd77SDwayne Grant McConnell 1908b9e3bd77SDwayne Grant McConnell static int spufs_info_open(struct inode *inode, struct file *file) 1909b9e3bd77SDwayne Grant McConnell { 1910b9e3bd77SDwayne Grant McConnell struct spufs_inode_info *i = SPUFS_I(inode); 1911b9e3bd77SDwayne Grant McConnell struct spu_context *ctx = i->i_ctx; 1912b9e3bd77SDwayne Grant McConnell file->private_data = ctx; 1913b9e3bd77SDwayne Grant McConnell return 0; 1914b9e3bd77SDwayne Grant McConnell } 1915b9e3bd77SDwayne Grant McConnell 1916cbe709c1SBenjamin Herrenschmidt static int spufs_caps_show(struct seq_file *s, void *private) 1917cbe709c1SBenjamin Herrenschmidt { 1918cbe709c1SBenjamin Herrenschmidt struct spu_context *ctx = s->private; 1919cbe709c1SBenjamin Herrenschmidt 1920cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_NOSCHED)) 1921cbe709c1SBenjamin Herrenschmidt seq_puts(s, "sched\n"); 1922cbe709c1SBenjamin Herrenschmidt if (!(ctx->flags & SPU_CREATE_ISOLATE)) 1923cbe709c1SBenjamin Herrenschmidt seq_puts(s, "step\n"); 1924cbe709c1SBenjamin Herrenschmidt return 0; 1925cbe709c1SBenjamin Herrenschmidt } 1926cbe709c1SBenjamin Herrenschmidt 1927cbe709c1SBenjamin Herrenschmidt static int spufs_caps_open(struct inode *inode, struct file *file) 1928cbe709c1SBenjamin Herrenschmidt { 1929cbe709c1SBenjamin Herrenschmidt return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); 1930cbe709c1SBenjamin Herrenschmidt } 1931cbe709c1SBenjamin Herrenschmidt 1932cbe709c1SBenjamin Herrenschmidt static const struct file_operations spufs_caps_fops = { 1933cbe709c1SBenjamin Herrenschmidt .open = spufs_caps_open, 1934cbe709c1SBenjamin Herrenschmidt .read = seq_read, 1935cbe709c1SBenjamin Herrenschmidt .llseek = seq_lseek, 1936cbe709c1SBenjamin Herrenschmidt .release = single_release, 1937cbe709c1SBenjamin Herrenschmidt }; 1938cbe709c1SBenjamin Herrenschmidt 19395456ffdeSChristoph Hellwig static ssize_t spufs_mbox_info_dump(struct spu_context *ctx, 19405456ffdeSChristoph Hellwig struct coredump_params *cprm) 1941bf1ab978SDwayne Grant McConnell { 1942cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0x0000ff)) 1943cbea9238SJeremy Kerr return 0; 19445456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, &ctx->csa.prob.pu_mb_R, 19455456ffdeSChristoph Hellwig sizeof(ctx->csa.prob.pu_mb_R)); 1946bf1ab978SDwayne Grant McConnell } 1947bf1ab978SDwayne Grant McConnell 194869a2f00cSDwayne Grant McConnell static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, 194969a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 195069a2f00cSDwayne Grant McConnell { 195169a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 195288413a6bSJeremy Kerr u32 stat, data; 195388413a6bSJeremy Kerr int ret; 195469a2f00cSDwayne Grant McConnell 1955c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1956c9101bdbSChristoph Hellwig if (ret) 1957c9101bdbSChristoph Hellwig return ret; 195869a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 195988413a6bSJeremy Kerr stat = ctx->csa.prob.mb_stat_R; 196088413a6bSJeremy Kerr data = ctx->csa.prob.pu_mb_R; 196169a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 196227b1ea09SChristoph Hellwig spu_release_saved(ctx); 196369a2f00cSDwayne Grant McConnell 196488413a6bSJeremy Kerr /* EOF if there's no entry in the mbox */ 196588413a6bSJeremy Kerr if (!(stat & 0x0000ff)) 196688413a6bSJeremy Kerr return 0; 196788413a6bSJeremy Kerr 196888413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &data, sizeof(data)); 196969a2f00cSDwayne Grant McConnell } 197069a2f00cSDwayne Grant McConnell 19715dfe4c96SArjan van de Ven static const struct file_operations spufs_mbox_info_fops = { 197269a2f00cSDwayne Grant McConnell .open = spufs_info_open, 197369a2f00cSDwayne Grant McConnell .read = spufs_mbox_info_read, 197469a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 197569a2f00cSDwayne Grant McConnell }; 197669a2f00cSDwayne Grant McConnell 19775456ffdeSChristoph Hellwig static ssize_t spufs_ibox_info_dump(struct spu_context *ctx, 19785456ffdeSChristoph Hellwig struct coredump_params *cprm) 1979bf1ab978SDwayne Grant McConnell { 1980cbea9238SJeremy Kerr if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) 1981cbea9238SJeremy Kerr return 0; 19825456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, &ctx->csa.priv2.puint_mb_R, 19835456ffdeSChristoph Hellwig sizeof(ctx->csa.priv2.puint_mb_R)); 1984bf1ab978SDwayne Grant McConnell } 1985bf1ab978SDwayne Grant McConnell 198669a2f00cSDwayne Grant McConnell static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, 198769a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 198869a2f00cSDwayne Grant McConnell { 198969a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 199088413a6bSJeremy Kerr u32 stat, data; 1991bf1ab978SDwayne Grant McConnell int ret; 199269a2f00cSDwayne Grant McConnell 1993c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 1994c9101bdbSChristoph Hellwig if (ret) 1995c9101bdbSChristoph Hellwig return ret; 199669a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 199788413a6bSJeremy Kerr stat = ctx->csa.prob.mb_stat_R; 199888413a6bSJeremy Kerr data = ctx->csa.priv2.puint_mb_R; 199969a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 200027b1ea09SChristoph Hellwig spu_release_saved(ctx); 200169a2f00cSDwayne Grant McConnell 200288413a6bSJeremy Kerr /* EOF if there's no entry in the ibox */ 200388413a6bSJeremy Kerr if (!(stat & 0xff0000)) 200488413a6bSJeremy Kerr return 0; 200588413a6bSJeremy Kerr 200688413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &data, sizeof(data)); 200769a2f00cSDwayne Grant McConnell } 200869a2f00cSDwayne Grant McConnell 20095dfe4c96SArjan van de Ven static const struct file_operations spufs_ibox_info_fops = { 201069a2f00cSDwayne Grant McConnell .open = spufs_info_open, 201169a2f00cSDwayne Grant McConnell .read = spufs_ibox_info_read, 201269a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 201369a2f00cSDwayne Grant McConnell }; 201469a2f00cSDwayne Grant McConnell 201588413a6bSJeremy Kerr static size_t spufs_wbox_info_cnt(struct spu_context *ctx) 201688413a6bSJeremy Kerr { 201788413a6bSJeremy Kerr return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32); 201888413a6bSJeremy Kerr } 201988413a6bSJeremy Kerr 20205456ffdeSChristoph Hellwig static ssize_t spufs_wbox_info_dump(struct spu_context *ctx, 20215456ffdeSChristoph Hellwig struct coredump_params *cprm) 2022bf1ab978SDwayne Grant McConnell { 20235456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, &ctx->csa.spu_mailbox_data, 20245456ffdeSChristoph Hellwig spufs_wbox_info_cnt(ctx)); 2025bf1ab978SDwayne Grant McConnell } 2026bf1ab978SDwayne Grant McConnell 202769a2f00cSDwayne Grant McConnell static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, 202869a2f00cSDwayne Grant McConnell size_t len, loff_t *pos) 202969a2f00cSDwayne Grant McConnell { 203069a2f00cSDwayne Grant McConnell struct spu_context *ctx = file->private_data; 203188413a6bSJeremy Kerr u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)]; 203288413a6bSJeremy Kerr int ret, count; 203369a2f00cSDwayne Grant McConnell 2034c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2035c9101bdbSChristoph Hellwig if (ret) 2036c9101bdbSChristoph Hellwig return ret; 203769a2f00cSDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 203888413a6bSJeremy Kerr count = spufs_wbox_info_cnt(ctx); 203988413a6bSJeremy Kerr memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data)); 204069a2f00cSDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 204127b1ea09SChristoph Hellwig spu_release_saved(ctx); 204269a2f00cSDwayne Grant McConnell 204388413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &data, 204488413a6bSJeremy Kerr count * sizeof(u32)); 204569a2f00cSDwayne Grant McConnell } 204669a2f00cSDwayne Grant McConnell 20475dfe4c96SArjan van de Ven static const struct file_operations spufs_wbox_info_fops = { 204869a2f00cSDwayne Grant McConnell .open = spufs_info_open, 204969a2f00cSDwayne Grant McConnell .read = spufs_wbox_info_read, 205069a2f00cSDwayne Grant McConnell .llseek = generic_file_llseek, 205169a2f00cSDwayne Grant McConnell }; 205269a2f00cSDwayne Grant McConnell 205388413a6bSJeremy Kerr static void spufs_get_dma_info(struct spu_context *ctx, 205488413a6bSJeremy Kerr struct spu_dma_info *info) 2055b9e3bd77SDwayne Grant McConnell { 2056b9e3bd77SDwayne Grant McConnell int i; 2057b9e3bd77SDwayne Grant McConnell 205888413a6bSJeremy Kerr info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; 205988413a6bSJeremy Kerr info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; 206088413a6bSJeremy Kerr info->dma_info_status = ctx->csa.spu_chnldata_RW[24]; 206188413a6bSJeremy Kerr info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25]; 206288413a6bSJeremy Kerr info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27]; 2063b9e3bd77SDwayne Grant McConnell for (i = 0; i < 16; i++) { 206488413a6bSJeremy Kerr struct mfc_cq_sr *qp = &info->dma_info_command_data[i]; 206588413a6bSJeremy Kerr struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i]; 2066b9e3bd77SDwayne Grant McConnell 2067b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; 2068b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; 2069b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; 2070b9e3bd77SDwayne Grant McConnell qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; 2071b9e3bd77SDwayne Grant McConnell } 207288413a6bSJeremy Kerr } 207388413a6bSJeremy Kerr 20745456ffdeSChristoph Hellwig static ssize_t spufs_dma_info_dump(struct spu_context *ctx, 20755456ffdeSChristoph Hellwig struct coredump_params *cprm) 207688413a6bSJeremy Kerr { 207788413a6bSJeremy Kerr struct spu_dma_info info; 207888413a6bSJeremy Kerr 207988413a6bSJeremy Kerr spufs_get_dma_info(ctx, &info); 20805456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, &info, sizeof(info)); 2081b9e3bd77SDwayne Grant McConnell } 2082b9e3bd77SDwayne Grant McConnell 2083bf1ab978SDwayne Grant McConnell static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, 2084bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2085bf1ab978SDwayne Grant McConnell { 2086bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 208788413a6bSJeremy Kerr struct spu_dma_info info; 2088bf1ab978SDwayne Grant McConnell int ret; 2089bf1ab978SDwayne Grant McConnell 2090c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2091c9101bdbSChristoph Hellwig if (ret) 2092c9101bdbSChristoph Hellwig return ret; 2093bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 209488413a6bSJeremy Kerr spufs_get_dma_info(ctx, &info); 2095bf1ab978SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 209627b1ea09SChristoph Hellwig spu_release_saved(ctx); 2097bf1ab978SDwayne Grant McConnell 209888413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &info, 209988413a6bSJeremy Kerr sizeof(info)); 2100bf1ab978SDwayne Grant McConnell } 2101bf1ab978SDwayne Grant McConnell 21025dfe4c96SArjan van de Ven static const struct file_operations spufs_dma_info_fops = { 2103b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2104b9e3bd77SDwayne Grant McConnell .read = spufs_dma_info_read, 2105fc15351dSArnd Bergmann .llseek = no_llseek, 2106b9e3bd77SDwayne Grant McConnell }; 2107b9e3bd77SDwayne Grant McConnell 210888413a6bSJeremy Kerr static void spufs_get_proxydma_info(struct spu_context *ctx, 210988413a6bSJeremy Kerr struct spu_proxydma_info *info) 211088413a6bSJeremy Kerr { 211188413a6bSJeremy Kerr int i; 211288413a6bSJeremy Kerr 211388413a6bSJeremy Kerr info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW; 211488413a6bSJeremy Kerr info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; 211588413a6bSJeremy Kerr info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; 211688413a6bSJeremy Kerr 211788413a6bSJeremy Kerr for (i = 0; i < 8; i++) { 211888413a6bSJeremy Kerr struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i]; 211988413a6bSJeremy Kerr struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i]; 212088413a6bSJeremy Kerr 212188413a6bSJeremy Kerr qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; 212288413a6bSJeremy Kerr qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; 212388413a6bSJeremy Kerr qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; 212488413a6bSJeremy Kerr qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; 212588413a6bSJeremy Kerr } 212688413a6bSJeremy Kerr } 212788413a6bSJeremy Kerr 21285456ffdeSChristoph Hellwig static ssize_t spufs_proxydma_info_dump(struct spu_context *ctx, 21295456ffdeSChristoph Hellwig struct coredump_params *cprm) 2130b9e3bd77SDwayne Grant McConnell { 2131b9e3bd77SDwayne Grant McConnell struct spu_proxydma_info info; 2132b9e3bd77SDwayne Grant McConnell 213388413a6bSJeremy Kerr spufs_get_proxydma_info(ctx, &info); 21345456ffdeSChristoph Hellwig return spufs_dump_emit(cprm, &info, sizeof(info)); 2135bf1ab978SDwayne Grant McConnell } 2136bf1ab978SDwayne Grant McConnell 2137bf1ab978SDwayne Grant McConnell static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, 2138bf1ab978SDwayne Grant McConnell size_t len, loff_t *pos) 2139bf1ab978SDwayne Grant McConnell { 2140bf1ab978SDwayne Grant McConnell struct spu_context *ctx = file->private_data; 214188413a6bSJeremy Kerr struct spu_proxydma_info info; 2142bf1ab978SDwayne Grant McConnell int ret; 2143bf1ab978SDwayne Grant McConnell 21445456ffdeSChristoph Hellwig if (len < sizeof(info)) 21455456ffdeSChristoph Hellwig return -EINVAL; 21465456ffdeSChristoph Hellwig 2147c9101bdbSChristoph Hellwig ret = spu_acquire_saved(ctx); 2148c9101bdbSChristoph Hellwig if (ret) 2149c9101bdbSChristoph Hellwig return ret; 2150bf1ab978SDwayne Grant McConnell spin_lock(&ctx->csa.register_lock); 215188413a6bSJeremy Kerr spufs_get_proxydma_info(ctx, &info); 2152b9e3bd77SDwayne Grant McConnell spin_unlock(&ctx->csa.register_lock); 215327b1ea09SChristoph Hellwig spu_release_saved(ctx); 2154b9e3bd77SDwayne Grant McConnell 215588413a6bSJeremy Kerr return simple_read_from_buffer(buf, len, pos, &info, 215688413a6bSJeremy Kerr sizeof(info)); 2157b9e3bd77SDwayne Grant McConnell } 2158b9e3bd77SDwayne Grant McConnell 21595dfe4c96SArjan van de Ven static const struct file_operations spufs_proxydma_info_fops = { 2160b9e3bd77SDwayne Grant McConnell .open = spufs_info_open, 2161b9e3bd77SDwayne Grant McConnell .read = spufs_proxydma_info_read, 2162fc15351dSArnd Bergmann .llseek = no_llseek, 2163b9e3bd77SDwayne Grant McConnell }; 2164b9e3bd77SDwayne Grant McConnell 2165476273adSChristoph Hellwig static int spufs_show_tid(struct seq_file *s, void *private) 2166476273adSChristoph Hellwig { 2167476273adSChristoph Hellwig struct spu_context *ctx = s->private; 2168476273adSChristoph Hellwig 2169476273adSChristoph Hellwig seq_printf(s, "%d\n", ctx->tid); 2170476273adSChristoph Hellwig return 0; 2171476273adSChristoph Hellwig } 2172476273adSChristoph Hellwig 2173476273adSChristoph Hellwig static int spufs_tid_open(struct inode *inode, struct file *file) 2174476273adSChristoph Hellwig { 2175476273adSChristoph Hellwig return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); 2176476273adSChristoph Hellwig } 2177476273adSChristoph Hellwig 2178476273adSChristoph Hellwig static const struct file_operations spufs_tid_fops = { 2179476273adSChristoph Hellwig .open = spufs_tid_open, 2180476273adSChristoph Hellwig .read = seq_read, 2181476273adSChristoph Hellwig .llseek = seq_lseek, 2182476273adSChristoph Hellwig .release = single_release, 2183476273adSChristoph Hellwig }; 2184476273adSChristoph Hellwig 2185e9f8a0b6SChristoph Hellwig static const char *ctx_state_names[] = { 2186e9f8a0b6SChristoph Hellwig "user", "system", "iowait", "loaded" 2187e9f8a0b6SChristoph Hellwig }; 2188e9f8a0b6SChristoph Hellwig 2189e9f8a0b6SChristoph Hellwig static unsigned long long spufs_acct_time(struct spu_context *ctx, 219027ec41d3SAndre Detsch enum spu_utilization_state state) 2191e9f8a0b6SChristoph Hellwig { 219227ec41d3SAndre Detsch unsigned long long time = ctx->stats.times[state]; 2193e9f8a0b6SChristoph Hellwig 219427ec41d3SAndre Detsch /* 219527ec41d3SAndre Detsch * In general, utilization statistics are updated by the controlling 219627ec41d3SAndre Detsch * thread as the spu context moves through various well defined 219727ec41d3SAndre Detsch * state transitions, but if the context is lazily loaded its 219827ec41d3SAndre Detsch * utilization statistics are not updated as the controlling thread 219927ec41d3SAndre Detsch * is not tightly coupled with the execution of the spu context. We 220027ec41d3SAndre Detsch * calculate and apply the time delta from the last recorded state 220127ec41d3SAndre Detsch * of the spu context. 220227ec41d3SAndre Detsch */ 220327ec41d3SAndre Detsch if (ctx->spu && ctx->stats.util_state == state) { 2204f2dec1eaSThomas Gleixner time += ktime_get_ns() - ctx->stats.tstamp; 220527ec41d3SAndre Detsch } 2206e9f8a0b6SChristoph Hellwig 220727ec41d3SAndre Detsch return time / NSEC_PER_MSEC; 2208e9f8a0b6SChristoph Hellwig } 2209e9f8a0b6SChristoph Hellwig 2210e9f8a0b6SChristoph Hellwig static unsigned long long spufs_slb_flts(struct spu_context *ctx) 2211e9f8a0b6SChristoph Hellwig { 2212e9f8a0b6SChristoph Hellwig unsigned long long slb_flts = ctx->stats.slb_flt; 2213e9f8a0b6SChristoph Hellwig 2214e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2215e9f8a0b6SChristoph Hellwig slb_flts += (ctx->spu->stats.slb_flt - 2216e9f8a0b6SChristoph Hellwig ctx->stats.slb_flt_base); 2217e9f8a0b6SChristoph Hellwig } 2218e9f8a0b6SChristoph Hellwig 2219e9f8a0b6SChristoph Hellwig return slb_flts; 2220e9f8a0b6SChristoph Hellwig } 2221e9f8a0b6SChristoph Hellwig 2222e9f8a0b6SChristoph Hellwig static unsigned long long spufs_class2_intrs(struct spu_context *ctx) 2223e9f8a0b6SChristoph Hellwig { 2224e9f8a0b6SChristoph Hellwig unsigned long long class2_intrs = ctx->stats.class2_intr; 2225e9f8a0b6SChristoph Hellwig 2226e9f8a0b6SChristoph Hellwig if (ctx->state == SPU_STATE_RUNNABLE) { 2227e9f8a0b6SChristoph Hellwig class2_intrs += (ctx->spu->stats.class2_intr - 2228e9f8a0b6SChristoph Hellwig ctx->stats.class2_intr_base); 2229e9f8a0b6SChristoph Hellwig } 2230e9f8a0b6SChristoph Hellwig 2231e9f8a0b6SChristoph Hellwig return class2_intrs; 2232e9f8a0b6SChristoph Hellwig } 2233e9f8a0b6SChristoph Hellwig 2234e9f8a0b6SChristoph Hellwig 2235e9f8a0b6SChristoph Hellwig static int spufs_show_stat(struct seq_file *s, void *private) 2236e9f8a0b6SChristoph Hellwig { 2237e9f8a0b6SChristoph Hellwig struct spu_context *ctx = s->private; 2238c9101bdbSChristoph Hellwig int ret; 2239e9f8a0b6SChristoph Hellwig 2240c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 2241c9101bdbSChristoph Hellwig if (ret) 2242c9101bdbSChristoph Hellwig return ret; 2243c9101bdbSChristoph Hellwig 2244e9f8a0b6SChristoph Hellwig seq_printf(s, "%s %llu %llu %llu %llu " 2245e9f8a0b6SChristoph Hellwig "%llu %llu %llu %llu %llu %llu %llu %llu\n", 224627ec41d3SAndre Detsch ctx_state_names[ctx->stats.util_state], 224727ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_USER), 224827ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 224927ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 225027ec41d3SAndre Detsch spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 2251e9f8a0b6SChristoph Hellwig ctx->stats.vol_ctx_switch, 2252e9f8a0b6SChristoph Hellwig ctx->stats.invol_ctx_switch, 2253e9f8a0b6SChristoph Hellwig spufs_slb_flts(ctx), 2254e9f8a0b6SChristoph Hellwig ctx->stats.hash_flt, 2255e9f8a0b6SChristoph Hellwig ctx->stats.min_flt, 2256e9f8a0b6SChristoph Hellwig ctx->stats.maj_flt, 2257e9f8a0b6SChristoph Hellwig spufs_class2_intrs(ctx), 2258e9f8a0b6SChristoph Hellwig ctx->stats.libassist); 2259e9f8a0b6SChristoph Hellwig spu_release(ctx); 2260e9f8a0b6SChristoph Hellwig return 0; 2261e9f8a0b6SChristoph Hellwig } 2262e9f8a0b6SChristoph Hellwig 2263e9f8a0b6SChristoph Hellwig static int spufs_stat_open(struct inode *inode, struct file *file) 2264e9f8a0b6SChristoph Hellwig { 2265e9f8a0b6SChristoph Hellwig return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); 2266e9f8a0b6SChristoph Hellwig } 2267e9f8a0b6SChristoph Hellwig 2268e9f8a0b6SChristoph Hellwig static const struct file_operations spufs_stat_fops = { 2269e9f8a0b6SChristoph Hellwig .open = spufs_stat_open, 2270e9f8a0b6SChristoph Hellwig .read = seq_read, 2271e9f8a0b6SChristoph Hellwig .llseek = seq_lseek, 2272e9f8a0b6SChristoph Hellwig .release = single_release, 2273e9f8a0b6SChristoph Hellwig }; 2274e9f8a0b6SChristoph Hellwig 22755158e9b5SChristoph Hellwig static inline int spufs_switch_log_used(struct spu_context *ctx) 22765158e9b5SChristoph Hellwig { 22775158e9b5SChristoph Hellwig return (ctx->switch_log->head - ctx->switch_log->tail) % 22785158e9b5SChristoph Hellwig SWITCH_LOG_BUFSIZE; 22795158e9b5SChristoph Hellwig } 22805158e9b5SChristoph Hellwig 22815158e9b5SChristoph Hellwig static inline int spufs_switch_log_avail(struct spu_context *ctx) 22825158e9b5SChristoph Hellwig { 22835158e9b5SChristoph Hellwig return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx); 22845158e9b5SChristoph Hellwig } 22855158e9b5SChristoph Hellwig 22865158e9b5SChristoph Hellwig static int spufs_switch_log_open(struct inode *inode, struct file *file) 22875158e9b5SChristoph Hellwig { 22885158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 2289f5ed0eb6SJeremy Kerr int rc; 22905158e9b5SChristoph Hellwig 2291f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2292f5ed0eb6SJeremy Kerr if (rc) 2293f5ed0eb6SJeremy Kerr return rc; 2294f5ed0eb6SJeremy Kerr 22955158e9b5SChristoph Hellwig if (ctx->switch_log) { 2296f5ed0eb6SJeremy Kerr rc = -EBUSY; 2297f5ed0eb6SJeremy Kerr goto out; 2298f5ed0eb6SJeremy Kerr } 2299f5ed0eb6SJeremy Kerr 230000def713SGustavo A. R. Silva ctx->switch_log = kmalloc(struct_size(ctx->switch_log, log, 230100def713SGustavo A. R. Silva SWITCH_LOG_BUFSIZE), GFP_KERNEL); 2302f5ed0eb6SJeremy Kerr 2303f5ed0eb6SJeremy Kerr if (!ctx->switch_log) { 2304f5ed0eb6SJeremy Kerr rc = -ENOMEM; 23055158e9b5SChristoph Hellwig goto out; 23065158e9b5SChristoph Hellwig } 2307f5ed0eb6SJeremy Kerr 2308837ef884SJeremy Kerr ctx->switch_log->head = ctx->switch_log->tail = 0; 2309f5ed0eb6SJeremy Kerr init_waitqueue_head(&ctx->switch_log->wait); 2310f5ed0eb6SJeremy Kerr rc = 0; 2311f5ed0eb6SJeremy Kerr 2312f5ed0eb6SJeremy Kerr out: 2313f5ed0eb6SJeremy Kerr spu_release(ctx); 2314f5ed0eb6SJeremy Kerr return rc; 2315f5ed0eb6SJeremy Kerr } 2316f5ed0eb6SJeremy Kerr 2317f5ed0eb6SJeremy Kerr static int spufs_switch_log_release(struct inode *inode, struct file *file) 2318f5ed0eb6SJeremy Kerr { 2319f5ed0eb6SJeremy Kerr struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 2320f5ed0eb6SJeremy Kerr int rc; 2321f5ed0eb6SJeremy Kerr 2322f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2323f5ed0eb6SJeremy Kerr if (rc) 2324f5ed0eb6SJeremy Kerr return rc; 2325f5ed0eb6SJeremy Kerr 2326f5ed0eb6SJeremy Kerr kfree(ctx->switch_log); 2327f5ed0eb6SJeremy Kerr ctx->switch_log = NULL; 2328f5ed0eb6SJeremy Kerr spu_release(ctx); 23295158e9b5SChristoph Hellwig 23305158e9b5SChristoph Hellwig return 0; 23315158e9b5SChristoph Hellwig } 23325158e9b5SChristoph Hellwig 23335158e9b5SChristoph Hellwig static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) 23345158e9b5SChristoph Hellwig { 23355158e9b5SChristoph Hellwig struct switch_log_entry *p; 23365158e9b5SChristoph Hellwig 23375158e9b5SChristoph Hellwig p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE; 23385158e9b5SChristoph Hellwig 2339cef37ac1SArnd Bergmann return snprintf(tbuf, n, "%llu.%09u %d %u %u %llu\n", 2340cef37ac1SArnd Bergmann (unsigned long long) p->tstamp.tv_sec, 23415158e9b5SChristoph Hellwig (unsigned int) p->tstamp.tv_nsec, 23425158e9b5SChristoph Hellwig p->spu_id, 23435158e9b5SChristoph Hellwig (unsigned int) p->type, 23445158e9b5SChristoph Hellwig (unsigned int) p->val, 23455158e9b5SChristoph Hellwig (unsigned long long) p->timebase); 23465158e9b5SChristoph Hellwig } 23475158e9b5SChristoph Hellwig 23485158e9b5SChristoph Hellwig static ssize_t spufs_switch_log_read(struct file *file, char __user *buf, 23495158e9b5SChristoph Hellwig size_t len, loff_t *ppos) 23505158e9b5SChristoph Hellwig { 2351496ad9aaSAl Viro struct inode *inode = file_inode(file); 23525158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 23535158e9b5SChristoph Hellwig int error = 0, cnt = 0; 23545158e9b5SChristoph Hellwig 235517e37675Sroel kluin if (!buf) 23565158e9b5SChristoph Hellwig return -EINVAL; 23575158e9b5SChristoph Hellwig 2358f5ed0eb6SJeremy Kerr error = spu_acquire(ctx); 2359f5ed0eb6SJeremy Kerr if (error) 2360f5ed0eb6SJeremy Kerr return error; 2361f5ed0eb6SJeremy Kerr 23625158e9b5SChristoph Hellwig while (cnt < len) { 23635158e9b5SChristoph Hellwig char tbuf[128]; 23645158e9b5SChristoph Hellwig int width; 23655158e9b5SChristoph Hellwig 2366f5ed0eb6SJeremy Kerr if (spufs_switch_log_used(ctx) == 0) { 236714f693eeSJeremy Kerr if (cnt > 0) { 236814f693eeSJeremy Kerr /* If there's data ready to go, we can 236914f693eeSJeremy Kerr * just return straight away */ 237014f693eeSJeremy Kerr break; 237114f693eeSJeremy Kerr 237214f693eeSJeremy Kerr } else if (file->f_flags & O_NONBLOCK) { 2373f5ed0eb6SJeremy Kerr error = -EAGAIN; 23745158e9b5SChristoph Hellwig break; 237514f693eeSJeremy Kerr 2376f5ed0eb6SJeremy Kerr } else { 237714f693eeSJeremy Kerr /* spufs_wait will drop the mutex and 237814f693eeSJeremy Kerr * re-acquire, but since we're in read(), the 237914f693eeSJeremy Kerr * file cannot be _released (and so 238014f693eeSJeremy Kerr * ctx->switch_log is stable). 2381f5ed0eb6SJeremy Kerr */ 2382f5ed0eb6SJeremy Kerr error = spufs_wait(ctx->switch_log->wait, 2383f5ed0eb6SJeremy Kerr spufs_switch_log_used(ctx) > 0); 23845158e9b5SChristoph Hellwig 2385f5ed0eb6SJeremy Kerr /* On error, spufs_wait returns without the 2386f5ed0eb6SJeremy Kerr * state mutex held */ 2387f5ed0eb6SJeremy Kerr if (error) 2388f5ed0eb6SJeremy Kerr return error; 23895158e9b5SChristoph Hellwig 239014f693eeSJeremy Kerr /* We may have had entries read from underneath 239114f693eeSJeremy Kerr * us while we dropped the mutex in spufs_wait, 239214f693eeSJeremy Kerr * so re-check */ 239314f693eeSJeremy Kerr if (spufs_switch_log_used(ctx) == 0) 2394f5ed0eb6SJeremy Kerr continue; 239514f693eeSJeremy Kerr } 239614f693eeSJeremy Kerr } 2397f5ed0eb6SJeremy Kerr 23985158e9b5SChristoph Hellwig width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); 2399f5ed0eb6SJeremy Kerr if (width < len) 24005158e9b5SChristoph Hellwig ctx->switch_log->tail = 24015158e9b5SChristoph Hellwig (ctx->switch_log->tail + 1) % 24025158e9b5SChristoph Hellwig SWITCH_LOG_BUFSIZE; 2403f5ed0eb6SJeremy Kerr else 2404f5ed0eb6SJeremy Kerr /* If the record is greater than space available return 2405f5ed0eb6SJeremy Kerr * partial buffer (so far) */ 24065158e9b5SChristoph Hellwig break; 24075158e9b5SChristoph Hellwig 24085158e9b5SChristoph Hellwig error = copy_to_user(buf + cnt, tbuf, width); 24095158e9b5SChristoph Hellwig if (error) 24105158e9b5SChristoph Hellwig break; 24115158e9b5SChristoph Hellwig cnt += width; 24125158e9b5SChristoph Hellwig } 24135158e9b5SChristoph Hellwig 2414f5ed0eb6SJeremy Kerr spu_release(ctx); 2415f5ed0eb6SJeremy Kerr 24165158e9b5SChristoph Hellwig return cnt == 0 ? error : cnt; 24175158e9b5SChristoph Hellwig } 24185158e9b5SChristoph Hellwig 24198153a5eaSAl Viro static __poll_t spufs_switch_log_poll(struct file *file, poll_table *wait) 24205158e9b5SChristoph Hellwig { 2421496ad9aaSAl Viro struct inode *inode = file_inode(file); 24225158e9b5SChristoph Hellwig struct spu_context *ctx = SPUFS_I(inode)->i_ctx; 24238153a5eaSAl Viro __poll_t mask = 0; 2424f5ed0eb6SJeremy Kerr int rc; 24255158e9b5SChristoph Hellwig 24265158e9b5SChristoph Hellwig poll_wait(file, &ctx->switch_log->wait, wait); 24275158e9b5SChristoph Hellwig 2428f5ed0eb6SJeremy Kerr rc = spu_acquire(ctx); 2429f5ed0eb6SJeremy Kerr if (rc) 2430f5ed0eb6SJeremy Kerr return rc; 2431f5ed0eb6SJeremy Kerr 24325158e9b5SChristoph Hellwig if (spufs_switch_log_used(ctx) > 0) 2433a9a08845SLinus Torvalds mask |= EPOLLIN; 24345158e9b5SChristoph Hellwig 2435f5ed0eb6SJeremy Kerr spu_release(ctx); 2436f5ed0eb6SJeremy Kerr 24375158e9b5SChristoph Hellwig return mask; 24385158e9b5SChristoph Hellwig } 24395158e9b5SChristoph Hellwig 24405158e9b5SChristoph Hellwig static const struct file_operations spufs_switch_log_fops = { 24415158e9b5SChristoph Hellwig .open = spufs_switch_log_open, 24425158e9b5SChristoph Hellwig .read = spufs_switch_log_read, 24435158e9b5SChristoph Hellwig .poll = spufs_switch_log_poll, 2444f5ed0eb6SJeremy Kerr .release = spufs_switch_log_release, 2445fc15351dSArnd Bergmann .llseek = no_llseek, 24465158e9b5SChristoph Hellwig }; 24475158e9b5SChristoph Hellwig 2448f5ed0eb6SJeremy Kerr /** 2449f5ed0eb6SJeremy Kerr * Log a context switch event to a switch log reader. 2450f5ed0eb6SJeremy Kerr * 2451f5ed0eb6SJeremy Kerr * Must be called with ctx->state_mutex held. 2452f5ed0eb6SJeremy Kerr */ 24535158e9b5SChristoph Hellwig void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, 24545158e9b5SChristoph Hellwig u32 type, u32 val) 24555158e9b5SChristoph Hellwig { 24565158e9b5SChristoph Hellwig if (!ctx->switch_log) 24575158e9b5SChristoph Hellwig return; 24585158e9b5SChristoph Hellwig 24595158e9b5SChristoph Hellwig if (spufs_switch_log_avail(ctx) > 1) { 24605158e9b5SChristoph Hellwig struct switch_log_entry *p; 24615158e9b5SChristoph Hellwig 24625158e9b5SChristoph Hellwig p = ctx->switch_log->log + ctx->switch_log->head; 2463cef37ac1SArnd Bergmann ktime_get_ts64(&p->tstamp); 24645158e9b5SChristoph Hellwig p->timebase = get_tb(); 24655158e9b5SChristoph Hellwig p->spu_id = spu ? spu->number : -1; 24665158e9b5SChristoph Hellwig p->type = type; 24675158e9b5SChristoph Hellwig p->val = val; 24685158e9b5SChristoph Hellwig 24695158e9b5SChristoph Hellwig ctx->switch_log->head = 24705158e9b5SChristoph Hellwig (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE; 24715158e9b5SChristoph Hellwig } 24725158e9b5SChristoph Hellwig 24735158e9b5SChristoph Hellwig wake_up(&ctx->switch_log->wait); 24745158e9b5SChristoph Hellwig } 2475e9f8a0b6SChristoph Hellwig 247646deed69SLuke Browning static int spufs_show_ctx(struct seq_file *s, void *private) 247746deed69SLuke Browning { 247846deed69SLuke Browning struct spu_context *ctx = s->private; 247946deed69SLuke Browning u64 mfc_control_RW; 248046deed69SLuke Browning 248146deed69SLuke Browning mutex_lock(&ctx->state_mutex); 248246deed69SLuke Browning if (ctx->spu) { 248346deed69SLuke Browning struct spu *spu = ctx->spu; 248446deed69SLuke Browning struct spu_priv2 __iomem *priv2 = spu->priv2; 248546deed69SLuke Browning 248646deed69SLuke Browning spin_lock_irq(&spu->register_lock); 248746deed69SLuke Browning mfc_control_RW = in_be64(&priv2->mfc_control_RW); 248846deed69SLuke Browning spin_unlock_irq(&spu->register_lock); 248946deed69SLuke Browning } else { 249046deed69SLuke Browning struct spu_state *csa = &ctx->csa; 249146deed69SLuke Browning 249246deed69SLuke Browning mfc_control_RW = csa->priv2.mfc_control_RW; 249346deed69SLuke Browning } 249446deed69SLuke Browning 249546deed69SLuke Browning seq_printf(s, "%c flgs(%lx) sflgs(%lx) pri(%d) ts(%d) spu(%02d)" 24969477e455SStephen Rothwell " %c %llx %llx %llx %llx %x %x\n", 249746deed69SLuke Browning ctx->state == SPU_STATE_SAVED ? 'S' : 'R', 249846deed69SLuke Browning ctx->flags, 249946deed69SLuke Browning ctx->sched_flags, 250046deed69SLuke Browning ctx->prio, 250146deed69SLuke Browning ctx->time_slice, 250246deed69SLuke Browning ctx->spu ? ctx->spu->number : -1, 250346deed69SLuke Browning !list_empty(&ctx->rq) ? 'q' : ' ', 250446deed69SLuke Browning ctx->csa.class_0_pending, 250546deed69SLuke Browning ctx->csa.class_0_dar, 250646deed69SLuke Browning ctx->csa.class_1_dsisr, 250746deed69SLuke Browning mfc_control_RW, 250846deed69SLuke Browning ctx->ops->runcntl_read(ctx), 250946deed69SLuke Browning ctx->ops->status_read(ctx)); 251046deed69SLuke Browning 251146deed69SLuke Browning mutex_unlock(&ctx->state_mutex); 251246deed69SLuke Browning 251346deed69SLuke Browning return 0; 251446deed69SLuke Browning } 251546deed69SLuke Browning 251646deed69SLuke Browning static int spufs_ctx_open(struct inode *inode, struct file *file) 251746deed69SLuke Browning { 251846deed69SLuke Browning return single_open(file, spufs_show_ctx, SPUFS_I(inode)->i_ctx); 251946deed69SLuke Browning } 252046deed69SLuke Browning 252146deed69SLuke Browning static const struct file_operations spufs_ctx_fops = { 252246deed69SLuke Browning .open = spufs_ctx_open, 252346deed69SLuke Browning .read = seq_read, 252446deed69SLuke Browning .llseek = seq_lseek, 252546deed69SLuke Browning .release = single_release, 252646deed69SLuke Browning }; 252746deed69SLuke Browning 252874254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_contents[] = { 2529cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 25306f7dde81SJeremy Kerr { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, 25316f7dde81SJeremy Kerr { "regs", &spufs_regs_fops, 0666, sizeof(struct spu_reg128[128]), }, 253267207b96SArnd Bergmann { "mbox", &spufs_mbox_fops, 0444, }, 253367207b96SArnd Bergmann { "ibox", &spufs_ibox_fops, 0444, }, 253467207b96SArnd Bergmann { "wbox", &spufs_wbox_fops, 0222, }, 25356f7dde81SJeremy Kerr { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, 25366f7dde81SJeremy Kerr { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, 25376f7dde81SJeremy Kerr { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, 2538603c4612SJeremy Kerr { "signal1", &spufs_signal1_fops, 0666, }, 2539603c4612SJeremy Kerr { "signal2", &spufs_signal2_fops, 0666, }, 254067207b96SArnd Bergmann { "signal1_type", &spufs_signal1_type, 0666, }, 254167207b96SArnd Bergmann { "signal2_type", &spufs_signal2_type, 0666, }, 25426df10a82SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 25436f7dde81SJeremy Kerr { "fpcr", &spufs_fpcr_fops, 0666, sizeof(struct spu_reg128), }, 2544b9e3bd77SDwayne Grant McConnell { "lslr", &spufs_lslr_ops, 0444, }, 2545b9e3bd77SDwayne Grant McConnell { "mfc", &spufs_mfc_fops, 0666, }, 2546b9e3bd77SDwayne Grant McConnell { "mss", &spufs_mss_fops, 0666, }, 2547b9e3bd77SDwayne Grant McConnell { "npc", &spufs_npc_ops, 0666, }, 2548b9e3bd77SDwayne Grant McConnell { "srr0", &spufs_srr0_ops, 0666, }, 25498b3d6663SArnd Bergmann { "decr", &spufs_decr_ops, 0666, }, 25508b3d6663SArnd Bergmann { "decr_status", &spufs_decr_status_ops, 0666, }, 25518b3d6663SArnd Bergmann { "event_mask", &spufs_event_mask_ops, 0666, }, 2552b9e3bd77SDwayne Grant McConnell { "event_status", &spufs_event_status_ops, 0444, }, 25536f7dde81SJeremy Kerr { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, 255486767277SArnd Bergmann { "phys-id", &spufs_id_ops, 0666, }, 255586767277SArnd Bergmann { "object-id", &spufs_object_id_ops, 0666, }, 25566f7dde81SJeremy Kerr { "mbox_info", &spufs_mbox_info_fops, 0444, sizeof(u32), }, 25576f7dde81SJeremy Kerr { "ibox_info", &spufs_ibox_info_fops, 0444, sizeof(u32), }, 25586f7dde81SJeremy Kerr { "wbox_info", &spufs_wbox_info_fops, 0444, sizeof(u32), }, 25596f7dde81SJeremy Kerr { "dma_info", &spufs_dma_info_fops, 0444, 25606f7dde81SJeremy Kerr sizeof(struct spu_dma_info), }, 25616f7dde81SJeremy Kerr { "proxydma_info", &spufs_proxydma_info_fops, 0444, 25626f7dde81SJeremy Kerr sizeof(struct spu_proxydma_info)}, 2563476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2564e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 25655158e9b5SChristoph Hellwig { "switch_log", &spufs_switch_log_fops, 0444 }, 256667207b96SArnd Bergmann {}, 256767207b96SArnd Bergmann }; 25685737edd1SMark Nutter 256974254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_nosched_contents[] = { 2570cbe709c1SBenjamin Herrenschmidt { "capabilities", &spufs_caps_fops, 0444, }, 25716f7dde81SJeremy Kerr { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, 25725737edd1SMark Nutter { "mbox", &spufs_mbox_fops, 0444, }, 25735737edd1SMark Nutter { "ibox", &spufs_ibox_fops, 0444, }, 25745737edd1SMark Nutter { "wbox", &spufs_wbox_fops, 0222, }, 25756f7dde81SJeremy Kerr { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, 25766f7dde81SJeremy Kerr { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, 25776f7dde81SJeremy Kerr { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, 2578d054b36fSJeremy Kerr { "signal1", &spufs_signal1_nosched_fops, 0222, }, 2579d054b36fSJeremy Kerr { "signal2", &spufs_signal2_nosched_fops, 0222, }, 25805737edd1SMark Nutter { "signal1_type", &spufs_signal1_type, 0666, }, 25815737edd1SMark Nutter { "signal2_type", &spufs_signal2_type, 0666, }, 25825737edd1SMark Nutter { "mss", &spufs_mss_fops, 0666, }, 25835737edd1SMark Nutter { "mfc", &spufs_mfc_fops, 0666, }, 25845737edd1SMark Nutter { "cntl", &spufs_cntl_fops, 0666, }, 25855737edd1SMark Nutter { "npc", &spufs_npc_ops, 0666, }, 25866f7dde81SJeremy Kerr { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, 25875737edd1SMark Nutter { "phys-id", &spufs_id_ops, 0666, }, 25885737edd1SMark Nutter { "object-id", &spufs_object_id_ops, 0666, }, 2589476273adSChristoph Hellwig { "tid", &spufs_tid_fops, 0444, }, 2590e9f8a0b6SChristoph Hellwig { "stat", &spufs_stat_fops, 0444, }, 25912c3e4787SJeremy Kerr {}, 25922c3e4787SJeremy Kerr }; 25932c3e4787SJeremy Kerr 259474254647SJeremy Kerr const struct spufs_tree_descr spufs_dir_debug_contents[] = { 259546deed69SLuke Browning { ".ctx", &spufs_ctx_fops, 0444, }, 25965737edd1SMark Nutter {}, 25975737edd1SMark Nutter }; 2598bf1ab978SDwayne Grant McConnell 259974254647SJeremy Kerr const struct spufs_coredump_reader spufs_coredump_read[] = { 26005456ffdeSChristoph Hellwig { "regs", spufs_regs_dump, NULL, sizeof(struct spu_reg128[128])}, 26015456ffdeSChristoph Hellwig { "fpcr", spufs_fpcr_dump, NULL, sizeof(struct spu_reg128) }, 2602104f0cc2SMichael Ellerman { "lslr", NULL, spufs_lslr_get, 19 }, 2603104f0cc2SMichael Ellerman { "decr", NULL, spufs_decr_get, 19 }, 2604104f0cc2SMichael Ellerman { "decr_status", NULL, spufs_decr_status_get, 19 }, 26055456ffdeSChristoph Hellwig { "mem", spufs_mem_dump, NULL, LS_SIZE, }, 26065456ffdeSChristoph Hellwig { "signal1", spufs_signal1_dump, NULL, sizeof(u32) }, 2607104f0cc2SMichael Ellerman { "signal1_type", NULL, spufs_signal1_type_get, 19 }, 26085456ffdeSChristoph Hellwig { "signal2", spufs_signal2_dump, NULL, sizeof(u32) }, 2609104f0cc2SMichael Ellerman { "signal2_type", NULL, spufs_signal2_type_get, 19 }, 2610104f0cc2SMichael Ellerman { "event_mask", NULL, spufs_event_mask_get, 19 }, 2611104f0cc2SMichael Ellerman { "event_status", NULL, spufs_event_status_get, 19 }, 26125456ffdeSChristoph Hellwig { "mbox_info", spufs_mbox_info_dump, NULL, sizeof(u32) }, 26135456ffdeSChristoph Hellwig { "ibox_info", spufs_ibox_info_dump, NULL, sizeof(u32) }, 26145456ffdeSChristoph Hellwig { "wbox_info", spufs_wbox_info_dump, NULL, 4 * sizeof(u32)}, 26155456ffdeSChristoph Hellwig { "dma_info", spufs_dma_info_dump, NULL, sizeof(struct spu_dma_info)}, 26165456ffdeSChristoph Hellwig { "proxydma_info", spufs_proxydma_info_dump, 26174fca9c42SMichael Ellerman NULL, sizeof(struct spu_proxydma_info)}, 2618104f0cc2SMichael Ellerman { "object-id", NULL, spufs_object_id_get, 19 }, 2619104f0cc2SMichael Ellerman { "npc", NULL, spufs_npc_get, 19 }, 2620936d5bf1SMichael Ellerman { NULL }, 2621bf1ab978SDwayne Grant McConnell }; 2622