📄 file.c
字号:
/* * SPU file system -- file contents * * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 * * Author: Arnd Bergmann <arndb@de.ibm.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#undef DEBUG#include <linux/fs.h>#include <linux/ioctl.h>#include <linux/module.h>#include <linux/pagemap.h>#include <linux/poll.h>#include <linux/ptrace.h>#include <linux/seq_file.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/spu.h>#include <asm/spu_info.h>#include <asm/uaccess.h>#include "spufs.h"#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)static intspufs_mem_open(struct inode *inode, struct file *file){ struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->local_store = inode->i_mapping; mutex_unlock(&ctx->mapping_lock); return 0;}static intspufs_mem_release(struct inode *inode, struct file *file){ struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->local_store = NULL; mutex_unlock(&ctx->mapping_lock); return 0;}static ssize_t__spufs_mem_read(struct spu_context *ctx, char __user *buffer, size_t size, loff_t *pos){ char *local_store = ctx->ops->get_ls(ctx); return simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);}static ssize_tspufs_mem_read(struct file *file, char __user *buffer, size_t size, loff_t *pos){ struct spu_context *ctx = file->private_data; ssize_t ret; spu_acquire(ctx); ret = __spufs_mem_read(ctx, buffer, size, pos); spu_release(ctx); return ret;}static ssize_tspufs_mem_write(struct file *file, const char __user *buffer, size_t size, loff_t *ppos){ struct spu_context *ctx = file->private_data; char *local_store; loff_t pos = *ppos; int ret; if (pos < 0) return -EINVAL; if (pos > LS_SIZE) return -EFBIG; if (size > LS_SIZE - pos) size = LS_SIZE - pos; spu_acquire(ctx); local_store = ctx->ops->get_ls(ctx); ret = copy_from_user(local_store + pos, buffer, size); spu_release(ctx); if (ret) return -EFAULT; *ppos = pos + size; return size;}static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, unsigned long address){ struct spu_context *ctx = vma->vm_file->private_data; unsigned long pfn, offset, addr0 = address;#ifdef CONFIG_SPU_FS_64K_LS struct spu_state *csa = &ctx->csa; int psize; /* Check what page size we are using */ psize = get_slice_psize(vma->vm_mm, address); /* Some sanity checking */ BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K)); /* Wow, 64K, cool, we need to align the address though */ if (csa->use_big_pages) { BUG_ON(vma->vm_start & 0xffff); address &= ~0xfffful; }#endif /* CONFIG_SPU_FS_64K_LS */ offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); if (offset >= LS_SIZE) return NOPFN_SIGBUS; pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n", addr0, address, offset); spu_acquire(ctx); if (ctx->state == SPU_STATE_SAVED) { vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) & ~_PAGE_NO_CACHE); pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); } else { vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE); pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; } vm_insert_pfn(vma, address, pfn); spu_release(ctx); return NOPFN_REFAULT;}static struct vm_operations_struct spufs_mem_mmap_vmops = { .nopfn = spufs_mem_mmap_nopfn,};static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma){#ifdef CONFIG_SPU_FS_64K_LS struct spu_context *ctx = file->private_data; struct spu_state *csa = &ctx->csa; /* Sanity check VMA alignment */ if (csa->use_big_pages) { pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx," " pgoff=0x%lx\n", vma->vm_start, vma->vm_end, vma->vm_pgoff); if (vma->vm_start & 0xffff) return -EINVAL; if (vma->vm_pgoff & 0xf) return -EINVAL; }#endif /* CONFIG_SPU_FS_64K_LS */ if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE); vma->vm_ops = &spufs_mem_mmap_vmops; return 0;}#ifdef CONFIG_SPU_FS_64K_LSstatic unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags){ struct spu_context *ctx = file->private_data; struct spu_state *csa = &ctx->csa; /* If not using big pages, fallback to normal MM g_u_a */ if (!csa->use_big_pages) return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); /* Else, try to obtain a 64K pages slice */ return slice_get_unmapped_area(addr, len, flags, MMU_PAGE_64K, 1, 0);}#endif /* CONFIG_SPU_FS_64K_LS */static const struct file_operations spufs_mem_fops = { .open = spufs_mem_open, .release = spufs_mem_release, .read = spufs_mem_read, .write = spufs_mem_write, .llseek = generic_file_llseek, .mmap = spufs_mem_mmap,#ifdef CONFIG_SPU_FS_64K_LS .get_unmapped_area = spufs_get_unmapped_area,#endif};static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, unsigned long address, unsigned long ps_offs, unsigned long ps_size){ struct spu_context *ctx = vma->vm_file->private_data; unsigned long area, offset = address - vma->vm_start; int ret; offset += vma->vm_pgoff << PAGE_SHIFT; if (offset >= ps_size) return NOPFN_SIGBUS; /* error here usually means a signal.. we might want to test * the error code more precisely though */ ret = spu_acquire_runnable(ctx, 0); if (ret) return NOPFN_REFAULT; area = ctx->spu->problem_phys + ps_offs; vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); spu_release(ctx); return NOPFN_REFAULT;}#if SPUFS_MMAP_4Kstatic unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, unsigned long address){ return spufs_ps_nopfn(vma, address, 0x4000, 0x1000);}static struct vm_operations_struct spufs_cntl_mmap_vmops = { .nopfn = spufs_cntl_mmap_nopfn,};/* * mmap support for problem state control area [0x4000 - 0x4fff]. */static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma){ if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); vma->vm_ops = &spufs_cntl_mmap_vmops; return 0;}#else /* SPUFS_MMAP_4K */#define spufs_cntl_mmap NULL#endif /* !SPUFS_MMAP_4K */static u64 spufs_cntl_get(void *data){ struct spu_context *ctx = data; u64 val; spu_acquire(ctx); val = ctx->ops->status_read(ctx); spu_release(ctx); return val;}static void spufs_cntl_set(void *data, u64 val){ struct spu_context *ctx = data; spu_acquire(ctx); ctx->ops->runcntl_write(ctx, val); spu_release(ctx);}static int spufs_cntl_open(struct inode *inode, struct file *file){ struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->cntl = inode->i_mapping; mutex_unlock(&ctx->mapping_lock); return simple_attr_open(inode, file, spufs_cntl_get, spufs_cntl_set, "0x%08lx");}static intspufs_cntl_release(struct inode *inode, struct file *file){ struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; simple_attr_close(inode, file); mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->cntl = NULL; mutex_unlock(&ctx->mapping_lock); return 0;}static const struct file_operations spufs_cntl_fops = { .open = spufs_cntl_open, .release = spufs_cntl_release, .read = simple_attr_read, .write = simple_attr_write, .mmap = spufs_cntl_mmap,};static intspufs_regs_open(struct inode *inode, struct file *file){ struct spufs_inode_info *i = SPUFS_I(inode); file->private_data = i->i_ctx; return 0;}static ssize_t__spufs_regs_read(struct spu_context *ctx, char __user *buffer, size_t size, loff_t *pos){ struct spu_lscsa *lscsa = ctx->csa.lscsa; return simple_read_from_buffer(buffer, size, pos, lscsa->gprs, sizeof lscsa->gprs);}static ssize_tspufs_regs_read(struct file *file, char __user *buffer, size_t size, loff_t *pos){ int ret; struct spu_context *ctx = file->private_data; spu_acquire_saved(ctx); ret = __spufs_regs_read(ctx, buffer, size, pos); spu_release_saved(ctx); return ret;}static ssize_tspufs_regs_write(struct file *file, const char __user *buffer, size_t size, loff_t *pos){ struct spu_context *ctx = file->private_data; struct spu_lscsa *lscsa = ctx->csa.lscsa; int ret; size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); if (size <= 0) return -EFBIG; *pos += size; spu_acquire_saved(ctx); ret = copy_from_user(lscsa->gprs + *pos - size, buffer, size) ? -EFAULT : size; spu_release_saved(ctx); return ret;}static const struct file_operations spufs_regs_fops = { .open = spufs_regs_open, .read = spufs_regs_read, .write = spufs_regs_write, .llseek = generic_file_llseek,};static ssize_t__spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, size_t size, loff_t * pos){ struct spu_lscsa *lscsa = ctx->csa.lscsa; return simple_read_from_buffer(buffer, size, pos, &lscsa->fpcr, sizeof(lscsa->fpcr));}static ssize_tspufs_fpcr_read(struct file *file, char __user * buffer, size_t size, loff_t * pos){ int ret; struct spu_context *ctx = file->private_data; spu_acquire_saved(ctx); ret = __spufs_fpcr_read(ctx, buffer, size, pos); spu_release_saved(ctx); return ret;}static ssize_tspufs_fpcr_write(struct file *file, const char __user * buffer, size_t size, loff_t * pos){ struct spu_context *ctx = file->private_data; struct spu_lscsa *lscsa = ctx->csa.lscsa; int ret; size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); if (size <= 0) return -EFBIG; *pos += size; spu_acquire_saved(ctx); ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, buffer, size) ? -EFAULT : size; spu_release_saved(ctx); return ret;}static const struct file_operations spufs_fpcr_fops = { .open = spufs_regs_open, .read = spufs_fpcr_read, .write = spufs_fpcr_write, .llseek = generic_file_llseek,};/* generic open function for all pipe-like files */static int spufs_pipe_open(struct inode *inode, struct file *file){ struct spufs_inode_info *i = SPUFS_I(inode); file->private_data = i->i_ctx; return nonseekable_open(inode, file);}/* * Read as many bytes from the mailbox as possible, until * one of the conditions becomes true: * * - no more data available in the mailbox * - end of the user provided buffer * - end of the mapped area */static ssize_t spufs_mbox_read(struct file *file, char __user *buf, size_t len, loff_t *pos){ struct spu_context *ctx = file->private_data; u32 mbox_data, __user *udata; ssize_t count; if (len < 4) return -EINVAL; if (!access_ok(VERIFY_WRITE, buf, len)) return -EFAULT; udata = (void __user *)buf; spu_acquire(ctx); for (count = 0; (count + 4) <= len; count += 4, udata++) { int ret; ret = ctx->ops->mbox_read(ctx, &mbox_data); if (ret == 0) break; /* * at the end of the mapped area, we can fault * but still need to return the data we have * read successfully so far. */ ret = __put_user(mbox_data, udata); if (ret) { if (!count) count = -EFAULT; break; } } spu_release(ctx); if (!count) count = -EAGAIN; return count;}static const struct file_operations spufs_mbox_fops = { .open = spufs_pipe_open, .read = spufs_mbox_read,};static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, size_t len, loff_t *pos){ struct spu_context *ctx = file->private_data; u32 mbox_stat; if (len < 4) return -EINVAL; spu_acquire(ctx); mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; spu_release(ctx); if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) return -EFAULT; return 4;}static const struct file_operations spufs_mbox_stat_fops = { .open = spufs_pipe_open, .read = spufs_mbox_stat_read,};/* low-level ibox access function */size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -