All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Osipenko <digetx@gmail.com>
To: Thierry Reding <thierry.reding@gmail.com>
Cc: Jonathan Hunter <jonathanh@nvidia.com>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/2] memory: tegra: Introduce memory client hot reset API
Date: Mon, 19 Feb 2018 15:44:00 +0300	[thread overview]
Message-ID: <a489c730-999a-e1fd-c547-77cad46bbefb@gmail.com> (raw)
In-Reply-To: <e061ce8f-fe3a-8697-3ec2-eed40e00ee8d@gmail.com>

On 19.02.2018 15:35, Dmitry Osipenko wrote:
> On 13.02.2018 14:24, Thierry Reding wrote:
>> On Mon, Feb 12, 2018 at 08:06:31PM +0300, Dmitry Osipenko wrote:
>>> In order to reset busy HW properly, memory controller needs to be
>>> involved, otherwise it possible to get corrupted memory if HW was reset
>>> during DMA. Introduce memory client 'hot reset' API that will be used
>>> for resetting busy HW. The primary users are memory clients related to
>>> video (decoder/encoder/camera) and graphics (2d/3d).
>>>
>>> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
>>> ---
>>>  drivers/memory/tegra/mc.c       | 249 ++++++++++++++++++++++++++++++++++++++++
>>>  drivers/memory/tegra/tegra114.c |  25 ++++
>>>  drivers/memory/tegra/tegra124.c |  32 ++++++
>>>  drivers/memory/tegra/tegra20.c  |  23 ++++
>>>  drivers/memory/tegra/tegra210.c |  27 +++++
>>>  drivers/memory/tegra/tegra30.c  |  25 ++++
>>>  include/soc/tegra/mc.h          |  77 +++++++++++++
>>>  7 files changed, 458 insertions(+)
>>
>> As discussed on IRC, I typed up a variant of this in an attempt to fix
>> an unrelated bug report. The code is here:
>>
>> 	https://github.com/thierryreding/linux/commit/e104e703cb75dfe742b2e051194a0af8ddefcd03
>>
>> I think we can make this without adding a custom API. The reset control
>> API should work just fine. The above version doesn't take into account
>> some of Tegra20's quirks, but I think it should still work for Tegra20
>> with just slightly different implementations for ->assert() and
>> ->deassert().
>>
>> A couple of more specific comments below.
>>
>>> diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
>>> index 187a9005351b..9838f588d64d 100644
>>> --- a/drivers/memory/tegra/mc.c
>>> +++ b/drivers/memory/tegra/mc.c
>>> @@ -7,11 +7,13 @@
>>>   */
>>>  
>>>  #include <linux/clk.h>
>>> +#include <linux/delay.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/kernel.h>
>>>  #include <linux/module.h>
>>>  #include <linux/of.h>
>>>  #include <linux/platform_device.h>
>>> +#include <linux/reset.h>
>>>  #include <linux/slab.h>
>>>  #include <linux/sort.h>
>>>  
>>> @@ -81,6 +83,172 @@ static const struct of_device_id tegra_mc_of_match[] = {
>>>  };
>>>  MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
>>>  
>>> +static int terga_mc_flush_dma(struct tegra_mc *mc, unsigned int id)
>>> +{
>>> +	unsigned int hw_id = mc->soc->modules[id].hw_id;
>>> +	u32 value, reg_poll = mc->soc->reg_client_flush_status;
>>> +	int retries = 3;
>>> +
>>> +	value = mc_readl(mc, mc->soc->reg_client_ctrl);
>>> +
>>> +	if (mc->soc->tegra20)
>>> +		value &= ~BIT(hw_id);
>>> +	else
>>> +		value |= BIT(hw_id);
>>> +
>>> +	/* block clients DMA requests */
>>> +	mc_writel(mc, value, mc->soc->reg_client_ctrl);
>>> +
>>> +	/* wait for completion of the outstanding DMA requests */
>>> +	if (mc->soc->tegra20) {
>>> +		while (mc_readl(mc, reg_poll + hw_id * sizeof(u32)) != 0) {
>>> +			if (!retries--)
>>> +				return -EBUSY;
>>> +
>>> +			usleep_range(1000, 2000);
>>> +		}
>>> +	} else {
>>> +		while ((mc_readl(mc, reg_poll) & BIT(hw_id)) == 0) {
>>> +			if (!retries--)
>>> +				return -EBUSY;
>>> +
>>> +			usleep_range(1000, 2000);
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>
>> I think this suffers from too much unification. The programming model is
>> too different to stash this into a single function implementation and as
>> a result this becomes very difficult to read. In my experience it's more
>> readable to split this into separate implementations and pass around
>> pointers to them.
>>
>>> +
>>> +static int terga_mc_unblock_dma(struct tegra_mc *mc, unsigned int id)
>>> +{
>>> +	unsigned int hw_id = mc->soc->modules[id].hw_id;
>>> +	u32 value;
>>> +
>>> +	value = mc_readl(mc, mc->soc->reg_client_ctrl);
>>> +
>>> +	if (mc->soc->tegra20)
>>> +		value |= BIT(hw_id);
>>> +	else
>>> +		value &= ~BIT(hw_id);
>>> +
>>> +	mc_writel(mc, value, mc->soc->reg_client_ctrl);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int terga_mc_hotreset_assert(struct tegra_mc *mc, unsigned int id)
>>> +{
>>> +	unsigned int hw_id = mc->soc->modules[id].hw_id;
>>> +	u32 value;
>>> +
>>> +	if (mc->soc->tegra20) {
>>> +		value = mc_readl(mc, mc->soc->reg_client_hotresetn);
>>> +
>>> +		mc_writel(mc, value & ~BIT(hw_id),
>>> +			  mc->soc->reg_client_hotresetn);
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int terga_mc_hotreset_deassert(struct tegra_mc *mc, unsigned int id)
>>> +{
>>> +	unsigned int hw_id = mc->soc->modules[id].hw_id;
>>> +	u32 value;
>>> +
>>> +	if (mc->soc->tegra20) {
>>> +		value = mc_readl(mc, mc->soc->reg_client_hotresetn);
>>> +
>>> +		mc_writel(mc, value | BIT(hw_id),
>>> +			  mc->soc->reg_client_hotresetn);
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>
>> The same goes for these. I think we can do this much more easily by
>> providing reset controller API ->assert() and ->deassert()
>> implementations for Tegra20 and Tegra30+, and then register the reset
>> controller device using the ops stored in the MC SoC structure.
>>
>>> +static int tegra_mc_hot_reset_assert(struct tegra_mc *mc, unsigned int id,
>>> +				     struct reset_control *rst)
>>> +{
>>> +	int err;
>>> +
>>> +	/*
>>> +	 * Block clients DMA requests and wait for completion of the
>>> +	 * outstanding requests.
>>> +	 */
>>> +	err = terga_mc_flush_dma(mc, id);
>>> +	if (err) {
>>> +		dev_err(mc->dev, "Failed to flush DMA: %d\n", err);
>>> +		return err;
>>> +	}
>>> +
>>> +	/* put in reset HW that corresponds to the memory client */
>>> +	err = reset_control_assert(rst);
>>> +	if (err) {
>>> +		dev_err(mc->dev, "Failed to assert HW reset: %d\n", err);
>>> +		return err;
>>> +	}
>>> +
>>> +	/* clear the client requests sitting before arbitration */
>>> +	err = terga_mc_hotreset_assert(mc, id);
>>> +	if (err) {
>>> +		dev_err(mc->dev, "Failed to hot reset client: %d\n", err);
>>> +		return err;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>
>> This is very strictly according to the TRM, but I don't see a reason why
>> you couldn't stash the DMA blocking and the hot reset into a ->assert()
>> implementation...
>>
>>> +
>>> +static int tegra_mc_hot_reset_deassert(struct tegra_mc *mc, unsigned int id,
>>> +				       struct reset_control *rst)
>>> +{
>>> +	int err;
>>> +
>>> +	/* take out client from hot reset */
>>> +	err = terga_mc_hotreset_deassert(mc, id);
>>> +	if (err) {
>>> +		dev_err(mc->dev, "Failed to deassert hot reset: %d\n", err);
>>> +		return err;
>>> +	}
>>> +
>>> +	/* take out from reset corresponding clients HW */
>>> +	err = reset_control_deassert(rst);
>>> +	if (err) {
>>> +		dev_err(mc->dev, "Failed to deassert HW reset: %d\n", err);
>>> +		return err;
>>> +	}
>>> +
>>> +	/* allow new DMA requests to proceed to arbitration */
>>> +	err = terga_mc_unblock_dma(mc, id);
>>> +	if (err) {
>>> +		dev_err(mc->dev, "Failed to unblock client: %d\n", err);
>>> +		return err;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>
>> ... and the hot reset deassertion and the DMA unblocking into a
>> ->deassert() implementation.
>>
>> I think the important part is that DMA is blocked and the requests are
>> cleared before the module reset, and similarily that the hot reset is
>> released and DMA is unblocked after the module reset.
> 
> Okay, let's try the way you're suggesting and see if anything breaks..

Although, it would be awesome if you could ask somebody who is familiar with the
actual HW implementation. I can imagine that HW is simplified and expecting SW
to take that into account, there could be hazards.

      reply	other threads:[~2018-02-19 12:44 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-12 17:06 [PATCH v2 0/2] Memory controller hot reset Dmitry Osipenko
2018-02-12 17:06 ` Dmitry Osipenko
2018-02-12 17:06 ` [PATCH v2 1/2] memory: tegra: Squash tegra20-mc into common tegra-mc driver Dmitry Osipenko
     [not found]   ` <148ce8c56ad764fc8133e0d97e43f9639cae15ff.1518452709.git.digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2018-02-13 10:30     ` Thierry Reding
2018-02-13 10:30       ` Thierry Reding
2018-02-14 11:15       ` Peter De Schrijver
2018-02-14 11:15         ` Peter De Schrijver
     [not found]         ` <20180214111546.GR5850-Rysk9IDjsxmJz7etNGeUX8VPkgjIgRvpAL8bYrjMMd8@public.gmane.org>
2018-02-14 15:42           ` Dmitry Osipenko
2018-02-14 15:42             ` Dmitry Osipenko
2018-02-19  2:04       ` Dmitry Osipenko
2018-02-19  2:16         ` Dmitry Osipenko
     [not found] ` <cover.1518452709.git.digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2018-02-12 17:06   ` [PATCH v2 2/2] memory: tegra: Introduce memory client hot reset API Dmitry Osipenko
2018-02-12 17:06     ` Dmitry Osipenko
2018-02-13 11:24     ` Thierry Reding
2018-02-19 12:35       ` Dmitry Osipenko
2018-02-19 12:44         ` Dmitry Osipenko [this message]

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=a489c730-999a-e1fd-c547-77cad46bbefb@gmail.com \
    --to=digetx@gmail.com \
    --cc=jonathanh@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=p.zabel@pengutronix.de \
    --cc=thierry.reding@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.