⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 file.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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 + -