mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
dmaengine: ste_dma40: Fix memcpy channel parsing
d40_of_probe() validates the memcpy-channels property against
D40_MEMCPY_MAX_CHANS, but reads the property directly into a smaller global
array. A long property can therefore overwrite adjacent data. The mutable
global also lets a later DMA40 instance replace the memcpy channel mapping
used for future allocations on an earlier instance.
Store the mapping in the per-device platform data, validate the property
against that storage, and check the property read result. The property is
required and d40_probe() always populates the platform data, so remove the
obsolete global mapping and fallback.
Fixes: a7dacb68b3 ("dmaengine: ste_dma40: Allow memcpy channels to be configured from DT")
Reported-by: sashiko-bot@kernel.org
Closes: https://lore.kernel.org/dmaengine/20260819225215.5EA2F1F000E9@smtp.kernel.org/
Assisted-by: LLM
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260927-dma40-fixes-v7-15-89f595e8851d@kernel.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
9a3762b470
commit
f2baf04a69
|
|
@ -28,6 +28,8 @@
|
|||
#include "ste_dma40.h"
|
||||
#include "ste_dma40_ll.h"
|
||||
|
||||
#define D40_MEMCPY_MAX_CHANS 8
|
||||
|
||||
/**
|
||||
* struct stedma40_platform_data - Configuration struct for the dma device.
|
||||
*
|
||||
|
|
@ -41,6 +43,7 @@
|
|||
* to use SoftLLI.
|
||||
* @use_esram_lcla: flag for mapping the lcla into esram region
|
||||
* @num_of_memcpy_chans: The number of channels reserved for memcpy.
|
||||
* @memcpy_channels: The event lines used for memcpy.
|
||||
* @num_of_phy_chans: The number of physical channels implemented in HW.
|
||||
* 0 means reading the number of channels from DMA HW but this is only valid
|
||||
* for 'multiple of 4' channels, like 8.
|
||||
|
|
@ -51,6 +54,7 @@ struct stedma40_platform_data {
|
|||
int num_of_soft_lli_chans;
|
||||
bool use_esram_lcla;
|
||||
int num_of_memcpy_chans;
|
||||
u32 memcpy_channels[D40_MEMCPY_MAX_CHANS];
|
||||
int num_of_phy_chans;
|
||||
};
|
||||
|
||||
|
|
@ -89,25 +93,6 @@ struct stedma40_platform_data {
|
|||
#define D40_ALLOC_PHY BIT(30)
|
||||
#define D40_ALLOC_LOG_FREE 0
|
||||
|
||||
#define D40_MEMCPY_MAX_CHANS 8
|
||||
|
||||
/* Reserved event lines for memcpy only. */
|
||||
#define DB8500_DMA_MEMCPY_EV_0 51
|
||||
#define DB8500_DMA_MEMCPY_EV_1 56
|
||||
#define DB8500_DMA_MEMCPY_EV_2 57
|
||||
#define DB8500_DMA_MEMCPY_EV_3 58
|
||||
#define DB8500_DMA_MEMCPY_EV_4 59
|
||||
#define DB8500_DMA_MEMCPY_EV_5 60
|
||||
|
||||
static int dma40_memcpy_channels[] = {
|
||||
DB8500_DMA_MEMCPY_EV_0,
|
||||
DB8500_DMA_MEMCPY_EV_1,
|
||||
DB8500_DMA_MEMCPY_EV_2,
|
||||
DB8500_DMA_MEMCPY_EV_3,
|
||||
DB8500_DMA_MEMCPY_EV_4,
|
||||
DB8500_DMA_MEMCPY_EV_5,
|
||||
};
|
||||
|
||||
/* Default configuration for physical memcpy */
|
||||
static const struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
|
||||
.mode = STEDMA40_MODE_PHYSICAL,
|
||||
|
|
@ -2149,7 +2134,8 @@ static int d40_config_memcpy(struct d40_chan *d40c)
|
|||
|
||||
if (dma_has_cap(DMA_MEMCPY, cap) && !dma_has_cap(DMA_SLAVE, cap)) {
|
||||
d40c->dma_cfg = dma40_memcpy_conf_log;
|
||||
d40c->dma_cfg.dev_type = dma40_memcpy_channels[d40c->chan.chan_id];
|
||||
d40c->dma_cfg.dev_type =
|
||||
d40c->base->plat_data->memcpy_channels[d40c->chan.chan_id];
|
||||
|
||||
d40_log_cfg(&d40c->dma_cfg,
|
||||
&d40c->log_def.lcsp1, &d40c->log_def.lcsp3);
|
||||
|
|
@ -3429,12 +3415,7 @@ static int __init d40_hw_detect_init(struct platform_device *pdev,
|
|||
num_phy_chans = min(num_phy_chans, STEDMA40_MAX_PHYS);
|
||||
|
||||
/* The number of channels used for memcpy */
|
||||
if (plat_data->num_of_memcpy_chans)
|
||||
num_memcpy_chans = plat_data->num_of_memcpy_chans;
|
||||
else
|
||||
num_memcpy_chans = ARRAY_SIZE(dma40_memcpy_channels);
|
||||
|
||||
num_memcpy_chans = min(num_memcpy_chans, D40_MEMCPY_MAX_CHANS);
|
||||
num_memcpy_chans = plat_data->num_of_memcpy_chans;
|
||||
num_log_chans = num_phy_chans * D40_MAX_LOG_CHAN_PER_PHY;
|
||||
|
||||
dev_info(dev,
|
||||
|
|
@ -3683,6 +3664,7 @@ static int __init d40_of_probe(struct device *dev,
|
|||
struct stedma40_platform_data *pdata;
|
||||
int num_phy = 0, num_memcpy = 0, num_disabled = 0;
|
||||
const __be32 *list;
|
||||
int ret;
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
|
|
@ -3696,18 +3678,19 @@ static int __init d40_of_probe(struct device *dev,
|
|||
list = of_get_property(np, "memcpy-channels", &num_memcpy);
|
||||
num_memcpy /= sizeof(*list);
|
||||
|
||||
if (num_memcpy > D40_MEMCPY_MAX_CHANS || num_memcpy <= 0) {
|
||||
if (num_memcpy > ARRAY_SIZE(pdata->memcpy_channels) ||
|
||||
num_memcpy <= 0) {
|
||||
d40_err(dev,
|
||||
"Invalid number of memcpy channels specified (%d)\n",
|
||||
num_memcpy);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = of_property_read_u32_array(np, "memcpy-channels",
|
||||
pdata->memcpy_channels, num_memcpy);
|
||||
if (ret)
|
||||
return ret;
|
||||
pdata->num_of_memcpy_chans = num_memcpy;
|
||||
|
||||
of_property_read_u32_array(np, "memcpy-channels",
|
||||
dma40_memcpy_channels,
|
||||
num_memcpy);
|
||||
|
||||
list = of_get_property(np, "disabled-channels", &num_disabled);
|
||||
num_disabled /= sizeof(*list);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user