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; while (remaining) { size_t consumed; if (!priv->hdr.num_relocs && !priv->hdr.num_cmdbufs && !priv->hdr.num_waitchks) { consumed = sizeof(struct nvhost_submit_hdr); if (remaining < consumed) break; if (copy_from_user(&priv->hdr, buf, consumed)) { err = -EFAULT; break; } priv->hdr.submit_version = NVHOST_SUBMIT_VERSION_V0; err = set_submit(priv); if (err) break; trace_nvhost_channel_write_submit(priv->ch->desc->name, count, priv->hdr.num_cmdbufs, priv->hdr.num_relocs); } else if (priv->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(priv->ch->desc->name, cmdbuf.mem, cmdbuf.words, cmdbuf.offset); add_gather(priv, cmdbuf.mem, cmdbuf.words, cmdbuf.offset); priv->hdr.num_cmdbufs--; } else if (priv->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(&priv->pinarray[priv->pinarray_size], buf, consumed)) { err = -EFAULT; break; } trace_nvhost_channel_write_relocs(priv->ch->desc->name, numrelocs); priv->pinarray_size += numrelocs; priv->hdr.num_relocs -= numrelocs; } else if (priv->hdr.num_waitchks) {
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; 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) {
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; }