Ejemplo n.º 1
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;

	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) {
Ejemplo n.º 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;
}