diff options
author | Vincent Guittot <vincent.guittot@linaro.org> | 2012-10-22 19:21:49 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2012-11-14 18:36:09 -0500 |
commit | dde8437d06560366d8988c92b5774039ec703864 (patch) | |
tree | 80ee897c0964a325be3c2d8a626ff82dd89013b3 /drivers | |
parent | 77b67063bb6bce6d475e910d3b886a606d0d91f7 (diff) |
PM / OPP: RCU reclaim
synchronize_rcu() blocks the caller of opp_enable/disbale
for a complete grace period. This blocking duration prevents
any intensive use of the functions. Replace synchronize_rcu()
by call_rcu() which will call our function for freeing the old
opp element.
The duration of opp_enable() and opp_disable() will be no more
dependant of the grace period.
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/power/opp.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index d9468642fc41..1211210b15b0 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c | |||
@@ -65,6 +65,7 @@ struct opp { | |||
65 | unsigned long u_volt; | 65 | unsigned long u_volt; |
66 | 66 | ||
67 | struct device_opp *dev_opp; | 67 | struct device_opp *dev_opp; |
68 | struct rcu_head head; | ||
68 | }; | 69 | }; |
69 | 70 | ||
70 | /** | 71 | /** |
@@ -442,6 +443,17 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) | |||
442 | } | 443 | } |
443 | 444 | ||
444 | /** | 445 | /** |
446 | * opp_free_rcu() - helper to clear the struct opp when grace period has | ||
447 | * elapsed without blocking the the caller of opp_set_availability | ||
448 | */ | ||
449 | static void opp_free_rcu(struct rcu_head *head) | ||
450 | { | ||
451 | struct opp *opp = container_of(head, struct opp, head); | ||
452 | |||
453 | kfree(opp); | ||
454 | } | ||
455 | |||
456 | /** | ||
445 | * opp_set_availability() - helper to set the availability of an opp | 457 | * opp_set_availability() - helper to set the availability of an opp |
446 | * @dev: device for which we do this operation | 458 | * @dev: device for which we do this operation |
447 | * @freq: OPP frequency to modify availability | 459 | * @freq: OPP frequency to modify availability |
@@ -512,7 +524,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, | |||
512 | 524 | ||
513 | list_replace_rcu(&opp->node, &new_opp->node); | 525 | list_replace_rcu(&opp->node, &new_opp->node); |
514 | mutex_unlock(&dev_opp_list_lock); | 526 | mutex_unlock(&dev_opp_list_lock); |
515 | synchronize_rcu(); | 527 | call_rcu(&opp->head, opp_free_rcu); |
516 | 528 | ||
517 | /* Notify the change of the OPP availability */ | 529 | /* Notify the change of the OPP availability */ |
518 | if (availability_req) | 530 | if (availability_req) |
@@ -522,13 +534,10 @@ static int opp_set_availability(struct device *dev, unsigned long freq, | |||
522 | srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE, | 534 | srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE, |
523 | new_opp); | 535 | new_opp); |
524 | 536 | ||
525 | /* clean up old opp */ | 537 | return 0; |
526 | new_opp = opp; | ||
527 | goto out; | ||
528 | 538 | ||
529 | unlock: | 539 | unlock: |
530 | mutex_unlock(&dev_opp_list_lock); | 540 | mutex_unlock(&dev_opp_list_lock); |
531 | out: | ||
532 | kfree(new_opp); | 541 | kfree(new_opp); |
533 | return r; | 542 | return r; |
534 | } | 543 | } |