All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
To: Serge Semin <fancer.lancer@gmail.com>
Cc: "Viresh Kumar" <vireshk@kernel.org>,
	"Vinod Koul" <vkoul@kernel.org>,
	"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Jiri Slaby" <jirislaby@kernel.org>,
	dmaengine@vger.kernel.org, linux-serial@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	"Viresh Kumar" <viresh.kumar@linaro.org>
Subject: Re: [PATCH 2/4] dmaengine: dw: Add memory bus width verification
Date: Tue, 16 Apr 2024 21:47:02 +0300	[thread overview]
Message-ID: <Zh7Hpuo-TzSmlz69@smile.fi.intel.com> (raw)
In-Reply-To: <20240416162908.24180-3-fancer.lancer@gmail.com>

On Tue, Apr 16, 2024 at 07:28:56PM +0300, Serge Semin wrote:
> Currently in case of the DEV_TO_MEM or MEM_TO_DEV DMA transfers the memory
> data width (single transfer width) is determined based on the buffer
> length, buffer base address or DMA master-channel max address width
> capability. It isn't enough in case of the channel disabling prior the
> block transfer is finished. Here is what DW AHB DMA IP-core databook says
> regarding the port suspension (DMA-transfer pause) implementation in the
> controller:
> 
> "When CTLx.SRC_TR_WIDTH < CTLx.DST_TR_WIDTH and the CFGx.CH_SUSP bit is
> high, the CFGx.FIFO_EMPTY is asserted once the contents of the FIFO do not
> permit a single word of CTLx.DST_TR_WIDTH to be formed. However, there may
> still be data in the channel FIFO, but not enough to form a single
> transfer of CTLx.DST_TR_WIDTH. In this scenario, once the channel is
> disabled, the remaining data in the channel FIFO is not transferred to the
> destination peripheral."
> 
> So in case if the port gets to be suspended and then disabled it's
> possible to have the data silently discarded even though the controller
> reported that FIFO is empty and the CTLx.BLOCK_TS indicated the dropped
> data already received from the source device. This looks as if the data
> somehow got lost on a way from the peripheral device to memory and causes
> problems for instance in the DW APB UART driver, which pauses and disables
> the DMA-transfer as soon as the recv data timeout happens. Here is the way
> it looks:
> 
>  Memory <------- DMA FIFO <------ UART FIFO <---------------- UART
>   DST_TR_WIDTH -+--------|       |         |
>                 |        |       |         |                No more data
>    Current lvl -+--------|       |---------+- DMA-burst lvl
>                 |        |       |---------+- Leftover data
>                 |        |       |---------+- SRC_TR_WIDTH
>                -+--------+-------+---------+
> 
> In the example above: no more data is getting received over the UART port
> and BLOCK_TS is not even close to be fully received; some data is left in
> the UART FIFO, but not enough to perform a bursted DMA-xfer to the DMA
> FIFO; some data is left in the DMA FIFO, but not enough to be passed
> further to the system memory in a single transfer. In this situation the
> 8250 UART driver catches the recv timeout interrupt, pauses the
> DMA-transfer and terminates it completely, after which the IRQ handler
> manually fetches the leftover data from the UART FIFO into the
> recv-buffer. But since the DMA-channel has been disabled with the data
> left in the DMA FIFO, that data will be just discarded and the recv-buffer
> will have a gap of the "current lvl" size in the recv-buffer at the tail
> of the lately received data portion. So the data will be lost just due to
> the misconfigured DMA transfer.
> 
> Note this is only relevant for the case of the transfer suspension and
> _disabling_. No problem will happen if the transfer will be re-enabled
> afterwards or the block transfer is fully completed. In the later case the
> "FIFO flush mode" will be executed at the transfer final stage in order to
> push out the data left in the DMA FIFO.
> 
> In order to fix the denoted problem the DW AHB DMA-engine driver needs to
> make sure that the _bursted_ source transfer width is greater or equal to
> the single destination transfer (note the HW databook describes more
> strict constraint than actually required). Since the peripheral-device
> side is prescribed by the client driver logic, the memory-side can be only
> used for that. The solution can be easily implemented for the DEV_TO_MEM
> transfers just by adjusting the memory-channel address width. Sadly it's
> not that easy for the MEM_TO_DEV transfers since the mem-to-dma burst size
> is normally dynamically determined by the controller. So the only thing
> that can be done is to make sure that memory-side address width can be
> greater than the peripheral device address width.

...

> +static int dwc_verify_m_buswidth(struct dma_chan *chan)
> +{
> +	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
> +	struct dw_dma *dw = to_dw_dma(chan->device);
> +	u32 reg_width, reg_burst, mem_width;
> +
> +	mem_width = dw->pdata->data_width[dwc->dws.m_master];
> +
> +	/* Make sure src and dst word widths are coherent */
> +	if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV) {
> +		reg_width = dwc->dma_sconfig.dst_addr_width;
> +		if (mem_width < reg_width)
> +			return -EINVAL;
> +
> +		dwc->dma_sconfig.src_addr_width = mem_width;
> +	} else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM) {
> +		reg_width = dwc->dma_sconfig.src_addr_width;
> +		reg_burst = rounddown_pow_of_two(dwc->dma_sconfig.src_maxburst);
> +
> +		dwc->dma_sconfig.dst_addr_width = min(mem_width, reg_width * reg_burst);

I understand the desire to go this way, but wouldn't be better to have
a symmetrical check and return an error?

> +	}
> +
> +	return 0;
> +}

IIRC MEM side of the DMA channel will ignore those in HW, so basically you are
(re-)using them purely for the __ffs() corrections.

...

>  	dwc->dma_sconfig.src_maxburst =
> -		clamp(dwc->dma_sconfig.src_maxburst, 0U, dwc->max_burst);
> +		clamp(dwc->dma_sconfig.src_maxburst, 1U, dwc->max_burst);
>  	dwc->dma_sconfig.dst_maxburst =
> -		clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst);
> +		clamp(dwc->dma_sconfig.dst_maxburst, 1U, dwc->max_burst);

-- 
With Best Regards,
Andy Shevchenko



  reply	other threads:[~2024-04-16 18:47 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-16 16:28 [PATCH 0/4] dmaengine: dw: Fix src/dst addr width misconfig Serge Semin
2024-04-16 16:28 ` [PATCH 1/4] dmaengine: dw: Add peripheral bus width verification Serge Semin
2024-04-16 18:00   ` Andy Shevchenko
2024-04-17 19:54     ` Serge Semin
2024-04-18  9:43       ` Andy Shevchenko
2024-04-18 15:47         ` Serge Semin
2024-04-16 16:28 ` [PATCH 2/4] dmaengine: dw: Add memory " Serge Semin
2024-04-16 18:47   ` Andy Shevchenko [this message]
2024-04-17 17:13     ` Serge Semin
2024-04-17 17:28       ` Andy Shevchenko
2024-04-17 18:52         ` Serge Semin
2024-04-18  9:37           ` Andy Shevchenko
2024-04-18 15:52             ` Serge Semin
2024-04-16 16:28 ` [PATCH 3/4] dmaengine: dw: Simplify prepare CTL_LO methods Serge Semin
2024-04-16 19:04   ` Andy Shevchenko
2024-04-17 20:11     ` Serge Semin
2024-04-18 11:47       ` Andy Shevchenko
2024-04-18 19:00         ` Serge Semin
2024-04-18 21:00           ` Andy Shevchenko
2024-04-19  9:19             ` Serge Semin
2024-04-16 16:28 ` [PATCH 4/4] dmaengine: dw: Simplify max-burst calculation procedure Serge Semin
2024-04-16 19:11   ` Andy Shevchenko
2024-04-17 20:35     ` Serge Semin
2024-04-18 11:49       ` Andy Shevchenko
2024-04-18 19:10         ` Serge Semin
2024-04-16 19:13 ` [PATCH 0/4] dmaengine: dw: Fix src/dst addr width misconfig Andy Shevchenko
2024-04-17 17:34   ` Serge Semin

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=Zh7Hpuo-TzSmlz69@smile.fi.intel.com \
    --to=andriy.shevchenko@linux.intel.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=fancer.lancer@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=jirislaby@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=viresh.kumar@linaro.org \
    --cc=vireshk@kernel.org \
    --cc=vkoul@kernel.org \
    /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.