Commit ccfa3131 authored by Joe Hattori's avatar Joe Hattori Committed by Vinod Koul
Browse files

dmaengine: fsl-edma: implement the cleanup path of fsl_edma3_attach_pd()



Current implementation of fsl_edma3_attach_pd() does not provide a
cleanup path, resulting in a memory leak. For example,
dev_pm_domain_detach() is not called after dev_pm_domain_attach_by_id(),
and the device link created with the DL_FLAG_STATELESS is not released
explicitly.

Therefore, provide a cleanup function fsl_edma3_detach_pd() and call it
upon failure. Also add a devm_add_action_or_reset() call with this
function after a successful fsl_edma3_attach_pd().

Fixes: 72f5801a ("dmaengine: fsl-edma: integrate v3 support")
Signed-off-by: default avatarJoe Hattori <joe@pf.is.s.u-tokyo.ac.jp>
Link: https://lore.kernel.org/r/20241221075712.3297200-1-joe@pf.is.s.u-tokyo.ac.jp


Signed-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent dcbef079
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -166,6 +166,7 @@ struct fsl_edma_chan {
	struct work_struct		issue_worker;
	struct platform_device		*pdev;
	struct device			*pd_dev;
	struct device_link		*pd_dev_link;
	u32				srcid;
	struct clk			*clk;
	int                             priority;
+36 −5
Original line number Diff line number Diff line
@@ -417,10 +417,33 @@ static const struct of_device_id fsl_edma_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);

static void fsl_edma3_detach_pd(struct fsl_edma_engine *fsl_edma)
{
	struct fsl_edma_chan *fsl_chan;
	int i;

	for (i = 0; i < fsl_edma->n_chans; i++) {
		if (fsl_edma->chan_masked & BIT(i))
			continue;
		fsl_chan = &fsl_edma->chans[i];
		if (fsl_chan->pd_dev_link)
			device_link_del(fsl_chan->pd_dev_link);
		if (fsl_chan->pd_dev) {
			dev_pm_domain_detach(fsl_chan->pd_dev, false);
			pm_runtime_dont_use_autosuspend(fsl_chan->pd_dev);
			pm_runtime_set_suspended(fsl_chan->pd_dev);
		}
	}
}

static void devm_fsl_edma3_detach_pd(void *data)
{
	fsl_edma3_detach_pd(data);
}

static int fsl_edma3_attach_pd(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
{
	struct fsl_edma_chan *fsl_chan;
	struct device_link *link;
	struct device *pd_chan;
	struct device *dev;
	int i;
@@ -436,15 +459,16 @@ static int fsl_edma3_attach_pd(struct platform_device *pdev, struct fsl_edma_eng
		pd_chan = dev_pm_domain_attach_by_id(dev, i);
		if (IS_ERR_OR_NULL(pd_chan)) {
			dev_err(dev, "Failed attach pd %d\n", i);
			return -EINVAL;
			goto detach;
		}

		link = device_link_add(dev, pd_chan, DL_FLAG_STATELESS |
		fsl_chan->pd_dev_link = device_link_add(dev, pd_chan, DL_FLAG_STATELESS |
					     DL_FLAG_PM_RUNTIME |
					     DL_FLAG_RPM_ACTIVE);
		if (!link) {
		if (!fsl_chan->pd_dev_link) {
			dev_err(dev, "Failed to add device_link to %d\n", i);
			return -EINVAL;
			dev_pm_domain_detach(pd_chan, false);
			goto detach;
		}

		fsl_chan->pd_dev = pd_chan;
@@ -455,6 +479,10 @@ static int fsl_edma3_attach_pd(struct platform_device *pdev, struct fsl_edma_eng
	}

	return 0;

detach:
	fsl_edma3_detach_pd(fsl_edma);
	return -EINVAL;
}

static int fsl_edma_probe(struct platform_device *pdev)
@@ -544,6 +572,9 @@ static int fsl_edma_probe(struct platform_device *pdev)
		ret = fsl_edma3_attach_pd(pdev, fsl_edma);
		if (ret)
			return ret;
		ret = devm_add_action_or_reset(&pdev->dev, devm_fsl_edma3_detach_pd, fsl_edma);
		if (ret)
			return ret;
	}

	if (drvdata->flags & FSL_EDMA_DRV_TCD64)