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 + -
显示快捷键?