Commit 59fb53ea75eef4aa029cf31c88cdacec2f7b794b

Authored by Rafael J. Wysocki

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

Showing 8 changed files Side-by-side Diff

Documentation/ABI/testing/sysfs-devices-power
... ... @@ -165,4 +165,22 @@
165 165  
166 166 Not all drivers support this attribute. If it isn't supported,
167 167 attempts to read or write it will yield I/O errors.
  168 +
  169 +What: /sys/devices/.../power/pm_qos_latency_us
  170 +Date: March 2012
  171 +Contact: Rafael J. Wysocki <rjw@sisk.pl>
  172 +Description:
  173 + The /sys/devices/.../power/pm_qos_resume_latency_us attribute
  174 + contains the PM QoS resume latency limit for the given device,
  175 + which is the maximum allowed time it can take to resume the
  176 + device, after it has been suspended at run time, from a resume
  177 + request to the moment the device will be ready to process I/O,
  178 + in microseconds. If it is equal to 0, however, this means that
  179 + the PM QoS resume latency may be arbitrary.
  180 +
  181 + Not all drivers support this attribute. If it isn't supported,
  182 + it is not present.
  183 +
  184 + This attribute has no effect on system-wide suspend/resume and
  185 + hibernation.
drivers/base/power/power.h
... ... @@ -71,6 +71,8 @@
71 71 extern void rpm_sysfs_remove(struct device *dev);
72 72 extern int wakeup_sysfs_add(struct device *dev);
73 73 extern void wakeup_sysfs_remove(struct device *dev);
  74 +extern int pm_qos_sysfs_add(struct device *dev);
  75 +extern void pm_qos_sysfs_remove(struct device *dev);
74 76  
75 77 #else /* CONFIG_PM */
76 78  
... ... @@ -79,6 +81,8 @@
79 81 static inline void rpm_sysfs_remove(struct device *dev) {}
80 82 static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
81 83 static inline void wakeup_sysfs_remove(struct device *dev) {}
  84 +static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
  85 +static inline void pm_qos_sysfs_remove(struct device *dev) {}
82 86  
83 87 #endif
drivers/base/power/qos.c
... ... @@ -41,6 +41,7 @@
41 41 #include <linux/mutex.h>
42 42 #include <linux/export.h>
43 43  
  44 +#include "power.h"
44 45  
45 46 static DEFINE_MUTEX(dev_pm_qos_mtx);
46 47  
... ... @@ -166,6 +167,12 @@
166 167 struct dev_pm_qos_request *req, *tmp;
167 168 struct pm_qos_constraints *c;
168 169  
  170 + /*
  171 + * If the device's PM QoS resume latency limit has been exposed to user
  172 + * space, it has to be hidden at this point.
  173 + */
  174 + dev_pm_qos_hide_latency_limit(dev);
  175 +
169 176 mutex_lock(&dev_pm_qos_mtx);
170 177  
171 178 dev->power.power_state = PMSG_INVALID;
... ... @@ -445,4 +452,58 @@
445 452 return error;
446 453 }
447 454 EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
  455 +
  456 +#ifdef CONFIG_PM_RUNTIME
  457 +static void __dev_pm_qos_drop_user_request(struct device *dev)
  458 +{
  459 + dev_pm_qos_remove_request(dev->power.pq_req);
  460 + dev->power.pq_req = 0;
  461 +}
  462 +
  463 +/**
  464 + * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
  465 + * @dev: Device whose PM QoS latency limit is to be exposed to user space.
  466 + * @value: Initial value of the latency limit.
  467 + */
  468 +int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
  469 +{
  470 + struct dev_pm_qos_request *req;
  471 + int ret;
  472 +
  473 + if (!device_is_registered(dev) || value < 0)
  474 + return -EINVAL;
  475 +
  476 + if (dev->power.pq_req)
  477 + return -EEXIST;
  478 +
  479 + req = kzalloc(sizeof(*req), GFP_KERNEL);
  480 + if (!req)
  481 + return -ENOMEM;
  482 +
  483 + ret = dev_pm_qos_add_request(dev, req, value);
  484 + if (ret < 0)
  485 + return ret;
  486 +
  487 + dev->power.pq_req = req;
  488 + ret = pm_qos_sysfs_add(dev);
  489 + if (ret)
  490 + __dev_pm_qos_drop_user_request(dev);
  491 +
  492 + return ret;
  493 +}
  494 +EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
  495 +
  496 +/**
  497 + * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
  498 + * @dev: Device whose PM QoS latency limit is to be hidden from user space.
  499 + */
  500 +void dev_pm_qos_hide_latency_limit(struct device *dev)
  501 +{
  502 + if (dev->power.pq_req) {
  503 + pm_qos_sysfs_remove(dev);
  504 + __dev_pm_qos_drop_user_request(dev);
  505 + }
  506 +}
  507 +EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
  508 +#endif /* CONFIG_PM_RUNTIME */
drivers/base/power/sysfs.c
... ... @@ -5,6 +5,7 @@
5 5 #include <linux/device.h>
6 6 #include <linux/string.h>
7 7 #include <linux/export.h>
  8 +#include <linux/pm_qos.h>
8 9 #include <linux/pm_runtime.h>
9 10 #include <linux/atomic.h>
10 11 #include <linux/jiffies.h>
... ... @@ -217,6 +218,31 @@
217 218 static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
218 219 autosuspend_delay_ms_store);
219 220  
  221 +static ssize_t pm_qos_latency_show(struct device *dev,
  222 + struct device_attribute *attr, char *buf)
  223 +{
  224 + return sprintf(buf, "%d\n", dev->power.pq_req->node.prio);
  225 +}
  226 +
  227 +static ssize_t pm_qos_latency_store(struct device *dev,
  228 + struct device_attribute *attr,
  229 + const char *buf, size_t n)
  230 +{
  231 + s32 value;
  232 + int ret;
  233 +
  234 + if (kstrtos32(buf, 0, &value))
  235 + return -EINVAL;
  236 +
  237 + if (value < 0)
  238 + return -EINVAL;
  239 +
  240 + ret = dev_pm_qos_update_request(dev->power.pq_req, value);
  241 + return ret < 0 ? ret : n;
  242 +}
  243 +
  244 +static DEVICE_ATTR(pm_qos_resume_latency_us, 0644,
  245 + pm_qos_latency_show, pm_qos_latency_store);
220 246 #endif /* CONFIG_PM_RUNTIME */
221 247  
222 248 #ifdef CONFIG_PM_SLEEP
... ... @@ -490,6 +516,17 @@
490 516 .attrs = runtime_attrs,
491 517 };
492 518  
  519 +static struct attribute *pm_qos_attrs[] = {
  520 +#ifdef CONFIG_PM_RUNTIME
  521 + &dev_attr_pm_qos_resume_latency_us.attr,
  522 +#endif /* CONFIG_PM_RUNTIME */
  523 + NULL,
  524 +};
  525 +static struct attribute_group pm_qos_attr_group = {
  526 + .name = power_group_name,
  527 + .attrs = pm_qos_attrs,
  528 +};
  529 +
493 530 int dpm_sysfs_add(struct device *dev)
494 531 {
495 532 int rc;
... ... @@ -528,6 +565,16 @@
528 565 void wakeup_sysfs_remove(struct device *dev)
529 566 {
530 567 sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
  568 +}
  569 +
  570 +int pm_qos_sysfs_add(struct device *dev)
  571 +{
  572 + return sysfs_merge_group(&dev->kobj, &pm_qos_attr_group);
  573 +}
  574 +
  575 +void pm_qos_sysfs_remove(struct device *dev)
  576 +{
  577 + sysfs_unmerge_group(&dev->kobj, &pm_qos_attr_group);
531 578 }
532 579  
533 580 void rpm_sysfs_remove(struct device *dev)
drivers/mmc/host/sh_mmcif.c
... ... @@ -56,6 +56,7 @@
56 56 #include <linux/mmc/sh_mmcif.h>
57 57 #include <linux/pagemap.h>
58 58 #include <linux/platform_device.h>
  59 +#include <linux/pm_qos.h>
59 60 #include <linux/pm_runtime.h>
60 61 #include <linux/spinlock.h>
61 62 #include <linux/module.h>
... ... @@ -1346,6 +1347,8 @@
1346 1347 if (ret < 0)
1347 1348 goto clean_up5;
1348 1349  
  1350 + dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
  1351 +
1349 1352 dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
1350 1353 dev_dbg(&pdev->dev, "chip ver H'%04x\n",
1351 1354 sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
... ... @@ -1375,6 +1378,8 @@
1375 1378  
1376 1379 host->dying = true;
1377 1380 pm_runtime_get_sync(&pdev->dev);
  1381 +
  1382 + dev_pm_qos_hide_latency_limit(&pdev->dev);
1378 1383  
1379 1384 mmc_remove_host(host->mmc);
1380 1385 sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
drivers/mmc/host/tmio_mmc_pio.c
... ... @@ -39,6 +39,7 @@
39 39 #include <linux/module.h>
40 40 #include <linux/pagemap.h>
41 41 #include <linux/platform_device.h>
  42 +#include <linux/pm_qos.h>
42 43 #include <linux/pm_runtime.h>
43 44 #include <linux/scatterlist.h>
44 45 #include <linux/spinlock.h>
... ... @@ -955,6 +956,8 @@
955 956  
956 957 mmc_add_host(mmc);
957 958  
  959 + dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
  960 +
958 961 /* Unmask the IRQs we want to know about */
959 962 if (!_host->chan_rx)
960 963 irq_mask |= TMIO_MASK_READOP;
... ... @@ -992,6 +995,8 @@
992 995 || host->mmc->caps & MMC_CAP_NEEDS_POLL
993 996 || host->mmc->caps & MMC_CAP_NONREMOVABLE)
994 997 pm_runtime_get_sync(&pdev->dev);
  998 +
  999 + dev_pm_qos_hide_latency_limit(&pdev->dev);
995 1000  
996 1001 mmc_remove_host(host->mmc);
997 1002 cancel_work_sync(&host->done);
... ... @@ -546,6 +546,7 @@
546 546 unsigned long accounting_timestamp;
547 547 ktime_t suspend_time;
548 548 s64 max_time_suspended_ns;
  549 + struct dev_pm_qos_request *pq_req;
549 550 #endif
550 551 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
551 552 struct pm_qos_constraints *constraints;
include/linux/pm_qos.h
... ... @@ -137,5 +137,14 @@
137 137 { return 0; }
138 138 #endif
139 139  
  140 +#ifdef CONFIG_PM_RUNTIME
  141 +int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value);
  142 +void dev_pm_qos_hide_latency_limit(struct device *dev);
  143 +#else
  144 +static inline int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
  145 + { return 0; }
  146 +static inline void dev_pm_qos_hide_latency_limit(struct device *dev) {}
  147 +#endif
  148 +
140 149 #endif