From: Vincent Guittot Date: Mon, 22 Oct 2012 23:21:49 +0000 (+0200) Subject: PM / OPP: RCU reclaim X-Git-Tag: next-20121024~35^2~3^2~1 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=d28a395464faf6c5bb1aae4857a8b5ae85e5d74c;p=karo-tx-linux.git 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 Reviewed-by: Paul E. McKenney Signed-off-by: Rafael J. Wysocki --- 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 { unsigned long u_volt; struct device_opp *dev_opp; + struct rcu_head head; }; /** @@ -441,6 +442,17 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) return 0; } +/** + * opp_free_rcu() - helper to clear the struct opp when grace period has + * elapsed without blocking the the caller of opp_set_availability + */ +static void opp_free_rcu(struct rcu_head *head) +{ + struct opp *opp = container_of(head, struct opp, head); + + kfree(opp); +} + /** * opp_set_availability() - helper to set the availability of an opp * @dev: device for which we do this operation @@ -512,7 +524,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, list_replace_rcu(&opp->node, &new_opp->node); mutex_unlock(&dev_opp_list_lock); - synchronize_rcu(); + call_rcu(&opp->head, opp_free_rcu); /* Notify the change of the OPP availability */ if (availability_req) @@ -522,13 +534,10 @@ static int opp_set_availability(struct device *dev, unsigned long freq, srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE, new_opp); - /* clean up old opp */ - new_opp = opp; - goto out; + return 0; unlock: mutex_unlock(&dev_opp_list_lock); -out: kfree(new_opp); return r; }