devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thierry Reding <thierry.reding@gmail.com>
To: Sowjanya Komatineni <skomatineni@nvidia.com>
Cc: jonathanh@nvidia.com, frankc@nvidia.com, hverkuil@xs4all.nl,
	helen.koike@collabora.com, sboyd@kernel.org,
	linux-media@vger.kernel.org, devicetree@vger.kernel.org,
	linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH v2 4/6] media: tegra: Add Tegra210 Video input driver
Date: Fri, 14 Feb 2020 17:46:42 +0100	[thread overview]
Message-ID: <20200214164642.GA1310813@ulmo> (raw)
In-Reply-To: <1580937806-17376-5-git-send-email-skomatineni@nvidia.com>

[-- Attachment #1: Type: text/plain, Size: 5669 bytes --]

On Wed, Feb 05, 2020 at 01:23:24PM -0800, Sowjanya Komatineni wrote:
[...]
> +static int tegra_channel_capture_frame(struct tegra_vi_channel *chan,
> +				       struct tegra_channel_buffer *buf)
> +{
> +	int err = 0;
> +	u32 thresh, value, frame_start;
> +	int bytes_per_line = chan->format.bytesperline;
> +
> +	/* program buffer address by using surface 0 */
> +	vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_OFFSET_MSB, 0x0);
> +	vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_OFFSET_LSB, buf->addr);
> +	vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_STRIDE, bytes_per_line);
> +
> +	/* increase syncpoint max */
> +	thresh = host1x_syncpt_incr_max(chan->sp, 1);
> +
> +	/* program syncpoint */
> +	frame_start = VI_CSI_PP_FRAME_START(chan->portno);
> +	value = VI_CFG_VI_INCR_SYNCPT_COND(frame_start) |
> +		host1x_syncpt_id(chan->sp);
> +	tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, value);

Okay, so this programs the VI to increment the given syncpoint upon
frame start? What is that VI_CSI_PP_FRAME_START(chan->portno) exactly?

> +
> +	vi_csi_write(chan, TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE);

And now we start capturing in single-shot mode.

> +
> +	/* move buffer to capture done queue */
> +	spin_lock(&chan->done_lock);
> +	list_add_tail(&buf->queue, &chan->done);
> +	spin_unlock(&chan->done_lock);
> +
> +	/* wait up kthread for capture done */
> +	wake_up_interruptible(&chan->done_wait);

But this I don't understand. You wake up the kthread...

> +
> +	/* use syncpoint to wake up */
> +	err = host1x_syncpt_wait(chan->sp, thresh,
> +				 TEGRA_VI_SYNCPT_WAIT_TIMEOUT, &value);

... and then wait for the syncpoint to reach the given threshold? Isn't
that the wrong way around? Don't we need to wait for the syncpoint
increment *before* we wake up the kthread that will return the buffer
to userspace?

> +	if (err) {
> +		dev_err(&chan->video.dev,
> +			"frame start syncpt timeout: %d\n", err);
> +		tegra_channel_capture_error_status(chan);
> +	}
> +
> +	return err;
> +}
> +
> +static int tegra_channel_capture_done(struct tegra_vi_channel *chan,
> +				      struct tegra_channel_buffer *buf)
> +{
> +	struct vb2_v4l2_buffer *vb = &buf->buf;
> +	u32 thresh, value, mw_ack_done;
> +	int ret = 0;
> +
> +	/* increase syncpoint max */
> +	thresh = host1x_syncpt_incr_max(chan->sp, 1);
> +
> +	/* program syncpoint */
> +	mw_ack_done = VI_CSI_MW_ACK_DONE(chan->portno);
> +	value = VI_CFG_VI_INCR_SYNCPT_COND(mw_ack_done) |
> +		host1x_syncpt_id(chan->sp);
> +	tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, value);
> +
> +	if (!vi_csi_read(chan, TEGRA_VI_CSI_SINGLE_SHOT))
> +		vi_csi_write(chan, TEGRA_VI_CSI_SINGLE_SHOT,
> +			     SINGLE_SHOT_CAPTURE);
> +
> +	/* use syncpoint to wake up */
> +	ret = host1x_syncpt_wait(chan->sp, thresh,
> +				 TEGRA_VI_SYNCPT_WAIT_TIMEOUT, &value);
> +	if (ret)
> +		dev_err(&chan->video.dev,
> +			"MW_ACK_DONE syncpoint timeout: %d\n", ret);

Actually... there's another syncpoint wait here, so I guess this will
stall until VI has actually completed writing the captured frame to
memory.

> +
> +	/* captured one frame */
> +	vb->sequence = chan->sequence++;
> +	vb->field = V4L2_FIELD_NONE;
> +	vb->vb2_buf.timestamp = ktime_get_ns();
> +	vb2_buffer_done(&vb->vb2_buf,
> +			ret < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);

So it's really only at this point that we return the buffer to
userspace, which should be after the hardware is done writing to the
buffer, so this should be fine.

That said, I'm wondering if host1x_syncpt_wait() is a good interface
for this use-case. We don't really have anything else right now, but
I think we may be able to add something to have a function called in
case the syncpoint reaches a threshold. Having to spawn two separate
threads with wait queues seems a bit overkill for this.

It's fine to leave this as it is for now, but maybe something to
consider as improvement in the future.

> +	return ret;
> +}
> +
> +static int chan_capture_kthread_start(void *data)
> +{
> +	struct tegra_vi_channel *chan = data;
> +	struct tegra_channel_buffer *buf;
> +	int err = 0;
> +
> +	set_freezable();
> +
> +	while (1) {
> +		try_to_freeze();
> +
> +		wait_event_interruptible(chan->start_wait,
> +					 !list_empty(&chan->capture) ||
> +					 kthread_should_stop());
> +		if (kthread_should_stop())
> +			break;
> +
> +		if (err)
> +			continue;
> +
> +		spin_lock(&chan->start_lock);
> +		if (list_empty(&chan->capture)) {
> +			spin_unlock(&chan->start_lock);
> +			continue;
> +		}
> +
> +		buf = list_entry(chan->capture.next,
> +				 struct tegra_channel_buffer, queue);
> +		list_del_init(&buf->queue);
> +		spin_unlock(&chan->start_lock);
> +		err = tegra_channel_capture_frame(chan, buf);
> +	}
> +
> +	return 0;
> +}
> +
> +static int chan_capture_kthread_done(void *data)
> +{
> +	struct tegra_vi_channel *chan = data;
> +	struct tegra_channel_buffer *buf;
> +	int err = 0;
> +
> +	set_freezable();
> +
> +	while (1) {
> +		try_to_freeze();
> +
> +		wait_event_interruptible(chan->done_wait,
> +					 !list_empty(&chan->done) ||
> +					 kthread_should_stop());
> +
> +		if (kthread_should_stop())
> +			break;
> +
> +		spin_lock(&chan->done_lock);
> +		if (list_empty(&chan->done)) {
> +			spin_unlock(&chan->done_lock);
> +			continue;
> +		}
> +
> +		buf = list_entry(chan->done.next, struct tegra_channel_buffer,
> +				 queue);
> +		if (!buf)
> +			continue;
> +
> +		list_del_init(&buf->queue);
> +		spin_unlock(&chan->done_lock);
> +		err = tegra_channel_capture_done(chan, buf);

What's with the error here? I think we should either handle it in some
way, or just avoid even returning an error if we're not going to deal
with it anyway.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2020-02-14 16:46 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-05 21:23 [RFC PATCH v2 0/6] Add Tegra driver for video capture Sowjanya Komatineni
2020-02-05 21:23 ` [RFC PATCH v2 1/6] dt-bindings: clock: tegra: Add clk id for CSI TPG clock Sowjanya Komatineni
2020-02-05 21:23 ` [RFC PATCH v2 2/6] clk: tegra: Add Tegra210 CSI TPG clock gate Sowjanya Komatineni
2020-02-05 21:23 ` [RFC PATCH v2 3/6] dt-binding: tegra: Add VI and CSI bindings Sowjanya Komatineni
2020-02-06 21:49   ` Rob Herring
2020-02-05 21:23 ` [RFC PATCH v2 4/6] media: tegra: Add Tegra210 Video input driver Sowjanya Komatineni
2020-02-14 16:46   ` Thierry Reding [this message]
2020-02-14 17:20     ` Sowjanya Komatineni
2020-02-05 21:23 ` [RFC PATCH v2 5/6] MAINTAINERS: Add Tegra Video driver section Sowjanya Komatineni
2020-02-05 21:23 ` [RFC PATCH v2 6/6] arm64: tegra: Add Tegra VI CSI support in device tree Sowjanya Komatineni
2020-02-06 12:01 ` [RFC PATCH v2 0/6] Add Tegra driver for video capture Hans Verkuil
2020-02-06 15:51   ` Sowjanya Komatineni
2020-02-06 16:54     ` Helen Koike
2020-02-06 16:57       ` Sowjanya Komatineni
2020-02-06 17:13         ` Sowjanya Komatineni
2020-02-06 18:26           ` Sowjanya Komatineni
2020-02-07 13:01     ` Hans Verkuil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200214164642.GA1310813@ulmo \
    --to=thierry.reding@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=frankc@nvidia.com \
    --cc=helen.koike@collabora.com \
    --cc=hverkuil@xs4all.nl \
    --cc=jonathanh@nvidia.com \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=sboyd@kernel.org \
    --cc=skomatineni@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).