clk: st: Fix error paths and allocation style

The error paths in this file leak memory and mappings and test
for pointers being valid after dereferencing them. Fix these
problems and properly free resources on errors. Fix some
stylistic things too like using sizeof(*ptr) and fitting more
code on a single line. Note that we don't unregister clocks here.
That needs a clk_composite_unregister() API that we don't have
right now.

Acked-by: Gabriel Fernandez <gabriel.fernandez@linaro.org>
Cc: Pankaj Dev <pankaj.dev@st.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
This commit is contained in:
Stephen Boyd 2015-07-07 18:30:05 -07:00
Родитель f04b8b48d3
Коммит 86665d2897
1 изменённых файлов: 45 добавлений и 38 удалений

Просмотреть файл

@ -30,7 +30,7 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np,
if (WARN_ON(nparents <= 0)) if (WARN_ON(nparents <= 0))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL); parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL);
if (!parents) if (!parents)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
@ -215,7 +215,7 @@ static const struct clk_ops clkgena_divmux_ops = {
/** /**
* clk_register_genamux - register a genamux clock with the clock framework * clk_register_genamux - register a genamux clock with the clock framework
*/ */
static struct clk *clk_register_genamux(const char *name, static struct clk * __init clk_register_genamux(const char *name,
const char **parent_names, u8 num_parents, const char **parent_names, u8 num_parents,
void __iomem *reg, void __iomem *reg,
const struct clkgena_divmux_data *muxdata, const struct clkgena_divmux_data *muxdata,
@ -369,11 +369,10 @@ static const struct of_device_id clkgena_divmux_of_match[] = {
{} {}
}; };
static void __iomem * __init clkgen_get_register_base( static void __iomem * __init clkgen_get_register_base(struct device_node *np)
struct device_node *np)
{ {
struct device_node *pnode; struct device_node *pnode;
void __iomem *reg = NULL; void __iomem *reg;
pnode = of_get_parent(np); pnode = of_get_parent(np);
if (!pnode) if (!pnode)
@ -398,7 +397,7 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np)
if (WARN_ON(!match)) if (WARN_ON(!match))
return; return;
data = (struct clkgena_divmux_data *)match->data; data = match->data;
reg = clkgen_get_register_base(np); reg = clkgen_get_register_base(np);
if (!reg) if (!reg)
@ -406,18 +405,18 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np)
parents = clkgen_mux_get_parents(np, &num_parents); parents = clkgen_mux_get_parents(np, &num_parents);
if (IS_ERR(parents)) if (IS_ERR(parents))
return; goto err_parents;
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data) if (!clk_data)
goto err; goto err_alloc;
clk_data->clk_num = data->num_outputs; clk_data->clk_num = data->num_outputs;
clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
GFP_KERNEL); GFP_KERNEL);
if (!clk_data->clks) if (!clk_data->clks)
goto err; goto err_alloc_clks;
for (i = 0; i < clk_data->clk_num; i++) { for (i = 0; i < clk_data->clk_num; i++) {
struct clk *clk; struct clk *clk;
@ -447,11 +446,13 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np)
of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
return; return;
err: err:
if (clk_data) kfree(clk_data->clks);
kfree(clk_data->clks); err_alloc_clks:
kfree(clk_data); kfree(clk_data);
err_alloc:
kfree(parents); kfree(parents);
err_parents:
iounmap(reg);
} }
CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup); CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup);
@ -491,7 +492,7 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
void __iomem *reg; void __iomem *reg;
const char *parent_name, *clk_name; const char *parent_name, *clk_name;
struct clk *clk; struct clk *clk;
struct clkgena_prediv_data *data; const struct clkgena_prediv_data *data;
match = of_match_node(clkgena_prediv_of_match, np); match = of_match_node(clkgena_prediv_of_match, np);
if (!match) { if (!match) {
@ -499,7 +500,7 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
return; return;
} }
data = (struct clkgena_prediv_data *)match->data; data = match->data;
reg = clkgen_get_register_base(np); reg = clkgen_get_register_base(np);
if (!reg) if (!reg)
@ -507,18 +508,18 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
parent_name = of_clk_get_parent_name(np, 0); parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name) if (!parent_name)
return; goto err;
if (of_property_read_string_index(np, "clock-output-names", if (of_property_read_string_index(np, "clock-output-names",
0, &clk_name)) 0, &clk_name))
return; goto err;
clk = clk_register_divider_table(NULL, clk_name, parent_name, clk = clk_register_divider_table(NULL, clk_name, parent_name,
CLK_GET_RATE_NOCACHE, CLK_GET_RATE_NOCACHE,
reg + data->offset, data->shift, 1, reg + data->offset, data->shift, 1,
0, data->table, NULL); 0, data->table, NULL);
if (IS_ERR(clk)) if (IS_ERR(clk))
return; goto err;
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
pr_debug("%s: parent %s rate %u\n", pr_debug("%s: parent %s rate %u\n",
@ -527,6 +528,8 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
(unsigned int)clk_get_rate(clk)); (unsigned int)clk_get_rate(clk));
return; return;
err:
iounmap(reg);
} }
CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup); CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup);
@ -630,7 +633,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np)
void __iomem *reg; void __iomem *reg;
const char **parents; const char **parents;
int num_parents; int num_parents;
struct clkgen_mux_data *data; const struct clkgen_mux_data *data;
match = of_match_node(mux_of_match, np); match = of_match_node(mux_of_match, np);
if (!match) { if (!match) {
@ -638,7 +641,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np)
return; return;
} }
data = (struct clkgen_mux_data *)match->data; data = match->data;
reg = of_iomap(np, 0); reg = of_iomap(np, 0);
if (!reg) { if (!reg) {
@ -650,7 +653,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np)
if (IS_ERR(parents)) { if (IS_ERR(parents)) {
pr_err("%s: Failed to get parents (%ld)\n", pr_err("%s: Failed to get parents (%ld)\n",
__func__, PTR_ERR(parents)); __func__, PTR_ERR(parents));
return; goto err_parents;
} }
clk = clk_register_mux(NULL, np->name, parents, num_parents, clk = clk_register_mux(NULL, np->name, parents, num_parents,
@ -666,12 +669,14 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np)
__clk_get_name(clk_get_parent(clk)), __clk_get_name(clk_get_parent(clk)),
(unsigned int)clk_get_rate(clk)); (unsigned int)clk_get_rate(clk));
kfree(parents);
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
return;
err: err:
kfree(parents); kfree(parents);
err_parents:
return; iounmap(reg);
} }
CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup); CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup);
@ -707,12 +712,12 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np)
const char **parents; const char **parents;
int num_parents, i; int num_parents, i;
struct clk_onecell_data *clk_data; struct clk_onecell_data *clk_data;
struct clkgen_vcc_data *data; const struct clkgen_vcc_data *data;
match = of_match_node(vcc_of_match, np); match = of_match_node(vcc_of_match, np);
if (WARN_ON(!match)) if (WARN_ON(!match))
return; return;
data = (struct clkgen_vcc_data *)match->data; data = match->data;
reg = of_iomap(np, 0); reg = of_iomap(np, 0);
if (!reg) if (!reg)
@ -720,18 +725,18 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np)
parents = clkgen_mux_get_parents(np, &num_parents); parents = clkgen_mux_get_parents(np, &num_parents);
if (IS_ERR(parents)) if (IS_ERR(parents))
return; goto err_parents;
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data) if (!clk_data)
goto err; goto err_alloc;
clk_data->clk_num = VCC_MAX_CHANNELS; clk_data->clk_num = VCC_MAX_CHANNELS;
clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
GFP_KERNEL); GFP_KERNEL);
if (!clk_data->clks) if (!clk_data->clks)
goto err; goto err_alloc_clks;
for (i = 0; i < clk_data->clk_num; i++) { for (i = 0; i < clk_data->clk_num; i++) {
struct clk *clk; struct clk *clk;
@ -750,21 +755,21 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np)
if (*clk_name == '\0') if (*clk_name == '\0')
continue; continue;
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) if (!gate)
break; goto err;
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div) { if (!div) {
kfree(gate); kfree(gate);
break; goto err;
} }
mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux) { if (!mux) {
kfree(gate); kfree(gate);
kfree(div); kfree(div);
break; goto err;
} }
gate->reg = reg + VCC_GATE_OFFSET; gate->reg = reg + VCC_GATE_OFFSET;
@ -823,10 +828,12 @@ err:
kfree(container_of(composite->mux_hw, struct clk_mux, hw)); kfree(container_of(composite->mux_hw, struct clk_mux, hw));
} }
if (clk_data) kfree(clk_data->clks);
kfree(clk_data->clks); err_alloc_clks:
kfree(clk_data); kfree(clk_data);
err_alloc:
kfree(parents); kfree(parents);
err_parents:
iounmap(reg);
} }
CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup); CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup);