aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorVincent Guittot <vincent.guittot@linaro.org>2012-10-22 19:21:49 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-14 18:36:09 -0500
commitdde8437d06560366d8988c92b5774039ec703864 (patch)
tree80ee897c0964a325be3c2d8a626ff82dd89013b3 /drivers/base/power
parent77b67063bb6bce6d475e910d3b886a606d0d91f7 (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/base/power')
-rw-r--r--drivers/base/power/opp.c19
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 */
449static 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
529unlock: 539unlock:
530 mutex_unlock(&dev_opp_list_lock); 540 mutex_unlock(&dev_opp_list_lock);
531out:
532 kfree(new_opp); 541 kfree(new_opp);
533 return r; 542 return r;
534} 543}