From 30fba404d278e54e58a266b7fe92bde3bcd1d9b8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 12 Mar 2025 22:51:00 +0900 Subject: [PATCH] pmdomain: core: Fix error path in pm_genpd_init() when ida alloc fails BugLink: https://bugs.launchpad.net/bugs/2102118 [ Upstream commit 3e3b71d35a02cee4b2cc3d4255668a6609165518 ] When the ida allocation fails we need to free up the previously allocated memory before returning the error code. Let's fix this and while at it, let's also move the ida allocation to genpd_alloc_data() and the freeing to genpd_free_data(), as it better belongs there. Fixes: 899f44531fe6 ("pmdomain: core: Add GENPD_FLAG_DEV_NAME_FW flag") Signed-off-by: Ulf Hansson Message-ID: <20241122134207.157283-3-ulf.hansson@linaro.org> Signed-off-by: Sasha Levin Signed-off-by: Koichiro Den Signed-off-by: Stefan Bader --- drivers/pmdomain/core.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index fb3c34cd883c..1e890266a4d2 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -2033,8 +2033,24 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd) } genpd->gd = gd; - return 0; + device_initialize(&genpd->dev); + if (!genpd_is_dev_name_fw(genpd)) { + dev_set_name(&genpd->dev, "%s", genpd->name); + } else { + ret = ida_alloc(&genpd_ida, GFP_KERNEL); + if (ret < 0) + goto put; + + genpd->device_id = ret; + dev_set_name(&genpd->dev, "%s_%u", genpd->name, genpd->device_id); + } + + return 0; +put: + put_device(&genpd->dev); + if (genpd->free_states == genpd_free_default_power_state) + kfree(genpd->states); free: if (genpd_is_cpu_domain(genpd)) free_cpumask_var(genpd->cpus); @@ -2045,6 +2061,8 @@ free: static void genpd_free_data(struct generic_pm_domain *genpd) { put_device(&genpd->dev); + if (genpd->device_id != -ENXIO) + ida_free(&genpd_ida, genpd->device_id); if (genpd_is_cpu_domain(genpd)) free_cpumask_var(genpd->cpus); if (genpd->free_states) @@ -2130,20 +2148,6 @@ int pm_genpd_init(struct generic_pm_domain *genpd, if (ret) return ret; - device_initialize(&genpd->dev); - - if (!genpd_is_dev_name_fw(genpd)) { - dev_set_name(&genpd->dev, "%s", genpd->name); - } else { - ret = ida_alloc(&genpd_ida, GFP_KERNEL); - if (ret < 0) { - put_device(&genpd->dev); - return ret; - } - genpd->device_id = ret; - dev_set_name(&genpd->dev, "%s_%u", genpd->name, genpd->device_id); - } - mutex_lock(&gpd_list_lock); list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); @@ -2184,8 +2188,6 @@ static int genpd_remove(struct generic_pm_domain *genpd) genpd_unlock(genpd); genpd_debug_remove(genpd); cancel_work_sync(&genpd->power_off_work); - if (genpd->device_id != -ENXIO) - ida_free(&genpd_ida, genpd->device_id); genpd_free_data(genpd); pr_debug("%s: removed %s\n", __func__, dev_name(&genpd->dev));