mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 09:20:13 -04:00
clk: mediatek: pllfh: Fix IO remapping leak in register_pllfhs error path
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: d7964de8a8 ("clk: mediatek: Add new clock driver to handle FHCTL hardware")
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
Reviewed-by: Brian Masney <bmasney@redhat.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Brian Masney <bmasney@redhat.com>
This commit is contained in:
committed by
Brian Masney
parent
f726279f5e
commit
540d91480b
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user