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;
}
Example #2
0
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;
}