Thread (12 messages) flat view 12 messages, 3 authors, 9d ago

Re: [PATCH v1 4/5] dmaengine: cix-sky1-dma350: Add Sky1 integration driver

From: sashiko-bot@kernel.org
Date: 2026-09-07 03:44:15
Also in: linux-devicetree

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Race condition allocating DMA buffers due to delayed reserved memory attachment.
- [High] Infinite probe deferral if the child 'arm,dma-350' device node is disabled.
- [Medium] Improper mixing of pulse and level reset semantics leads to ignored errors and potential power-off failures.
- [Medium] Leaking partially populated child platform devices on `of_platform_populate` error path.
--

commit a340fbf6d0923e08511995628a9b9b856250a6c8
Author: Jelly Jia [off-list ref]

dmaengine: cix-sky1-dma350: Add Sky1 integration driver

Add a CIX Sky1 integration driver for Arm DMA-350 instances. The driver
manages clocks, reset, optional interrupt routing, optional reserved
memory attachment, and populates the child Arm DMA-350 controller.
quoted hunk ↗ jump to hunk
diff --git a/drivers/dma/cix-sky1-dma350.c b/drivers/dma/cix-sky1-dma350.c
new file mode 100644
index 0000000000000..5904453f34818
--- /dev/null
+++ b/drivers/dma/cix-sky1-dma350.c
[ ... ]
+static int cix_sky1_dma350_enable_resources(struct device *dev)
+{
+	struct cix_sky1_dma350 *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_bulk_prepare_enable(data->num_clks, data->clks);
+	if (ret)
+		return ret;
+
+	ret = reset_control_reset(data->reset);
+	if (ret)
+		goto err_disable_clks;
[ ... ]
+static void cix_sky1_dma350_disable_resources(struct device *dev)
+{
+	struct cix_sky1_dma350 *data = dev_get_drvdata(dev);
+
+	reset_control_assert(data->reset);
[Severity: Medium]
Is it safe to mix pulse and level reset semantics here?

The enable path uses reset_control_reset() for a pulse, but the disable path
uses reset_control_assert() for a level assertion.

If the underlying reset controller only implements the .reset callback
(pulse), reset_control_assert() will return -ENOTSUPP. Because the return
value is ignored, won't this silently fail to reset the hardware during
unbind or system suspend, leaving it active?
+	clk_bulk_disable_unprepare(data->num_clks, data->clks);
+}
+
+static int cix_sky1_dma350_attach_reserved_mem(struct device *dev)
+{
+	struct cix_sky1_dma350 *data = dev_get_drvdata(dev);
+	struct platform_device *child_pdev;
+	struct device_node *child_np;
+	int ret;
+
+	if (!of_property_present(dev->of_node, "memory-region"))
+		return 0;
+
+	child_np = of_get_compatible_child(dev->of_node, "arm,dma-350");
+	if (!child_np)
+		return -ENODEV;
+
+	child_pdev = of_find_device_by_node(child_np);
+	of_node_put(child_np);
+	if (!child_pdev)
+		return -EPROBE_DEFER;
[Severity: High]
Can this lead to an infinite probe deferral loop if the child device node is
disabled in the device tree?

of_get_compatible_child() does not check the node's availability, so it will
return the child node even if it has status = "disabled". Because
of_platform_populate() correctly skips disabled nodes, no device will be
instantiated.

As a result, of_find_device_by_node() will return NULL, causing the driver
to continually return -EPROBE_DEFER instead of ignoring the disabled device.
+
+	/*
+	 * Reserved memory is attached after the child has probed. This relies
+	 * on arm-dma350 not allocating coherent command buffers in probe;
+	 * those allocations happen per descriptor at prep time.
+	 */
+	ret = of_reserved_mem_device_init_by_idx(&child_pdev->dev,
+						 dev->of_node, 0);
[Severity: High]
Is there a race condition with allocating DMA buffers here?

of_platform_populate() in the probe function synchronously instantiates and
probes the child device, exposing it to the rest of the system.

Could a concurrent DMA client request a channel and prepare a transfer before
cix_sky1_dma350_attach_reserved_mem() executes? If that happens, allocations
might draw from the default system pool instead of the designated reserved
region, potentially causing hardware faults.
+	if (ret) {
+		put_device(&child_pdev->dev);
+		return ret;
+	}
[ ... ]
+static int cix_sky1_dma350_probe(struct platform_device *pdev)
+{
[ ... ]
+	ret = cix_sky1_dma350_enable_resources(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable resources\n");
+
+	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (ret)
+		goto err_disable_resources;
[Severity: Medium]
Does this leak partially populated child platform devices?

If of_platform_populate() encounters an error while instantiating multiple
children, it breaks and returns an error without cleaning up the ones it
already created.

Bypassing err_depopulate here prevents cleanup of platform devices created
prior to the failure, permanently leaking them.
+
+	ret = cix_sky1_dma350_attach_reserved_mem(dev);
+	if (ret)
+		goto err_depopulate;
+
+	return 0;
-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260907033404.596839-1-Jelly.Jia@cixtech.com?part=4
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help