void nvhost_job_add_gather(struct nvhost_job *job, u32 mem_id, u32 words, u32 offset) { struct nvmap_pinarray_elem *pin; struct nvhost_channel_gather *cur_gather = &job->gathers[job->num_gathers]; pin = &job->pinarray[job->num_pins++]; pin->patch_mem = (u32)nvmap_ref_to_handle(job->gather_mem); pin->patch_offset = (void *)&(cur_gather->mem) - (void *)job->gathers; pin->pin_mem = nvmap_convert_handle_u2k(mem_id); pin->pin_offset = offset; cur_gather->words = words; cur_gather->mem_id = mem_id; cur_gather->offset = offset; job->num_gathers += 1; }
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; }