[PATCH v2] clk: mediatek: pllfh: Fix IO remapping leak in register_pllfhs error path
Louis-Alexis Eyraud
louisalexis.eyraud at collabora.com
Thu Jul 9 05:23:00 PDT 2026
When mtk_clk_register_pllfhs function fails to register a PLL, it
unregisters all PLLs and cleans up itself in its error path before
returning, so the function callers don't need to do it.
But contrary to mtk_clk_unregister_pllfhs function, that does almost
the same sequence, it does not free the IO memory mapped on fhctl node,
leading to a leak.
Fix this leak by factorizing the cleanup sequence in a new private
function and use it both mtk_clk_register_pllfhs and
mtk_clk_unregister_pllfhs functions.
Also, change the loop index start value to avoid the -1 operation on
index at each loop.
Fixes: d7964de8a8ea ("clk: mediatek: Add new clock driver to handle FHCTL hardware")
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
This patch aims to fix a issue, detected by Sashiko
during another series review ([1]), regarding the use of
mtk_clk_register_pllfhs function.
The patch is based on linux-next tree (tag: next-20260708).
[1]: https://sashiko.dev/#/patchset/20260701-mt8189-clocks-system-base-v1-0-2b048feea50a%40collabora.com?part=6
---
Changes in v2:
- Rebased on next-20260708
- Fixed loop stop condition in mtk_clk_cleanup_pllfhs function (B. Masney and
Sashiko)
- Reworked base and fhctl_base address handling in mtk_clk_cleanup_pllfhs.
The function has now both addresses as arguments, so it can either
use the provided addresses (register cleanup case) or find them in
the pllfh data structures if NULL addresses were given (unregister case) to
unmap them (B. Masney and Sashiko)
- Link to v1: https://lore.kernel.org/r/20260708-clk-mediatek-pllfh-fix-v1-1-2cfc2d6b258e@collabora.com
---
drivers/clk/mediatek/clk-pllfh.c | 98 ++++++++++++++++++++--------------------
1 file changed, 49 insertions(+), 49 deletions(-)
diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c
index aa95cd9197b3..6249fb87b1f5 100644
--- a/drivers/clk/mediatek/clk-pllfh.c
+++ b/drivers/clk/mediatek/clk-pllfh.c
@@ -197,12 +197,56 @@ static void mtk_clk_unregister_pllfh(struct clk_hw *hw)
kfree(fh);
}
+static void mtk_clk_cleanup_pllfhs(void __iomem *iomem_base,
+ const struct mtk_pll_data *plls, int num_plls,
+ void __iomem *iomem_fhctl_base,
+ struct mtk_pllfh_data *pllfhs, int num_fhs,
+ struct clk_hw_onecell_data *clk_data)
+{
+ void __iomem *base = iomem_base;
+ void __iomem *fhctl_base = iomem_fhctl_base;
+ int i;
+
+ for (i = num_plls - 1; i >= 0; i--) {
+ const struct mtk_pll_data *pll = &plls[i];
+ struct mtk_pllfh_data *pllfh;
+ bool use_fhctl;
+
+ if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
+ continue;
+
+ pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
+ use_fhctl = fhctl_is_supported_and_enabled(pllfh);
+
+ if (!base)
+ base = mtk_clk_pll_get_base(clk_data->hws[pll->id],
+ pll);
+
+ if (use_fhctl) {
+ if (!fhctl_base)
+ fhctl_base = pllfh->state.base;
+ mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
+ } else {
+ mtk_clk_unregister_pll(clk_data->hws[pll->id]);
+ }
+
+ clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
+ }
+
+ if (fhctl_base)
+ iounmap(fhctl_base);
+
+ if (base)
+ iounmap(base);
+}
+
+
int mtk_clk_register_pllfhs(struct device *dev,
const struct mtk_pll_data *plls, int num_plls,
struct mtk_pllfh_data *pllfhs, int num_fhs,
struct clk_hw_onecell_data *clk_data)
{
- void __iomem *base;
+ void __iomem *base, *fhctl_base = NULL;
int i;
struct clk_hw *hw;
@@ -238,24 +282,8 @@ int mtk_clk_register_pllfhs(struct device *dev,
return 0;
err:
- while (--i >= 0) {
- const struct mtk_pll_data *pll = &plls[i];
- struct mtk_pllfh_data *pllfh;
- bool use_fhctl;
-
- pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
- use_fhctl = fhctl_is_supported_and_enabled(pllfh);
-
- if (use_fhctl)
- mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
- else
- mtk_clk_unregister_pll(clk_data->hws[pll->id]);
-
- clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
- }
-
- iounmap(base);
-
+ mtk_clk_cleanup_pllfhs(base, plls, i, fhctl_base, pllfhs, num_fhs,
+ clk_data);
return PTR_ERR(hw);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_pllfhs);
@@ -264,38 +292,10 @@ void mtk_clk_unregister_pllfhs(const struct mtk_pll_data *plls, int num_plls,
struct mtk_pllfh_data *pllfhs, int num_fhs,
struct clk_hw_onecell_data *clk_data)
{
- void __iomem *base = NULL, *fhctl_base = NULL;
- int i;
-
if (!clk_data)
return;
- for (i = num_plls; i > 0; i--) {
- const struct mtk_pll_data *pll = &plls[i - 1];
- struct mtk_pllfh_data *pllfh;
- bool use_fhctl;
-
- if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
- continue;
-
- pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
- use_fhctl = fhctl_is_supported_and_enabled(pllfh);
-
- if (use_fhctl) {
- fhctl_base = pllfh->state.base;
- mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
- } else {
- base = mtk_clk_pll_get_base(clk_data->hws[pll->id],
- pll);
- mtk_clk_unregister_pll(clk_data->hws[pll->id]);
- }
-
- clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
- }
-
- if (fhctl_base)
- iounmap(fhctl_base);
-
- iounmap(base);
+ mtk_clk_cleanup_pllfhs(NULL, plls, num_plls, NULL, pllfhs,
+ num_fhs, clk_data);
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_pllfhs);
---
base-commit: 451b00e20bcd5526c6def9ee76f9bdb322ae9b46
change-id: 20260708-clk-mediatek-pllfh-fix-7e9ca35989e2
Best regards,
--
Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
More information about the Linux-mediatek
mailing list