Skip to content

Commit b336268

Browse files
fancervinodkoul
authored andcommitted
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: 029a40e ("dmaengine: dw: provide DMA capabilities") Signed-off-by: Serge Semin <fancer.lancer@gmail.com> Acked-by: Andy Shevchenko <andy@kernel.org> Link: https://lore.kernel.org/r/20240802075100.6475-2-fancer.lancer@gmail.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent 8400291 commit b336268

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

drivers/dma/dw/core.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/init.h>
1717
#include <linux/interrupt.h>
1818
#include <linux/io.h>
19+
#include <linux/log2.h>
1920
#include <linux/mm.h>
2021
#include <linux/module.h>
2122
#include <linux/slab.h>
@@ -780,10 +781,43 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
780781
}
781782
EXPORT_SYMBOL_GPL(dw_dma_filter);
782783

784+
static int dwc_verify_p_buswidth(struct dma_chan *chan)
785+
{
786+
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
787+
struct dw_dma *dw = to_dw_dma(chan->device);
788+
u32 reg_width, max_width;
789+
790+
if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
791+
reg_width = dwc->dma_sconfig.dst_addr_width;
792+
else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM)
793+
reg_width = dwc->dma_sconfig.src_addr_width;
794+
else /* DMA_MEM_TO_MEM */
795+
return 0;
796+
797+
max_width = dw->pdata->data_width[dwc->dws.p_master];
798+
799+
/* Fall-back to 1-byte transfer width if undefined */
800+
if (reg_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
801+
reg_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
802+
else if (!is_power_of_2(reg_width) || reg_width > max_width)
803+
return -EINVAL;
804+
else /* bus width is valid */
805+
return 0;
806+
807+
/* Update undefined addr width value */
808+
if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
809+
dwc->dma_sconfig.dst_addr_width = reg_width;
810+
else /* DMA_DEV_TO_MEM */
811+
dwc->dma_sconfig.src_addr_width = reg_width;
812+
813+
return 0;
814+
}
815+
783816
static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
784817
{
785818
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
786819
struct dw_dma *dw = to_dw_dma(chan->device);
820+
int ret;
787821

788822
memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
789823

@@ -792,6 +826,10 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
792826
dwc->dma_sconfig.dst_maxburst =
793827
clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst);
794828

829+
ret = dwc_verify_p_buswidth(chan);
830+
if (ret)
831+
return ret;
832+
795833
dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
796834
dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
797835

0 commit comments

Comments
 (0)