static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf, size_t count, loff_t *offp) { struct nvhost_channel_userctx *priv = filp->private_data; size_t remaining = count; int err = 0; struct nvhost_job *job = priv->job; struct nvhost_submit_hdr_ext *hdr = &priv->hdr; const char *chname = priv->ch->desc->name; while (remaining) { size_t consumed; if (!hdr->num_relocs && !priv->num_relocshifts && !hdr->num_cmdbufs && !hdr->num_waitchks) { consumed = sizeof(struct nvhost_submit_hdr); if (remaining < consumed) break; if (copy_from_user(hdr, buf, consumed)) { err = -EFAULT; break; } hdr->submit_version = NVHOST_SUBMIT_VERSION_V0; err = set_submit(priv); if (err) break; trace_nvhost_channel_write_submit(chname, count, hdr->num_cmdbufs, hdr->num_relocs, hdr->syncpt_id, hdr->syncpt_incrs); } else if (hdr->num_cmdbufs) { struct nvhost_cmdbuf cmdbuf; consumed = sizeof(cmdbuf); if (remaining < consumed) break; if (copy_from_user(&cmdbuf, buf, consumed)) { err = -EFAULT; break; } trace_nvhost_channel_write_cmdbuf(chname, cmdbuf.mem, cmdbuf.words, cmdbuf.offset); nvhost_job_add_gather(job, cmdbuf.mem, cmdbuf.words, cmdbuf.offset); hdr->num_cmdbufs--; } else if (hdr->num_relocs) { consumed = sizeof(struct nvhost_reloc); if (remaining < consumed) break; if (copy_from_user(&job->pinarray[job->num_pins], buf, consumed)) { err = -EFAULT; break; } trace_nvhost_channel_write_reloc(chname); job->num_pins++; hdr->num_relocs--; } else if (hdr->num_waitchks) { int numwaitchks = (remaining / sizeof(struct nvhost_waitchk)); if (!numwaitchks) break; numwaitchks = min_t(int, numwaitchks, hdr->num_waitchks); consumed = numwaitchks * sizeof(struct nvhost_waitchk); if (copy_from_user(&job->waitchk[job->num_waitchk], buf, consumed)) { err = -EFAULT; break; } trace_nvhost_channel_write_waitchks( chname, numwaitchks, hdr->waitchk_mask); job->num_waitchk += numwaitchks; hdr->num_waitchks -= numwaitchks; } else if (priv->num_relocshifts) {
static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf, size_t count, loff_t *offp) { struct nvhost_channel_userctx *priv = filp->private_data; size_t remaining = count; int err = 0; struct nvhost_job *job = priv->job; struct nvhost_submit_hdr_ext *hdr = &priv->hdr; const char *chname = priv->ch->desc->name; if (!job) return -ENOMEM; while (remaining) { size_t consumed; if (!hdr->num_relocs && !priv->num_relocshifts && !hdr->num_cmdbufs && !hdr->num_waitchks) { consumed = sizeof(struct nvhost_submit_hdr); if (remaining < consumed) break; if (copy_from_user(hdr, buf, consumed)) { err = -EFAULT; break; } hdr->submit_version = NVHOST_SUBMIT_VERSION_V0; err = set_submit(priv); if (err) break; trace_nvhost_channel_write_submit(chname, count, hdr->num_cmdbufs, hdr->num_relocs, hdr->syncpt_id, hdr->syncpt_incrs); } else if (hdr->num_cmdbufs) { struct nvhost_cmdbuf cmdbuf; consumed = sizeof(cmdbuf); if (remaining < consumed) break; if (copy_from_user(&cmdbuf, buf, consumed)) { err = -EFAULT; break; } trace_nvhost_channel_write_cmdbuf(chname, cmdbuf.mem, cmdbuf.words, cmdbuf.offset); nvhost_job_add_gather(job, cmdbuf.mem, cmdbuf.words, cmdbuf.offset); hdr->num_cmdbufs--; } else if (hdr->num_relocs) { struct nvmap_pinarray_elem *elem = &job->pinarray[job->num_pins]; consumed = sizeof(struct nvhost_reloc); if (remaining < consumed) break; if (copy_from_user(elem, buf, consumed)) { err = -EFAULT; break; } elem->patch_mem = nvmap_convert_handle_u2k(elem->patch_mem); elem->pin_mem = nvmap_convert_handle_u2k(elem->pin_mem); trace_nvhost_channel_write_reloc(chname); job->num_pins++; hdr->num_relocs--; } else if (hdr->num_waitchks) { struct nvhost_waitchk *waitchk = &job->waitchk[job->num_waitchk]; consumed = sizeof(struct nvhost_waitchk); if (remaining < consumed) break; if (copy_from_user(waitchk, buf, consumed)) { err = -EFAULT; break; } waitchk->mem = nvmap_convert_handle_u2k(waitchk->mem); trace_nvhost_channel_write_waitchks( chname, 1, hdr->waitchk_mask); job->num_waitchk++; hdr->num_waitchks--; } else if (priv->num_relocshifts) { int next_shift = job->num_pins - priv->num_relocshifts; consumed = sizeof(struct nvhost_reloc_shift); if (remaining < consumed) break; if (copy_from_user( &job->pinarray[next_shift].reloc_shift, buf, consumed)) { err = -EFAULT; break; } priv->num_relocshifts--; } else { err = -EFAULT; break; } remaining -= consumed; buf += consumed; } if (err < 0) { dev_err(&priv->ch->dev->pdev->dev, "channel write error\n"); reset_submit(priv); return err; } return count - remaining; }
static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf, size_t count, loff_t *offp) { struct nvhost_channel_userctx *priv = filp->private_data; size_t remaining = count; int err = 0; struct nvhost_job *job; struct nvhost_submit_hdr_ext *hdr; const char *chname; mutex_lock(&priv->mutex); job = priv->job; hdr = &priv->hdr; chname = priv->ch->dev->name; if (!job) { mutex_unlock(&priv->mutex); return -EIO; } while (remaining) { size_t consumed; if (!hdr->num_relocs && !priv->num_relocshifts && !hdr->num_cmdbufs && !hdr->num_waitchks) { consumed = sizeof(struct nvhost_submit_hdr); if (remaining < consumed) break; if (copy_from_user(hdr, buf, consumed)) { err = -EFAULT; break; } hdr->submit_version = NVHOST_SUBMIT_VERSION_V0; err = set_submit(priv); if (err) break; trace_nvhost_channel_write_submit(chname, count, hdr->num_cmdbufs, hdr->num_relocs, hdr->syncpt_id, hdr->syncpt_incrs); } else if (hdr->num_cmdbufs) { struct nvhost_cmdbuf cmdbuf; consumed = sizeof(cmdbuf); if (remaining < consumed) break; if (copy_from_user(&cmdbuf, buf, consumed)) { err = -EFAULT; break; } trace_nvhost_channel_write_cmdbuf(chname, cmdbuf.mem, cmdbuf.words, cmdbuf.offset); nvhost_job_add_gather(job, cmdbuf.mem, cmdbuf.words, cmdbuf.offset); hdr->num_cmdbufs--; } else if (hdr->num_relocs) { int numrelocs = remaining / sizeof(struct nvhost_reloc); if (!numrelocs) break; numrelocs = min_t(int, numrelocs, priv->hdr.num_relocs); consumed = numrelocs * sizeof(struct nvhost_reloc); if (copy_from_user(&job->relocarray[job->num_relocs], buf, consumed)) { err = -EFAULT; break; } while (numrelocs) { struct nvhost_reloc *reloc = &job->relocarray[job->num_relocs]; trace_nvhost_channel_write_reloc(chname, reloc->cmdbuf_mem, reloc->cmdbuf_offset, reloc->target, reloc->target_offset); job->num_relocs++; hdr->num_relocs--; numrelocs--; } } else if (hdr->num_waitchks) {
int nvhost_gr3d_t30_read_reg( struct platform_device *dev, struct nvhost_channel *channel, struct nvhost_hwctx *hwctx, u32 offset, u32 *value) { struct host1x_hwctx_handler *h = to_host1x_hwctx_handler(hwctx->h); u32 syncpt_incrs = 1; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); void *ref; void *read_waiter = NULL; struct nvhost_job *job; int err; struct mem_handle *mem = NULL; u32 *mem_ptr = NULL; u32 *cmdbuf_ptr = NULL; struct sg_table *mem_sgt = NULL; struct mem_mgr *memmgr = hwctx->memmgr; u32 opcodes[] = { /* Switch to 3D - set up output to memory */ nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0), nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 1), nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_ADDRESS, 1), 0xdeadbeef, /* Get host1x to request a register read */ nvhost_opcode_setclass(NV_HOST1X_CLASS_ID, host1x_uclass_indoff_r(), 1), nvhost_class_host_indoff_reg_read( host1x_uclass_indoff_indmodid_gr3d_v(), offset, false), nvhost_opcode_imm(host1x_uclass_inddata_r(), 0), /* send reg reads back to host */ nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0), nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 0), /* Finalize with syncpt increment */ nvhost_opcode_setclass(NV_HOST1X_CLASS_ID, host1x_uclass_incr_syncpt_base_r(), 1), nvhost_class_host_incr_syncpt_base(h->h.waitbase, 1), nvhost_opcode_imm_incr_syncpt( host1x_uclass_incr_syncpt_cond_immediate_v(), h->h.syncpt), }; /* 12 slots for gather, and one slot for storing the result value */ mem = nvhost_memmgr_alloc(memmgr, sizeof(opcodes)+4, 32, mem_mgr_flag_uncacheable); if (IS_ERR(mem)) return PTR_ERR(mem); mem_ptr = nvhost_memmgr_mmap(mem); if (!mem_ptr) { err = -ENOMEM; goto done; } cmdbuf_ptr = mem_ptr + 1; mem_sgt = nvhost_memmgr_pin(memmgr, mem, &channel->dev->dev); if (IS_ERR(mem_sgt)) { err = -ENOMEM; mem_sgt = NULL; goto done; } /* Set address of target memory slot to the stream */ opcodes[3] = sg_dma_address(mem_sgt->sgl); read_waiter = nvhost_intr_alloc_waiter(); if (!read_waiter) { err = -ENOMEM; goto done; } job = nvhost_job_alloc(channel, hwctx, 1, 0, 0, 1, memmgr); if (!job) { err = -ENOMEM; goto done; } job->hwctx_syncpt_idx = 0; job->sp->id = h->h.syncpt; job->sp->waitbase = h->h.waitbase; job->sp->incrs = syncpt_incrs; job->num_syncpts = 1; job->serialize = 1; memcpy(cmdbuf_ptr, opcodes, sizeof(opcodes)); /* Submit job */ nvhost_job_add_gather(job, nvhost_memmgr_handle_to_id(mem), ARRAY_SIZE(opcodes), 4); err = nvhost_job_pin(job, &nvhost_get_host(dev)->syncpt); if (err) goto done; err = nvhost_channel_submit(job); if (err) goto done; /* Wait for read to be ready */ err = nvhost_intr_add_action(&nvhost_get_host(dev)->intr, h->h.syncpt, job->sp->fence, NVHOST_INTR_ACTION_WAKEUP, &wq, read_waiter, &ref); read_waiter = NULL; WARN(err, "Failed to set wakeup interrupt"); wait_event(wq, nvhost_syncpt_is_expired(&nvhost_get_host(dev)->syncpt, h->h.syncpt, job->sp->fence)); nvhost_job_put(job); job = NULL; nvhost_intr_put_ref(&nvhost_get_host(dev)->intr, h->h.syncpt, ref); *value = *mem_ptr; done: kfree(read_waiter); if (mem_ptr) nvhost_memmgr_munmap(mem, mem_ptr); if (mem_sgt) nvhost_memmgr_unpin(memmgr, mem, &channel->dev->dev, mem_sgt); if (mem) nvhost_memmgr_put(memmgr, mem); return err; }