diff -ru linux-4.16.10.orig/Documentation/ABI/testing/sysfs-devices-power linux-4.16.10.new/Documentation/ABI/testing/sysfs-devices-power --- linux-4.16.10.orig/Documentation/ABI/testing/sysfs-devices-power 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/Documentation/ABI/testing/sysfs-devices-power 2018-05-21 12:25:49.757334328 +0200 @@ -211,9 +211,7 @@ 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 and the special value - "n/a" means that user space cannot accept any resume latency at - all for the given device. + the PM QoS resume latency may be arbitrary. Not all drivers support this attribute. If it isn't supported, it is not present. diff -ru linux-4.16.10.orig/drivers/base/cpu.c linux-4.16.10.new/drivers/base/cpu.c --- linux-4.16.10.orig/drivers/base/cpu.c 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/drivers/base/cpu.c 2018-05-21 13:59:23.261272605 +0200 @@ -23,6 +23,8 @@ #include "base.h" +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT S32_MAX + static DEFINE_PER_CPU(struct device *, cpu_sys_devices); static int cpu_subsys_match(struct device *dev, struct device_driver *drv) diff -ru linux-4.16.10.orig/drivers/base/power/domain.c linux-4.16.10.new/drivers/base/power/domain.c --- linux-4.16.10.orig/drivers/base/power/domain.c 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/drivers/base/power/domain.c 2018-05-21 12:26:01.257561411 +0200 @@ -1336,7 +1336,7 @@ gpd_data->base.dev = dev; gpd_data->td.constraint_changed = true; - gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS; + gpd_data->td.effective_constraint_ns = 0; gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; spin_lock_irq(&dev->power.lock); diff -ru linux-4.16.10.orig/drivers/base/power/domain_governor.c linux-4.16.10.new/drivers/base/power/domain_governor.c --- linux-4.16.10.orig/drivers/base/power/domain_governor.c 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/drivers/base/power/domain_governor.c 2018-05-21 12:51:23.279287688 +0200 @@ -11,32 +11,25 @@ #include #include +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT S32_MAX + static int dev_update_qos_constraint(struct device *dev, void *data) { s64 *constraint_ns_p = data; - s64 constraint_ns; + s64 constraint_ns = -1; - if (dev->power.subsys_data && dev->power.subsys_data->domain_data) { - /* - * Only take suspend-time QoS constraints of devices into - * account, because constraints updated after the device has - * been suspended are not guaranteed to be taken into account - * anyway. In order for them to take effect, the device has to - * be resumed and suspended again. - */ + if (dev->power.subsys_data && dev->power.subsys_data->domain_data) constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns; - } else { - /* - * The child is not in a domain and there's no info on its - * suspend/resume latencies, so assume them to be negligible and - * take its current PM QoS constraint (that's the only thing - * known at this point anyway). - */ + + if (constraint_ns < 0) constraint_ns = dev_pm_qos_read_value(dev); - constraint_ns *= NSEC_PER_USEC; - } - if (constraint_ns < *constraint_ns_p) + if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) + return 0; + + constraint_ns *= NSEC_PER_USEC; + + if (constraint_ns < *constraint_ns_p || *constraint_ns_p < 0) *constraint_ns_p = constraint_ns; return 0; @@ -64,7 +57,7 @@ } td->constraint_changed = false; td->cached_suspend_ok = false; - td->effective_constraint_ns = 0; + td->effective_constraint_ns = -1; constraint_ns = __dev_pm_qos_read_value(dev); spin_unlock_irqrestore(&dev->power.lock, flags); @@ -72,7 +65,11 @@ if (constraint_ns == 0) return false; - constraint_ns *= NSEC_PER_USEC; + if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) + constraint_ns = -1; + else + constraint_ns *= NSEC_PER_USEC; + /* * We can walk the children without any additional locking, because * they all have been suspended at this point and their @@ -82,25 +79,25 @@ device_for_each_child(dev, &constraint_ns, dev_update_qos_constraint); - if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) { + if (constraint_ns == 0) { /* "No restriction", so the device is allowed to suspend. */ - td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS; + td->effective_constraint_ns = 0; td->cached_suspend_ok = true; - } else if (constraint_ns == 0) { + } else if (constraint_ns < 0) { /* * This triggers if one of the children that don't belong to a - * domain has a zero PM QoS constraint and it's better not to - * suspend then. effective_constraint_ns is zero already and - * cached_suspend_ok is false, so bail out. + * domain has a negative PM QoS constraint and it's better not + * to suspend then. effective_constraint_ns is negative already + * and cached_suspend_ok is false, so bail out. */ return false; } else { constraint_ns -= td->suspend_latency_ns + td->resume_latency_ns; /* - * effective_constraint_ns is zero already and cached_suspend_ok - * is false, so if the computed value is not positive, return - * right away. + * effective_constraint_ns is negative already and + * cached_suspend_ok is false, so if the computed value is not + * positive, return right away. */ if (constraint_ns <= 0) return false; @@ -168,13 +165,19 @@ */ td = &to_gpd_data(pdd)->td; constraint_ns = td->effective_constraint_ns; - /* - * Zero means "no suspend at all" and this runs only when all - * devices in the domain are suspended, so it must be positive. - */ - if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) + /* default_suspend_ok() need not be called before us. */ + if (constraint_ns < 0) + constraint_ns = dev_pm_qos_read_value(pdd->dev); + + if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) continue; + constraint_ns *= NSEC_PER_USEC; + + /* + * constraint_ns cannot be negative here, because the device has + * been suspended. + */ if (constraint_ns <= off_on_time_ns) return false; diff -ru linux-4.16.10.orig/drivers/base/power/qos.c linux-4.16.10.new/drivers/base/power/qos.c --- linux-4.16.10.orig/drivers/base/power/qos.c 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/drivers/base/power/qos.c 2018-05-21 12:52:59.445271957 +0200 @@ -43,6 +43,8 @@ #include "power.h" +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT S32_MAX + static DEFINE_MUTEX(dev_pm_qos_mtx); static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx); @@ -139,9 +141,6 @@ switch(req->type) { case DEV_PM_QOS_RESUME_LATENCY: - if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0)) - value = 0; - ret = pm_qos_update_target(&qos->resume_latency, &req->data.pnode, action, value); break; diff -ru linux-4.16.10.orig/drivers/base/power/sysfs.c linux-4.16.10.new/drivers/base/power/sysfs.c --- linux-4.16.10.orig/drivers/base/power/sysfs.c 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/drivers/base/power/sysfs.c 2018-05-21 12:53:14.489580783 +0200 @@ -11,6 +11,8 @@ #include #include "power.h" +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT S32_MAX + /* * control - Report/change current runtime PM setting of the device * @@ -215,7 +217,7 @@ if (value == 0) return sprintf(buf, "n/a\n"); - if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) + else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) value = 0; return sprintf(buf, "%d\n", value); @@ -228,25 +230,8 @@ s32 value; int ret; - if (!kstrtos32(buf, 0, &value)) { - /* - * Prevent users from writing negative or "no constraint" values - * directly. - */ - if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) - return -EINVAL; - - if (value == 0) - value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; - } else if (sysfs_streq(buf, "n/a")) { - value = 0; - } else { + if (kstrtos32(buf, 0, &value)) return -EINVAL; - } - - ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req, - value); - return ret < 0 ? ret : n; } static DEVICE_ATTR_RW(pm_qos_resume_latency_us); diff -ru linux-4.16.10.orig/drivers/cpuidle/governors/ladder.c linux-4.16.10.new/drivers/cpuidle/governors/ladder.c --- linux-4.16.10.orig/drivers/cpuidle/governors/ladder.c 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/drivers/cpuidle/governors/ladder.c 2018-05-21 14:23:08.410207685 +0200 @@ -73,11 +73,6 @@ int last_residency, last_idx = ldev->last_state_idx; int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0; int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); - int resume_latency = dev_pm_qos_raw_read_value(device); - - if (resume_latency < latency_req && - resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) - latency_req = resume_latency; /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) { diff -ru linux-4.16.10.orig/drivers/cpuidle/governors/menu.c linux-4.16.10.new/drivers/cpuidle/governors/menu.c --- linux-4.16.10.orig/drivers/cpuidle/governors/menu.c 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/drivers/cpuidle/governors/menu.c 2018-05-21 12:26:09.153717278 +0200 @@ -298,8 +298,8 @@ data->needs_update = 0; } - if (resume_latency < latency_req && - resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) + /* resume_latency is 0 means no restriction */ + if (resume_latency && resume_latency < latency_req) latency_req = resume_latency; /* Special case when user has set very strict latency requirement */ diff -ru linux-4.16.10.orig/include/linux/pm_qos.h linux-4.16.10.new/include/linux/pm_qos.h --- linux-4.16.10.orig/include/linux/pm_qos.h 2018-05-19 10:19:37.000000000 +0200 +++ linux-4.16.10.new/include/linux/pm_qos.h 2018-05-21 12:26:09.797729990 +0200 @@ -28,19 +28,16 @@ PM_QOS_FLAGS_ALL, }; -#define PM_QOS_DEFAULT_VALUE (-1) -#define PM_QOS_LATENCY_ANY S32_MAX -#define PM_QOS_LATENCY_ANY_NS ((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC) +#define PM_QOS_DEFAULT_VALUE -1 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE 0 -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE PM_QOS_LATENCY_ANY -#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT PM_QOS_LATENCY_ANY -#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) +#define PM_QOS_LATENCY_ANY ((s32)(~(__u32)0 >> 1)) #define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) @@ -177,8 +174,7 @@ static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return IS_ERR_OR_NULL(dev->power.qos) ? - PM_QOS_RESUME_LATENCY_NO_CONSTRAINT : - pm_qos_read_value(&dev->power.qos->resume_latency); + 0 : pm_qos_read_value(&dev->power.qos->resume_latency); } #else static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, @@ -188,9 +184,9 @@ s32 mask) { return PM_QOS_FLAGS_UNDEFINED; } static inline s32 __dev_pm_qos_read_value(struct device *dev) - { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; } + { return 0; } static inline s32 dev_pm_qos_read_value(struct device *dev) - { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; } + { return 0; } static inline int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, enum dev_pm_qos_req_type type, @@ -236,15 +232,9 @@ { return 0; } static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {} -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) -{ - return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; -} +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; } static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; } -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) -{ - return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; -} +static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; } #endif #endif