Skip to content

Commit 6f049e7

Browse files
committed
Merge branch 'pm-opp'
* pm-opp: PM / Domains: Propagate performance state updates PM / Domains: Factorize dev_pm_genpd_set_performance_state() PM / Domains: Save OPP table pointer in genpd OPP: Don't return 0 on error from of_get_required_opp_performance_state() OPP: Add dev_pm_opp_xlate_performance_state() helper OPP: Improve _find_table_of_opp_np() PM / Domains: Make genpd performance states orthogonal to the idlestates OPP: Fix missing debugfs supply directory for OPPs OPP: Use opp_table->regulators to verify no regulator case OPP: Remove of_dev_pm_opp_find_required_opp() OPP: Rename and relocate of_genpd_opp_to_performance_state() OPP: Configure all required OPPs OPP: Add dev_pm_opp_{set|put}_genpd_virt_dev() helper PM / Domains: Add genpd_opp_to_performance_state() OPP: Populate OPPs from "required-opps" property OPP: Populate required opp tables from "required-opps" property OPP: Separate out custom OPP handler specific code OPP: Identify and mark genpd OPP tables PM / Domains: Rename genpd virtual devices as virt_dev
2 parents 3a56fe6 + bcbeef5 commit 6f049e7

File tree

6 files changed

+792
-229
lines changed

6 files changed

+792
-229
lines changed

drivers/base/power/domain.c

Lines changed: 175 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,127 @@ static void genpd_update_accounting(struct generic_pm_domain *genpd)
239239
static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
240240
#endif
241241

242+
static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd,
243+
unsigned int state)
244+
{
245+
struct generic_pm_domain_data *pd_data;
246+
struct pm_domain_data *pdd;
247+
struct gpd_link *link;
248+
249+
/* New requested state is same as Max requested state */
250+
if (state == genpd->performance_state)
251+
return state;
252+
253+
/* New requested state is higher than Max requested state */
254+
if (state > genpd->performance_state)
255+
return state;
256+
257+
/* Traverse all devices within the domain */
258+
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
259+
pd_data = to_gpd_data(pdd);
260+
261+
if (pd_data->performance_state > state)
262+
state = pd_data->performance_state;
263+
}
264+
265+
/*
266+
* Traverse all sub-domains within the domain. This can be
267+
* done without any additional locking as the link->performance_state
268+
* field is protected by the master genpd->lock, which is already taken.
269+
*
270+
* Also note that link->performance_state (subdomain's performance state
271+
* requirement to master domain) is different from
272+
* link->slave->performance_state (current performance state requirement
273+
* of the devices/sub-domains of the subdomain) and so can have a
274+
* different value.
275+
*
276+
* Note that we also take vote from powered-off sub-domains into account
277+
* as the same is done for devices right now.
278+
*/
279+
list_for_each_entry(link, &genpd->master_links, master_node) {
280+
if (link->performance_state > state)
281+
state = link->performance_state;
282+
}
283+
284+
return state;
285+
}
286+
287+
static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
288+
unsigned int state, int depth)
289+
{
290+
struct generic_pm_domain *master;
291+
struct gpd_link *link;
292+
int master_state, ret;
293+
294+
if (state == genpd->performance_state)
295+
return 0;
296+
297+
/* Propagate to masters of genpd */
298+
list_for_each_entry(link, &genpd->slave_links, slave_node) {
299+
master = link->master;
300+
301+
if (!master->set_performance_state)
302+
continue;
303+
304+
/* Find master's performance state */
305+
ret = dev_pm_opp_xlate_performance_state(genpd->opp_table,
306+
master->opp_table,
307+
state);
308+
if (unlikely(ret < 0))
309+
goto err;
310+
311+
master_state = ret;
312+
313+
genpd_lock_nested(master, depth + 1);
314+
315+
link->prev_performance_state = link->performance_state;
316+
link->performance_state = master_state;
317+
master_state = _genpd_reeval_performance_state(master,
318+
master_state);
319+
ret = _genpd_set_performance_state(master, master_state, depth + 1);
320+
if (ret)
321+
link->performance_state = link->prev_performance_state;
322+
323+
genpd_unlock(master);
324+
325+
if (ret)
326+
goto err;
327+
}
328+
329+
ret = genpd->set_performance_state(genpd, state);
330+
if (ret)
331+
goto err;
332+
333+
genpd->performance_state = state;
334+
return 0;
335+
336+
err:
337+
/* Encountered an error, lets rollback */
338+
list_for_each_entry_continue_reverse(link, &genpd->slave_links,
339+
slave_node) {
340+
master = link->master;
341+
342+
if (!master->set_performance_state)
343+
continue;
344+
345+
genpd_lock_nested(master, depth + 1);
346+
347+
master_state = link->prev_performance_state;
348+
link->performance_state = master_state;
349+
350+
master_state = _genpd_reeval_performance_state(master,
351+
master_state);
352+
if (_genpd_set_performance_state(master, master_state, depth + 1)) {
353+
pr_err("%s: Failed to roll back to %d performance state\n",
354+
master->name, master_state);
355+
}
356+
357+
genpd_unlock(master);
358+
}
359+
360+
return ret;
361+
}
362+
242363
/**
243364
* dev_pm_genpd_set_performance_state- Set performance state of device's power
244365
* domain.
@@ -257,10 +378,9 @@ static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
257378
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
258379
{
259380
struct generic_pm_domain *genpd;
260-
struct generic_pm_domain_data *gpd_data, *pd_data;
261-
struct pm_domain_data *pdd;
381+
struct generic_pm_domain_data *gpd_data;
262382
unsigned int prev;
263-
int ret = 0;
383+
int ret;
264384

265385
genpd = dev_to_genpd(dev);
266386
if (IS_ERR(genpd))
@@ -281,47 +401,11 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
281401
prev = gpd_data->performance_state;
282402
gpd_data->performance_state = state;
283403

284-
/* New requested state is same as Max requested state */
285-
if (state == genpd->performance_state)
286-
goto unlock;
287-
288-
/* New requested state is higher than Max requested state */
289-
if (state > genpd->performance_state)
290-
goto update_state;
291-
292-
/* Traverse all devices within the domain */
293-
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
294-
pd_data = to_gpd_data(pdd);
295-
296-
if (pd_data->performance_state > state)
297-
state = pd_data->performance_state;
298-
}
299-
300-
if (state == genpd->performance_state)
301-
goto unlock;
302-
303-
/*
304-
* We aren't propagating performance state changes of a subdomain to its
305-
* masters as we don't have hardware that needs it. Over that, the
306-
* performance states of subdomain and its masters may not have
307-
* one-to-one mapping and would require additional information. We can
308-
* get back to this once we have hardware that needs it. For that
309-
* reason, we don't have to consider performance state of the subdomains
310-
* of genpd here.
311-
*/
312-
313-
update_state:
314-
if (genpd_status_on(genpd)) {
315-
ret = genpd->set_performance_state(genpd, state);
316-
if (ret) {
317-
gpd_data->performance_state = prev;
318-
goto unlock;
319-
}
320-
}
321-
322-
genpd->performance_state = state;
404+
state = _genpd_reeval_performance_state(genpd, state);
405+
ret = _genpd_set_performance_state(genpd, state, 0);
406+
if (ret)
407+
gpd_data->performance_state = prev;
323408

324-
unlock:
325409
genpd_unlock(genpd);
326410

327411
return ret;
@@ -347,15 +431,6 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
347431
return ret;
348432

349433
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
350-
351-
if (unlikely(genpd->set_performance_state)) {
352-
ret = genpd->set_performance_state(genpd, genpd->performance_state);
353-
if (ret) {
354-
pr_warn("%s: Failed to set performance state %d (%d)\n",
355-
genpd->name, genpd->performance_state, ret);
356-
}
357-
}
358-
359434
if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
360435
return ret;
361436

@@ -1907,12 +1982,21 @@ int of_genpd_add_provider_simple(struct device_node *np,
19071982
ret);
19081983
goto unlock;
19091984
}
1985+
1986+
/*
1987+
* Save table for faster processing while setting performance
1988+
* state.
1989+
*/
1990+
genpd->opp_table = dev_pm_opp_get_opp_table(&genpd->dev);
1991+
WARN_ON(!genpd->opp_table);
19101992
}
19111993

19121994
ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
19131995
if (ret) {
1914-
if (genpd->set_performance_state)
1996+
if (genpd->set_performance_state) {
1997+
dev_pm_opp_put_opp_table(genpd->opp_table);
19151998
dev_pm_opp_of_remove_table(&genpd->dev);
1999+
}
19162000

19172001
goto unlock;
19182002
}
@@ -1965,6 +2049,13 @@ int of_genpd_add_provider_onecell(struct device_node *np,
19652049
i, ret);
19662050
goto error;
19672051
}
2052+
2053+
/*
2054+
* Save table for faster processing while setting
2055+
* performance state.
2056+
*/
2057+
genpd->opp_table = dev_pm_opp_get_opp_table_indexed(&genpd->dev, i);
2058+
WARN_ON(!genpd->opp_table);
19682059
}
19692060

19702061
genpd->provider = &np->fwnode;
@@ -1989,8 +2080,10 @@ int of_genpd_add_provider_onecell(struct device_node *np,
19892080
genpd->provider = NULL;
19902081
genpd->has_provider = false;
19912082

1992-
if (genpd->set_performance_state)
2083+
if (genpd->set_performance_state) {
2084+
dev_pm_opp_put_opp_table(genpd->opp_table);
19932085
dev_pm_opp_of_remove_table(&genpd->dev);
2086+
}
19942087
}
19952088

19962089
mutex_unlock(&gpd_list_lock);
@@ -2024,6 +2117,7 @@ void of_genpd_del_provider(struct device_node *np)
20242117
if (!gpd->set_performance_state)
20252118
continue;
20262119

2120+
dev_pm_opp_put_opp_table(gpd->opp_table);
20272121
dev_pm_opp_of_remove_table(&gpd->dev);
20282122
}
20292123
}
@@ -2338,7 +2432,7 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
23382432
struct device *genpd_dev_pm_attach_by_id(struct device *dev,
23392433
unsigned int index)
23402434
{
2341-
struct device *genpd_dev;
2435+
struct device *virt_dev;
23422436
int num_domains;
23432437
int ret;
23442438

@@ -2352,31 +2446,31 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,
23522446
return NULL;
23532447

23542448
/* Allocate and register device on the genpd bus. */
2355-
genpd_dev = kzalloc(sizeof(*genpd_dev), GFP_KERNEL);
2356-
if (!genpd_dev)
2449+
virt_dev = kzalloc(sizeof(*virt_dev), GFP_KERNEL);
2450+
if (!virt_dev)
23572451
return ERR_PTR(-ENOMEM);
23582452

2359-
dev_set_name(genpd_dev, "genpd:%u:%s", index, dev_name(dev));
2360-
genpd_dev->bus = &genpd_bus_type;
2361-
genpd_dev->release = genpd_release_dev;
2453+
dev_set_name(virt_dev, "genpd:%u:%s", index, dev_name(dev));
2454+
virt_dev->bus = &genpd_bus_type;
2455+
virt_dev->release = genpd_release_dev;
23622456

2363-
ret = device_register(genpd_dev);
2457+
ret = device_register(virt_dev);
23642458
if (ret) {
2365-
kfree(genpd_dev);
2459+
kfree(virt_dev);
23662460
return ERR_PTR(ret);
23672461
}
23682462

23692463
/* Try to attach the device to the PM domain at the specified index. */
2370-
ret = __genpd_dev_pm_attach(genpd_dev, dev->of_node, index, false);
2464+
ret = __genpd_dev_pm_attach(virt_dev, dev->of_node, index, false);
23712465
if (ret < 1) {
2372-
device_unregister(genpd_dev);
2466+
device_unregister(virt_dev);
23732467
return ret ? ERR_PTR(ret) : NULL;
23742468
}
23752469

2376-
pm_runtime_enable(genpd_dev);
2377-
genpd_queue_power_off_work(dev_to_genpd(genpd_dev));
2470+
pm_runtime_enable(virt_dev);
2471+
genpd_queue_power_off_work(dev_to_genpd(virt_dev));
23782472

2379-
return genpd_dev;
2473+
return virt_dev;
23802474
}
23812475
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach_by_id);
23822476

@@ -2521,52 +2615,36 @@ int of_genpd_parse_idle_states(struct device_node *dn,
25212615
EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
25222616

25232617
/**
2524-
* of_genpd_opp_to_performance_state- Gets performance state of device's
2525-
* power domain corresponding to a DT node's "required-opps" property.
2618+
* pm_genpd_opp_to_performance_state - Gets performance state of the genpd from its OPP node.
25262619
*
2527-
* @dev: Device for which the performance-state needs to be found.
2528-
* @np: DT node where the "required-opps" property is present. This can be
2529-
* the device node itself (if it doesn't have an OPP table) or a node
2530-
* within the OPP table of a device (if device has an OPP table).
2620+
* @genpd_dev: Genpd's device for which the performance-state needs to be found.
2621+
* @opp: struct dev_pm_opp of the OPP for which we need to find performance
2622+
* state.
25312623
*
2532-
* Returns performance state corresponding to the "required-opps" property of
2533-
* a DT node. This calls platform specific genpd->opp_to_performance_state()
2534-
* callback to translate power domain OPP to performance state.
2624+
* Returns performance state encoded in the OPP of the genpd. This calls
2625+
* platform specific genpd->opp_to_performance_state() callback to translate
2626+
* power domain OPP to performance state.
25352627
*
25362628
* Returns performance state on success and 0 on failure.
25372629
*/
2538-
unsigned int of_genpd_opp_to_performance_state(struct device *dev,
2539-
struct device_node *np)
2630+
unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev,
2631+
struct dev_pm_opp *opp)
25402632
{
2541-
struct generic_pm_domain *genpd;
2542-
struct dev_pm_opp *opp;
2543-
int state = 0;
2633+
struct generic_pm_domain *genpd = NULL;
2634+
int state;
25442635

2545-
genpd = dev_to_genpd(dev);
2546-
if (IS_ERR(genpd))
2547-
return 0;
2636+
genpd = container_of(genpd_dev, struct generic_pm_domain, dev);
25482637

2549-
if (unlikely(!genpd->set_performance_state))
2638+
if (unlikely(!genpd->opp_to_performance_state))
25502639
return 0;
25512640

25522641
genpd_lock(genpd);
2553-
2554-
opp = of_dev_pm_opp_find_required_opp(&genpd->dev, np);
2555-
if (IS_ERR(opp)) {
2556-
dev_err(dev, "Failed to find required OPP: %ld\n",
2557-
PTR_ERR(opp));
2558-
goto unlock;
2559-
}
2560-
25612642
state = genpd->opp_to_performance_state(genpd, opp);
2562-
dev_pm_opp_put(opp);
2563-
2564-
unlock:
25652643
genpd_unlock(genpd);
25662644

25672645
return state;
25682646
}
2569-
EXPORT_SYMBOL_GPL(of_genpd_opp_to_performance_state);
2647+
EXPORT_SYMBOL_GPL(pm_genpd_opp_to_performance_state);
25702648

25712649
static int __init genpd_bus_init(void)
25722650
{

0 commit comments

Comments
 (0)