file.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,306 行 · 第 1/2 页

C
1,306
字号
	ctx->ops->signal1_write(ctx, data);	spu_release(ctx);	return 4;}#ifdef CONFIG_SPUFS_MMAPstatic struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,					      unsigned long address, int *type){	return spufs_ps_nopage(vma, address, type, 0x14000);}static struct vm_operations_struct spufs_signal1_mmap_vmops = {	.nopage = spufs_signal1_mmap_nopage,};static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma){	if (!(vma->vm_flags & VM_SHARED))		return -EINVAL;	vma->vm_flags |= VM_RESERVED;	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)				     | _PAGE_NO_CACHE);	vma->vm_ops = &spufs_signal1_mmap_vmops;	return 0;}#endifstatic struct file_operations spufs_signal1_fops = {	.open = spufs_signal1_open,	.read = spufs_signal1_read,	.write = spufs_signal1_write,#ifdef CONFIG_SPUFS_MMAP	.mmap = spufs_signal1_mmap,#endif};static int spufs_signal2_open(struct inode *inode, struct file *file){	struct spufs_inode_info *i = SPUFS_I(inode);	struct spu_context *ctx = i->i_ctx;	file->private_data = ctx;	file->f_mapping = inode->i_mapping;	ctx->signal2 = inode->i_mapping;	return nonseekable_open(inode, file);}static ssize_t spufs_signal2_read(struct file *file, char __user *buf,			size_t len, loff_t *pos){	struct spu_context *ctx;	u32 data;	ctx = file->private_data;	if (len < 4)		return -EINVAL;	spu_acquire(ctx);	data = ctx->ops->signal2_read(ctx);	spu_release(ctx);	if (copy_to_user(buf, &data, 4))		return -EFAULT;	return 4;}static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,			size_t len, loff_t *pos){	struct spu_context *ctx;	u32 data;	ctx = file->private_data;	if (len < 4)		return -EINVAL;	if (copy_from_user(&data, buf, 4))		return -EFAULT;	spu_acquire(ctx);	ctx->ops->signal2_write(ctx, data);	spu_release(ctx);	return 4;}#ifdef CONFIG_SPUFS_MMAPstatic struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,					      unsigned long address, int *type){	return spufs_ps_nopage(vma, address, type, 0x1c000);}static struct vm_operations_struct spufs_signal2_mmap_vmops = {	.nopage = spufs_signal2_mmap_nopage,};static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma){	if (!(vma->vm_flags & VM_SHARED))		return -EINVAL;	/* FIXME: */	vma->vm_flags |= VM_RESERVED;	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)				     | _PAGE_NO_CACHE);	vma->vm_ops = &spufs_signal2_mmap_vmops;	return 0;}#endifstatic struct file_operations spufs_signal2_fops = {	.open = spufs_signal2_open,	.read = spufs_signal2_read,	.write = spufs_signal2_write,#ifdef CONFIG_SPUFS_MMAP	.mmap = spufs_signal2_mmap,#endif};static void spufs_signal1_type_set(void *data, u64 val){	struct spu_context *ctx = data;	spu_acquire(ctx);	ctx->ops->signal1_type_set(ctx, val);	spu_release(ctx);}static u64 spufs_signal1_type_get(void *data){	struct spu_context *ctx = data;	u64 ret;	spu_acquire(ctx);	ret = ctx->ops->signal1_type_get(ctx);	spu_release(ctx);	return ret;}DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,					spufs_signal1_type_set, "%llu");static void spufs_signal2_type_set(void *data, u64 val){	struct spu_context *ctx = data;	spu_acquire(ctx);	ctx->ops->signal2_type_set(ctx, val);	spu_release(ctx);}static u64 spufs_signal2_type_get(void *data){	struct spu_context *ctx = data;	u64 ret;	spu_acquire(ctx);	ret = ctx->ops->signal2_type_get(ctx);	spu_release(ctx);	return ret;}DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,					spufs_signal2_type_set, "%llu");#ifdef CONFIG_SPUFS_MMAPstatic struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,					   unsigned long address, int *type){	return spufs_ps_nopage(vma, address, type, 0x3000);}static struct vm_operations_struct spufs_mfc_mmap_vmops = {	.nopage = spufs_mfc_mmap_nopage,};/* * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. * Mapping this area requires that the application have CAP_SYS_RAWIO, * as these registers require special care when read/writing. */static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma){	if (!(vma->vm_flags & VM_SHARED))		return -EINVAL;	if (!capable(CAP_SYS_RAWIO))		return -EPERM;	vma->vm_flags |= VM_RESERVED;	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)				     | _PAGE_NO_CACHE);	vma->vm_ops = &spufs_mfc_mmap_vmops;	return 0;}#endifstatic int spufs_mfc_open(struct inode *inode, struct file *file){	struct spufs_inode_info *i = SPUFS_I(inode);	struct spu_context *ctx = i->i_ctx;	/* we don't want to deal with DMA into other processes */	if (ctx->owner != current->mm)		return -EINVAL;	if (atomic_read(&inode->i_count) != 1)		return -EBUSY;	file->private_data = ctx;	return nonseekable_open(inode, file);}/* interrupt-level mfc callback function. */void spufs_mfc_callback(struct spu *spu){	struct spu_context *ctx = spu->ctx;	wake_up_all(&ctx->mfc_wq);	pr_debug("%s %s\n", __FUNCTION__, spu->name);	if (ctx->mfc_fasync) {		u32 free_elements, tagstatus;		unsigned int mask;		/* no need for spu_acquire in interrupt context */		free_elements = ctx->ops->get_mfc_free_elements(ctx);		tagstatus = ctx->ops->read_mfc_tagstatus(ctx);		mask = 0;		if (free_elements & 0xffff)			mask |= POLLOUT;		if (tagstatus & ctx->tagwait)			mask |= POLLIN;		kill_fasync(&ctx->mfc_fasync, SIGIO, mask);	}}static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status){	/* See if there is one tag group is complete */	/* FIXME we need locking around tagwait */	*status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait;	ctx->tagwait &= ~*status;	if (*status)		return 1;	/* enable interrupt waiting for any tag group,	   may silently fail if interrupts are already enabled */	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);	return 0;}static ssize_t spufs_mfc_read(struct file *file, char __user *buffer,			size_t size, loff_t *pos){	struct spu_context *ctx = file->private_data;	int ret = -EINVAL;	u32 status;	if (size != 4)		goto out;	spu_acquire(ctx);	if (file->f_flags & O_NONBLOCK) {		status = ctx->ops->read_mfc_tagstatus(ctx);		if (!(status & ctx->tagwait))			ret = -EAGAIN;		else			ctx->tagwait &= ~status;	} else {		ret = spufs_wait(ctx->mfc_wq,			   spufs_read_mfc_tagstatus(ctx, &status));	}	spu_release(ctx);	if (ret)		goto out;	ret = 4;	if (copy_to_user(buffer, &status, 4))		ret = -EFAULT;out:	return ret;}static int spufs_check_valid_dma(struct mfc_dma_command *cmd){	pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa,		 cmd->ea, cmd->size, cmd->tag, cmd->cmd);	switch (cmd->cmd) {	case MFC_PUT_CMD:	case MFC_PUTF_CMD:	case MFC_PUTB_CMD:	case MFC_GET_CMD:	case MFC_GETF_CMD:	case MFC_GETB_CMD:		break;	default:		pr_debug("invalid DMA opcode %x\n", cmd->cmd);		return -EIO;	}	if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) {		pr_debug("invalid DMA alignment, ea %lx lsa %x\n",				cmd->ea, cmd->lsa);		return -EIO;	}	switch (cmd->size & 0xf) {	case 1:		break;	case 2:		if (cmd->lsa & 1)			goto error;		break;	case 4:		if (cmd->lsa & 3)			goto error;		break;	case 8:		if (cmd->lsa & 7)			goto error;		break;	case 0:		if (cmd->lsa & 15)			goto error;		break;	error:	default:		pr_debug("invalid DMA alignment %x for size %x\n",			cmd->lsa & 0xf, cmd->size);		return -EIO;	}	if (cmd->size > 16 * 1024) {		pr_debug("invalid DMA size %x\n", cmd->size);		return -EIO;	}	if (cmd->tag & 0xfff0) {		/* we reserve the higher tag numbers for kernel use */		pr_debug("invalid DMA tag\n");		return -EIO;	}	if (cmd->class) {		/* not supported in this version */		pr_debug("invalid DMA class\n");		return -EIO;	}	return 0;}static int spu_send_mfc_command(struct spu_context *ctx,				struct mfc_dma_command cmd,				int *error){	*error = ctx->ops->send_mfc_command(ctx, &cmd);	if (*error == -EAGAIN) {		/* wait for any tag group to complete		   so we have space for the new command */		ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);		/* try again, because the queue might be		   empty again */		*error = ctx->ops->send_mfc_command(ctx, &cmd);		if (*error == -EAGAIN)			return 0;	}	return 1;}static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,			size_t size, loff_t *pos){	struct spu_context *ctx = file->private_data;	struct mfc_dma_command cmd;	int ret = -EINVAL;	if (size != sizeof cmd)		goto out;	ret = -EFAULT;	if (copy_from_user(&cmd, buffer, sizeof cmd))		goto out;	ret = spufs_check_valid_dma(&cmd);	if (ret)		goto out;	spu_acquire_runnable(ctx);	if (file->f_flags & O_NONBLOCK) {		ret = ctx->ops->send_mfc_command(ctx, &cmd);	} else {		int status;		ret = spufs_wait(ctx->mfc_wq,				 spu_send_mfc_command(ctx, cmd, &status));		if (status)			ret = status;	}	spu_release(ctx);	if (ret)		goto out;	ctx->tagwait |= 1 << cmd.tag;out:	return ret;}static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait){	struct spu_context *ctx = file->private_data;	u32 free_elements, tagstatus;	unsigned int mask;	spu_acquire(ctx);	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);	free_elements = ctx->ops->get_mfc_free_elements(ctx);	tagstatus = ctx->ops->read_mfc_tagstatus(ctx);	spu_release(ctx);	poll_wait(file, &ctx->mfc_wq, wait);	mask = 0;	if (free_elements & 0xffff)		mask |= POLLOUT | POLLWRNORM;	if (tagstatus & ctx->tagwait)		mask |= POLLIN | POLLRDNORM;	pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__,		free_elements, tagstatus, ctx->tagwait);	return mask;}static int spufs_mfc_flush(struct file *file){	struct spu_context *ctx = file->private_data;	int ret;	spu_acquire(ctx);#if 0/* this currently hangs */	ret = spufs_wait(ctx->mfc_wq,			 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2));	if (ret)		goto out;	ret = spufs_wait(ctx->mfc_wq,			 ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait);out:#else	ret = 0;#endif	spu_release(ctx);	return ret;}static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,			   int datasync){	return spufs_mfc_flush(file);}static int spufs_mfc_fasync(int fd, struct file *file, int on){	struct spu_context *ctx = file->private_data;	return fasync_helper(fd, file, on, &ctx->mfc_fasync);}static struct file_operations spufs_mfc_fops = {	.open	 = spufs_mfc_open,	.read	 = spufs_mfc_read,	.write	 = spufs_mfc_write,	.poll	 = spufs_mfc_poll,	.flush	 = spufs_mfc_flush,	.fsync	 = spufs_mfc_fsync,	.fasync	 = spufs_mfc_fasync,#ifdef CONFIG_SPUFS_MMAP	.mmap	 = spufs_mfc_mmap,#endif};static void spufs_npc_set(void *data, u64 val){	struct spu_context *ctx = data;	spu_acquire(ctx);	ctx->ops->npc_write(ctx, val);	spu_release(ctx);}static u64 spufs_npc_get(void *data){	struct spu_context *ctx = data;	u64 ret;	spu_acquire(ctx);	ret = ctx->ops->npc_read(ctx);	spu_release(ctx);	return ret;}DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")static void spufs_decr_set(void *data, u64 val){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	spu_acquire_saved(ctx);	lscsa->decr.slot[0] = (u32) val;	spu_release(ctx);}static u64 spufs_decr_get(void *data){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	u64 ret;	spu_acquire_saved(ctx);	ret = lscsa->decr.slot[0];	spu_release(ctx);	return ret;}DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,			"%llx\n")static void spufs_decr_status_set(void *data, u64 val){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	spu_acquire_saved(ctx);	lscsa->decr_status.slot[0] = (u32) val;	spu_release(ctx);}static u64 spufs_decr_status_get(void *data){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	u64 ret;	spu_acquire_saved(ctx);	ret = lscsa->decr_status.slot[0];	spu_release(ctx);	return ret;}DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,			spufs_decr_status_set, "%llx\n")static void spufs_spu_tag_mask_set(void *data, u64 val){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	spu_acquire_saved(ctx);	lscsa->tag_mask.slot[0] = (u32) val;	spu_release(ctx);}static u64 spufs_spu_tag_mask_get(void *data){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	u64 ret;	spu_acquire_saved(ctx);	ret = lscsa->tag_mask.slot[0];	spu_release(ctx);	return ret;}DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,			spufs_spu_tag_mask_set, "%llx\n")static void spufs_event_mask_set(void *data, u64 val){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	spu_acquire_saved(ctx);	lscsa->event_mask.slot[0] = (u32) val;	spu_release(ctx);}static u64 spufs_event_mask_get(void *data){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	u64 ret;	spu_acquire_saved(ctx);	ret = lscsa->event_mask.slot[0];	spu_release(ctx);	return ret;}DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,			spufs_event_mask_set, "%llx\n")static void spufs_srr0_set(void *data, u64 val){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	spu_acquire_saved(ctx);	lscsa->srr0.slot[0] = (u32) val;	spu_release(ctx);}static u64 spufs_srr0_get(void *data){	struct spu_context *ctx = data;	struct spu_lscsa *lscsa = ctx->csa.lscsa;	u64 ret;	spu_acquire_saved(ctx);	ret = lscsa->srr0.slot[0];	spu_release(ctx);	return ret;}DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,			"%llx\n")struct tree_descr spufs_dir_contents[] = {	{ "mem",  &spufs_mem_fops,  0666, },	{ "regs", &spufs_regs_fops,  0666, },	{ "mbox", &spufs_mbox_fops, 0444, },	{ "ibox", &spufs_ibox_fops, 0444, },	{ "wbox", &spufs_wbox_fops, 0222, },	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },	{ "signal1", &spufs_signal1_fops, 0666, },	{ "signal2", &spufs_signal2_fops, 0666, },	{ "signal1_type", &spufs_signal1_type, 0666, },	{ "signal2_type", &spufs_signal2_type, 0666, },	{ "mfc", &spufs_mfc_fops, 0666, },	{ "cntl", &spufs_cntl_fops,  0666, },	{ "npc", &spufs_npc_ops, 0666, },	{ "fpcr", &spufs_fpcr_fops, 0666, },	{ "decr", &spufs_decr_ops, 0666, },	{ "decr_status", &spufs_decr_status_ops, 0666, },	{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },	{ "event_mask", &spufs_event_mask_ops, 0666, },	{ "srr0", &spufs_srr0_ops, 0666, },	{},};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?