Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * drivers/base/power/domain_governor.c - Governors for device PM domains.
  3 *
  4 * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
  5 *
  6 * This file is released under the GPLv2.
  7 */
  8
  9#include <linux/kernel.h>
 10#include <linux/pm_domain.h>
 11#include <linux/pm_qos.h>
 12#include <linux/hrtimer.h>
 13
 14static int dev_update_qos_constraint(struct device *dev, void *data)
 15{
 16	s64 *constraint_ns_p = data;
 17	s64 constraint_ns;
 18
 19	if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
 20		/*
 21		 * Only take suspend-time QoS constraints of devices into
 22		 * account, because constraints updated after the device has
 23		 * been suspended are not guaranteed to be taken into account
 24		 * anyway.  In order for them to take effect, the device has to
 25		 * be resumed and suspended again.
 26		 */
 27		constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
 28	} else {
 29		/*
 30		 * The child is not in a domain and there's no info on its
 31		 * suspend/resume latencies, so assume them to be negligible and
 32		 * take its current PM QoS constraint (that's the only thing
 33		 * known at this point anyway).
 34		 */
 35		constraint_ns = dev_pm_qos_read_value(dev);
 36		constraint_ns *= NSEC_PER_USEC;
 37	}
 38
 39	if (constraint_ns < *constraint_ns_p)
 40		*constraint_ns_p = constraint_ns;
 41
 42	return 0;
 43}
 44
 45/**
 46 * default_suspend_ok - Default PM domain governor routine to suspend devices.
 47 * @dev: Device to check.
 48 */
 49static bool default_suspend_ok(struct device *dev)
 50{
 51	struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
 52	unsigned long flags;
 53	s64 constraint_ns;
 54
 55	dev_dbg(dev, "%s()\n", __func__);
 56
 57	spin_lock_irqsave(&dev->power.lock, flags);
 58
 59	if (!td->constraint_changed) {
 60		bool ret = td->cached_suspend_ok;
 61
 62		spin_unlock_irqrestore(&dev->power.lock, flags);
 63		return ret;
 64	}
 65	td->constraint_changed = false;
 66	td->cached_suspend_ok = false;
 67	td->effective_constraint_ns = 0;
 68	constraint_ns = __dev_pm_qos_read_value(dev);
 69
 70	spin_unlock_irqrestore(&dev->power.lock, flags);
 71
 72	if (constraint_ns == 0)
 73		return false;
 74
 75	constraint_ns *= NSEC_PER_USEC;
 76	/*
 77	 * We can walk the children without any additional locking, because
 78	 * they all have been suspended at this point and their
 79	 * effective_constraint_ns fields won't be modified in parallel with us.
 80	 */
 81	if (!dev->power.ignore_children)
 82		device_for_each_child(dev, &constraint_ns,
 83				      dev_update_qos_constraint);
 84
 85	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
 86		/* "No restriction", so the device is allowed to suspend. */
 87		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 88		td->cached_suspend_ok = true;
 89	} else if (constraint_ns == 0) {
 90		/*
 91		 * This triggers if one of the children that don't belong to a
 92		 * domain has a zero PM QoS constraint and it's better not to
 93		 * suspend then.  effective_constraint_ns is zero already and
 94		 * cached_suspend_ok is false, so bail out.
 95		 */
 96		return false;
 97	} else {
 98		constraint_ns -= td->suspend_latency_ns +
 99				td->resume_latency_ns;
100		/*
101		 * effective_constraint_ns is zero already and cached_suspend_ok
102		 * is false, so if the computed value is not positive, return
103		 * right away.
104		 */
105		if (constraint_ns <= 0)
106			return false;
107
108		td->effective_constraint_ns = constraint_ns;
109		td->cached_suspend_ok = true;
110	}
111
112	/*
113	 * The children have been suspended already, so we don't need to take
114	 * their suspend latencies into account here.
115	 */
116	return td->cached_suspend_ok;
117}
118
119static bool __default_power_down_ok(struct dev_pm_domain *pd,
120				     unsigned int state)
121{
122	struct generic_pm_domain *genpd = pd_to_genpd(pd);
123	struct gpd_link *link;
124	struct pm_domain_data *pdd;
125	s64 min_off_time_ns;
126	s64 off_on_time_ns;
127
128	off_on_time_ns = genpd->states[state].power_off_latency_ns +
129		genpd->states[state].power_on_latency_ns;
130
131
132	min_off_time_ns = -1;
133	/*
134	 * Check if subdomains can be off for enough time.
135	 *
136	 * All subdomains have been powered off already at this point.
137	 */
138	list_for_each_entry(link, &genpd->master_links, master_node) {
139		struct generic_pm_domain *sd = link->slave;
140		s64 sd_max_off_ns = sd->max_off_time_ns;
141
142		if (sd_max_off_ns < 0)
143			continue;
144
145		/*
146		 * Check if the subdomain is allowed to be off long enough for
147		 * the current domain to turn off and on (that's how much time
148		 * it will have to wait worst case).
149		 */
150		if (sd_max_off_ns <= off_on_time_ns)
151			return false;
152
153		if (min_off_time_ns > sd_max_off_ns || min_off_time_ns < 0)
154			min_off_time_ns = sd_max_off_ns;
155	}
156
157	/*
158	 * Check if the devices in the domain can be off enough time.
159	 */
160	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
161		struct gpd_timing_data *td;
162		s64 constraint_ns;
163
164		/*
165		 * Check if the device is allowed to be off long enough for the
166		 * domain to turn off and on (that's how much time it will
167		 * have to wait worst case).
168		 */
169		td = &to_gpd_data(pdd)->td;
170		constraint_ns = td->effective_constraint_ns;
171		/*
172		 * Zero means "no suspend at all" and this runs only when all
173		 * devices in the domain are suspended, so it must be positive.
174		 */
175		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
176			continue;
177
178		if (constraint_ns <= off_on_time_ns)
179			return false;
180
181		if (min_off_time_ns > constraint_ns || min_off_time_ns < 0)
182			min_off_time_ns = constraint_ns;
183	}
184
185	/*
186	 * If the computed minimum device off time is negative, there are no
187	 * latency constraints, so the domain can spend arbitrary time in the
188	 * "off" state.
189	 */
190	if (min_off_time_ns < 0)
191		return true;
192
193	/*
194	 * The difference between the computed minimum subdomain or device off
195	 * time and the time needed to turn the domain on is the maximum
196	 * theoretical time this domain can spend in the "off" state.
197	 */
198	genpd->max_off_time_ns = min_off_time_ns -
199		genpd->states[state].power_on_latency_ns;
200	return true;
201}
202
203/**
204 * default_power_down_ok - Default generic PM domain power off governor routine.
205 * @pd: PM domain to check.
206 *
207 * This routine must be executed under the PM domain's lock.
208 */
209static bool default_power_down_ok(struct dev_pm_domain *pd)
210{
211	struct generic_pm_domain *genpd = pd_to_genpd(pd);
212	struct gpd_link *link;
213
214	if (!genpd->max_off_time_changed)
215		return genpd->cached_power_down_ok;
216
217	/*
218	 * We have to invalidate the cached results for the masters, so
219	 * use the observation that default_power_down_ok() is not
220	 * going to be called for any master until this instance
221	 * returns.
222	 */
223	list_for_each_entry(link, &genpd->slave_links, slave_node)
224		link->master->max_off_time_changed = true;
225
226	genpd->max_off_time_ns = -1;
227	genpd->max_off_time_changed = false;
228	genpd->cached_power_down_ok = true;
229	genpd->state_idx = genpd->state_count - 1;
230
231	/* Find a state to power down to, starting from the deepest. */
232	while (!__default_power_down_ok(pd, genpd->state_idx)) {
233		if (genpd->state_idx == 0) {
234			genpd->cached_power_down_ok = false;
235			break;
236		}
237		genpd->state_idx--;
238	}
239
240	return genpd->cached_power_down_ok;
241}
242
243static bool always_on_power_down_ok(struct dev_pm_domain *domain)
244{
245	return false;
246}
247
248struct dev_power_governor simple_qos_governor = {
249	.suspend_ok = default_suspend_ok,
250	.power_down_ok = default_power_down_ok,
251};
252
253/**
254 * pm_genpd_gov_always_on - A governor implementing an always-on policy
255 */
256struct dev_power_governor pm_domain_always_on_gov = {
257	.power_down_ok = always_on_power_down_ok,
258	.suspend_ok = default_suspend_ok,
259};