mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-28 08:43:37 +00:00
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: 72f5801a4e
("dmaengine: fsl-edma: integrate v3 support")
Signed-off-by: Joe 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: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
dcbef0798e
commit
ccfa3131d4
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user