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

Commit 740b68ea authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branches 'pm-qos', 'pm-opp' and 'pm-devfreq'

* pm-qos:
  PM / QoS: Use lockdep asserts to find missing hold of power.lock
  PM / QoS: Add debugfs support to view the list of constraints

* pm-opp:
  PM / OPP: Assert RCU lock in exported functions
  PM / OPP: Update kernel documentation
  PM / OPP: Ensure consistent naming of static functions
  PM / OPP: export dev_pm_opp_get_notifier

* pm-devfreq:
  PM / devfreq: event: Add documentation for exynos-ppmu devfreq-event driver
  devfreq: Fix build break of devfreq-event class
  PM / devfreq: event: Add devfreq_event class
  PM / devfreq: tegra: add devfreq driver for Tegra Activity Monitor
Loading
Loading
Loading
Loading
+110 −0
Original line number Original line Diff line number Diff line

* Samsung Exynos PPMU (Platform Performance Monitoring Unit) device

The Samsung Exynos SoC has PPMU (Platform Performance Monitoring Unit) for
each IP. PPMU provides the primitive values to get performance data. These
PPMU events provide information of the SoC's behaviors so that you may
use to analyze system performance, to make behaviors visible and to count
usages of each IP (DMC, CPU, RIGHTBUS, LEFTBUS, CAM interface, LCD, G3D, MFC).
The Exynos PPMU driver uses the devfreq-event class to provide event data
to various devfreq devices. The devfreq devices would use the event data when
derterming the current state of each IP.

Required properties:
- compatible: Should be "samsung,exynos-ppmu".
- reg: physical base address of each PPMU and length of memory mapped region.

Optional properties:
- clock-names : the name of clock used by the PPMU, "ppmu"
- clocks : phandles for clock specified in "clock-names" property
- #clock-cells: should be 1.

Example1 : PPMU nodes in exynos3250.dtsi are listed below.

		ppmu_dmc0: ppmu_dmc0@106a0000 {
			compatible = "samsung,exynos-ppmu";
			reg = <0x106a0000 0x2000>;
			status = "disabled";
		};

		ppmu_dmc1: ppmu_dmc1@106b0000 {
			compatible = "samsung,exynos-ppmu";
			reg = <0x106b0000 0x2000>;
			status = "disabled";
		};

		ppmu_cpu: ppmu_cpu@106c0000 {
			compatible = "samsung,exynos-ppmu";
			reg = <0x106c0000 0x2000>;
			status = "disabled";
		};

		ppmu_rightbus: ppmu_rightbus@112a0000 {
			compatible = "samsung,exynos-ppmu";
			reg = <0x112a0000 0x2000>;
			clocks = <&cmu CLK_PPMURIGHT>;
			clock-names = "ppmu";
			status = "disabled";
		};

		ppmu_leftbus: ppmu_leftbus0@116a0000 {
			compatible = "samsung,exynos-ppmu";
			reg = <0x116a0000 0x2000>;
			clocks = <&cmu CLK_PPMULEFT>;
			clock-names = "ppmu";
			status = "disabled";
		};

Example2 : Events of each PPMU node in exynos3250-rinato.dts are listed below.

	&ppmu_dmc0 {
		status = "okay";

		events {
			ppmu_dmc0_3: ppmu-event3-dmc0 {
				event-name = "ppmu-event3-dmc0";
			};

			ppmu_dmc0_2: ppmu-event2-dmc0 {
				event-name = "ppmu-event2-dmc0";
			};

			ppmu_dmc0_1: ppmu-event1-dmc0 {
				event-name = "ppmu-event1-dmc0";
			};

			ppmu_dmc0_0: ppmu-event0-dmc0 {
				event-name = "ppmu-event0-dmc0";
			};
		};
	};

	&ppmu_dmc1 {
		status = "okay";

		events {
			ppmu_dmc1_3: ppmu-event3-dmc1 {
				event-name = "ppmu-event3-dmc1";
			};
		};
	};

	&ppmu_leftbus {
		status = "okay";

		events {
			ppmu_leftbus_3: ppmu-event3-leftbus {
				event-name = "ppmu-event3-leftbus";
			};
		};
	};

	&ppmu_rightbus {
		status = "okay";

		events {
			ppmu_rightbus_3: ppmu-event3-rightbus {
				event-name = "ppmu-event3-rightbus";
			};
		};
	};
+150 −44
Original line number Original line Diff line number Diff line
@@ -117,20 +117,20 @@ do { \
} while (0)
} while (0)


/**
/**
 * find_device_opp() - find device_opp struct using device pointer
 * _find_device_opp() - find device_opp struct using device pointer
 * @dev:	device pointer used to lookup device OPPs
 * @dev:	device pointer used to lookup device OPPs
 *
 *
 * Search list of device OPPs for one containing matching device. Does a RCU
 * Search list of device OPPs for one containing matching device. Does a RCU
 * reader operation to grab the pointer needed.
 * reader operation to grab the pointer needed.
 *
 *
 * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
 * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or
 * -EINVAL based on type of error.
 * -EINVAL based on type of error.
 *
 *
 * Locking: This function must be called under rcu_read_lock(). device_opp
 * Locking: This function must be called under rcu_read_lock(). device_opp
 * is a RCU protected pointer. This means that device_opp is valid as long
 * is a RCU protected pointer. This means that device_opp is valid as long
 * as we are under RCU lock.
 * as we are under RCU lock.
 */
 */
static struct device_opp *find_device_opp(struct device *dev)
static struct device_opp *_find_device_opp(struct device *dev)
{
{
	struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
	struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);


@@ -153,7 +153,7 @@ static struct device_opp *find_device_opp(struct device *dev)
 * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp
 * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp
 * @opp:	opp for which voltage has to be returned for
 * @opp:	opp for which voltage has to be returned for
 *
 *
 * Return voltage in micro volt corresponding to the opp, else
 * Return: voltage in micro volt corresponding to the opp, else
 * return 0
 * return 0
 *
 *
 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
@@ -169,6 +169,8 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
	struct dev_pm_opp *tmp_opp;
	struct dev_pm_opp *tmp_opp;
	unsigned long v = 0;
	unsigned long v = 0;


	opp_rcu_lockdep_assert();

	tmp_opp = rcu_dereference(opp);
	tmp_opp = rcu_dereference(opp);
	if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
	if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
		pr_err("%s: Invalid parameters\n", __func__);
		pr_err("%s: Invalid parameters\n", __func__);
@@ -183,7 +185,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
 * dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp
 * dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp
 * @opp:	opp for which frequency has to be returned for
 * @opp:	opp for which frequency has to be returned for
 *
 *
 * Return frequency in hertz corresponding to the opp, else
 * Return: frequency in hertz corresponding to the opp, else
 * return 0
 * return 0
 *
 *
 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
@@ -199,6 +201,8 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
	struct dev_pm_opp *tmp_opp;
	struct dev_pm_opp *tmp_opp;
	unsigned long f = 0;
	unsigned long f = 0;


	opp_rcu_lockdep_assert();

	tmp_opp = rcu_dereference(opp);
	tmp_opp = rcu_dereference(opp);
	if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
	if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
		pr_err("%s: Invalid parameters\n", __func__);
		pr_err("%s: Invalid parameters\n", __func__);
@@ -213,7 +217,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
 * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list
 * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list
 * @dev:	device for which we do this operation
 * @dev:	device for which we do this operation
 *
 *
 * This function returns the number of available opps if there are any,
 * Return: This function returns the number of available opps if there are any,
 * else returns 0 if none or the corresponding error value.
 * else returns 0 if none or the corresponding error value.
 *
 *
 * Locking: This function takes rcu_read_lock().
 * Locking: This function takes rcu_read_lock().
@@ -226,7 +230,7 @@ int dev_pm_opp_get_opp_count(struct device *dev)


	rcu_read_lock();
	rcu_read_lock();


	dev_opp = find_device_opp(dev);
	dev_opp = _find_device_opp(dev);
	if (IS_ERR(dev_opp)) {
	if (IS_ERR(dev_opp)) {
		count = PTR_ERR(dev_opp);
		count = PTR_ERR(dev_opp);
		dev_err(dev, "%s: device OPP not found (%d)\n",
		dev_err(dev, "%s: device OPP not found (%d)\n",
@@ -251,9 +255,9 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
 * @freq:		frequency to search for
 * @freq:		frequency to search for
 * @available:		true/false - match for available opp
 * @available:		true/false - match for available opp
 *
 *
 * Searches for exact match in the opp list and returns pointer to the matching
 * Return: Searches for exact match in the opp list and returns pointer to the
 * opp if found, else returns ERR_PTR in case of error and should be handled
 * matching opp if found, else returns ERR_PTR in case of error and should
 * using IS_ERR. Error return values can be:
 * be handled using IS_ERR. Error return values can be:
 * EINVAL:	for bad pointer
 * EINVAL:	for bad pointer
 * ERANGE:	no match found for search
 * ERANGE:	no match found for search
 * ENODEV:	if device not found in list of registered devices
 * ENODEV:	if device not found in list of registered devices
@@ -280,7 +284,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,


	opp_rcu_lockdep_assert();
	opp_rcu_lockdep_assert();


	dev_opp = find_device_opp(dev);
	dev_opp = _find_device_opp(dev);
	if (IS_ERR(dev_opp)) {
	if (IS_ERR(dev_opp)) {
		int r = PTR_ERR(dev_opp);
		int r = PTR_ERR(dev_opp);
		dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
		dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
@@ -307,7 +311,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
 * Search for the matching ceil *available* OPP from a starting freq
 * Search for the matching ceil *available* OPP from a starting freq
 * for a device.
 * for a device.
 *
 *
 * Returns matching *opp and refreshes *freq accordingly, else returns
 * Return: matching *opp and refreshes *freq accordingly, else returns
 * ERR_PTR in case of error and should be handled using IS_ERR. Error return
 * ERR_PTR in case of error and should be handled using IS_ERR. Error return
 * values can be:
 * values can be:
 * EINVAL:	for bad pointer
 * EINVAL:	for bad pointer
@@ -333,7 +337,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
		return ERR_PTR(-EINVAL);
		return ERR_PTR(-EINVAL);
	}
	}


	dev_opp = find_device_opp(dev);
	dev_opp = _find_device_opp(dev);
	if (IS_ERR(dev_opp))
	if (IS_ERR(dev_opp))
		return ERR_CAST(dev_opp);
		return ERR_CAST(dev_opp);


@@ -357,7 +361,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
 * Search for the matching floor *available* OPP from a starting freq
 * Search for the matching floor *available* OPP from a starting freq
 * for a device.
 * for a device.
 *
 *
 * Returns matching *opp and refreshes *freq accordingly, else returns
 * Return: matching *opp and refreshes *freq accordingly, else returns
 * ERR_PTR in case of error and should be handled using IS_ERR. Error return
 * ERR_PTR in case of error and should be handled using IS_ERR. Error return
 * values can be:
 * values can be:
 * EINVAL:	for bad pointer
 * EINVAL:	for bad pointer
@@ -383,7 +387,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
		return ERR_PTR(-EINVAL);
		return ERR_PTR(-EINVAL);
	}
	}


	dev_opp = find_device_opp(dev);
	dev_opp = _find_device_opp(dev);
	if (IS_ERR(dev_opp))
	if (IS_ERR(dev_opp))
		return ERR_CAST(dev_opp);
		return ERR_CAST(dev_opp);


@@ -403,7 +407,16 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
}
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);


static struct device_opp *add_device_opp(struct device *dev)
/**
 * _add_device_opp() - Allocate a new device OPP table
 * @dev:	device for which we do this operation
 *
 * New device node which uses OPPs - used when multiple devices with OPP tables
 * are maintained.
 *
 * Return: valid device_opp pointer if success, else NULL.
 */
static struct device_opp *_add_device_opp(struct device *dev)
{
{
	struct device_opp *dev_opp;
	struct device_opp *dev_opp;


@@ -424,8 +437,35 @@ static struct device_opp *add_device_opp(struct device *dev)
	return dev_opp;
	return dev_opp;
}
}


static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
/**
				  unsigned long u_volt, bool dynamic)
 * _opp_add_dynamic() - Allocate a dynamic OPP.
 * @dev:	device for which we do this operation
 * @freq:	Frequency in Hz for this OPP
 * @u_volt:	Voltage in uVolts for this OPP
 * @dynamic:	Dynamically added OPPs.
 *
 * This function adds an opp definition to the opp list and returns status.
 * The opp is made available by default and it can be controlled using
 * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove.
 *
 * NOTE: "dynamic" parameter impacts OPPs added by the of_init_opp_table and
 * freed by of_free_opp_table.
 *
 * Locking: The internal device_opp and opp structures are RCU protected.
 * Hence this function internally uses RCU updater strategy with mutex locks
 * to keep the integrity of the internal data structures. Callers should ensure
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex cannot be locked.
 *
 * Return:
 * 0		On success OR
 *		Duplicate OPPs (both freq and volt are same) and opp->available
 * -EEXIST	Freq are same and volt are different OR
 *		Duplicate OPPs (both freq and volt are same) and !opp->available
 * -ENOMEM	Memory allocation failure
 */
static int _opp_add_dynamic(struct device *dev, unsigned long freq,
			    long u_volt, bool dynamic)
{
{
	struct device_opp *dev_opp = NULL;
	struct device_opp *dev_opp = NULL;
	struct dev_pm_opp *opp, *new_opp;
	struct dev_pm_opp *opp, *new_opp;
@@ -449,9 +489,9 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
	new_opp->dynamic = dynamic;
	new_opp->dynamic = dynamic;


	/* Check for existing list for 'dev' */
	/* Check for existing list for 'dev' */
	dev_opp = find_device_opp(dev);
	dev_opp = _find_device_opp(dev);
	if (IS_ERR(dev_opp)) {
	if (IS_ERR(dev_opp)) {
		dev_opp = add_device_opp(dev);
		dev_opp = _add_device_opp(dev);
		if (!dev_opp) {
		if (!dev_opp) {
			ret = -ENOMEM;
			ret = -ENOMEM;
			goto free_opp;
			goto free_opp;
@@ -519,33 +559,52 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
 * mutex cannot be locked.
 * mutex cannot be locked.
 *
 *
 * Return:
 * Return:
 * 0:		On success OR
 * 0		On success OR
 *		Duplicate OPPs (both freq and volt are same) and opp->available
 *		Duplicate OPPs (both freq and volt are same) and opp->available
 * -EEXIST:	Freq are same and volt are different OR
 * -EEXIST	Freq are same and volt are different OR
 *		Duplicate OPPs (both freq and volt are same) and !opp->available
 *		Duplicate OPPs (both freq and volt are same) and !opp->available
 * -ENOMEM:	Memory allocation failure
 * -ENOMEM	Memory allocation failure
 */
 */
int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
{
{
	return dev_pm_opp_add_dynamic(dev, freq, u_volt, true);
	return _opp_add_dynamic(dev, freq, u_volt, true);
}
}
EXPORT_SYMBOL_GPL(dev_pm_opp_add);
EXPORT_SYMBOL_GPL(dev_pm_opp_add);


static void kfree_opp_rcu(struct rcu_head *head)
/**
 * _kfree_opp_rcu() - Free OPP RCU handler
 * @head:	RCU head
 */
static void _kfree_opp_rcu(struct rcu_head *head)
{
{
	struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head);
	struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head);


	kfree_rcu(opp, rcu_head);
	kfree_rcu(opp, rcu_head);
}
}


static void kfree_device_rcu(struct rcu_head *head)
/**
 * _kfree_device_rcu() - Free device_opp RCU handler
 * @head:	RCU head
 */
static void _kfree_device_rcu(struct rcu_head *head)
{
{
	struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head);
	struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head);


	kfree_rcu(device_opp, rcu_head);
	kfree_rcu(device_opp, rcu_head);
}
}


static void __dev_pm_opp_remove(struct device_opp *dev_opp,
/**
 * _opp_remove()  - Remove an OPP from a table definition
 * @dev_opp:	points back to the device_opp struct this opp belongs to
 * @opp:	pointer to the OPP to remove
 *
 * This function removes an opp definition from the opp list.
 *
 * Locking: The internal device_opp and opp structures are RCU protected.
 * It is assumed that the caller holds required mutex for an RCU updater
 * strategy.
 */
static void _opp_remove(struct device_opp *dev_opp,
			struct dev_pm_opp *opp)
			struct dev_pm_opp *opp)
{
{
	/*
	/*
@@ -554,12 +613,12 @@ static void __dev_pm_opp_remove(struct device_opp *dev_opp,
	 */
	 */
	srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp);
	srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp);
	list_del_rcu(&opp->node);
	list_del_rcu(&opp->node);
	call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
	call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);


	if (list_empty(&dev_opp->opp_list)) {
	if (list_empty(&dev_opp->opp_list)) {
		list_del_rcu(&dev_opp->node);
		list_del_rcu(&dev_opp->node);
		call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head,
		call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head,
			  kfree_device_rcu);
			  _kfree_device_rcu);
	}
	}
}
}


@@ -569,6 +628,12 @@ static void __dev_pm_opp_remove(struct device_opp *dev_opp,
 * @freq:	OPP to remove with matching 'freq'
 * @freq:	OPP to remove with matching 'freq'
 *
 *
 * This function removes an opp from the opp list.
 * This function removes an opp from the opp list.
 *
 * Locking: The internal device_opp and opp structures are RCU protected.
 * Hence this function internally uses RCU updater strategy with mutex locks
 * to keep the integrity of the internal data structures. Callers should ensure
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex cannot be locked.
 */
 */
void dev_pm_opp_remove(struct device *dev, unsigned long freq)
void dev_pm_opp_remove(struct device *dev, unsigned long freq)
{
{
@@ -579,7 +644,7 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
	/* Hold our list modification lock here */
	/* Hold our list modification lock here */
	mutex_lock(&dev_opp_list_lock);
	mutex_lock(&dev_opp_list_lock);


	dev_opp = find_device_opp(dev);
	dev_opp = _find_device_opp(dev);
	if (IS_ERR(dev_opp))
	if (IS_ERR(dev_opp))
		goto unlock;
		goto unlock;


@@ -596,14 +661,14 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
		goto unlock;
		goto unlock;
	}
	}


	__dev_pm_opp_remove(dev_opp, opp);
	_opp_remove(dev_opp, opp);
unlock:
unlock:
	mutex_unlock(&dev_opp_list_lock);
	mutex_unlock(&dev_opp_list_lock);
}
}
EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
EXPORT_SYMBOL_GPL(dev_pm_opp_remove);


/**
/**
 * opp_set_availability() - helper to set the availability of an opp
 * _opp_set_availability() - helper to set the availability of an opp
 * @dev:		device for which we do this operation
 * @dev:		device for which we do this operation
 * @freq:		OPP frequency to modify availability
 * @freq:		OPP frequency to modify availability
 * @availability_req:	availability status requested for this opp
 * @availability_req:	availability status requested for this opp
@@ -611,7 +676,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
 * Set the availability of an OPP with an RCU operation, opp_{enable,disable}
 * Set the availability of an OPP with an RCU operation, opp_{enable,disable}
 * share a common logic which is isolated here.
 * share a common logic which is isolated here.
 *
 *
 * Returns -EINVAL for bad pointers, -ENOMEM if no memory available for the
 * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
 * copy operation, returns 0 if no modifcation was done OR modification was
 * copy operation, returns 0 if no modifcation was done OR modification was
 * successful.
 * successful.
 *
 *
@@ -621,7 +686,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
 * that this function is *NOT* called under RCU protection or in contexts where
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex locking or synchronize_rcu() blocking calls cannot be used.
 * mutex locking or synchronize_rcu() blocking calls cannot be used.
 */
 */
static int opp_set_availability(struct device *dev, unsigned long freq,
static int _opp_set_availability(struct device *dev, unsigned long freq,
				 bool availability_req)
				 bool availability_req)
{
{
	struct device_opp *dev_opp;
	struct device_opp *dev_opp;
@@ -638,7 +703,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
	mutex_lock(&dev_opp_list_lock);
	mutex_lock(&dev_opp_list_lock);


	/* Find the device_opp */
	/* Find the device_opp */
	dev_opp = find_device_opp(dev);
	dev_opp = _find_device_opp(dev);
	if (IS_ERR(dev_opp)) {
	if (IS_ERR(dev_opp)) {
		r = PTR_ERR(dev_opp);
		r = PTR_ERR(dev_opp);
		dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
		dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
@@ -668,7 +733,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq,


	list_replace_rcu(&opp->node, &new_opp->node);
	list_replace_rcu(&opp->node, &new_opp->node);
	mutex_unlock(&dev_opp_list_lock);
	mutex_unlock(&dev_opp_list_lock);
	call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
	call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);


	/* Notify the change of the OPP availability */
	/* Notify the change of the OPP availability */
	if (availability_req)
	if (availability_req)
@@ -700,10 +765,14 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
 * integrity of the internal data structures. Callers should ensure that
 * integrity of the internal data structures. Callers should ensure that
 * this function is *NOT* called under RCU protection or in contexts where
 * this function is *NOT* called under RCU protection or in contexts where
 * mutex locking or synchronize_rcu() blocking calls cannot be used.
 * mutex locking or synchronize_rcu() blocking calls cannot be used.
 *
 * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
 * copy operation, returns 0 if no modifcation was done OR modification was
 * successful.
 */
 */
int dev_pm_opp_enable(struct device *dev, unsigned long freq)
int dev_pm_opp_enable(struct device *dev, unsigned long freq)
{
{
	return opp_set_availability(dev, freq, true);
	return _opp_set_availability(dev, freq, true);
}
}
EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
EXPORT_SYMBOL_GPL(dev_pm_opp_enable);


@@ -722,26 +791,41 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
 * integrity of the internal data structures. Callers should ensure that
 * integrity of the internal data structures. Callers should ensure that
 * this function is *NOT* called under RCU protection or in contexts where
 * this function is *NOT* called under RCU protection or in contexts where
 * mutex locking or synchronize_rcu() blocking calls cannot be used.
 * mutex locking or synchronize_rcu() blocking calls cannot be used.
 *
 * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
 * copy operation, returns 0 if no modifcation was done OR modification was
 * successful.
 */
 */
int dev_pm_opp_disable(struct device *dev, unsigned long freq)
int dev_pm_opp_disable(struct device *dev, unsigned long freq)
{
{
	return opp_set_availability(dev, freq, false);
	return _opp_set_availability(dev, freq, false);
}
}
EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
EXPORT_SYMBOL_GPL(dev_pm_opp_disable);


/**
/**
 * dev_pm_opp_get_notifier() - find notifier_head of the device with opp
 * dev_pm_opp_get_notifier() - find notifier_head of the device with opp
 * @dev:	device pointer used to lookup device OPPs.
 * @dev:	device pointer used to lookup device OPPs.
 *
 * Return: pointer to  notifier head if found, otherwise -ENODEV or
 * -EINVAL based on type of error casted as pointer. value must be checked
 *  with IS_ERR to determine valid pointer or error result.
 *
 * Locking: This function must be called under rcu_read_lock(). dev_opp is a RCU
 * protected pointer. The reason for the same is that the opp pointer which is
 * returned will remain valid for use with opp_get_{voltage, freq} only while
 * under the locked area. The pointer returned must be used prior to unlocking
 * with rcu_read_unlock() to maintain the integrity of the pointer.
 */
 */
struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
{
{
	struct device_opp *dev_opp = find_device_opp(dev);
	struct device_opp *dev_opp = _find_device_opp(dev);


	if (IS_ERR(dev_opp))
	if (IS_ERR(dev_opp))
		return ERR_CAST(dev_opp); /* matching type */
		return ERR_CAST(dev_opp); /* matching type */


	return &dev_opp->srcu_head;
	return &dev_opp->srcu_head;
}
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);


#ifdef CONFIG_OF
#ifdef CONFIG_OF
/**
/**
@@ -749,6 +833,22 @@ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
 * @dev:	device pointer used to lookup device OPPs.
 * @dev:	device pointer used to lookup device OPPs.
 *
 *
 * Register the initial OPP table with the OPP library for given device.
 * Register the initial OPP table with the OPP library for given device.
 *
 * Locking: The internal device_opp and opp structures are RCU protected.
 * Hence this function indirectly uses RCU updater strategy with mutex locks
 * to keep the integrity of the internal data structures. Callers should ensure
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex cannot be locked.
 *
 * Return:
 * 0		On success OR
 *		Duplicate OPPs (both freq and volt are same) and opp->available
 * -EEXIST	Freq are same and volt are different OR
 *		Duplicate OPPs (both freq and volt are same) and !opp->available
 * -ENOMEM	Memory allocation failure
 * -ENODEV	when 'operating-points' property is not found or is invalid data
 *		in device node.
 * -ENODATA	when empty 'operating-points' property is found
 */
 */
int of_init_opp_table(struct device *dev)
int of_init_opp_table(struct device *dev)
{
{
@@ -777,7 +877,7 @@ int of_init_opp_table(struct device *dev)
		unsigned long freq = be32_to_cpup(val++) * 1000;
		unsigned long freq = be32_to_cpup(val++) * 1000;
		unsigned long volt = be32_to_cpup(val++);
		unsigned long volt = be32_to_cpup(val++);


		if (dev_pm_opp_add_dynamic(dev, freq, volt, false))
		if (_opp_add_dynamic(dev, freq, volt, false))
			dev_warn(dev, "%s: Failed to add OPP %ld\n",
			dev_warn(dev, "%s: Failed to add OPP %ld\n",
				 __func__, freq);
				 __func__, freq);
		nr -= 2;
		nr -= 2;
@@ -792,6 +892,12 @@ EXPORT_SYMBOL_GPL(of_init_opp_table);
 * @dev:	device pointer used to lookup device OPPs.
 * @dev:	device pointer used to lookup device OPPs.
 *
 *
 * Free OPPs created using static entries present in DT.
 * Free OPPs created using static entries present in DT.
 *
 * Locking: The internal device_opp and opp structures are RCU protected.
 * Hence this function indirectly uses RCU updater strategy with mutex locks
 * to keep the integrity of the internal data structures. Callers should ensure
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex cannot be locked.
 */
 */
void of_free_opp_table(struct device *dev)
void of_free_opp_table(struct device *dev)
{
{
@@ -799,7 +905,7 @@ void of_free_opp_table(struct device *dev)
	struct dev_pm_opp *opp, *tmp;
	struct dev_pm_opp *opp, *tmp;


	/* Check for existing list for 'dev' */
	/* Check for existing list for 'dev' */
	dev_opp = find_device_opp(dev);
	dev_opp = _find_device_opp(dev);
	if (IS_ERR(dev_opp)) {
	if (IS_ERR(dev_opp)) {
		int error = PTR_ERR(dev_opp);
		int error = PTR_ERR(dev_opp);
		if (error != -ENODEV)
		if (error != -ENODEV)
@@ -816,7 +922,7 @@ void of_free_opp_table(struct device *dev)
	/* Free static OPPs */
	/* Free static OPPs */
	list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) {
	list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) {
		if (!opp->dynamic)
		if (!opp->dynamic)
			__dev_pm_opp_remove(dev_opp, opp);
			_opp_remove(dev_opp, opp);
	}
	}


	mutex_unlock(&dev_opp_list_lock);
	mutex_unlock(&dev_opp_list_lock);
+4 −0
Original line number Original line Diff line number Diff line
@@ -64,6 +64,8 @@ enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
	struct pm_qos_flags *pqf;
	struct pm_qos_flags *pqf;
	s32 val;
	s32 val;


	lockdep_assert_held(&dev->power.lock);

	if (IS_ERR_OR_NULL(qos))
	if (IS_ERR_OR_NULL(qos))
		return PM_QOS_FLAGS_UNDEFINED;
		return PM_QOS_FLAGS_UNDEFINED;


@@ -104,6 +106,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
 */
 */
s32 __dev_pm_qos_read_value(struct device *dev)
s32 __dev_pm_qos_read_value(struct device *dev)
{
{
	lockdep_assert_held(&dev->power.lock);

	return IS_ERR_OR_NULL(dev->power.qos) ?
	return IS_ERR_OR_NULL(dev->power.qos) ?
		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
}
}
+12 −0
Original line number Original line Diff line number Diff line
@@ -87,4 +87,16 @@ config ARM_EXYNOS5_BUS_DEVFREQ
	  It reads PPMU counters of memory controllers and adjusts the
	  It reads PPMU counters of memory controllers and adjusts the
	  operating frequencies and voltages with OPP support.
	  operating frequencies and voltages with OPP support.


config ARM_TEGRA_DEVFREQ
       tristate "Tegra DEVFREQ Driver"
       depends on ARCH_TEGRA_124_SOC
       select DEVFREQ_GOV_SIMPLE_ONDEMAND
       select PM_OPP
       help
         This adds the DEVFREQ driver for the Tegra family of SoCs.
         It reads ACTMON counters of memory controllers and adjusts the
         operating frequencies and voltages with OPP support.

source "drivers/devfreq/event/Kconfig"

endif # PM_DEVFREQ
endif # PM_DEVFREQ
+5 −0
Original line number Original line Diff line number Diff line
obj-$(CONFIG_PM_DEVFREQ)	+= devfreq.o
obj-$(CONFIG_PM_DEVFREQ)	+= devfreq.o
obj-$(CONFIG_PM_DEVFREQ_EVENT)	+= devfreq-event.o
obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)	+= governor_simpleondemand.o
obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)	+= governor_simpleondemand.o
obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)	+= governor_performance.o
obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)	+= governor_performance.o
obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
@@ -7,3 +8,7 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
# DEVFREQ Drivers
# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos/
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos/
obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)	+= exynos/
obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)	+= exynos/
obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra-devfreq.o

# DEVFREQ Event Drivers
obj-$(CONFIG_PM_DEVFREQ_EVENT)		+= event/
Loading