Skip to contentSkip to conversation

dmaengine: dw: Fix src/dst addr width misconfig

PATCH RESEND Applied Serge Semin 5 participants 24 messages Aug 2, 2024 – Sep 19, 2024

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v4 cover dmaengine: dw: Fix src/dst addr width misconfig

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

In addition to that three cleanup patches follow the fixes described above in order to make the DWC-engine configuration procedure more coherent. First one simplifies the CTL_LO register setup methods. Second and third patches simplify the max-burst calculation procedure and unify it with the rest of the verification methods. Please see the patches log for more details.

Final patch is another cleanup which unifies the status variables naming in the driver.

Changelog v2:
- Add a note to the Patch #1 commit message about having the verification method called in the dwc_config() function. (Andy)
- Add hyphen to "1byte" in the in-situ comment. (Andy)
- Convert "err" to "ret" variables and add a new patch which unifies the status variables naming. (Andy)
- Add a in-situ comment regarding why the memory-side bus width verification was required. (Andy)
- Group sms+dms and smsize+dmsize local variables initializations up. (Andy)
- Move the zero initializations out to the variables init block
in the prepare_ctllo() callbacks. (Andy)
- Directly refer to dwc_config() in the commit messages. (Andy)
- Convert dwc_verify_maxburst() to returning zero. (Andy)
- Add a comment regarding the values utilized in dwc_verify_p_buswidth() being pre-verified before the method is called. (Andy)
- Add new patches:
[PATCH v2 4/6] dmaengine: dw: Define encode_maxburst() above prepare_ctllo() callbacks [PATCH v2 6/6] dmaengine: dw: Unify ret-val local variable naming
(Andy)

Changelog v3:
- Rebase onto the kernel 6.10-rc4.
- Just resend.

Changelog v4:
- Rebase onto the kernel 6.11-rc1.
- Just resend.

base-commit: 8400291e289ee6b2bf9779ff1c83a291501f017b

Serge Semin (6):
dmaengine: dw: Add peripheral bus width verification
dmaengine: dw: Add memory bus width verification
dmaengine: dw: Simplify prepare CTL_LO methods
dmaengine: dw: Define encode_maxburst() above prepare_ctllo()
callbacks
dmaengine: dw: Simplify max-burst calculation procedure
dmaengine: dw: Unify ret-val local variables naming

 drivers/dma/dw/core.c     | 131 +++++++++++++++++++++++++++++++-------
 drivers/dma/dw/dw.c       |  40 +++++++-----
 drivers/dma/dw/idma32.c   |  19 +++---
 drivers/dma/dw/platform.c |  20 +++---
 drivers/dma/dw/regs.h     |   1 -
 5 files changed, 154 insertions(+), 57 deletions(-)
Signature · 1 line
2.43.0
#1 lore raw

PATCH RESEND v4 1/6 dmaengine: dw: Add peripheral bus width verification

Currently the src_addr_width and dst_addr_width fields of the dma_slave_config structure are mapped to the CTLx.SRC_TR_WIDTH and CTLx.DST_TR_WIDTH fields of the peripheral bus side in order to have the properly aligned data passed to the target device. It's done just by converting the passed peripheral bus width to the encoded value using the __ffs() function. This implementation has several problematic sides:

1. __ffs() is undefined if no bit exist in the passed value. Thus if the specified addr-width is DMA_SLAVE_BUSWIDTH_UNDEFINED, __ffs() may return unexpected value depending on the platform-specific implementation.

2. DW AHB DMA-engine permits having the power-of-2 transfer width limited by the DMAH_Mk_HDATA_WIDTH IP-core synthesize parameter. Specifying bus-width out of that constraints scope will definitely cause unexpected result since the destination reg will be only partly touched than the client driver implied.

Let's fix all of that by adding the peripheral bus width verification method and calling it in dwc_config() which is supposed to be executed before preparing any transfer. The new method will make sure that the passed source or destination address width is valid and if undefined then the driver will just fallback to the 1-byte width transfer.

Fixes 029a40e97d0d ("dmaengine: dw: provide DMA capabilities")

---

Changelog v2:
- Add a note to the commit message about having the verification method called in the dwc_config() function. (Andy)
- Add hyphen to "1byte" in the in-situ comment. (Andy)
- Convert "err" to "ret" variable. (Andy)

---
 drivers/dma/dw/core.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
drivers/dma/dw/core.c +38 -0
index 4b3402156eae..d4c694b0f55a 100644
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/log2.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -780,10 +781,43 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
 }
 EXPORT_SYMBOL_GPL(dw_dma_filter);
 
+static int dwc_verify_p_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, max_width;
+
+	if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
+		reg_width = dwc->dma_sconfig.dst_addr_width;
+	else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM)
+		reg_width = dwc->dma_sconfig.src_addr_width;
+	else /* DMA_MEM_TO_MEM */
+		return 0;
+
+	max_width = dw->pdata->data_width[dwc->dws.p_master];
+
+	/* Fall-back to 1-byte transfer width if undefined */
+	if (reg_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+		reg_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	else if (!is_power_of_2(reg_width) || reg_width > max_width)
+		return -EINVAL;
+	else /* bus width is valid */
+		return 0;
+
+	/* Update undefined addr width value */
+	if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
+		dwc->dma_sconfig.dst_addr_width = reg_width;
+	else /* DMA_DEV_TO_MEM */
+		dwc->dma_sconfig.src_addr_width = reg_width;
+
+	return 0;
+}
+
 static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 {
 	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
 	struct dw_dma *dw = to_dw_dma(chan->device);
+	int ret;
 
 	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
 
@@ -792,6 +826,10 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 	dwc->dma_sconfig.dst_maxburst =
 		clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst);
 
+	ret = dwc_verify_p_buswidth(chan);
+	if (ret)
+		return ret;
+
 	dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
 	dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
 
Signature · 1 line
2.43.0
#2 lore raw

Re: [PATCH RESEND v4 1/6] dmaengine: dw: Add peripheral bus width verification

Quoted 17 lines · Serge Semin

Currently the src_addr_width and dst_addr_width fields of the dma_slave_config structure are mapped to the CTLx.SRC_TR_WIDTH and CTLx.DST_TR_WIDTH fields of the peripheral bus side in order to have the properly aligned data passed to the target device. It's done just by converting the passed peripheral bus width to the encoded value using the __ffs() function. This implementation has several problematic sides:

1. __ffs() is undefined if no bit exist in the passed value. Thus if the specified addr-width is DMA_SLAVE_BUSWIDTH_UNDEFINED, __ffs() may return unexpected value depending on the platform-specific implementation.

2. DW AHB DMA-engine permits having the power-of-2 transfer width limited by the DMAH_Mk_HDATA_WIDTH IP-core synthesize parameter. Specifying bus-width out of that constraints scope will definitely cause unexpected result since the destination reg will be only partly touched than the client driver implied.

Quoted 5 lines

Let's fix all of that by adding the peripheral bus width verification method and calling it in dwc_config() which is supposed to be executed before preparing any transfer. The new method will make sure that the passed source or destination address width is valid and if undefined then the driver will just fallback to the 1-byte width transfer.

This patch broke Intel Merrifield iDMA32 + SPI PXA2xx configuration to me. Since it's first in the series and most likely the rest is dependent and we are almost at the release date I propose to roll back and start again after v6.12-rc1 will be out. Vinod, can we revert the entire series, please?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#3 lore raw

Re: [PATCH RESEND v4 1/6] dmaengine: dw: Add peripheral bus width verification

Quoted 24 lines · Andy Shevchenko
Quoted 17 lines · Serge Semin

Currently the src_addr_width and dst_addr_width fields of the dma_slave_config structure are mapped to the CTLx.SRC_TR_WIDTH and CTLx.DST_TR_WIDTH fields of the peripheral bus side in order to have the properly aligned data passed to the target device. It's done just by converting the passed peripheral bus width to the encoded value using the __ffs() function. This implementation has several problematic sides:

1. __ffs() is undefined if no bit exist in the passed value. Thus if the specified addr-width is DMA_SLAVE_BUSWIDTH_UNDEFINED, __ffs() may return unexpected value depending on the platform-specific implementation.

2. DW AHB DMA-engine permits having the power-of-2 transfer width limited by the DMAH_Mk_HDATA_WIDTH IP-core synthesize parameter. Specifying bus-width out of that constraints scope will definitely cause unexpected result since the destination reg will be only partly touched than the client driver implied.

Quoted 5 lines

Let's fix all of that by adding the peripheral bus width verification method and calling it in dwc_config() which is supposed to be executed before preparing any transfer. The new method will make sure that the passed source or destination address width is valid and if undefined then the driver will just fallback to the 1-byte width transfer.

Quoted 5 lines

This patch broke Intel Merrifield iDMA32 + SPI PXA2xx configuration to me. Since it's first in the series and most likely the rest is dependent and we are almost at the release date I propose to roll back and start again after v6.12-rc1 will be out. Vinod, can we revert the entire series, please?

I guess it's not the best option, since the patch has already been backported to the stable kernels anyway. Rolling back it from all of them seems tiresome. Let's at least try to fix the just discovered problem?

Could you please provide more details about what exactly happening?

-Serge(y)

Quoted 6 lines
Signature · 3 lines
-- 
With Best Regards,
Andy Shevchenko
#4 lore raw

Re: [PATCH RESEND v4 1/6] dmaengine: dw: Add peripheral bus width verification

Hi,

Op 14-09-2024 om 21:22 schreef Serge Semin:

Quoted 24 lines · Andy Shevchenko
Quoted 23 lines · Serge Semin
Quoted 22 lines

Currently the src_addr_width and dst_addr_width fields of the dma_slave_config structure are mapped to the CTLx.SRC_TR_WIDTH and CTLx.DST_TR_WIDTH fields of the peripheral bus side in order to have the properly aligned data passed to the target device. It's done just by converting the passed peripheral bus width to the encoded value using the __ffs() function. This implementation has several problematic sides:

1. __ffs() is undefined if no bit exist in the passed value. Thus if the specified addr-width is DMA_SLAVE_BUSWIDTH_UNDEFINED, __ffs() may return unexpected value depending on the platform-specific implementation.

2. DW AHB DMA-engine permits having the power-of-2 transfer width limited by the DMAH_Mk_HDATA_WIDTH IP-core synthesize parameter. Specifying bus-width out of that constraints scope will definitely cause unexpected result since the destination reg will be only partly touched than the client driver implied.

Let's fix all of that by adding the peripheral bus width verification method and calling it in dwc_config() which is supposed to be executed before preparing any transfer. The new method will make sure that the passed source or destination address width is valid and if undefined then the driver will just fallback to the 1-byte width transfer.

Quoted 5 lines
Quoted 5 lines

This patch broke Intel Merrifield iDMA32 + SPI PXA2xx configuration to me. Since it's first in the series and most likely the rest is dependent and we are almost at the release date I propose to roll back and start again after v6.12-rc1 will be out. Vinod, can we revert the entire series, please?

Indeed all six need to be reverted due to dependency.

Quoted 6 lines
Quoted 6 lines

I guess it's not the best option, since the patch has already been backported to the stable kernels anyway. Rolling back it from all of them seems tiresome. Let's at least try to fix the just discovered problem?

Could you please provide more details about what exactly happening?

I can reproduce (after working around another issue with the following tip from Andy: The DMA module is loaded _after_ the SPI, and for some reason the DMA engine APIs haven't returned deferred probe and hence the SPI considered the absence of DMA even if we have ACPI description non-fatal. So, you may try to manually unload SPI and load again and it should start showing DMA).

On 6.11.0-rc6 I get:

root@edison:~# ./spidev_test -D /dev/spidev5.1 -l
spi mode: 0x20
bits per word: 8
max speed: 500000 Hz (500 kHz)
can't send spi message: Device or resource busy
Aborted (core dumped)

And on 6.11.0-rc7 with the 6 patches reverted:

root@edison:~# ./spidev_test -D /dev/spidev5.1 -l -v
spi mode: 0x20
bits per word: 8
max speed: 500000 Hz (500 kHz)
TX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  |......@.........................|
RX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  |......@.........................|
Quoted 7 lines
Quoted 7 lines

-Serge(y)

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#5 lore raw

Re: [PATCH RESEND v4 1/6] dmaengine: dw: Add peripheral bus width verification

In reply to Serge Semin
Quoted 31 lines · Serge Semin
Quoted 24 lines · Andy Shevchenko
Quoted 17 lines · Serge Semin

Currently the src_addr_width and dst_addr_width fields of the dma_slave_config structure are mapped to the CTLx.SRC_TR_WIDTH and CTLx.DST_TR_WIDTH fields of the peripheral bus side in order to have the properly aligned data passed to the target device. It's done just by converting the passed peripheral bus width to the encoded value using the __ffs() function. This implementation has several problematic sides:

1. __ffs() is undefined if no bit exist in the passed value. Thus if the specified addr-width is DMA_SLAVE_BUSWIDTH_UNDEFINED, __ffs() may return unexpected value depending on the platform-specific implementation.

2. DW AHB DMA-engine permits having the power-of-2 transfer width limited by the DMAH_Mk_HDATA_WIDTH IP-core synthesize parameter. Specifying bus-width out of that constraints scope will definitely cause unexpected result since the destination reg will be only partly touched than the client driver implied.

Quoted 5 lines

Let's fix all of that by adding the peripheral bus width verification method and calling it in dwc_config() which is supposed to be executed before preparing any transfer. The new method will make sure that the passed source or destination address width is valid and if undefined then the driver will just fallback to the 1-byte width transfer.

Quoted 5 lines

This patch broke Intel Merrifield iDMA32 + SPI PXA2xx configuration to me. Since it's first in the series and most likely the rest is dependent and we are almost at the release date I propose to roll back and start again after v6.12-rc1 will be out. Vinod, can we revert the entire series, please?

Quoted 4 lines

I guess it's not the best option, since the patch has already been backported to the stable kernels anyway. Rolling back it from all of them seems tiresome. Let's at least try to fix the just discovered problem?

Please, provide one we can test!

Quoted 1 line

Could you please provide more details about what exactly happening?

Sure. AFAICT the only problematic line is this:

        else if (!is_power_of_2(reg_width) || reg_width > max_width)

in your patch, and it may trigger, for example, when max_width == 0. This, in accordance with my brief investigation, happens due to the following.

The DMA slave configuration is being copied twice in DW DMA code:
1) when respective filter function triggers (see acpi/of glue code);
2) when the channel is about to be allocated.

The iDMA32 has only a single master, and hence m_master == p_master, BUT the filter function in the acpi code is universal and it copies the wrong (from the iDMA32 perspective) value to p_master. As the result, when you retrieve the max_width, it takes the value from p_master, which is defined to 1 (sic!), and hence assigns it to 0.

I don't know how to quickfix this as the proper fix seems to provide the correct data in the first place.

Any ideas, patches we may test?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#6 lore raw

Re: [PATCH RESEND v4 1/6] dmaengine: dw: Add peripheral bus width verification

Quoted 58 lines · Andy Shevchenko
Quoted 31 lines · Serge Semin
Quoted 24 lines · Andy Shevchenko
Quoted 17 lines · Serge Semin

Currently the src_addr_width and dst_addr_width fields of the dma_slave_config structure are mapped to the CTLx.SRC_TR_WIDTH and CTLx.DST_TR_WIDTH fields of the peripheral bus side in order to have the properly aligned data passed to the target device. It's done just by converting the passed peripheral bus width to the encoded value using the __ffs() function. This implementation has several problematic sides:

1. __ffs() is undefined if no bit exist in the passed value. Thus if the specified addr-width is DMA_SLAVE_BUSWIDTH_UNDEFINED, __ffs() may return unexpected value depending on the platform-specific implementation.

2. DW AHB DMA-engine permits having the power-of-2 transfer width limited by the DMAH_Mk_HDATA_WIDTH IP-core synthesize parameter. Specifying bus-width out of that constraints scope will definitely cause unexpected result since the destination reg will be only partly touched than the client driver implied.

Quoted 5 lines

Let's fix all of that by adding the peripheral bus width verification method and calling it in dwc_config() which is supposed to be executed before preparing any transfer. The new method will make sure that the passed source or destination address width is valid and if undefined then the driver will just fallback to the 1-byte width transfer.

Quoted 5 lines

This patch broke Intel Merrifield iDMA32 + SPI PXA2xx configuration to me. Since it's first in the series and most likely the rest is dependent and we are almost at the release date I propose to roll back and start again after v6.12-rc1 will be out. Vinod, can we revert the entire series, please?

Quoted 4 lines

I guess it's not the best option, since the patch has already been backported to the stable kernels anyway. Rolling back it from all of them seems tiresome. Let's at least try to fix the just discovered problem?

Please, provide one we can test!

Quoted 1 line

Could you please provide more details about what exactly happening?

Sure. AFAICT the only problematic line is this:

        else if (!is_power_of_2(reg_width) || reg_width > max_width)

in your patch, and it may trigger, for example, when max_width == 0. This, in accordance with my brief investigation, happens due to the following.

The DMA slave configuration is being copied twice in DW DMA code:
1) when respective filter function triggers (see acpi/of glue code);
2) when the channel is about to be allocated.

The iDMA32 has only a single master, and hence m_master == p_master, BUT the filter function in the acpi code is universal and it copies the wrong (from the iDMA32 perspective) value to p_master. As the result, when you retrieve the max_width, it takes the value from p_master, which is defined to 1 (sic!), and hence assigns it to 0.

Quoted 4 lines

I don't know how to quickfix this as the proper fix seems to provide the correct data in the first place.

Any ideas, patches we may test?

P.S. for your advocacy it seems that your change actually revealed an inconsistency in the existing code. But still, it made a regression.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#7 lore raw

Re: [PATCH RESEND v4 1/6] dmaengine: dw: Add peripheral bus width verification

Quoted 53 lines · Andy Shevchenko
Quoted 52 lines · Andy Shevchenko
Quoted 31 lines · Serge Semin
Quoted 24 lines · Andy Shevchenko
Quoted 17 lines · Serge Semin

Currently the src_addr_width and dst_addr_width fields of the dma_slave_config structure are mapped to the CTLx.SRC_TR_WIDTH and CTLx.DST_TR_WIDTH fields of the peripheral bus side in order to have the properly aligned data passed to the target device. It's done just by converting the passed peripheral bus width to the encoded value using the __ffs() function. This implementation has several problematic sides:

1. __ffs() is undefined if no bit exist in the passed value. Thus if the specified addr-width is DMA_SLAVE_BUSWIDTH_UNDEFINED, __ffs() may return unexpected value depending on the platform-specific implementation.

2. DW AHB DMA-engine permits having the power-of-2 transfer width limited by the DMAH_Mk_HDATA_WIDTH IP-core synthesize parameter. Specifying bus-width out of that constraints scope will definitely cause unexpected result since the destination reg will be only partly touched than the client driver implied.

Quoted 5 lines

Let's fix all of that by adding the peripheral bus width verification method and calling it in dwc_config() which is supposed to be executed before preparing any transfer. The new method will make sure that the passed source or destination address width is valid and if undefined then the driver will just fallback to the 1-byte width transfer.

Quoted 5 lines

This patch broke Intel Merrifield iDMA32 + SPI PXA2xx configuration to me. Since it's first in the series and most likely the rest is dependent and we are almost at the release date I propose to roll back and start again after v6.12-rc1 will be out. Vinod, can we revert the entire series, please?

Quoted 4 lines

I guess it's not the best option, since the patch has already been backported to the stable kernels anyway. Rolling back it from all of them seems tiresome. Let's at least try to fix the just discovered problem?

Please, provide one we can test!

Quoted 1 line

Could you please provide more details about what exactly happening?

Sure. AFAICT the only problematic line is this:

        else if (!is_power_of_2(reg_width) || reg_width > max_width)

in your patch, and it may trigger, for example, when max_width == 0. This, in accordance with my brief investigation, happens due to the following.

The DMA slave configuration is being copied twice in DW DMA code:
1) when respective filter function triggers (see acpi/of glue code);
2) when the channel is about to be allocated.

Quoted 5 lines
Quoted 5 lines

The iDMA32 has only a single master, and hence m_master == p_master, BUT the filter function in the acpi code is universal and it copies the wrong (from the iDMA32 perspective) value to p_master. As the result, when you retrieve the max_width, it takes the value from p_master, which is defined to 1 (sic!), and hence assigns it to 0.

Okay that was the theory, now I made a hack patch, i.e. supply 0 in acpi.c in the filter function and everything starts to work. So, my theory is correct.

Quoted 7 lines
Quoted 4 lines

I don't know how to quickfix this as the proper fix seems to provide the correct data in the first place.

Any ideas, patches we may test?

P.S. for your advocacy it seems that your change actually revealed an inconsistency in the existing code. But still, it made a regression.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#8 lore raw

Re: [PATCH RESEND v4 1/6] dmaengine: dw: Add peripheral bus width verification

Quoted 1 line · Andy Shevchenko

On Mon, Sep 16, 2024 at 02:45:41PM +0300, Andy Shevchenko wrote:

...

Quoted 2 lines

Okay that was the theory, now I made a hack patch, i.e. supply 0 in acpi.c in the filter function and everything starts to work. So, my theory is correct.

FWIW, I have reapplied the whole series and it seems fine, so the only regression is that I described in the previous replies.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#9 lore raw

Re: [PATCH RESEND v4 1/6] dmaengine: dw: Add peripheral bus width verification

Hi Andy, Ferry

Quoted 10 lines · Andy Shevchenko
Quoted 1 line · Andy Shevchenko

On Mon, Sep 16, 2024 at 02:45:41PM +0300, Andy Shevchenko wrote:

...

Quoted 2 lines

Okay that was the theory, now I made a hack patch, i.e. supply 0 in acpi.c in the filter function and everything starts to work. So, my theory is correct.

FWIW, I have reapplied the whole series and it seems fine, so the only regression is that I described in the previous replies.

Just submitted a fix of the issue based on the Andy' and my problem investigation. You've been Cc'ed. Please test the patch out on your hardware:
https://lore.kernel.org/dmaengine/[email protected]

Hope it works.

-Serge(y)

Quoted 6 lines
Signature · 3 lines
-- 
With Best Regards,
Andy Shevchenko
#10 lore raw

PATCH RESEND v4 2/6 dmaengine: dw: Add memory bus width verification

In reply to Serge Semin

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 is greater than the peripheral device address width.

Fixes a09820043c9e ("dw_dmac: autoconfigure data_width or get it via platform data")

---

Changelog v2:
- Add a in-situ comment regarding why the memory-side bus width verification was required. (Andy)
- Convert "err" to "ret" variable. (Andy)

---
 drivers/dma/dw/core.c | 51 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 7 deletions(-)
drivers/dma/dw/core.c +44 -7
index d4c694b0f55a..4987bfa10461 100644
@@ -622,12 +622,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	struct dw_desc		*prev;
 	struct dw_desc		*first;
 	u32			ctllo, ctlhi;
-	u8			m_master = dwc->dws.m_master;
-	u8			lms = DWC_LLP_LMS(m_master);
+	u8			lms = DWC_LLP_LMS(dwc->dws.m_master);
 	dma_addr_t		reg;
 	unsigned int		reg_width;
 	unsigned int		mem_width;
-	unsigned int		data_width = dw->pdata->data_width[m_master];
 	unsigned int		i;
 	struct scatterlist	*sg;
 	size_t			total_len = 0;
@@ -661,7 +659,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			mem_width = __ffs(data_width | mem | len);
+			mem_width = __ffs(sconfig->src_addr_width | mem | len);
 
 slave_sg_todev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -721,7 +719,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			lli_write(desc, sar, reg);
 			lli_write(desc, dar, mem);
 			lli_write(desc, ctlhi, ctlhi);
-			mem_width = __ffs(data_width | mem);
+			mem_width = __ffs(sconfig->dst_addr_width | mem);
 			lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
 			desc->len = dlen;
 
@@ -813,6 +811,41 @@ static int dwc_verify_p_buswidth(struct dma_chan *chan)
 	return 0;
 }
 
+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];
+
+	/*
+	 * It's possible to have a data portion locked in the DMA FIFO in case
+	 * of the channel suspension. Subsequent channel disabling will cause
+	 * that data silent loss. In order to prevent that maintain the src and
+	 * dst transfer widths coherency by means of the relation:
+	 * (CTLx.SRC_TR_WIDTH * CTLx.SRC_MSIZE >= CTLx.DST_TR_WIDTH)
+	 * Look for the details in the commit message that brings this change.
+	 *
+	 * Note the DMA configs utilized in the calculations below must have
+	 * been verified to have correct values by this method call.
+	 */
+	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);
+	}
+
+	return 0;
+}
+
 static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 {
 	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
@@ -822,14 +855,18 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
 
 	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);
 
 	ret = dwc_verify_p_buswidth(chan);
 	if (ret)
 		return ret;
 
+	ret = dwc_verify_m_buswidth(chan);
+	if (ret)
+		return ret;
+
 	dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
 	dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
 
Signature · 1 line
2.43.0
#11 lore raw

PATCH RESEND v4 3/6 dmaengine: dw: Simplify prepare CTL_LO methods

In reply to Serge Semin

Currently the CTL LO fields are calculated on the platform-specific basis. It's implemented by means of the prepare_ctllo() callbacks using the ternary operator within the local variables init block at the beginning of the block scope. The functions code currently is relatively hard to comprehend and isn't that optimal since implies four conditional statements executed and two additional local variables defined. Let's simplify the DW AHB DMA prepare_ctllo() method by unrolling the ternary operators into the normal if-else statement, dropping redundant master-interface ID variables and initializing the local variables based on the singly evaluated DMA-transfer direction check. Thus the method will look much more readable since now the fields content can be easily inferred right from the if-else branch. Provide the same update in the Intel DMA32 core driver for the sake of the driver code unification.

Note besides of the effects described above this update is basically a preparation before dropping the max burst encoding callback. The dropping will require to call the burst fields calculation methods right in the prepare_ctllo() callbacks. It would have made the later functions code even more complex should they were left in the original state.

---

Changelog v2:
- Group sms+dms and smsize+dmsize variables initializations up. (Andy)
- Move the zero initializations out to the variables init block. (Andy)

---
 drivers/dma/dw/dw.c     | 21 +++++++++++++++------
 drivers/dma/dw/idma32.c |  8 ++++++--
 2 files changed, 21 insertions(+), 8 deletions(-)
drivers/dma/dw/dw.c +15 -6
index a4862263ff14..e3d2cc3ea68c 100644
@@ -67,12 +67,21 @@ static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
 static u32 dw_dma_prepare_ctllo(struct dw_dma_chan *dwc)
 {
 	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
-	u8 smsize = (dwc->direction == DMA_DEV_TO_MEM) ? sconfig->src_maxburst : 0;
-	u8 dmsize = (dwc->direction == DMA_MEM_TO_DEV) ? sconfig->dst_maxburst : 0;
-	u8 p_master = dwc->dws.p_master;
-	u8 m_master = dwc->dws.m_master;
-	u8 dms = (dwc->direction == DMA_MEM_TO_DEV) ? p_master : m_master;
-	u8 sms = (dwc->direction == DMA_DEV_TO_MEM) ? p_master : m_master;
+	u8 smsize = 0, dmsize = 0;
+	u8 sms, dms;
+
+	if (dwc->direction == DMA_MEM_TO_DEV) {
+		sms = dwc->dws.m_master;
+		dms = dwc->dws.p_master;
+		dmsize = sconfig->dst_maxburst;
+	} else if (dwc->direction == DMA_DEV_TO_MEM) {
+		sms = dwc->dws.p_master;
+		dms = dwc->dws.m_master;
+		smsize = sconfig->src_maxburst;
+	} else /* DMA_MEM_TO_MEM */ {
+		sms = dwc->dws.m_master;
+		dms = dwc->dws.m_master;
+	}
 
 	return DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN |
 	       DWC_CTLL_DST_MSIZE(dmsize) | DWC_CTLL_SRC_MSIZE(smsize) |
drivers/dma/dw/idma32.c +6 -2
index 58f4078d83fe..e0c31f77cd0f 100644
@@ -202,8 +202,12 @@ static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
 static u32 idma32_prepare_ctllo(struct dw_dma_chan *dwc)
 {
 	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
-	u8 smsize = (dwc->direction == DMA_DEV_TO_MEM) ? sconfig->src_maxburst : 0;
-	u8 dmsize = (dwc->direction == DMA_MEM_TO_DEV) ? sconfig->dst_maxburst : 0;
+	u8 smsize = 0, dmsize = 0;
+
+	if (dwc->direction == DMA_MEM_TO_DEV)
+		dmsize = sconfig->dst_maxburst;
+	else if (dwc->direction == DMA_DEV_TO_MEM)
+		smsize = sconfig->src_maxburst;
 
 	return DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN |
 	       DWC_CTLL_DST_MSIZE(dmsize) | DWC_CTLL_SRC_MSIZE(smsize);
Signature · 1 line
2.43.0
#12 lore raw

PATCH RESEND v4 4/6 dmaengine: dw: Define encode_maxburst() above prepare_ctllo() callbacks

In reply to Serge Semin

As a preparatory change before dropping the encode_maxburst() callbacks let's move dw_dma_encode_maxburst() and idma32_encode_maxburst() to being defined above the dw_dma_prepare_ctllo() and idma32_prepare_ctllo() methods respectively. That's required since the former methods will be called from the later ones directly.

---

Changelog v2:
- New patch created on v2 review stage. (Andy)

---
 drivers/dma/dw/dw.c     | 18 +++++++++---------
 drivers/dma/dw/idma32.c | 10 +++++-----
 2 files changed, 14 insertions(+), 14 deletions(-)
drivers/dma/dw/dw.c +9 -9
index e3d2cc3ea68c..628ee1e77505 100644
@@ -64,6 +64,15 @@ static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
 	return DWC_CTLH_BLOCK_TS(block) << width;
 }
 
+static void dw_dma_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
+{
+	/*
+	 * Fix burst size according to dw_dmac. We need to convert them as:
+	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
+	 */
+	*maxburst = *maxburst > 1 ? fls(*maxburst) - 2 : 0;
+}
+
 static u32 dw_dma_prepare_ctllo(struct dw_dma_chan *dwc)
 {
 	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
@@ -88,15 +97,6 @@ static u32 dw_dma_prepare_ctllo(struct dw_dma_chan *dwc)
 	       DWC_CTLL_DMS(dms) | DWC_CTLL_SMS(sms);
 }
 
-static void dw_dma_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
-{
-	/*
-	 * Fix burst size according to dw_dmac. We need to convert them as:
-	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
-	 */
-	*maxburst = *maxburst > 1 ? fls(*maxburst) - 2 : 0;
-}
-
 static void dw_dma_set_device_name(struct dw_dma *dw, int id)
 {
 	snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", id);
drivers/dma/dw/idma32.c +5 -5
index e0c31f77cd0f..493fcbafa2b8 100644
@@ -199,6 +199,11 @@ static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
 	return IDMA32C_CTLH_BLOCK_TS(block);
 }
 
+static void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
+{
+	*maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0;
+}
+
 static u32 idma32_prepare_ctllo(struct dw_dma_chan *dwc)
 {
 	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
@@ -213,11 +218,6 @@ static u32 idma32_prepare_ctllo(struct dw_dma_chan *dwc)
 	       DWC_CTLL_DST_MSIZE(dmsize) | DWC_CTLL_SRC_MSIZE(smsize);
 }
 
-static void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
-{
-	*maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0;
-}
-
 static void idma32_set_device_name(struct dw_dma *dw, int id)
 {
 	snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", id);
Signature · 1 line
2.43.0
#13 lore raw

PATCH RESEND v4 5/6 dmaengine: dw: Simplify max-burst calculation procedure

In reply to Serge Semin

In order to have a more coherent DW AHB DMA slave configuration method - dwc_config() - let's simplify the source and destination channel max-burst calculation procedure:

1. Create the max-burst verification method as it has been just done for the memory and peripheral address widths. Thus the dwc_config() method will turn to a set of the verification methods execution.

2. Since both the generic DW AHB DMA and Intel iDMA 32-bit engines support the power-of-2 bursts only, then the specified by the client driver max-burst values can be converted to being power-of-2 right in the max-burst verification method.

3. Since max-burst encoded value is required on the CTL_LO fields calculation stage, the encode_maxburst() callback can be easily dropped from the dw_dma structure meanwhile the encoding procedure will be executed right in the CTL_LO register value calculation.

Thus the update will provide the next positive effects: the internal DMA-slave config structure will contain only the real DMA-transfer config values, which will be encoded to the DMA-controller register fields only when it's required on the buffer mapping; the redundant encode_maxburst() callback will be dropped simplifying the internal HW-abstraction API; dwc_config() will look more readable executing the verification functions one-by-one.

---

Changelog v2:
- Refer to dwc_config() in the commit message. (Andy)
- Convert dwc_verify_maxburst() to returning zero. (Andy)
- Add a comment regarding the values utilized in the dwc_verify_p_buswidth() being verified before the method is called. (Andy, see patch 2)
- Detach the dw_dma_encode_maxburst() and idma32_encode_maxburst() movement to a preparatory patch. (Andy)

---
 drivers/dma/dw/core.c   | 30 +++++++++++++++++++++---------
 drivers/dma/dw/dw.c     |  9 ++++-----
 drivers/dma/dw/idma32.c |  9 ++++-----
 drivers/dma/dw/regs.h   |  1 -
 4 files changed, 29 insertions(+), 20 deletions(-)
drivers/dma/dw/core.c +21 -9
index 4987bfa10461..c696d79b911a 100644
@@ -779,6 +779,23 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
 }
 EXPORT_SYMBOL_GPL(dw_dma_filter);
 
+static int dwc_verify_maxburst(struct dma_chan *chan)
+{
+	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+
+	dwc->dma_sconfig.src_maxburst =
+		clamp(dwc->dma_sconfig.src_maxburst, 1U, dwc->max_burst);
+	dwc->dma_sconfig.dst_maxburst =
+		clamp(dwc->dma_sconfig.dst_maxburst, 1U, dwc->max_burst);
+
+	dwc->dma_sconfig.src_maxburst =
+		rounddown_pow_of_two(dwc->dma_sconfig.src_maxburst);
+	dwc->dma_sconfig.dst_maxburst =
+		rounddown_pow_of_two(dwc->dma_sconfig.dst_maxburst);
+
+	return 0;
+}
+
 static int dwc_verify_p_buswidth(struct dma_chan *chan)
 {
 	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
@@ -838,7 +855,7 @@ static int dwc_verify_m_buswidth(struct dma_chan *chan)
 		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);
+		reg_burst = dwc->dma_sconfig.src_maxburst;
 
 		dwc->dma_sconfig.dst_addr_width = min(mem_width, reg_width * reg_burst);
 	}
@@ -849,15 +866,13 @@ static int dwc_verify_m_buswidth(struct dma_chan *chan)
 static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 {
 	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
-	struct dw_dma *dw = to_dw_dma(chan->device);
 	int ret;
 
 	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
 
-	dwc->dma_sconfig.src_maxburst =
-		clamp(dwc->dma_sconfig.src_maxburst, 1U, dwc->max_burst);
-	dwc->dma_sconfig.dst_maxburst =
-		clamp(dwc->dma_sconfig.dst_maxburst, 1U, dwc->max_burst);
+	ret = dwc_verify_maxburst(chan);
+	if (ret)
+		return ret;
 
 	ret = dwc_verify_p_buswidth(chan);
 	if (ret)
@@ -867,9 +882,6 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 	if (ret)
 		return ret;
 
-	dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
-	dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
-
 	return 0;
 }
 
drivers/dma/dw/dw.c +4 -5
index 628ee1e77505..6766142884b6 100644
@@ -64,13 +64,13 @@ static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
 	return DWC_CTLH_BLOCK_TS(block) << width;
 }
 
-static void dw_dma_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
+static inline u8 dw_dma_encode_maxburst(u32 maxburst)
 {
 	/*
 	 * Fix burst size according to dw_dmac. We need to convert them as:
 	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
 	 */
-	*maxburst = *maxburst > 1 ? fls(*maxburst) - 2 : 0;
+	return maxburst > 1 ? fls(maxburst) - 2 : 0;
 }
 
 static u32 dw_dma_prepare_ctllo(struct dw_dma_chan *dwc)
@@ -82,11 +82,11 @@ static u32 dw_dma_prepare_ctllo(struct dw_dma_chan *dwc)
 	if (dwc->direction == DMA_MEM_TO_DEV) {
 		sms = dwc->dws.m_master;
 		dms = dwc->dws.p_master;
-		dmsize = sconfig->dst_maxburst;
+		dmsize = dw_dma_encode_maxburst(sconfig->dst_maxburst);
 	} else if (dwc->direction == DMA_DEV_TO_MEM) {
 		sms = dwc->dws.p_master;
 		dms = dwc->dws.m_master;
-		smsize = sconfig->src_maxburst;
+		smsize = dw_dma_encode_maxburst(sconfig->src_maxburst);
 	} else /* DMA_MEM_TO_MEM */ {
 		sms = dwc->dws.m_master;
 		dms = dwc->dws.m_master;
@@ -125,7 +125,6 @@ int dw_dma_probe(struct dw_dma_chip *chip)
 	dw->suspend_chan = dw_dma_suspend_chan;
 	dw->resume_chan = dw_dma_resume_chan;
 	dw->prepare_ctllo = dw_dma_prepare_ctllo;
-	dw->encode_maxburst = dw_dma_encode_maxburst;
 	dw->bytes2block = dw_dma_bytes2block;
 	dw->block2bytes = dw_dma_block2bytes;
 
drivers/dma/dw/idma32.c +4 -5
index 493fcbafa2b8..dac617c183e6 100644
@@ -199,9 +199,9 @@ static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
 	return IDMA32C_CTLH_BLOCK_TS(block);
 }
 
-static void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
+static inline u8 idma32_encode_maxburst(u32 maxburst)
 {
-	*maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0;
+	return maxburst > 1 ? fls(maxburst) - 1 : 0;
 }
 
 static u32 idma32_prepare_ctllo(struct dw_dma_chan *dwc)
@@ -210,9 +210,9 @@ static u32 idma32_prepare_ctllo(struct dw_dma_chan *dwc)
 	u8 smsize = 0, dmsize = 0;
 
 	if (dwc->direction == DMA_MEM_TO_DEV)
-		dmsize = sconfig->dst_maxburst;
+		dmsize = idma32_encode_maxburst(sconfig->dst_maxburst);
 	else if (dwc->direction == DMA_DEV_TO_MEM)
-		smsize = sconfig->src_maxburst;
+		smsize = idma32_encode_maxburst(sconfig->src_maxburst);
 
 	return DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN |
 	       DWC_CTLL_DST_MSIZE(dmsize) | DWC_CTLL_SRC_MSIZE(smsize);
@@ -274,7 +274,6 @@ int idma32_dma_probe(struct dw_dma_chip *chip)
 	dw->suspend_chan = idma32_suspend_chan;
 	dw->resume_chan = idma32_resume_chan;
 	dw->prepare_ctllo = idma32_prepare_ctllo;
-	dw->encode_maxburst = idma32_encode_maxburst;
 	dw->bytes2block = idma32_bytes2block;
 	dw->block2bytes = idma32_block2bytes;
 
drivers/dma/dw/regs.h +0 -1
index 76654bd13c1a..5969d9cc8d7a 100644
@@ -327,7 +327,6 @@ struct dw_dma {
 	void	(*suspend_chan)(struct dw_dma_chan *dwc, bool drain);
 	void	(*resume_chan)(struct dw_dma_chan *dwc, bool drain);
 	u32	(*prepare_ctllo)(struct dw_dma_chan *dwc);
-	void	(*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst);
 	u32	(*bytes2block)(struct dw_dma_chan *dwc, size_t bytes,
 			       unsigned int width, size_t *len);
 	size_t	(*block2bytes)(struct dw_dma_chan *dwc, u32 block, u32 width);
Signature · 1 line
2.43.0
#14 lore raw

PATCH RESEND v4 6/6 dmaengine: dw: Unify ret-val local variables naming

In reply to Serge Semin

Currently there are two names utilized in the driver to keep the functions call status: ret and err. For the sake of unification convert to using the first version only.

---

Changelog v2:
- New patch created on v2 review stage. (Andy)

---
 drivers/dma/dw/core.c     | 20 ++++++++++----------
 drivers/dma/dw/platform.c | 20 ++++++++++----------
 2 files changed, 20 insertions(+), 20 deletions(-)
drivers/dma/dw/core.c +10 -10
index c696d79b911a..602f1208ab9b 100644
@@ -1149,7 +1149,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
 	bool			autocfg = false;
 	unsigned int		dw_params;
 	unsigned int		i;
-	int			err;
+	int			ret;
 
 	dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL);
 	if (!dw->pdata)
@@ -1165,7 +1165,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
 
 		autocfg = dw_params >> DW_PARAMS_EN & 1;
 		if (!autocfg) {
-			err = -EINVAL;
+			ret = -EINVAL;
 			goto err_pdata;
 		}
 
@@ -1185,7 +1185,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
 		pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING;
 		pdata->chan_priority = CHAN_PRIORITY_ASCENDING;
 	} else if (chip->pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
-		err = -EINVAL;
+		ret = -EINVAL;
 		goto err_pdata;
 	} else {
 		memcpy(dw->pdata, chip->pdata, sizeof(*dw->pdata));
@@ -1197,7 +1197,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
 	dw->chan = devm_kcalloc(chip->dev, pdata->nr_channels, sizeof(*dw->chan),
 				GFP_KERNEL);
 	if (!dw->chan) {
-		err = -ENOMEM;
+		ret = -ENOMEM;
 		goto err_pdata;
 	}
 
@@ -1215,15 +1215,15 @@ int do_dma_probe(struct dw_dma_chip *chip)
 					 sizeof(struct dw_desc), 4, 0);
 	if (!dw->desc_pool) {
 		dev_err(chip->dev, "No memory for descriptors dma pool\n");
-		err = -ENOMEM;
+		ret = -ENOMEM;
 		goto err_pdata;
 	}
 
 	tasklet_setup(&dw->tasklet, dw_dma_tasklet);
 
-	err = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED,
+	ret = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED,
 			  dw->name, dw);
-	if (err)
+	if (ret)
 		goto err_pdata;
 
 	INIT_LIST_HEAD(&dw->dma.channels);
@@ -1335,8 +1335,8 @@ int do_dma_probe(struct dw_dma_chip *chip)
 	 */
 	dma_set_max_seg_size(dw->dma.dev, dw->chan[0].block_size);
 
-	err = dma_async_device_register(&dw->dma);
-	if (err)
+	ret = dma_async_device_register(&dw->dma);
+	if (ret)
 		goto err_dma_register;
 
 	dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n",
@@ -1350,7 +1350,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
 	free_irq(chip->irq, dw);
 err_pdata:
 	pm_runtime_put_sync_suspend(chip->dev);
-	return err;
+	return ret;
 }
 
 int do_dma_remove(struct dw_dma_chip *chip)
drivers/dma/dw/platform.c +10 -10
index 7d9d4c951724..47c58ad468cb 100644
@@ -29,7 +29,7 @@ static int dw_probe(struct platform_device *pdev)
 	struct dw_dma_chip_pdata *data;
 	struct dw_dma_chip *chip;
 	struct device *dev = &pdev->dev;
-	int err;
+	int ret;
 
 	match = device_get_match_data(dev);
 	if (!match)
@@ -51,9 +51,9 @@ static int dw_probe(struct platform_device *pdev)
 	if (IS_ERR(chip->regs))
 		return PTR_ERR(chip->regs);
 
-	err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-	if (err)
-		return err;
+	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
 
 	if (!data->pdata)
 		data->pdata = dev_get_platdata(dev);
@@ -69,14 +69,14 @@ static int dw_probe(struct platform_device *pdev)
 	chip->clk = devm_clk_get_optional(chip->dev, "hclk");
 	if (IS_ERR(chip->clk))
 		return PTR_ERR(chip->clk);
-	err = clk_prepare_enable(chip->clk);
-	if (err)
-		return err;
+	ret = clk_prepare_enable(chip->clk);
+	if (ret)
+		return ret;
 
 	pm_runtime_enable(&pdev->dev);
 
-	err = data->probe(chip);
-	if (err)
+	ret = data->probe(chip);
+	if (ret)
 		goto err_dw_dma_probe;
 
 	platform_set_drvdata(pdev, data);
@@ -90,7 +90,7 @@ static int dw_probe(struct platform_device *pdev)
 err_dw_dma_probe:
 	pm_runtime_disable(&pdev->dev);
 	clk_disable_unprepare(chip->clk);
-	return err;
+	return ret;
 }
 
 static void dw_remove(struct platform_device *pdev)
Signature · 1 line
2.43.0
Acked-by on the v4 series
#15 lore raw
In reply to Serge Semin
Quoted 19 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

In addition to that three cleanup patches follow the fixes described above in order to make the DWC-engine configuration procedure more coherent. First one simplifies the CTL_LO register setup methods. Second and third patches simplify the max-burst calculation procedure and unify it with the rest of the verification methods. Please see the patches log for more details.

Quoted 2 lines

Final patch is another cleanup which unifies the status variables naming in the driver.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#16 lore raw

Hi Andy,

Quoted 20 lines · Andy Shevchenko
Quoted 19 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

In addition to that three cleanup patches follow the fixes described above in order to make the DWC-engine configuration procedure more coherent. First one simplifies the CTL_LO register setup methods. Second and third patches simplify the max-burst calculation procedure and unify it with the rest of the verification methods. Please see the patches log for more details.

Quoted 4 lines
Quoted 2 lines

Final patch is another cleanup which unifies the status variables naming in the driver.

Awesome! Thanks.

-Serge(y)

Quoted 4 lines
Signature · 3 lines
-- 
With Best Regards,
Andy Shevchenko
#17 lore raw
Quoted 21 lines · Serge Semin
Quoted 20 lines · Andy Shevchenko
Quoted 19 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

In addition to that three cleanup patches follow the fixes described above in order to make the DWC-engine configuration procedure more coherent. First one simplifies the CTL_LO register setup methods. Second and third patches simplify the max-burst calculation procedure and unify it with the rest of the verification methods. Please see the patches log for more details.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

Final patch is another cleanup which unifies the status variables naming in the driver.

Awesome! Thanks.

Not really :-)
This series broke iDMA32 + SPI PXA2xx on Intel Merrifield. I haven't had time to investigate further, but rolling back all patches helps.

+Cc: Ferry who might also test and maybe investigate as he reported the issue to me initially.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#18 lore raw

Hi Andy

Quoted 25 lines · Andy Shevchenko
Quoted 24 lines · Serge Semin
Quoted 23 lines · Andy Shevchenko
Quoted 21 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

In addition to that three cleanup patches follow the fixes described above in order to make the DWC-engine configuration procedure more coherent. First one simplifies the CTL_LO register setup methods. Second and third patches simplify the max-burst calculation procedure and unify it with the rest of the verification methods. Please see the patches log for more details.

Final patch is another cleanup which unifies the status variables naming in the driver.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Awesome! Thanks.

Not really :-)
This series broke iDMA32 + SPI PXA2xx on Intel Merrifield.

Damn. Sorry to hear that.(

Quoted 5 lines

I haven't
had time to investigate further, but rolling back all patches helps.

+Cc: Ferry who might also test and maybe investigate as he reported the issue to me initially.

Ferry, could you please roll back the series patch-by-patch to find out the particular commit to blame?

-Serge(y)

Quoted 7 lines
Signature · 3 lines
-- 
With Best Regards,
Andy Shevchenko
#19 lore raw
Quoted 37 lines · Serge Semin

Hi Andy

Quoted 25 lines · Andy Shevchenko
Quoted 24 lines · Serge Semin
Quoted 23 lines · Andy Shevchenko
Quoted 21 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

In addition to that three cleanup patches follow the fixes described above in order to make the DWC-engine configuration procedure more coherent. First one simplifies the CTL_LO register setup methods. Second and third patches simplify the max-burst calculation procedure and unify it with the rest of the verification methods. Please see the patches log for more details.

Final patch is another cleanup which unifies the status variables naming in the driver.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Awesome! Thanks.

Not really :-)
This series broke iDMA32 + SPI PXA2xx on Intel Merrifield.

Damn. Sorry to hear that.(

Quoted 8 lines
Quoted 5 lines

I haven't
had time to investigate further, but rolling back all patches helps.

+Cc: Ferry who might also test and maybe investigate as he reported the issue to me initially.

Ferry, could you please roll back the series patch-by-patch to find out the particular commit to blame?

Plus to that it would be nice to have some log/info/details/etc about what exactly is happening.

-Serge(y)

Quoted 10 lines

-Serge(y)

Quoted 7 lines
Signature · 3 lines
-- 
With Best Regards,
Andy Shevchenko
#20 lore raw
Quoted 42 lines · Serge Semin
Quoted 40 lines · Serge Semin

Hi Andy

Quoted 25 lines · Andy Shevchenko
Quoted 24 lines · Serge Semin
Quoted 23 lines · Andy Shevchenko
Quoted 21 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

In addition to that three cleanup patches follow the fixes described above in order to make the DWC-engine configuration procedure more coherent. First one simplifies the CTL_LO register setup methods. Second and third patches simplify the max-burst calculation procedure and unify it with the rest of the verification methods. Please see the patches log for more details.

Final patch is another cleanup which unifies the status variables naming in the driver.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Awesome! Thanks.

Not really :-)
This series broke iDMA32 + SPI PXA2xx on Intel Merrifield.

Damn. Sorry to hear that.(

Quoted 3 lines

I haven't
had time to investigate further, but rolling back all patches helps.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

+Cc: Ferry who might also test and maybe investigate as he reported the issue to me initially.

Ferry, could you please roll back the series patch-by-patch to find out the particular commit to blame?

Plus to that it would be nice to have some log/info/details/etc about what exactly is happening.

For me with patch

spitest -l -s1000000 -b128 /dev/spidev5.1
SPI: [mode 0x20, bits_per_word 8, speed 1000000 Hz]

[  164.525604] pxa2xx_spi_pci 0000:00:07.1: DMA slave config failed
[  164.536105] pxa2xx_spi_pci 0000:00:07.1: failed to get DMA TX descriptor
[  164.543213] spidev spi-SPT0001:00: SPI transfer failed: -16
[  164.550140] spi_master spi5: failed to transfer one message from queue
[  164.557126] spi_master spi5: noqueue transfer failed

spitest: SPI transfer failed in iteration #0: Device or resource busy

Without

spitest -s 1000000 -b 128 -l /dev/spidev5.1
SPI: [mode 0x20, bits_per_word 8, speed 1000000 Hz]
SEND: [00000000] ff 97 d0 54 d5 69 85 6e ca e7 b3 e1 a1 e5 1a 9d
...
RECV: [00000000] ff 97 d0 54 d5 69 85 6e ca e7 b3 e1 a1 e5 1a 9d
...

spitest is our internal tool, so what it does there is:
1) opens SPI device for speed 1MHz in loopback mode
2) generates 128 byte of random data
3) tries to send and receive them
4) compares

I believe the similar behaviour can be achieved with the one that is in the kernel tree.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#21 lore raw
Quoted 55 lines · Andy Shevchenko
Quoted 42 lines · Serge Semin
Quoted 40 lines · Serge Semin

Hi Andy

Quoted 25 lines · Andy Shevchenko
Quoted 24 lines · Serge Semin
Quoted 23 lines · Andy Shevchenko
Quoted 21 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

In addition to that three cleanup patches follow the fixes described above in order to make the DWC-engine configuration procedure more coherent. First one simplifies the CTL_LO register setup methods. Second and third patches simplify the max-burst calculation procedure and unify it with the rest of the verification methods. Please see the patches log for more details.

Final patch is another cleanup which unifies the status variables naming in the driver.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Awesome! Thanks.

Not really :-)
This series broke iDMA32 + SPI PXA2xx on Intel Merrifield.

Damn. Sorry to hear that.(

Quoted 3 lines

I haven't
had time to investigate further, but rolling back all patches helps.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

+Cc: Ferry who might also test and maybe investigate as he reported the issue to me initially.

Ferry, could you please roll back the series patch-by-patch to find out the particular commit to blame?

Plus to that it would be nice to have some log/info/details/etc about what exactly is happening.

For me with patch

Quoted 8 lines

spitest -l -s1000000 -b128 /dev/spidev5.1
SPI: [mode 0x20, bits_per_word 8, speed 1000000 Hz]

[  164.525604] pxa2xx_spi_pci 0000:00:07.1: DMA slave config failed
[  164.536105] pxa2xx_spi_pci 0000:00:07.1: failed to get DMA TX descriptor
[  164.543213] spidev spi-SPT0001:00: SPI transfer failed: -16
[  164.550140] spi_master spi5: failed to transfer one message from queue
[  164.557126] spi_master spi5: noqueue transfer failed

spitest: SPI transfer failed in iteration #0: Device or resource busy

Thanks for the log. As I suspected there is a safety-check failure, which prevents the client driver from using the DMA-controller with the specified transfer parameters.

It would be helpful if you find out which conditional statement in the dwc_verify_p_buswidth(), dwc_verify_m_buswidth() methods cause the failure. Also it would be useful to get the max_width, mem_width, reg_width and reg_burst variables values.

-Serge(y)

Quoted 22 lines

Without

spitest -s 1000000 -b 128 -l /dev/spidev5.1
SPI: [mode 0x20, bits_per_word 8, speed 1000000 Hz]
SEND: [00000000] ff 97 d0 54 d5 69 85 6e ca e7 b3 e1 a1 e5 1a 9d
...
RECV: [00000000] ff 97 d0 54 d5 69 85 6e ca e7 b3 e1 a1 e5 1a 9d
...

spitest is our internal tool, so what it does there is:
1) opens SPI device for speed 1MHz in loopback mode
2) generates 128 byte of random data
3) tries to send and receive them
4) compares

I believe the similar behaviour can be achieved with the one that is in the kernel tree.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
maintainer Applied
#22 lore raw
In reply to Serge Semin
Quoted 11 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

Quoted 1 line

[...]

Applied, thanks!

[1/6] dmaengine: dw: Add peripheral bus width verification

      commit: b336268dde75cb09bd795cb24893d52152a9191f
[2/6] dmaengine: dw: Add memory bus width verification
      commit: d04b21bfa1c50a2ade4816cab6fdc91827b346b1
[3/6] dmaengine: dw: Simplify prepare CTL_LO methods
      commit: 1fd6fe89055e6dbb4be8f16b8dcab8602e3603d6
[4/6] dmaengine: dw: Define encode_maxburst() above prepare_ctllo() callbacks
      commit: 3acb301d33749a8974e61ecda16a5f5441fc9628
[5/6] dmaengine: dw: Simplify max-burst calculation procedure
      commit: d8fa0802f63502c0409d02c6b701d51841a6f1bd
[6/6] dmaengine: dw: Unify ret-val local variables naming
      commit: 2ebc36b9581df31eed271e5de61fc8a8b66dbc56

Best regards,

Signature · 1 line
Vinod Koul <[email protected]>
maintainer Applied
#23 lore raw
In reply to Serge Semin
Quoted 11 lines · Serge Semin

The main goal of this series is to fix the data disappearance in case of the DW UART handled by the DW AHB DMA engine. The problem happens on a portion of the data received when the pre-initialized DEV_TO_MEM DMA-transfer is paused and then disabled. The data just hangs up in the DMA-engine FIFO and isn't flushed out to the memory on the DMA-channel suspension (see the second commit log for details). On a way to find the denoted problem fix it was discovered that the driver doesn't verify the peripheral device address width specified by a client driver, which in its turn if unsupported or undefined value passed may cause DMA-transfer being misconfigured. It's fixed in the first patch of the series.

Quoted 1 line

[...]

Applied, thanks!

[1/6] dmaengine: dw: Add peripheral bus width verification

      commit: e2c97d200ac3558e6c34258c96a01a0b9472292f
[2/6] dmaengine: dw: Add memory bus width verification
      commit: 5bb11aedb5309c232967ce490d7b826536f697c0
[3/6] dmaengine: dw: Simplify prepare CTL_LO methods
      commit: d34e8466c63389ef250c380cd615826afb2a049c
[4/6] dmaengine: dw: Define encode_maxburst() above prepare_ctllo() callbacks
      commit: 2f87a9671ed532fc088ef0b05e350637afdf001a
[5/6] dmaengine: dw: Simplify max-burst calculation procedure
      commit: 17d4353413a4d931e89b2c37106acae4a0972ad8
[6/6] dmaengine: dw: Unify ret-val local variables naming
      commit: 3f92ee7c4a4e2319d510eb2ddcfdd3105b235f0e

Best regards,

Signature · 1 line
~Vinod