aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2018-01-23 15:43:08 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-02-07 06:02:01 -0500
commita3381e3a65cbaf612c8f584906c4dba27e84267c (patch)
tree2fb763468bf084673a35b23fc00dc5e0d9f1b206
parent7f3fdd40a7dfaa7405185250974b0fabd08c1f8b (diff)
PM / domains: Fix up domain-idle-states OF parsing
Commit b539cc82d493 (PM / Domains: Ignore domain-idle-states that are not compatible), made it possible to ignore non-compatible domain-idle-states OF nodes. However, in case that happens while doing the OF parsing, the number of elements in the allocated array would exceed the numbers actually needed, thus wasting memory. Fix this by pre-iterating the genpd OF node and counting the number of compatible domain-idle-states nodes, before doing the allocation. While doing this, it makes sense to rework the code a bit to avoid open coding, of parts responsible for the OF node iteration. Let's also take the opportunity to clarify the function header for of_genpd_parse_idle_states(), about what is being returned in case of errors. Fixes: b539cc82d493 (PM / Domains: Ignore domain-idle-states that are not compatible) Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Lina Iyer <ilina@codeaurora.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/power/domain.c76
1 files changed, 45 insertions, 31 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 528b24149bc7..1ea0e2502e8e 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -2290,6 +2290,38 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state,
2290 return 0; 2290 return 0;
2291} 2291}
2292 2292
2293static int genpd_iterate_idle_states(struct device_node *dn,
2294 struct genpd_power_state *states)
2295{
2296 int ret;
2297 struct of_phandle_iterator it;
2298 struct device_node *np;
2299 int i = 0;
2300
2301 ret = of_count_phandle_with_args(dn, "domain-idle-states", NULL);
2302 if (ret <= 0)
2303 return ret;
2304
2305 /* Loop over the phandles until all the requested entry is found */
2306 of_for_each_phandle(&it, ret, dn, "domain-idle-states", NULL, 0) {
2307 np = it.node;
2308 if (!of_match_node(idle_state_match, np))
2309 continue;
2310 if (states) {
2311 ret = genpd_parse_state(&states[i], np);
2312 if (ret) {
2313 pr_err("Parsing idle state node %pOF failed with err %d\n",
2314 np, ret);
2315 of_node_put(np);
2316 return ret;
2317 }
2318 }
2319 i++;
2320 }
2321
2322 return i;
2323}
2324
2293/** 2325/**
2294 * of_genpd_parse_idle_states: Return array of idle states for the genpd. 2326 * of_genpd_parse_idle_states: Return array of idle states for the genpd.
2295 * 2327 *
@@ -2299,49 +2331,31 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state,
2299 * 2331 *
2300 * Returns the device states parsed from the OF node. The memory for the states 2332 * Returns the device states parsed from the OF node. The memory for the states
2301 * is allocated by this function and is the responsibility of the caller to 2333 * is allocated by this function and is the responsibility of the caller to
2302 * free the memory after use. 2334 * free the memory after use. If no domain idle states is found it returns
2335 * -EINVAL and in case of errors, a negative error code.
2303 */ 2336 */
2304int of_genpd_parse_idle_states(struct device_node *dn, 2337int of_genpd_parse_idle_states(struct device_node *dn,
2305 struct genpd_power_state **states, int *n) 2338 struct genpd_power_state **states, int *n)
2306{ 2339{
2307 struct genpd_power_state *st; 2340 struct genpd_power_state *st;
2308 struct device_node *np; 2341 int ret;
2309 int i = 0;
2310 int err, ret;
2311 int count;
2312 struct of_phandle_iterator it;
2313 const struct of_device_id *match_id;
2314 2342
2315 count = of_count_phandle_with_args(dn, "domain-idle-states", NULL); 2343 ret = genpd_iterate_idle_states(dn, NULL);
2316 if (count <= 0) 2344 if (ret <= 0)
2317 return -EINVAL; 2345 return ret < 0 ? ret : -EINVAL;
2318 2346
2319 st = kcalloc(count, sizeof(*st), GFP_KERNEL); 2347 st = kcalloc(ret, sizeof(*st), GFP_KERNEL);
2320 if (!st) 2348 if (!st)
2321 return -ENOMEM; 2349 return -ENOMEM;
2322 2350
2323 /* Loop over the phandles until all the requested entry is found */ 2351 ret = genpd_iterate_idle_states(dn, st);
2324 of_for_each_phandle(&it, err, dn, "domain-idle-states", NULL, 0) { 2352 if (ret <= 0) {
2325 np = it.node; 2353 kfree(st);
2326 match_id = of_match_node(idle_state_match, np); 2354 return ret < 0 ? ret : -EINVAL;
2327 if (!match_id)
2328 continue;
2329 ret = genpd_parse_state(&st[i++], np);
2330 if (ret) {
2331 pr_err
2332 ("Parsing idle state node %pOF failed with err %d\n",
2333 np, ret);
2334 of_node_put(np);
2335 kfree(st);
2336 return ret;
2337 }
2338 } 2355 }
2339 2356
2340 *n = i; 2357 *states = st;
2341 if (!i) 2358 *n = ret;
2342 kfree(st);
2343 else
2344 *states = st;
2345 2359
2346 return 0; 2360 return 0;
2347} 2361}