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

Commit 59fb53ea authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-qos'

* pm-qos:
  sh_mmcif / PM: Use PM QoS latency constraint
  tmio_mmc / PM: Use PM QoS latency constraint
  PM / QoS: Make it possible to expose PM QoS latency constraints
parents ed819e3b efe6a8ad
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -165,3 +165,21 @@ Description:

		Not all drivers support this attribute.  If it isn't supported,
		attempts to read or write it will yield I/O errors.

What:		/sys/devices/.../power/pm_qos_latency_us
Date:		March 2012
Contact:	Rafael J. Wysocki <rjw@sisk.pl>
Description:
		The /sys/devices/.../power/pm_qos_resume_latency_us attribute
		contains the PM QoS resume latency limit for the given device,
		which is the maximum allowed time it can take to resume the
		device, after it has been suspended at run time, from a resume
		request to the moment the device will be ready to process I/O,
		in microseconds.  If it is equal to 0, however, this means that
		the PM QoS resume latency may be arbitrary.

		Not all drivers support this attribute.  If it isn't supported,
		it is not present.

		This attribute has no effect on system-wide suspend/resume and
		hibernation.
+4 −0
Original line number Diff line number Diff line
@@ -71,6 +71,8 @@ extern void dpm_sysfs_remove(struct device *dev);
extern void rpm_sysfs_remove(struct device *dev);
extern int wakeup_sysfs_add(struct device *dev);
extern void wakeup_sysfs_remove(struct device *dev);
extern int pm_qos_sysfs_add(struct device *dev);
extern void pm_qos_sysfs_remove(struct device *dev);

#else /* CONFIG_PM */

@@ -79,5 +81,7 @@ static inline void dpm_sysfs_remove(struct device *dev) {}
static inline void rpm_sysfs_remove(struct device *dev) {}
static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
static inline void wakeup_sysfs_remove(struct device *dev) {}
static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
static inline void pm_qos_sysfs_remove(struct device *dev) {}

#endif
+61 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include <linux/mutex.h>
#include <linux/export.h>

#include "power.h"

static DEFINE_MUTEX(dev_pm_qos_mtx);

@@ -166,6 +167,12 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
	struct dev_pm_qos_request *req, *tmp;
	struct pm_qos_constraints *c;

	/*
	 * If the device's PM QoS resume latency limit has been exposed to user
	 * space, it has to be hidden at this point.
	 */
	dev_pm_qos_hide_latency_limit(dev);

	mutex_lock(&dev_pm_qos_mtx);

	dev->power.power_state = PMSG_INVALID;
@@ -445,3 +452,57 @@ int dev_pm_qos_add_ancestor_request(struct device *dev,
	return error;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);

#ifdef CONFIG_PM_RUNTIME
static void __dev_pm_qos_drop_user_request(struct device *dev)
{
	dev_pm_qos_remove_request(dev->power.pq_req);
	dev->power.pq_req = 0;
}

/**
 * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
 * @dev: Device whose PM QoS latency limit is to be exposed to user space.
 * @value: Initial value of the latency limit.
 */
int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
{
	struct dev_pm_qos_request *req;
	int ret;

	if (!device_is_registered(dev) || value < 0)
		return -EINVAL;

	if (dev->power.pq_req)
		return -EEXIST;

	req = kzalloc(sizeof(*req), GFP_KERNEL);
	if (!req)
		return -ENOMEM;

	ret = dev_pm_qos_add_request(dev, req, value);
	if (ret < 0)
		return ret;

	dev->power.pq_req = req;
	ret = pm_qos_sysfs_add(dev);
	if (ret)
		__dev_pm_qos_drop_user_request(dev);

	return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);

/**
 * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
 * @dev: Device whose PM QoS latency limit is to be hidden from user space.
 */
void dev_pm_qos_hide_latency_limit(struct device *dev)
{
	if (dev->power.pq_req) {
		pm_qos_sysfs_remove(dev);
		__dev_pm_qos_drop_user_request(dev);
	}
}
EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
#endif /* CONFIG_PM_RUNTIME */
+47 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <linux/device.h>
#include <linux/string.h>
#include <linux/export.h>
#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
#include <linux/atomic.h>
#include <linux/jiffies.h>
@@ -217,6 +218,31 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev,
static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
		autosuspend_delay_ms_store);

static ssize_t pm_qos_latency_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", dev->power.pq_req->node.prio);
}

static ssize_t pm_qos_latency_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t n)
{
	s32 value;
	int ret;

	if (kstrtos32(buf, 0, &value))
		return -EINVAL;

	if (value < 0)
		return -EINVAL;

	ret = dev_pm_qos_update_request(dev->power.pq_req, value);
	return ret < 0 ? ret : n;
}

static DEVICE_ATTR(pm_qos_resume_latency_us, 0644,
		   pm_qos_latency_show, pm_qos_latency_store);
#endif /* CONFIG_PM_RUNTIME */

#ifdef CONFIG_PM_SLEEP
@@ -490,6 +516,17 @@ static struct attribute_group pm_runtime_attr_group = {
	.attrs	= runtime_attrs,
};

static struct attribute *pm_qos_attrs[] = {
#ifdef CONFIG_PM_RUNTIME
	&dev_attr_pm_qos_resume_latency_us.attr,
#endif /* CONFIG_PM_RUNTIME */
	NULL,
};
static struct attribute_group pm_qos_attr_group = {
	.name	= power_group_name,
	.attrs	= pm_qos_attrs,
};

int dpm_sysfs_add(struct device *dev)
{
	int rc;
@@ -530,6 +567,16 @@ void wakeup_sysfs_remove(struct device *dev)
	sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
}

int pm_qos_sysfs_add(struct device *dev)
{
	return sysfs_merge_group(&dev->kobj, &pm_qos_attr_group);
}

void pm_qos_sysfs_remove(struct device *dev)
{
	sysfs_unmerge_group(&dev->kobj, &pm_qos_attr_group);
}

void rpm_sysfs_remove(struct device *dev)
{
	sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
+5 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@
#include <linux/mmc/sh_mmcif.h>
#include <linux/pagemap.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <linux/module.h>
@@ -1346,6 +1347,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
	if (ret < 0)
		goto clean_up5;

	dev_pm_qos_expose_latency_limit(&pdev->dev, 100);

	dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
	dev_dbg(&pdev->dev, "chip ver H'%04x\n",
		sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
@@ -1376,6 +1379,8 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
	host->dying = true;
	pm_runtime_get_sync(&pdev->dev);

	dev_pm_qos_hide_latency_limit(&pdev->dev);

	mmc_remove_host(host->mmc);
	sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);

Loading