Message ID | 1948004.bU45lK7TsE@aspire.rjw.lan (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
On 2017-10-24 at 13:35:05 +0200, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > [cut] > @@ -63,10 +60,14 @@ static bool default_suspend_ok(struct de > > spin_unlock_irqrestore(&dev->power.lock, flags); > > - if (constraint_ns < 0) > + 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 > @@ -76,14 +77,19 @@ static bool default_suspend_ok(struct de > device_for_each_child(dev, &constraint_ns, > dev_update_qos_constraint); > > - if (constraint_ns > 0) { > - constraint_ns -= td->suspend_latency_ns + > - td->resume_latency_ns; > - if (constraint_ns == 0) > - return false; > + if (constraint_ns < 0) { > + /* The children have no constraints. */ > + td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; > + td->cached_suspend_ok = true; > + } else { > + constraint_ns -= td->suspend_latency_ns + td->resume_latency_ns; > + if (constraint_ns > 0) { > + td->effective_constraint_ns = constraint_ns; > + td->cached_suspend_ok = true; > + } else { > + td->effective_constraint_ns = 0; If the resume latency constraint was increased after this, default_power_down_ok may not consider the new value. default_suspend_ok needs to get called first if the new value is to be read. This is because dev_pm_qos_read_value will get called only if effective_constraint_ns has a negative value. default_suspend_ok initializes effective_constraint_ns with -1 before doing the calculations. default_power_down_ok does not initialize it to -1 and uses the existing value. A comment in default_power_down_ok implies it is not necessary to call default_suspend_ok before calling default_power_down_ok. In that case, default_power_down_ok should be able to get the new latency constraint value. > + } > } > - td->effective_constraint_ns = constraint_ns; > - td->cached_suspend_ok = constraint_ns >= 0; > > /* > * The children have been suspended already, so we don't need to take > @@ -145,13 +151,14 @@ static bool __default_power_down_ok(stru > td = &to_gpd_data(pdd)->td; > constraint_ns = td->effective_constraint_ns; > /* default_suspend_ok() need not be called before us. */ > - if (constraint_ns < 0) { > + if (constraint_ns < 0) > constraint_ns = dev_pm_qos_read_value(pdd->dev); > - constraint_ns *= NSEC_PER_USEC; > - } > - if (constraint_ns == 0) > + > + 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.
On 2017-10-25 at 00:16:25 -0700, Ramesh Thomas wrote: > On 2017-10-24 at 13:35:05 +0200, Rafael J. Wysocki wrote: > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > [cut] > > > @@ -63,10 +60,14 @@ static bool default_suspend_ok(struct de > > > > spin_unlock_irqrestore(&dev->power.lock, flags); > > > > - if (constraint_ns < 0) > > + 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 > > @@ -76,14 +77,19 @@ static bool default_suspend_ok(struct de > > device_for_each_child(dev, &constraint_ns, > > dev_update_qos_constraint); > > > > - if (constraint_ns > 0) { > > - constraint_ns -= td->suspend_latency_ns + > > - td->resume_latency_ns; > > - if (constraint_ns == 0) > > - return false; > > + if (constraint_ns < 0) { > > + /* The children have no constraints. */ > > + td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; > > + td->cached_suspend_ok = true; > > + } else { > > + constraint_ns -= td->suspend_latency_ns + td->resume_latency_ns; > > + if (constraint_ns > 0) { > > + td->effective_constraint_ns = constraint_ns; > > + td->cached_suspend_ok = true; > > + } else { > > + td->effective_constraint_ns = 0; > > If the resume latency constraint was increased after this, > default_power_down_ok may not consider the new value. default_suspend_ok needs > to get called first if the new value is to be read. > > This is because dev_pm_qos_read_value will get called only if > effective_constraint_ns has a negative value. default_suspend_ok initializes > effective_constraint_ns with -1 before doing the calculations. > default_power_down_ok does not initialize it to -1 and uses > the existing value. > > A comment in default_power_down_ok implies it is not necessary to call > default_suspend_ok before calling default_power_down_ok. In that case, > default_power_down_ok should be able to get the new latency constraint value. > The design expects default_suspend_ok would always be called before default_power_down_ok if the device was made "active" after start. Changes to resume latency constraint will not be considered if it happened between suspend and power down of a device. However, that is the design and not a behavior introduced by this patch. Acked-by: Ramesh Thomas <ramesh.thomas@intel.com>
On Thu, Oct 26, 2017 at 4:00 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote: > On 2017-10-25 at 00:16:25 -0700, Ramesh Thomas wrote: >> On 2017-10-24 at 13:35:05 +0200, Rafael J. Wysocki wrote: >> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> >> > >> >> [cut] >> >> > @@ -63,10 +60,14 @@ static bool default_suspend_ok(struct de >> > >> > spin_unlock_irqrestore(&dev->power.lock, flags); >> > >> > - if (constraint_ns < 0) >> > + 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 >> > @@ -76,14 +77,19 @@ static bool default_suspend_ok(struct de >> > device_for_each_child(dev, &constraint_ns, >> > dev_update_qos_constraint); >> > >> > - if (constraint_ns > 0) { >> > - constraint_ns -= td->suspend_latency_ns + >> > - td->resume_latency_ns; >> > - if (constraint_ns == 0) >> > - return false; >> > + if (constraint_ns < 0) { >> > + /* The children have no constraints. */ >> > + td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; >> > + td->cached_suspend_ok = true; >> > + } else { >> > + constraint_ns -= td->suspend_latency_ns + td->resume_latency_ns; >> > + if (constraint_ns > 0) { >> > + td->effective_constraint_ns = constraint_ns; >> > + td->cached_suspend_ok = true; >> > + } else { >> > + td->effective_constraint_ns = 0; >> >> If the resume latency constraint was increased after this, >> default_power_down_ok may not consider the new value. default_suspend_ok needs >> to get called first if the new value is to be read. >> >> This is because dev_pm_qos_read_value will get called only if >> effective_constraint_ns has a negative value. default_suspend_ok initializes >> effective_constraint_ns with -1 before doing the calculations. >> default_power_down_ok does not initialize it to -1 and uses >> the existing value. >> >> A comment in default_power_down_ok implies it is not necessary to call >> default_suspend_ok before calling default_power_down_ok. In that case, >> default_power_down_ok should be able to get the new latency constraint value. >> > > The design expects default_suspend_ok would always be called before > default_power_down_ok if the device was made "active" after start. Changes > to resume latency constraint will not be considered if it happened between > suspend and power down of a device. However, that is the design and not a > behavior introduced by this patch. > > Acked-by: Ramesh Thomas <ramesh.thomas@intel.com> Cool, thanks! I'll go ahead and push this to Linus, then. Thanks, Rafael
Index: linux-pm/drivers/base/power/sysfs.c =================================================================== --- linux-pm.orig/drivers/base/power/sysfs.c +++ linux-pm/drivers/base/power/sysfs.c @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev)); + s32 value = dev_pm_qos_requested_resume_latency(dev); + + if (value == 0) + return sprintf(buf, "n/a\n"); + else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) + value = 0; + + return sprintf(buf, "%d\n", value); } static ssize_t pm_qos_resume_latency_store(struct device *dev, @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto s32 value; int ret; - if (kstrtos32(buf, 0, &value)) - return -EINVAL; + 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) + if (value == 0) + value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; + } else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) { + value = 0; + } else { return -EINVAL; + } ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req, value); Index: linux-pm/include/linux/pm_qos.h =================================================================== --- linux-pm.orig/include/linux/pm_qos.h +++ linux-pm/include/linux/pm_qos.h @@ -27,16 +27,17 @@ enum pm_qos_flags_status { PM_QOS_FLAGS_ALL, }; -#define PM_QOS_DEFAULT_VALUE -1 +#define PM_QOS_DEFAULT_VALUE (-1) +#define PM_QOS_LATENCY_ANY S32_MAX #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 0 +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT PM_QOS_LATENCY_ANY #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) #define PM_QOS_FLAG_REMOTE_WAKEUP (1 << 1) Index: linux-pm/drivers/cpuidle/governors/menu.c =================================================================== --- linux-pm.orig/drivers/cpuidle/governors/menu.c +++ linux-pm/drivers/cpuidle/governors/menu.c @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr data->needs_update = 0; } - /* resume_latency is 0 means no restriction */ - if (resume_latency && resume_latency < latency_req) + 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 */ Index: linux-pm/drivers/base/power/domain_governor.c =================================================================== --- linux-pm.orig/drivers/base/power/domain_governor.c +++ linux-pm/drivers/base/power/domain_governor.c @@ -14,23 +14,20 @@ static int dev_update_qos_constraint(struct device *dev, void *data) { s64 *constraint_ns_p = data; - s32 constraint_ns = -1; + s64 constraint_ns = -1; if (dev->power.subsys_data && dev->power.subsys_data->domain_data) constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns; - if (constraint_ns < 0) { + if (constraint_ns < 0) constraint_ns = dev_pm_qos_read_value(dev); - constraint_ns *= NSEC_PER_USEC; - } - if (constraint_ns == 0) + + if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) return 0; - /* - * constraint_ns cannot be negative here, because the device has been - * suspended. - */ - if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0) + constraint_ns *= NSEC_PER_USEC; + + if (constraint_ns < *constraint_ns_p || *constraint_ns_p < 0) *constraint_ns_p = constraint_ns; return 0; @@ -63,10 +60,14 @@ static bool default_suspend_ok(struct de spin_unlock_irqrestore(&dev->power.lock, flags); - if (constraint_ns < 0) + 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 @@ -76,14 +77,19 @@ static bool default_suspend_ok(struct de device_for_each_child(dev, &constraint_ns, dev_update_qos_constraint); - if (constraint_ns > 0) { - constraint_ns -= td->suspend_latency_ns + - td->resume_latency_ns; - if (constraint_ns == 0) - return false; + if (constraint_ns < 0) { + /* The children have no constraints. */ + td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; + td->cached_suspend_ok = true; + } else { + constraint_ns -= td->suspend_latency_ns + td->resume_latency_ns; + if (constraint_ns > 0) { + td->effective_constraint_ns = constraint_ns; + td->cached_suspend_ok = true; + } else { + td->effective_constraint_ns = 0; + } } - td->effective_constraint_ns = constraint_ns; - td->cached_suspend_ok = constraint_ns >= 0; /* * The children have been suspended already, so we don't need to take @@ -145,13 +151,14 @@ static bool __default_power_down_ok(stru td = &to_gpd_data(pdd)->td; constraint_ns = td->effective_constraint_ns; /* default_suspend_ok() need not be called before us. */ - if (constraint_ns < 0) { + if (constraint_ns < 0) constraint_ns = dev_pm_qos_read_value(pdd->dev); - constraint_ns *= NSEC_PER_USEC; - } - if (constraint_ns == 0) + + 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. Index: linux-pm/drivers/base/power/runtime.c =================================================================== --- linux-pm.orig/drivers/base/power/runtime.c +++ linux-pm/drivers/base/power/runtime.c @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str || (dev->power.request_pending && dev->power.request == RPM_REQ_RESUME)) retval = -EAGAIN; - else if (__dev_pm_qos_read_value(dev) < 0) + else if (__dev_pm_qos_read_value(dev) == 0) retval = -EPERM; else if (dev->power.runtime_status == RPM_SUSPENDED) retval = 1; Index: linux-pm/drivers/base/cpu.c =================================================================== --- linux-pm.orig/drivers/base/cpu.c +++ linux-pm/drivers/base/cpu.c @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu per_cpu(cpu_sys_devices, num) = &cpu->dev; register_cpu_under_node(num, cpu_to_node(num)); - dev_pm_qos_expose_latency_limit(&cpu->dev, 0); + dev_pm_qos_expose_latency_limit(&cpu->dev, + PM_QOS_RESUME_LATENCY_NO_CONSTRAINT); return 0; } Index: linux-pm/drivers/base/power/qos.c =================================================================== --- linux-pm.orig/drivers/base/power/qos.c +++ linux-pm/drivers/base/power/qos.c @@ -189,7 +189,7 @@ static int dev_pm_qos_constraints_alloca plist_head_init(&c->list); c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; - c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; + c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; c->type = PM_QOS_MIN; c->notifiers = n; Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power =================================================================== --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power @@ -211,7 +211,9 @@ Description: 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. + 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. Not all drivers support this attribute. If it isn't supported, it is not present.