Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dde8437d authored by Vincent Guittot's avatar Vincent Guittot Committed by Rafael J. Wysocki
Browse files

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: default avatarVincent Guittot <vincent.guittot@linaro.org>
Reviewed-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 77b67063
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -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;
}