]> git.itanic.dy.fi Git - linux-stable/commitdiff
soc: brcmstb: pm-arm: Fix refcount leak and __iomem leak bugs
authorLiang He <windhl@126.com>
Thu, 7 Jul 2022 01:56:20 +0000 (09:56 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 15 Sep 2022 10:17:05 +0000 (12:17 +0200)
[ Upstream commit 1085f5080647f0c9f357c270a537869191f7f2a1 ]

In brcmstb_pm_probe(), there are two kinds of leak bugs:

(1) we need to add of_node_put() when for_each__matching_node() breaks
(2) we need to add iounmap() for each iomap in fail path

Fixes: 0b741b8234c8 ("soc: bcm: brcmstb: Add support for S2/S3/S5 suspend states (ARM)")
Signed-off-by: Liang He <windhl@126.com>
Link: https://lore.kernel.org/r/20220707015620.306468-1-windhl@126.com
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/soc/bcm/brcmstb/pm/pm-arm.c

index f4ad45a1efabe4a6c137efb97b760d713c4b1e75..fd124e0850207c2dc9d1e1d4ebac5c89da6dbd1a 100644 (file)
@@ -689,13 +689,14 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        const struct of_device_id *of_id = NULL;
        struct device_node *dn;
        void __iomem *base;
-       int ret, i;
+       int ret, i, s;
 
        /* AON ctrl registers */
        base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 0, NULL);
        if (IS_ERR(base)) {
                pr_err("error mapping AON_CTRL\n");
-               return PTR_ERR(base);
+               ret = PTR_ERR(base);
+               goto aon_err;
        }
        ctrl.aon_ctrl_base = base;
 
@@ -705,8 +706,10 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
                /* Assume standard offset */
                ctrl.aon_sram = ctrl.aon_ctrl_base +
                                     AON_CTRL_SYSTEM_DATA_RAM_OFS;
+               s = 0;
        } else {
                ctrl.aon_sram = base;
+               s = 1;
        }
 
        writel_relaxed(0, ctrl.aon_sram + AON_REG_PANIC);
@@ -716,7 +719,8 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
                                     (const void **)&ddr_phy_data);
        if (IS_ERR(base)) {
                pr_err("error mapping DDR PHY\n");
-               return PTR_ERR(base);
+               ret = PTR_ERR(base);
+               goto ddr_phy_err;
        }
        ctrl.support_warm_boot = ddr_phy_data->supports_warm_boot;
        ctrl.pll_status_offset = ddr_phy_data->pll_status_offset;
@@ -736,17 +740,20 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        for_each_matching_node(dn, ddr_shimphy_dt_ids) {
                i = ctrl.num_memc;
                if (i >= MAX_NUM_MEMC) {
+                       of_node_put(dn);
                        pr_warn("too many MEMCs (max %d)\n", MAX_NUM_MEMC);
                        break;
                }
 
                base = of_io_request_and_map(dn, 0, dn->full_name);
                if (IS_ERR(base)) {
+                       of_node_put(dn);
                        if (!ctrl.support_warm_boot)
                                break;
 
                        pr_err("error mapping DDR SHIMPHY %d\n", i);
-                       return PTR_ERR(base);
+                       ret = PTR_ERR(base);
+                       goto ddr_shimphy_err;
                }
                ctrl.memcs[i].ddr_shimphy_base = base;
                ctrl.num_memc++;
@@ -757,14 +764,18 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        for_each_matching_node(dn, brcmstb_memc_of_match) {
                base = of_iomap(dn, 0);
                if (!base) {
+                       of_node_put(dn);
                        pr_err("error mapping DDR Sequencer %d\n", i);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto brcmstb_memc_err;
                }
 
                of_id = of_match_node(brcmstb_memc_of_match, dn);
                if (!of_id) {
                        iounmap(base);
-                       return -EINVAL;
+                       of_node_put(dn);
+                       ret = -EINVAL;
+                       goto brcmstb_memc_err;
                }
 
                ddr_seq_data = of_id->data;
@@ -784,21 +795,24 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        dn = of_find_matching_node(NULL, sram_dt_ids);
        if (!dn) {
                pr_err("SRAM not found\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto brcmstb_memc_err;
        }
 
        ret = brcmstb_init_sram(dn);
        of_node_put(dn);
        if (ret) {
                pr_err("error setting up SRAM for PM\n");
-               return ret;
+               goto brcmstb_memc_err;
        }
 
        ctrl.pdev = pdev;
 
        ctrl.s3_params = kmalloc(sizeof(*ctrl.s3_params), GFP_KERNEL);
-       if (!ctrl.s3_params)
-               return -ENOMEM;
+       if (!ctrl.s3_params) {
+               ret = -ENOMEM;
+               goto s3_params_err;
+       }
        ctrl.s3_params_pa = dma_map_single(&pdev->dev, ctrl.s3_params,
                                           sizeof(*ctrl.s3_params),
                                           DMA_TO_DEVICE);
@@ -818,7 +832,21 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
 
 out:
        kfree(ctrl.s3_params);
-
+s3_params_err:
+       iounmap(ctrl.boot_sram);
+brcmstb_memc_err:
+       for (i--; i >= 0; i--)
+               iounmap(ctrl.memcs[i].ddr_ctrl);
+ddr_shimphy_err:
+       for (i = 0; i < ctrl.num_memc; i++)
+               iounmap(ctrl.memcs[i].ddr_shimphy_base);
+
+       iounmap(ctrl.memcs[0].ddr_phy_base);
+ddr_phy_err:
+       iounmap(ctrl.aon_ctrl_base);
+       if (s)
+               iounmap(ctrl.aon_sram);
+aon_err:
        pr_warn("PM: initialization failed with code %d\n", ret);
 
        return ret;