Linux kernel -stable discussions
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>,
	linux-media@vger.kernel.org, Benoit Parrot <bparrot@ti.com>,
	stable@vger.kernel.org
Subject: Re: [PATCH] media: ti-vpe: cal: fix DMA memory corruption
Date: Mon, 16 Mar 2020 12:28:30 +0200	[thread overview]
Message-ID: <20200316102830.GT4732@pendragon.ideasonboard.com> (raw)
In-Reply-To: <79e87213-6648-8056-1db5-718ed3963ed3@ti.com>

Hi Tomi,

On Fri, Mar 13, 2020 at 04:18:13PM +0200, Tomi Valkeinen wrote:
> On 13/03/2020 16:03, Laurent Pinchart wrote:
> 
> >> +	/* wait for stream and dma to finish */
> >> +	dma_act = true;
> >> +	timeout = jiffies + msecs_to_jiffies(500);
> >> +	while (dma_act && time_before(jiffies, timeout)) {
> >> +		msleep(50);
> >> +
> >> +		spin_lock_irqsave(&ctx->slock, flags);
> >> +		dma_act = ctx->dma_act;
> >> +		spin_unlock_irqrestore(&ctx->slock, flags);
> >> +	}
> > 
> > Waiting for the transfer to complete seems to be a good idea, but how
> > about using a wait queue instead of such a loop ? That would allow
> > better usage of CPU time and faster reaction time, and shouldn't be
> > difficult to implement. You may also want to replace dma_act with a
> > state if needed (in case you need to express running/stopping/stopped
> > states), and I would rename it to running if you just need a boolean.
> 
> Maybe, but I wasn't sure how to implement it safely.
> 
> So, when we call csi2_ppi_disable() (just above the wait code above), the HW will stop the DMA after 
> the next frame has ended.
> 
> But there's no way to know in the irq handler if the DMA transfer that just ended was the last one 
> or not. And I don't see how I could set a "disabling" flag before calling csi2_ppi_disable(), as I 
> think that would always be racy with the irq handler.
> 
> So I went with a safe way: call csi2_ppi_disable(), then wait a bit so that we are sure that either 
> 1) the last frame is on going 2) the last frame has finished (instead of the previous-to-last frame 
> is on going or finished). Then see if the DMA is active. If yes, we loop for it to end.
> 
> I think the loop could be replaced with a wait queue, but we still need the initial sleep to ensure 
> we don't end the wait when the previous-to-last frame DMA has been finished.

I think you can solve this by introducing a new enum state field with
RUNNING, STOPPING and STOPPED values, protected by a spinlock. Here's
what I have in the VSP1 driver for instance:

bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe)
{
	unsigned long flags;
	bool stopped;

	spin_lock_irqsave(&pipe->irqlock, flags);
	stopped = pipe->state == VSP1_PIPELINE_STOPPED;
	spin_unlock_irqrestore(&pipe->irqlock, flags);

	return stopped;
}

int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
{
	...
	spin_lock_irqsave(&pipe->irqlock, flags);
	if (pipe->state == VSP1_PIPELINE_RUNNING)
		pipe->state = VSP1_PIPELINE_STOPPING;
	spin_unlock_irqrestore(&pipe->irqlock, flags);

	ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe),
				 msecs_to_jiffies(500));
	ret = ret == 0 ? -ETIMEDOUT : 0;
	...
}

and in the interrupt handler:

	state = pipe->state;
	pipe->state = VSP1_PIPELINE_STOPPED;

	/*
	 * If a stop has been requested, mark the pipeline as stopped and
	 * return. Otherwise restart the pipeline if ready.
	 */
	if (state == VSP1_PIPELINE_STOPPING)
		wake_up(&pipe->wq);
	else if (vsp1_pipeline_ready(pipe))
		vsp1_video_pipeline_run(pipe);

-- 
Regards,

Laurent Pinchart

  reply	other threads:[~2020-03-16 10:28 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-13  8:26 [PATCH] media: ti-vpe: cal: fix DMA memory corruption Tomi Valkeinen
2020-03-13 14:03 ` Laurent Pinchart
2020-03-13 14:18   ` Tomi Valkeinen
2020-03-16 10:28     ` Laurent Pinchart [this message]
2020-03-16 11:02       ` Tomi Valkeinen

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=20200316102830.GT4732@pendragon.ideasonboard.com \
    --to=laurent.pinchart@ideasonboard.com \
    --cc=bparrot@ti.com \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=tomi.valkeinen@ti.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