xref: /openbmc/linux/drivers/base/power/domain.c (revision cbc9ef02)
1f721889fSRafael J. Wysocki /*
2f721889fSRafael J. Wysocki  * drivers/base/power/domain.c - Common code related to device power domains.
3f721889fSRafael J. Wysocki  *
4f721889fSRafael J. Wysocki  * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
5f721889fSRafael J. Wysocki  *
6f721889fSRafael J. Wysocki  * This file is released under the GPLv2.
7f721889fSRafael J. Wysocki  */
8f721889fSRafael J. Wysocki 
9f721889fSRafael J. Wysocki #include <linux/init.h>
10f721889fSRafael J. Wysocki #include <linux/kernel.h>
11f721889fSRafael J. Wysocki #include <linux/io.h>
12f721889fSRafael J. Wysocki #include <linux/pm_runtime.h>
13f721889fSRafael J. Wysocki #include <linux/pm_domain.h>
146ff7bb0dSRafael J. Wysocki #include <linux/pm_qos.h>
15f721889fSRafael J. Wysocki #include <linux/slab.h>
16f721889fSRafael J. Wysocki #include <linux/err.h>
1717b75ecaSRafael J. Wysocki #include <linux/sched.h>
1817b75ecaSRafael J. Wysocki #include <linux/suspend.h>
19d5e4cbfeSRafael J. Wysocki #include <linux/export.h>
20d5e4cbfeSRafael J. Wysocki 
21d5e4cbfeSRafael J. Wysocki #define GENPD_DEV_CALLBACK(genpd, type, callback, dev)		\
22d5e4cbfeSRafael J. Wysocki ({								\
23d5e4cbfeSRafael J. Wysocki 	type (*__routine)(struct device *__d); 			\
24d5e4cbfeSRafael J. Wysocki 	type __ret = (type)0;					\
25d5e4cbfeSRafael J. Wysocki 								\
26d5e4cbfeSRafael J. Wysocki 	__routine = genpd->dev_ops.callback; 			\
27d5e4cbfeSRafael J. Wysocki 	if (__routine) {					\
28d5e4cbfeSRafael J. Wysocki 		__ret = __routine(dev); 			\
29d5e4cbfeSRafael J. Wysocki 	} else {						\
30d5e4cbfeSRafael J. Wysocki 		__routine = dev_gpd_data(dev)->ops.callback;	\
31d5e4cbfeSRafael J. Wysocki 		if (__routine) 					\
32d5e4cbfeSRafael J. Wysocki 			__ret = __routine(dev);			\
33d5e4cbfeSRafael J. Wysocki 	}							\
34d5e4cbfeSRafael J. Wysocki 	__ret;							\
35d5e4cbfeSRafael J. Wysocki })
36f721889fSRafael J. Wysocki 
370140d8bdSRafael J. Wysocki #define GENPD_DEV_TIMED_CALLBACK(genpd, type, callback, dev, field, name)	\
380140d8bdSRafael J. Wysocki ({										\
390140d8bdSRafael J. Wysocki 	ktime_t __start = ktime_get();						\
400140d8bdSRafael J. Wysocki 	type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev);		\
410140d8bdSRafael J. Wysocki 	s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start));		\
426ff7bb0dSRafael J. Wysocki 	struct gpd_timing_data *__td = &dev_gpd_data(dev)->td;			\
436ff7bb0dSRafael J. Wysocki 	if (!__retval && __elapsed > __td->field) {				\
446ff7bb0dSRafael J. Wysocki 		__td->field = __elapsed;					\
450140d8bdSRafael J. Wysocki 		dev_warn(dev, name " latency exceeded, new value %lld ns\n",	\
460140d8bdSRafael J. Wysocki 			__elapsed);						\
476ff7bb0dSRafael J. Wysocki 		genpd->max_off_time_changed = true;				\
486ff7bb0dSRafael J. Wysocki 		__td->constraint_changed = true;				\
490140d8bdSRafael J. Wysocki 	}									\
500140d8bdSRafael J. Wysocki 	__retval;								\
510140d8bdSRafael J. Wysocki })
520140d8bdSRafael J. Wysocki 
535125bbf3SRafael J. Wysocki static LIST_HEAD(gpd_list);
545125bbf3SRafael J. Wysocki static DEFINE_MUTEX(gpd_list_lock);
555125bbf3SRafael J. Wysocki 
565248051bSRafael J. Wysocki #ifdef CONFIG_PM
575248051bSRafael J. Wysocki 
58b02c999aSRafael J. Wysocki struct generic_pm_domain *dev_to_genpd(struct device *dev)
595248051bSRafael J. Wysocki {
605248051bSRafael J. Wysocki 	if (IS_ERR_OR_NULL(dev->pm_domain))
615248051bSRafael J. Wysocki 		return ERR_PTR(-EINVAL);
625248051bSRafael J. Wysocki 
63596ba34bSRafael J. Wysocki 	return pd_to_genpd(dev->pm_domain);
645248051bSRafael J. Wysocki }
65f721889fSRafael J. Wysocki 
66d5e4cbfeSRafael J. Wysocki static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
67d5e4cbfeSRafael J. Wysocki {
680140d8bdSRafael J. Wysocki 	return GENPD_DEV_TIMED_CALLBACK(genpd, int, stop, dev,
690140d8bdSRafael J. Wysocki 					stop_latency_ns, "stop");
70d5e4cbfeSRafael J. Wysocki }
71d5e4cbfeSRafael J. Wysocki 
72d5e4cbfeSRafael J. Wysocki static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
73d5e4cbfeSRafael J. Wysocki {
740140d8bdSRafael J. Wysocki 	return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev,
750140d8bdSRafael J. Wysocki 					start_latency_ns, "start");
76d5e4cbfeSRafael J. Wysocki }
77d5e4cbfeSRafael J. Wysocki 
78ecf00475SRafael J. Wysocki static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
79ecf00475SRafael J. Wysocki {
800140d8bdSRafael J. Wysocki 	return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
810140d8bdSRafael J. Wysocki 					save_state_latency_ns, "state save");
82ecf00475SRafael J. Wysocki }
83ecf00475SRafael J. Wysocki 
84ecf00475SRafael J. Wysocki static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
85ecf00475SRafael J. Wysocki {
860140d8bdSRafael J. Wysocki 	return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
870140d8bdSRafael J. Wysocki 					restore_state_latency_ns,
880140d8bdSRafael J. Wysocki 					"state restore");
89ecf00475SRafael J. Wysocki }
90ecf00475SRafael J. Wysocki 
91c4bb3160SRafael J. Wysocki static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
92f721889fSRafael J. Wysocki {
93c4bb3160SRafael J. Wysocki 	bool ret = false;
94c4bb3160SRafael J. Wysocki 
95c4bb3160SRafael J. Wysocki 	if (!WARN_ON(atomic_read(&genpd->sd_count) == 0))
96c4bb3160SRafael J. Wysocki 		ret = !!atomic_dec_and_test(&genpd->sd_count);
97c4bb3160SRafael J. Wysocki 
98c4bb3160SRafael J. Wysocki 	return ret;
99c4bb3160SRafael J. Wysocki }
100c4bb3160SRafael J. Wysocki 
101c4bb3160SRafael J. Wysocki static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
102c4bb3160SRafael J. Wysocki {
103c4bb3160SRafael J. Wysocki 	atomic_inc(&genpd->sd_count);
104c4bb3160SRafael J. Wysocki 	smp_mb__after_atomic_inc();
105f721889fSRafael J. Wysocki }
106f721889fSRafael J. Wysocki 
10717b75ecaSRafael J. Wysocki static void genpd_acquire_lock(struct generic_pm_domain *genpd)
10817b75ecaSRafael J. Wysocki {
10917b75ecaSRafael J. Wysocki 	DEFINE_WAIT(wait);
11017b75ecaSRafael J. Wysocki 
11117b75ecaSRafael J. Wysocki 	mutex_lock(&genpd->lock);
11217b75ecaSRafael J. Wysocki 	/*
11317b75ecaSRafael J. Wysocki 	 * Wait for the domain to transition into either the active,
11417b75ecaSRafael J. Wysocki 	 * or the power off state.
11517b75ecaSRafael J. Wysocki 	 */
11617b75ecaSRafael J. Wysocki 	for (;;) {
11717b75ecaSRafael J. Wysocki 		prepare_to_wait(&genpd->status_wait_queue, &wait,
11817b75ecaSRafael J. Wysocki 				TASK_UNINTERRUPTIBLE);
119c6d22b37SRafael J. Wysocki 		if (genpd->status == GPD_STATE_ACTIVE
120c6d22b37SRafael J. Wysocki 		    || genpd->status == GPD_STATE_POWER_OFF)
12117b75ecaSRafael J. Wysocki 			break;
12217b75ecaSRafael J. Wysocki 		mutex_unlock(&genpd->lock);
12317b75ecaSRafael J. Wysocki 
12417b75ecaSRafael J. Wysocki 		schedule();
12517b75ecaSRafael J. Wysocki 
12617b75ecaSRafael J. Wysocki 		mutex_lock(&genpd->lock);
12717b75ecaSRafael J. Wysocki 	}
12817b75ecaSRafael J. Wysocki 	finish_wait(&genpd->status_wait_queue, &wait);
12917b75ecaSRafael J. Wysocki }
13017b75ecaSRafael J. Wysocki 
13117b75ecaSRafael J. Wysocki static void genpd_release_lock(struct generic_pm_domain *genpd)
13217b75ecaSRafael J. Wysocki {
13317b75ecaSRafael J. Wysocki 	mutex_unlock(&genpd->lock);
13417b75ecaSRafael J. Wysocki }
13517b75ecaSRafael J. Wysocki 
136c6d22b37SRafael J. Wysocki static void genpd_set_active(struct generic_pm_domain *genpd)
137c6d22b37SRafael J. Wysocki {
138c6d22b37SRafael J. Wysocki 	if (genpd->resume_count == 0)
139c6d22b37SRafael J. Wysocki 		genpd->status = GPD_STATE_ACTIVE;
140c6d22b37SRafael J. Wysocki }
141c6d22b37SRafael J. Wysocki 
142cbc9ef02SRafael J. Wysocki static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
143cbc9ef02SRafael J. Wysocki {
144cbc9ef02SRafael J. Wysocki 	s64 usecs64;
145cbc9ef02SRafael J. Wysocki 
146cbc9ef02SRafael J. Wysocki 	if (!genpd->cpu_data)
147cbc9ef02SRafael J. Wysocki 		return;
148cbc9ef02SRafael J. Wysocki 
149cbc9ef02SRafael J. Wysocki 	usecs64 = genpd->power_on_latency_ns;
150cbc9ef02SRafael J. Wysocki 	do_div(usecs64, NSEC_PER_USEC);
151cbc9ef02SRafael J. Wysocki 	usecs64 += genpd->cpu_data->saved_exit_latency;
152cbc9ef02SRafael J. Wysocki 	genpd->cpu_data->idle_state->exit_latency = usecs64;
153cbc9ef02SRafael J. Wysocki }
154cbc9ef02SRafael J. Wysocki 
155f721889fSRafael J. Wysocki /**
1565063ce15SRafael J. Wysocki  * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
1575248051bSRafael J. Wysocki  * @genpd: PM domain to power up.
1585248051bSRafael J. Wysocki  *
1595063ce15SRafael J. Wysocki  * Restore power to @genpd and all of its masters so that it is possible to
1605248051bSRafael J. Wysocki  * resume a device belonging to it.
1615248051bSRafael J. Wysocki  */
1623f241775SRafael J. Wysocki int __pm_genpd_poweron(struct generic_pm_domain *genpd)
1633f241775SRafael J. Wysocki 	__releases(&genpd->lock) __acquires(&genpd->lock)
1645248051bSRafael J. Wysocki {
1655063ce15SRafael J. Wysocki 	struct gpd_link *link;
1663f241775SRafael J. Wysocki 	DEFINE_WAIT(wait);
1675248051bSRafael J. Wysocki 	int ret = 0;
1685248051bSRafael J. Wysocki 
1695063ce15SRafael J. Wysocki 	/* If the domain's master is being waited for, we have to wait too. */
1703f241775SRafael J. Wysocki 	for (;;) {
1713f241775SRafael J. Wysocki 		prepare_to_wait(&genpd->status_wait_queue, &wait,
1723f241775SRafael J. Wysocki 				TASK_UNINTERRUPTIBLE);
17317877eb5SRafael J. Wysocki 		if (genpd->status != GPD_STATE_WAIT_MASTER)
1743f241775SRafael J. Wysocki 			break;
1753f241775SRafael J. Wysocki 		mutex_unlock(&genpd->lock);
1763f241775SRafael J. Wysocki 
1773f241775SRafael J. Wysocki 		schedule();
1783f241775SRafael J. Wysocki 
17917b75ecaSRafael J. Wysocki 		mutex_lock(&genpd->lock);
1803f241775SRafael J. Wysocki 	}
1813f241775SRafael J. Wysocki 	finish_wait(&genpd->status_wait_queue, &wait);
18217b75ecaSRafael J. Wysocki 
18317b75ecaSRafael J. Wysocki 	if (genpd->status == GPD_STATE_ACTIVE
184596ba34bSRafael J. Wysocki 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
1853f241775SRafael J. Wysocki 		return 0;
1865248051bSRafael J. Wysocki 
187c6d22b37SRafael J. Wysocki 	if (genpd->status != GPD_STATE_POWER_OFF) {
188c6d22b37SRafael J. Wysocki 		genpd_set_active(genpd);
1893f241775SRafael J. Wysocki 		return 0;
190c6d22b37SRafael J. Wysocki 	}
191c6d22b37SRafael J. Wysocki 
192cbc9ef02SRafael J. Wysocki 	if (genpd->cpu_data) {
193cbc9ef02SRafael J. Wysocki 		cpuidle_pause_and_lock();
194cbc9ef02SRafael J. Wysocki 		genpd->cpu_data->idle_state->disabled = true;
195cbc9ef02SRafael J. Wysocki 		cpuidle_resume_and_unlock();
196cbc9ef02SRafael J. Wysocki 		goto out;
197cbc9ef02SRafael J. Wysocki 	}
198cbc9ef02SRafael J. Wysocki 
1995063ce15SRafael J. Wysocki 	/*
2005063ce15SRafael J. Wysocki 	 * The list is guaranteed not to change while the loop below is being
2015063ce15SRafael J. Wysocki 	 * executed, unless one of the masters' .power_on() callbacks fiddles
2025063ce15SRafael J. Wysocki 	 * with it.
2035063ce15SRafael J. Wysocki 	 */
2045063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
2055063ce15SRafael J. Wysocki 		genpd_sd_counter_inc(link->master);
20617877eb5SRafael J. Wysocki 		genpd->status = GPD_STATE_WAIT_MASTER;
2073c07cbc4SRafael J. Wysocki 
2085248051bSRafael J. Wysocki 		mutex_unlock(&genpd->lock);
2095248051bSRafael J. Wysocki 
2105063ce15SRafael J. Wysocki 		ret = pm_genpd_poweron(link->master);
2119e08cf42SRafael J. Wysocki 
2129e08cf42SRafael J. Wysocki 		mutex_lock(&genpd->lock);
2139e08cf42SRafael J. Wysocki 
2143f241775SRafael J. Wysocki 		/*
2153f241775SRafael J. Wysocki 		 * The "wait for parent" status is guaranteed not to change
2165063ce15SRafael J. Wysocki 		 * while the master is powering on.
2173f241775SRafael J. Wysocki 		 */
2183f241775SRafael J. Wysocki 		genpd->status = GPD_STATE_POWER_OFF;
2193f241775SRafael J. Wysocki 		wake_up_all(&genpd->status_wait_queue);
2205063ce15SRafael J. Wysocki 		if (ret) {
2215063ce15SRafael J. Wysocki 			genpd_sd_counter_dec(link->master);
2229e08cf42SRafael J. Wysocki 			goto err;
2235248051bSRafael J. Wysocki 		}
2245063ce15SRafael J. Wysocki 	}
2255248051bSRafael J. Wysocki 
2269e08cf42SRafael J. Wysocki 	if (genpd->power_on) {
2270140d8bdSRafael J. Wysocki 		ktime_t time_start = ktime_get();
2280140d8bdSRafael J. Wysocki 		s64 elapsed_ns;
2290140d8bdSRafael J. Wysocki 
230fe202fdeSRafael J. Wysocki 		ret = genpd->power_on(genpd);
2319e08cf42SRafael J. Wysocki 		if (ret)
2329e08cf42SRafael J. Wysocki 			goto err;
2330140d8bdSRafael J. Wysocki 
2340140d8bdSRafael J. Wysocki 		elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
235e84b2c20SRafael J. Wysocki 		if (elapsed_ns > genpd->power_on_latency_ns) {
2360140d8bdSRafael J. Wysocki 			genpd->power_on_latency_ns = elapsed_ns;
2376ff7bb0dSRafael J. Wysocki 			genpd->max_off_time_changed = true;
238cbc9ef02SRafael J. Wysocki 			genpd_recalc_cpu_exit_latency(genpd);
239e84b2c20SRafael J. Wysocki 			if (genpd->name)
240e84b2c20SRafael J. Wysocki 				pr_warning("%s: Power-on latency exceeded, "
241e84b2c20SRafael J. Wysocki 					"new value %lld ns\n", genpd->name,
242e84b2c20SRafael J. Wysocki 					elapsed_ns);
243e84b2c20SRafael J. Wysocki 		}
2443c07cbc4SRafael J. Wysocki 	}
2455248051bSRafael J. Wysocki 
246cbc9ef02SRafael J. Wysocki  out:
2479e08cf42SRafael J. Wysocki 	genpd_set_active(genpd);
2489e08cf42SRafael J. Wysocki 
2493f241775SRafael J. Wysocki 	return 0;
2509e08cf42SRafael J. Wysocki 
2519e08cf42SRafael J. Wysocki  err:
2525063ce15SRafael J. Wysocki 	list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node)
2535063ce15SRafael J. Wysocki 		genpd_sd_counter_dec(link->master);
2549e08cf42SRafael J. Wysocki 
2553f241775SRafael J. Wysocki 	return ret;
2563f241775SRafael J. Wysocki }
2573f241775SRafael J. Wysocki 
2583f241775SRafael J. Wysocki /**
2595063ce15SRafael J. Wysocki  * pm_genpd_poweron - Restore power to a given PM domain and its masters.
2603f241775SRafael J. Wysocki  * @genpd: PM domain to power up.
2613f241775SRafael J. Wysocki  */
2623f241775SRafael J. Wysocki int pm_genpd_poweron(struct generic_pm_domain *genpd)
2633f241775SRafael J. Wysocki {
2643f241775SRafael J. Wysocki 	int ret;
2653f241775SRafael J. Wysocki 
2663f241775SRafael J. Wysocki 	mutex_lock(&genpd->lock);
2673f241775SRafael J. Wysocki 	ret = __pm_genpd_poweron(genpd);
2683f241775SRafael J. Wysocki 	mutex_unlock(&genpd->lock);
2693f241775SRafael J. Wysocki 	return ret;
2705248051bSRafael J. Wysocki }
2715248051bSRafael J. Wysocki 
2725248051bSRafael J. Wysocki #endif /* CONFIG_PM */
2735248051bSRafael J. Wysocki 
2745248051bSRafael J. Wysocki #ifdef CONFIG_PM_RUNTIME
2755248051bSRafael J. Wysocki 
2766ff7bb0dSRafael J. Wysocki static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
2776ff7bb0dSRafael J. Wysocki 				     unsigned long val, void *ptr)
2786ff7bb0dSRafael J. Wysocki {
2796ff7bb0dSRafael J. Wysocki 	struct generic_pm_domain_data *gpd_data;
2806ff7bb0dSRafael J. Wysocki 	struct device *dev;
2816ff7bb0dSRafael J. Wysocki 
2826ff7bb0dSRafael J. Wysocki 	gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
2836ff7bb0dSRafael J. Wysocki 
2846ff7bb0dSRafael J. Wysocki 	mutex_lock(&gpd_data->lock);
2856ff7bb0dSRafael J. Wysocki 	dev = gpd_data->base.dev;
2866ff7bb0dSRafael J. Wysocki 	if (!dev) {
2876ff7bb0dSRafael J. Wysocki 		mutex_unlock(&gpd_data->lock);
2886ff7bb0dSRafael J. Wysocki 		return NOTIFY_DONE;
2896ff7bb0dSRafael J. Wysocki 	}
2906ff7bb0dSRafael J. Wysocki 	mutex_unlock(&gpd_data->lock);
2916ff7bb0dSRafael J. Wysocki 
2926ff7bb0dSRafael J. Wysocki 	for (;;) {
2936ff7bb0dSRafael J. Wysocki 		struct generic_pm_domain *genpd;
2946ff7bb0dSRafael J. Wysocki 		struct pm_domain_data *pdd;
2956ff7bb0dSRafael J. Wysocki 
2966ff7bb0dSRafael J. Wysocki 		spin_lock_irq(&dev->power.lock);
2976ff7bb0dSRafael J. Wysocki 
2986ff7bb0dSRafael J. Wysocki 		pdd = dev->power.subsys_data ?
2996ff7bb0dSRafael J. Wysocki 				dev->power.subsys_data->domain_data : NULL;
3006ff7bb0dSRafael J. Wysocki 		if (pdd) {
3016ff7bb0dSRafael J. Wysocki 			to_gpd_data(pdd)->td.constraint_changed = true;
3026ff7bb0dSRafael J. Wysocki 			genpd = dev_to_genpd(dev);
3036ff7bb0dSRafael J. Wysocki 		} else {
3046ff7bb0dSRafael J. Wysocki 			genpd = ERR_PTR(-ENODATA);
3056ff7bb0dSRafael J. Wysocki 		}
3066ff7bb0dSRafael J. Wysocki 
3076ff7bb0dSRafael J. Wysocki 		spin_unlock_irq(&dev->power.lock);
3086ff7bb0dSRafael J. Wysocki 
3096ff7bb0dSRafael J. Wysocki 		if (!IS_ERR(genpd)) {
3106ff7bb0dSRafael J. Wysocki 			mutex_lock(&genpd->lock);
3116ff7bb0dSRafael J. Wysocki 			genpd->max_off_time_changed = true;
3126ff7bb0dSRafael J. Wysocki 			mutex_unlock(&genpd->lock);
3136ff7bb0dSRafael J. Wysocki 		}
3146ff7bb0dSRafael J. Wysocki 
3156ff7bb0dSRafael J. Wysocki 		dev = dev->parent;
3166ff7bb0dSRafael J. Wysocki 		if (!dev || dev->power.ignore_children)
3176ff7bb0dSRafael J. Wysocki 			break;
3186ff7bb0dSRafael J. Wysocki 	}
3196ff7bb0dSRafael J. Wysocki 
3206ff7bb0dSRafael J. Wysocki 	return NOTIFY_DONE;
3216ff7bb0dSRafael J. Wysocki }
3226ff7bb0dSRafael J. Wysocki 
3235248051bSRafael J. Wysocki /**
324f721889fSRafael J. Wysocki  * __pm_genpd_save_device - Save the pre-suspend state of a device.
3254605ab65SRafael J. Wysocki  * @pdd: Domain data of the device to save the state of.
326f721889fSRafael J. Wysocki  * @genpd: PM domain the device belongs to.
327f721889fSRafael J. Wysocki  */
3284605ab65SRafael J. Wysocki static int __pm_genpd_save_device(struct pm_domain_data *pdd,
329f721889fSRafael J. Wysocki 				  struct generic_pm_domain *genpd)
33017b75ecaSRafael J. Wysocki 	__releases(&genpd->lock) __acquires(&genpd->lock)
331f721889fSRafael J. Wysocki {
332cd0ea672SRafael J. Wysocki 	struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
3334605ab65SRafael J. Wysocki 	struct device *dev = pdd->dev;
334f721889fSRafael J. Wysocki 	int ret = 0;
335f721889fSRafael J. Wysocki 
336cd0ea672SRafael J. Wysocki 	if (gpd_data->need_restore)
337f721889fSRafael J. Wysocki 		return 0;
338f721889fSRafael J. Wysocki 
33917b75ecaSRafael J. Wysocki 	mutex_unlock(&genpd->lock);
34017b75ecaSRafael J. Wysocki 
341d5e4cbfeSRafael J. Wysocki 	genpd_start_dev(genpd, dev);
342ecf00475SRafael J. Wysocki 	ret = genpd_save_dev(genpd, dev);
343d5e4cbfeSRafael J. Wysocki 	genpd_stop_dev(genpd, dev);
344f721889fSRafael J. Wysocki 
34517b75ecaSRafael J. Wysocki 	mutex_lock(&genpd->lock);
34617b75ecaSRafael J. Wysocki 
347f721889fSRafael J. Wysocki 	if (!ret)
348cd0ea672SRafael J. Wysocki 		gpd_data->need_restore = true;
349f721889fSRafael J. Wysocki 
350f721889fSRafael J. Wysocki 	return ret;
351f721889fSRafael J. Wysocki }
352f721889fSRafael J. Wysocki 
353f721889fSRafael J. Wysocki /**
354f721889fSRafael J. Wysocki  * __pm_genpd_restore_device - Restore the pre-suspend state of a device.
3554605ab65SRafael J. Wysocki  * @pdd: Domain data of the device to restore the state of.
356f721889fSRafael J. Wysocki  * @genpd: PM domain the device belongs to.
357f721889fSRafael J. Wysocki  */
3584605ab65SRafael J. Wysocki static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
359f721889fSRafael J. Wysocki 				      struct generic_pm_domain *genpd)
36017b75ecaSRafael J. Wysocki 	__releases(&genpd->lock) __acquires(&genpd->lock)
361f721889fSRafael J. Wysocki {
362cd0ea672SRafael J. Wysocki 	struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
3634605ab65SRafael J. Wysocki 	struct device *dev = pdd->dev;
36480de3d7fSRafael J. Wysocki 	bool need_restore = gpd_data->need_restore;
365f721889fSRafael J. Wysocki 
36680de3d7fSRafael J. Wysocki 	gpd_data->need_restore = false;
36717b75ecaSRafael J. Wysocki 	mutex_unlock(&genpd->lock);
36817b75ecaSRafael J. Wysocki 
369d5e4cbfeSRafael J. Wysocki 	genpd_start_dev(genpd, dev);
37080de3d7fSRafael J. Wysocki 	if (need_restore)
371ecf00475SRafael J. Wysocki 		genpd_restore_dev(genpd, dev);
372f721889fSRafael J. Wysocki 
37317b75ecaSRafael J. Wysocki 	mutex_lock(&genpd->lock);
374f721889fSRafael J. Wysocki }
375f721889fSRafael J. Wysocki 
376f721889fSRafael J. Wysocki /**
377c6d22b37SRafael J. Wysocki  * genpd_abort_poweroff - Check if a PM domain power off should be aborted.
378c6d22b37SRafael J. Wysocki  * @genpd: PM domain to check.
379c6d22b37SRafael J. Wysocki  *
380c6d22b37SRafael J. Wysocki  * Return true if a PM domain's status changed to GPD_STATE_ACTIVE during
381c6d22b37SRafael J. Wysocki  * a "power off" operation, which means that a "power on" has occured in the
382c6d22b37SRafael J. Wysocki  * meantime, or if its resume_count field is different from zero, which means
383c6d22b37SRafael J. Wysocki  * that one of its devices has been resumed in the meantime.
384c6d22b37SRafael J. Wysocki  */
385c6d22b37SRafael J. Wysocki static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
386c6d22b37SRafael J. Wysocki {
38717877eb5SRafael J. Wysocki 	return genpd->status == GPD_STATE_WAIT_MASTER
3883f241775SRafael J. Wysocki 		|| genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
389c6d22b37SRafael J. Wysocki }
390c6d22b37SRafael J. Wysocki 
391c6d22b37SRafael J. Wysocki /**
39256375fd4SRafael J. Wysocki  * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff().
39356375fd4SRafael J. Wysocki  * @genpd: PM domait to power off.
39456375fd4SRafael J. Wysocki  *
39556375fd4SRafael J. Wysocki  * Queue up the execution of pm_genpd_poweroff() unless it's already been done
39656375fd4SRafael J. Wysocki  * before.
39756375fd4SRafael J. Wysocki  */
3980bc5b2deSRafael J. Wysocki void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
39956375fd4SRafael J. Wysocki {
40056375fd4SRafael J. Wysocki 	if (!work_pending(&genpd->power_off_work))
40156375fd4SRafael J. Wysocki 		queue_work(pm_wq, &genpd->power_off_work);
40256375fd4SRafael J. Wysocki }
40356375fd4SRafael J. Wysocki 
40456375fd4SRafael J. Wysocki /**
405f721889fSRafael J. Wysocki  * pm_genpd_poweroff - Remove power from a given PM domain.
406f721889fSRafael J. Wysocki  * @genpd: PM domain to power down.
407f721889fSRafael J. Wysocki  *
408f721889fSRafael J. Wysocki  * If all of the @genpd's devices have been suspended and all of its subdomains
409f721889fSRafael J. Wysocki  * have been powered down, run the runtime suspend callbacks provided by all of
410f721889fSRafael J. Wysocki  * the @genpd's devices' drivers and remove power from @genpd.
411f721889fSRafael J. Wysocki  */
412f721889fSRafael J. Wysocki static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
41317b75ecaSRafael J. Wysocki 	__releases(&genpd->lock) __acquires(&genpd->lock)
414f721889fSRafael J. Wysocki {
4154605ab65SRafael J. Wysocki 	struct pm_domain_data *pdd;
4165063ce15SRafael J. Wysocki 	struct gpd_link *link;
417f721889fSRafael J. Wysocki 	unsigned int not_suspended;
418c6d22b37SRafael J. Wysocki 	int ret = 0;
419f721889fSRafael J. Wysocki 
420c6d22b37SRafael J. Wysocki  start:
421c6d22b37SRafael J. Wysocki 	/*
422c6d22b37SRafael J. Wysocki 	 * Do not try to power off the domain in the following situations:
423c6d22b37SRafael J. Wysocki 	 * (1) The domain is already in the "power off" state.
4245063ce15SRafael J. Wysocki 	 * (2) The domain is waiting for its master to power up.
425c6d22b37SRafael J. Wysocki 	 * (3) One of the domain's devices is being resumed right now.
4263f241775SRafael J. Wysocki 	 * (4) System suspend is in progress.
427c6d22b37SRafael J. Wysocki 	 */
4283f241775SRafael J. Wysocki 	if (genpd->status == GPD_STATE_POWER_OFF
42917877eb5SRafael J. Wysocki 	    || genpd->status == GPD_STATE_WAIT_MASTER
4303f241775SRafael J. Wysocki 	    || genpd->resume_count > 0 || genpd->prepared_count > 0)
431f721889fSRafael J. Wysocki 		return 0;
432f721889fSRafael J. Wysocki 
433c4bb3160SRafael J. Wysocki 	if (atomic_read(&genpd->sd_count) > 0)
434f721889fSRafael J. Wysocki 		return -EBUSY;
435f721889fSRafael J. Wysocki 
436f721889fSRafael J. Wysocki 	not_suspended = 0;
4374605ab65SRafael J. Wysocki 	list_for_each_entry(pdd, &genpd->dev_list, list_node)
4380aa2a221SRafael J. Wysocki 		if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
4391e78a0c7SRafael J. Wysocki 		    || pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on))
440f721889fSRafael J. Wysocki 			not_suspended++;
441f721889fSRafael J. Wysocki 
442f721889fSRafael J. Wysocki 	if (not_suspended > genpd->in_progress)
443f721889fSRafael J. Wysocki 		return -EBUSY;
444f721889fSRafael J. Wysocki 
445c6d22b37SRafael J. Wysocki 	if (genpd->poweroff_task) {
446c6d22b37SRafael J. Wysocki 		/*
447c6d22b37SRafael J. Wysocki 		 * Another instance of pm_genpd_poweroff() is executing
448c6d22b37SRafael J. Wysocki 		 * callbacks, so tell it to start over and return.
449c6d22b37SRafael J. Wysocki 		 */
450c6d22b37SRafael J. Wysocki 		genpd->status = GPD_STATE_REPEAT;
451c6d22b37SRafael J. Wysocki 		return 0;
452c6d22b37SRafael J. Wysocki 	}
453c6d22b37SRafael J. Wysocki 
454f721889fSRafael J. Wysocki 	if (genpd->gov && genpd->gov->power_down_ok) {
455f721889fSRafael J. Wysocki 		if (!genpd->gov->power_down_ok(&genpd->domain))
456f721889fSRafael J. Wysocki 			return -EAGAIN;
457f721889fSRafael J. Wysocki 	}
458f721889fSRafael J. Wysocki 
45917b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_BUSY;
460c6d22b37SRafael J. Wysocki 	genpd->poweroff_task = current;
46117b75ecaSRafael J. Wysocki 
4624605ab65SRafael J. Wysocki 	list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
4633c07cbc4SRafael J. Wysocki 		ret = atomic_read(&genpd->sd_count) == 0 ?
4644605ab65SRafael J. Wysocki 			__pm_genpd_save_device(pdd, genpd) : -EBUSY;
4653f241775SRafael J. Wysocki 
4663f241775SRafael J. Wysocki 		if (genpd_abort_poweroff(genpd))
4673f241775SRafael J. Wysocki 			goto out;
4683f241775SRafael J. Wysocki 
469697a7f37SRafael J. Wysocki 		if (ret) {
470697a7f37SRafael J. Wysocki 			genpd_set_active(genpd);
471697a7f37SRafael J. Wysocki 			goto out;
472697a7f37SRafael J. Wysocki 		}
473f721889fSRafael J. Wysocki 
474c6d22b37SRafael J. Wysocki 		if (genpd->status == GPD_STATE_REPEAT) {
475c6d22b37SRafael J. Wysocki 			genpd->poweroff_task = NULL;
476c6d22b37SRafael J. Wysocki 			goto start;
477c6d22b37SRafael J. Wysocki 		}
478c6d22b37SRafael J. Wysocki 	}
47917b75ecaSRafael J. Wysocki 
480cbc9ef02SRafael J. Wysocki 	if (genpd->cpu_data) {
481cbc9ef02SRafael J. Wysocki 		/*
482cbc9ef02SRafael J. Wysocki 		 * If cpu_data is set, cpuidle should turn the domain off when
483cbc9ef02SRafael J. Wysocki 		 * the CPU in it is idle.  In that case we don't decrement the
484cbc9ef02SRafael J. Wysocki 		 * subdomain counts of the master domains, so that power is not
485cbc9ef02SRafael J. Wysocki 		 * removed from the current domain prematurely as a result of
486cbc9ef02SRafael J. Wysocki 		 * cutting off the masters' power.
487cbc9ef02SRafael J. Wysocki 		 */
488cbc9ef02SRafael J. Wysocki 		genpd->status = GPD_STATE_POWER_OFF;
489cbc9ef02SRafael J. Wysocki 		cpuidle_pause_and_lock();
490cbc9ef02SRafael J. Wysocki 		genpd->cpu_data->idle_state->disabled = false;
491cbc9ef02SRafael J. Wysocki 		cpuidle_resume_and_unlock();
492cbc9ef02SRafael J. Wysocki 		goto out;
493cbc9ef02SRafael J. Wysocki 	}
494cbc9ef02SRafael J. Wysocki 
4953c07cbc4SRafael J. Wysocki 	if (genpd->power_off) {
4960140d8bdSRafael J. Wysocki 		ktime_t time_start;
4970140d8bdSRafael J. Wysocki 		s64 elapsed_ns;
4980140d8bdSRafael J. Wysocki 
4993c07cbc4SRafael J. Wysocki 		if (atomic_read(&genpd->sd_count) > 0) {
5003c07cbc4SRafael J. Wysocki 			ret = -EBUSY;
501c6d22b37SRafael J. Wysocki 			goto out;
502c6d22b37SRafael J. Wysocki 		}
50317b75ecaSRafael J. Wysocki 
5040140d8bdSRafael J. Wysocki 		time_start = ktime_get();
5050140d8bdSRafael J. Wysocki 
5063c07cbc4SRafael J. Wysocki 		/*
5075063ce15SRafael J. Wysocki 		 * If sd_count > 0 at this point, one of the subdomains hasn't
5085063ce15SRafael J. Wysocki 		 * managed to call pm_genpd_poweron() for the master yet after
5093c07cbc4SRafael J. Wysocki 		 * incrementing it.  In that case pm_genpd_poweron() will wait
5103c07cbc4SRafael J. Wysocki 		 * for us to drop the lock, so we can call .power_off() and let
5113c07cbc4SRafael J. Wysocki 		 * the pm_genpd_poweron() restore power for us (this shouldn't
5123c07cbc4SRafael J. Wysocki 		 * happen very often).
5133c07cbc4SRafael J. Wysocki 		 */
514d2805402SRafael J. Wysocki 		ret = genpd->power_off(genpd);
515d2805402SRafael J. Wysocki 		if (ret == -EBUSY) {
516d2805402SRafael J. Wysocki 			genpd_set_active(genpd);
517d2805402SRafael J. Wysocki 			goto out;
518d2805402SRafael J. Wysocki 		}
5190140d8bdSRafael J. Wysocki 
5200140d8bdSRafael J. Wysocki 		elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
521e84b2c20SRafael J. Wysocki 		if (elapsed_ns > genpd->power_off_latency_ns) {
5220140d8bdSRafael J. Wysocki 			genpd->power_off_latency_ns = elapsed_ns;
5236ff7bb0dSRafael J. Wysocki 			genpd->max_off_time_changed = true;
524e84b2c20SRafael J. Wysocki 			if (genpd->name)
525e84b2c20SRafael J. Wysocki 				pr_warning("%s: Power-off latency exceeded, "
526e84b2c20SRafael J. Wysocki 					"new value %lld ns\n", genpd->name,
527e84b2c20SRafael J. Wysocki 					elapsed_ns);
528e84b2c20SRafael J. Wysocki 		}
529d2805402SRafael J. Wysocki 	}
530f721889fSRafael J. Wysocki 
53117b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_POWER_OFF;
532221e9b58SRafael J. Wysocki 
5335063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
5345063ce15SRafael J. Wysocki 		genpd_sd_counter_dec(link->master);
5355063ce15SRafael J. Wysocki 		genpd_queue_power_off_work(link->master);
5365063ce15SRafael J. Wysocki 	}
53717b75ecaSRafael J. Wysocki 
538c6d22b37SRafael J. Wysocki  out:
539c6d22b37SRafael J. Wysocki 	genpd->poweroff_task = NULL;
540c6d22b37SRafael J. Wysocki 	wake_up_all(&genpd->status_wait_queue);
541c6d22b37SRafael J. Wysocki 	return ret;
542f721889fSRafael J. Wysocki }
543f721889fSRafael J. Wysocki 
544f721889fSRafael J. Wysocki /**
545f721889fSRafael J. Wysocki  * genpd_power_off_work_fn - Power off PM domain whose subdomain count is 0.
546f721889fSRafael J. Wysocki  * @work: Work structure used for scheduling the execution of this function.
547f721889fSRafael J. Wysocki  */
548f721889fSRafael J. Wysocki static void genpd_power_off_work_fn(struct work_struct *work)
549f721889fSRafael J. Wysocki {
550f721889fSRafael J. Wysocki 	struct generic_pm_domain *genpd;
551f721889fSRafael J. Wysocki 
552f721889fSRafael J. Wysocki 	genpd = container_of(work, struct generic_pm_domain, power_off_work);
553f721889fSRafael J. Wysocki 
55417b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
555f721889fSRafael J. Wysocki 	pm_genpd_poweroff(genpd);
55617b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
557f721889fSRafael J. Wysocki }
558f721889fSRafael J. Wysocki 
559f721889fSRafael J. Wysocki /**
560f721889fSRafael J. Wysocki  * pm_genpd_runtime_suspend - Suspend a device belonging to I/O PM domain.
561f721889fSRafael J. Wysocki  * @dev: Device to suspend.
562f721889fSRafael J. Wysocki  *
563f721889fSRafael J. Wysocki  * Carry out a runtime suspend of a device under the assumption that its
564f721889fSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
565f721889fSRafael J. Wysocki  * struct generic_pm_domain representing a PM domain consisting of I/O devices.
566f721889fSRafael J. Wysocki  */
567f721889fSRafael J. Wysocki static int pm_genpd_runtime_suspend(struct device *dev)
568f721889fSRafael J. Wysocki {
569f721889fSRafael J. Wysocki 	struct generic_pm_domain *genpd;
570b02c999aSRafael J. Wysocki 	bool (*stop_ok)(struct device *__dev);
571d5e4cbfeSRafael J. Wysocki 	int ret;
572f721889fSRafael J. Wysocki 
573f721889fSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
574f721889fSRafael J. Wysocki 
5755248051bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
5765248051bSRafael J. Wysocki 	if (IS_ERR(genpd))
577f721889fSRafael J. Wysocki 		return -EINVAL;
578f721889fSRafael J. Wysocki 
5790aa2a221SRafael J. Wysocki 	might_sleep_if(!genpd->dev_irq_safe);
5800aa2a221SRafael J. Wysocki 
5811e78a0c7SRafael J. Wysocki 	if (dev_gpd_data(dev)->always_on)
5821e78a0c7SRafael J. Wysocki 		return -EBUSY;
5831e78a0c7SRafael J. Wysocki 
584b02c999aSRafael J. Wysocki 	stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
585b02c999aSRafael J. Wysocki 	if (stop_ok && !stop_ok(dev))
586b02c999aSRafael J. Wysocki 		return -EBUSY;
587b02c999aSRafael J. Wysocki 
588d5e4cbfeSRafael J. Wysocki 	ret = genpd_stop_dev(genpd, dev);
589f721889fSRafael J. Wysocki 	if (ret)
59017b75ecaSRafael J. Wysocki 		return ret;
59117b75ecaSRafael J. Wysocki 
5920aa2a221SRafael J. Wysocki 	/*
5930aa2a221SRafael J. Wysocki 	 * If power.irq_safe is set, this routine will be run with interrupts
5940aa2a221SRafael J. Wysocki 	 * off, so it can't use mutexes.
5950aa2a221SRafael J. Wysocki 	 */
5960aa2a221SRafael J. Wysocki 	if (dev->power.irq_safe)
5970aa2a221SRafael J. Wysocki 		return 0;
5980aa2a221SRafael J. Wysocki 
599c6d22b37SRafael J. Wysocki 	mutex_lock(&genpd->lock);
600f721889fSRafael J. Wysocki 	genpd->in_progress++;
601f721889fSRafael J. Wysocki 	pm_genpd_poweroff(genpd);
602f721889fSRafael J. Wysocki 	genpd->in_progress--;
603c6d22b37SRafael J. Wysocki 	mutex_unlock(&genpd->lock);
604f721889fSRafael J. Wysocki 
605f721889fSRafael J. Wysocki 	return 0;
606f721889fSRafael J. Wysocki }
607f721889fSRafael J. Wysocki 
608f721889fSRafael J. Wysocki /**
609f721889fSRafael J. Wysocki  * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
610f721889fSRafael J. Wysocki  * @dev: Device to resume.
611f721889fSRafael J. Wysocki  *
612f721889fSRafael J. Wysocki  * Carry out a runtime resume of a device under the assumption that its
613f721889fSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
614f721889fSRafael J. Wysocki  * struct generic_pm_domain representing a PM domain consisting of I/O devices.
615f721889fSRafael J. Wysocki  */
616f721889fSRafael J. Wysocki static int pm_genpd_runtime_resume(struct device *dev)
617f721889fSRafael J. Wysocki {
618f721889fSRafael J. Wysocki 	struct generic_pm_domain *genpd;
619c6d22b37SRafael J. Wysocki 	DEFINE_WAIT(wait);
620f721889fSRafael J. Wysocki 	int ret;
621f721889fSRafael J. Wysocki 
622f721889fSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
623f721889fSRafael J. Wysocki 
6245248051bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
6255248051bSRafael J. Wysocki 	if (IS_ERR(genpd))
626f721889fSRafael J. Wysocki 		return -EINVAL;
627f721889fSRafael J. Wysocki 
6280aa2a221SRafael J. Wysocki 	might_sleep_if(!genpd->dev_irq_safe);
6290aa2a221SRafael J. Wysocki 
6300aa2a221SRafael J. Wysocki 	/* If power.irq_safe, the PM domain is never powered off. */
6310aa2a221SRafael J. Wysocki 	if (dev->power.irq_safe)
63280de3d7fSRafael J. Wysocki 		return genpd_start_dev(genpd, dev);
6330aa2a221SRafael J. Wysocki 
634c6d22b37SRafael J. Wysocki 	mutex_lock(&genpd->lock);
6353f241775SRafael J. Wysocki 	ret = __pm_genpd_poweron(genpd);
6363f241775SRafael J. Wysocki 	if (ret) {
6373f241775SRafael J. Wysocki 		mutex_unlock(&genpd->lock);
6383f241775SRafael J. Wysocki 		return ret;
6393f241775SRafael J. Wysocki 	}
64017b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_BUSY;
641c6d22b37SRafael J. Wysocki 	genpd->resume_count++;
642c6d22b37SRafael J. Wysocki 	for (;;) {
643c6d22b37SRafael J. Wysocki 		prepare_to_wait(&genpd->status_wait_queue, &wait,
644c6d22b37SRafael J. Wysocki 				TASK_UNINTERRUPTIBLE);
645c6d22b37SRafael J. Wysocki 		/*
646c6d22b37SRafael J. Wysocki 		 * If current is the powering off task, we have been called
647c6d22b37SRafael J. Wysocki 		 * reentrantly from one of the device callbacks, so we should
648c6d22b37SRafael J. Wysocki 		 * not wait.
649c6d22b37SRafael J. Wysocki 		 */
650c6d22b37SRafael J. Wysocki 		if (!genpd->poweroff_task || genpd->poweroff_task == current)
651c6d22b37SRafael J. Wysocki 			break;
652c6d22b37SRafael J. Wysocki 		mutex_unlock(&genpd->lock);
653c6d22b37SRafael J. Wysocki 
654c6d22b37SRafael J. Wysocki 		schedule();
655c6d22b37SRafael J. Wysocki 
656c6d22b37SRafael J. Wysocki 		mutex_lock(&genpd->lock);
657c6d22b37SRafael J. Wysocki 	}
658c6d22b37SRafael J. Wysocki 	finish_wait(&genpd->status_wait_queue, &wait);
659cd0ea672SRafael J. Wysocki 	__pm_genpd_restore_device(dev->power.subsys_data->domain_data, genpd);
660c6d22b37SRafael J. Wysocki 	genpd->resume_count--;
661c6d22b37SRafael J. Wysocki 	genpd_set_active(genpd);
66217b75ecaSRafael J. Wysocki 	wake_up_all(&genpd->status_wait_queue);
663c6d22b37SRafael J. Wysocki 	mutex_unlock(&genpd->lock);
66417b75ecaSRafael J. Wysocki 
665f721889fSRafael J. Wysocki 	return 0;
666f721889fSRafael J. Wysocki }
667f721889fSRafael J. Wysocki 
66817f2ae7fSRafael J. Wysocki /**
66917f2ae7fSRafael J. Wysocki  * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
67017f2ae7fSRafael J. Wysocki  */
67117f2ae7fSRafael J. Wysocki void pm_genpd_poweroff_unused(void)
67217f2ae7fSRafael J. Wysocki {
67317f2ae7fSRafael J. Wysocki 	struct generic_pm_domain *genpd;
67417f2ae7fSRafael J. Wysocki 
67517f2ae7fSRafael J. Wysocki 	mutex_lock(&gpd_list_lock);
67617f2ae7fSRafael J. Wysocki 
67717f2ae7fSRafael J. Wysocki 	list_for_each_entry(genpd, &gpd_list, gpd_list_node)
67817f2ae7fSRafael J. Wysocki 		genpd_queue_power_off_work(genpd);
67917f2ae7fSRafael J. Wysocki 
68017f2ae7fSRafael J. Wysocki 	mutex_unlock(&gpd_list_lock);
68117f2ae7fSRafael J. Wysocki }
68217f2ae7fSRafael J. Wysocki 
683f721889fSRafael J. Wysocki #else
684f721889fSRafael J. Wysocki 
6856ff7bb0dSRafael J. Wysocki static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
6866ff7bb0dSRafael J. Wysocki 					    unsigned long val, void *ptr)
6876ff7bb0dSRafael J. Wysocki {
6886ff7bb0dSRafael J. Wysocki 	return NOTIFY_DONE;
6896ff7bb0dSRafael J. Wysocki }
6906ff7bb0dSRafael J. Wysocki 
691f721889fSRafael J. Wysocki static inline void genpd_power_off_work_fn(struct work_struct *work) {}
692f721889fSRafael J. Wysocki 
693f721889fSRafael J. Wysocki #define pm_genpd_runtime_suspend	NULL
694f721889fSRafael J. Wysocki #define pm_genpd_runtime_resume		NULL
695f721889fSRafael J. Wysocki 
696f721889fSRafael J. Wysocki #endif /* CONFIG_PM_RUNTIME */
697f721889fSRafael J. Wysocki 
698596ba34bSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
699596ba34bSRafael J. Wysocki 
700d5e4cbfeSRafael J. Wysocki static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
701d5e4cbfeSRafael J. Wysocki 				    struct device *dev)
702d5e4cbfeSRafael J. Wysocki {
703d5e4cbfeSRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev);
704d5e4cbfeSRafael J. Wysocki }
705d5e4cbfeSRafael J. Wysocki 
706d23b9b00SRafael J. Wysocki static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev)
707d23b9b00SRafael J. Wysocki {
708d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, suspend, dev);
709d23b9b00SRafael J. Wysocki }
710d23b9b00SRafael J. Wysocki 
711d23b9b00SRafael J. Wysocki static int genpd_suspend_late(struct generic_pm_domain *genpd, struct device *dev)
712d23b9b00SRafael J. Wysocki {
713d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, suspend_late, dev);
714d23b9b00SRafael J. Wysocki }
715d23b9b00SRafael J. Wysocki 
716d23b9b00SRafael J. Wysocki static int genpd_resume_early(struct generic_pm_domain *genpd, struct device *dev)
717d23b9b00SRafael J. Wysocki {
718d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, resume_early, dev);
719d23b9b00SRafael J. Wysocki }
720d23b9b00SRafael J. Wysocki 
721d23b9b00SRafael J. Wysocki static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev)
722d23b9b00SRafael J. Wysocki {
723d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, resume, dev);
724d23b9b00SRafael J. Wysocki }
725d23b9b00SRafael J. Wysocki 
726d23b9b00SRafael J. Wysocki static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev)
727d23b9b00SRafael J. Wysocki {
728d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, freeze, dev);
729d23b9b00SRafael J. Wysocki }
730d23b9b00SRafael J. Wysocki 
731d23b9b00SRafael J. Wysocki static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev)
732d23b9b00SRafael J. Wysocki {
733d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev);
734d23b9b00SRafael J. Wysocki }
735d23b9b00SRafael J. Wysocki 
736d23b9b00SRafael J. Wysocki static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev)
737d23b9b00SRafael J. Wysocki {
738d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev);
739d23b9b00SRafael J. Wysocki }
740d23b9b00SRafael J. Wysocki 
741d23b9b00SRafael J. Wysocki static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev)
742d23b9b00SRafael J. Wysocki {
743d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, thaw, dev);
744d23b9b00SRafael J. Wysocki }
745d23b9b00SRafael J. Wysocki 
746596ba34bSRafael J. Wysocki /**
7475063ce15SRafael J. Wysocki  * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
748596ba34bSRafael J. Wysocki  * @genpd: PM domain to power off, if possible.
749596ba34bSRafael J. Wysocki  *
750596ba34bSRafael J. Wysocki  * Check if the given PM domain can be powered off (during system suspend or
7515063ce15SRafael J. Wysocki  * hibernation) and do that if so.  Also, in that case propagate to its masters.
752596ba34bSRafael J. Wysocki  *
753596ba34bSRafael J. Wysocki  * This function is only called in "noirq" stages of system power transitions,
754596ba34bSRafael J. Wysocki  * so it need not acquire locks (all of the "noirq" callbacks are executed
755596ba34bSRafael J. Wysocki  * sequentially, so it is guaranteed that it will never run twice in parallel).
756596ba34bSRafael J. Wysocki  */
757596ba34bSRafael J. Wysocki static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
758596ba34bSRafael J. Wysocki {
7595063ce15SRafael J. Wysocki 	struct gpd_link *link;
760596ba34bSRafael J. Wysocki 
76117b75ecaSRafael J. Wysocki 	if (genpd->status == GPD_STATE_POWER_OFF)
762596ba34bSRafael J. Wysocki 		return;
763596ba34bSRafael J. Wysocki 
764c4bb3160SRafael J. Wysocki 	if (genpd->suspended_count != genpd->device_count
765c4bb3160SRafael J. Wysocki 	    || atomic_read(&genpd->sd_count) > 0)
766596ba34bSRafael J. Wysocki 		return;
767596ba34bSRafael J. Wysocki 
768596ba34bSRafael J. Wysocki 	if (genpd->power_off)
769596ba34bSRafael J. Wysocki 		genpd->power_off(genpd);
770596ba34bSRafael J. Wysocki 
77117b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_POWER_OFF;
7725063ce15SRafael J. Wysocki 
7735063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
7745063ce15SRafael J. Wysocki 		genpd_sd_counter_dec(link->master);
7755063ce15SRafael J. Wysocki 		pm_genpd_sync_poweroff(link->master);
776596ba34bSRafael J. Wysocki 	}
777596ba34bSRafael J. Wysocki }
778596ba34bSRafael J. Wysocki 
779596ba34bSRafael J. Wysocki /**
7804ecd6e65SRafael J. Wysocki  * resume_needed - Check whether to resume a device before system suspend.
7814ecd6e65SRafael J. Wysocki  * @dev: Device to check.
7824ecd6e65SRafael J. Wysocki  * @genpd: PM domain the device belongs to.
7834ecd6e65SRafael J. Wysocki  *
7844ecd6e65SRafael J. Wysocki  * There are two cases in which a device that can wake up the system from sleep
7854ecd6e65SRafael J. Wysocki  * states should be resumed by pm_genpd_prepare(): (1) if the device is enabled
7864ecd6e65SRafael J. Wysocki  * to wake up the system and it has to remain active for this purpose while the
7874ecd6e65SRafael J. Wysocki  * system is in the sleep state and (2) if the device is not enabled to wake up
7884ecd6e65SRafael J. Wysocki  * the system from sleep states and it generally doesn't generate wakeup signals
7894ecd6e65SRafael J. Wysocki  * by itself (those signals are generated on its behalf by other parts of the
7904ecd6e65SRafael J. Wysocki  * system).  In the latter case it may be necessary to reconfigure the device's
7914ecd6e65SRafael J. Wysocki  * wakeup settings during system suspend, because it may have been set up to
7924ecd6e65SRafael J. Wysocki  * signal remote wakeup from the system's working state as needed by runtime PM.
7934ecd6e65SRafael J. Wysocki  * Return 'true' in either of the above cases.
7944ecd6e65SRafael J. Wysocki  */
7954ecd6e65SRafael J. Wysocki static bool resume_needed(struct device *dev, struct generic_pm_domain *genpd)
7964ecd6e65SRafael J. Wysocki {
7974ecd6e65SRafael J. Wysocki 	bool active_wakeup;
7984ecd6e65SRafael J. Wysocki 
7994ecd6e65SRafael J. Wysocki 	if (!device_can_wakeup(dev))
8004ecd6e65SRafael J. Wysocki 		return false;
8014ecd6e65SRafael J. Wysocki 
802d5e4cbfeSRafael J. Wysocki 	active_wakeup = genpd_dev_active_wakeup(genpd, dev);
8034ecd6e65SRafael J. Wysocki 	return device_may_wakeup(dev) ? active_wakeup : !active_wakeup;
8044ecd6e65SRafael J. Wysocki }
8054ecd6e65SRafael J. Wysocki 
8064ecd6e65SRafael J. Wysocki /**
807596ba34bSRafael J. Wysocki  * pm_genpd_prepare - Start power transition of a device in a PM domain.
808596ba34bSRafael J. Wysocki  * @dev: Device to start the transition of.
809596ba34bSRafael J. Wysocki  *
810596ba34bSRafael J. Wysocki  * Start a power transition of a device (during a system-wide power transition)
811596ba34bSRafael J. Wysocki  * under the assumption that its pm_domain field points to the domain member of
812596ba34bSRafael J. Wysocki  * an object of type struct generic_pm_domain representing a PM domain
813596ba34bSRafael J. Wysocki  * consisting of I/O devices.
814596ba34bSRafael J. Wysocki  */
815596ba34bSRafael J. Wysocki static int pm_genpd_prepare(struct device *dev)
816596ba34bSRafael J. Wysocki {
817596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
818b6c10c84SRafael J. Wysocki 	int ret;
819596ba34bSRafael J. Wysocki 
820596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
821596ba34bSRafael J. Wysocki 
822596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
823596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
824596ba34bSRafael J. Wysocki 		return -EINVAL;
825596ba34bSRafael J. Wysocki 
82617b75ecaSRafael J. Wysocki 	/*
82717b75ecaSRafael J. Wysocki 	 * If a wakeup request is pending for the device, it should be woken up
82817b75ecaSRafael J. Wysocki 	 * at this point and a system wakeup event should be reported if it's
82917b75ecaSRafael J. Wysocki 	 * set up to wake up the system from sleep states.
83017b75ecaSRafael J. Wysocki 	 */
83117b75ecaSRafael J. Wysocki 	pm_runtime_get_noresume(dev);
83217b75ecaSRafael J. Wysocki 	if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
83317b75ecaSRafael J. Wysocki 		pm_wakeup_event(dev, 0);
83417b75ecaSRafael J. Wysocki 
83517b75ecaSRafael J. Wysocki 	if (pm_wakeup_pending()) {
83617b75ecaSRafael J. Wysocki 		pm_runtime_put_sync(dev);
83717b75ecaSRafael J. Wysocki 		return -EBUSY;
83817b75ecaSRafael J. Wysocki 	}
83917b75ecaSRafael J. Wysocki 
8404ecd6e65SRafael J. Wysocki 	if (resume_needed(dev, genpd))
8414ecd6e65SRafael J. Wysocki 		pm_runtime_resume(dev);
8424ecd6e65SRafael J. Wysocki 
84317b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
844596ba34bSRafael J. Wysocki 
84565533bbfSRafael J. Wysocki 	if (genpd->prepared_count++ == 0) {
84665533bbfSRafael J. Wysocki 		genpd->suspended_count = 0;
84717b75ecaSRafael J. Wysocki 		genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
84865533bbfSRafael J. Wysocki 	}
84917b75ecaSRafael J. Wysocki 
85017b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
851596ba34bSRafael J. Wysocki 
852596ba34bSRafael J. Wysocki 	if (genpd->suspend_power_off) {
85317b75ecaSRafael J. Wysocki 		pm_runtime_put_noidle(dev);
854596ba34bSRafael J. Wysocki 		return 0;
855596ba34bSRafael J. Wysocki 	}
856596ba34bSRafael J. Wysocki 
857596ba34bSRafael J. Wysocki 	/*
85817b75ecaSRafael J. Wysocki 	 * The PM domain must be in the GPD_STATE_ACTIVE state at this point,
85917b75ecaSRafael J. Wysocki 	 * so pm_genpd_poweron() will return immediately, but if the device
860d5e4cbfeSRafael J. Wysocki 	 * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need
86117b75ecaSRafael J. Wysocki 	 * to make it operational.
862596ba34bSRafael J. Wysocki 	 */
86317b75ecaSRafael J. Wysocki 	pm_runtime_resume(dev);
864596ba34bSRafael J. Wysocki 	__pm_runtime_disable(dev, false);
865596ba34bSRafael J. Wysocki 
866b6c10c84SRafael J. Wysocki 	ret = pm_generic_prepare(dev);
867b6c10c84SRafael J. Wysocki 	if (ret) {
868b6c10c84SRafael J. Wysocki 		mutex_lock(&genpd->lock);
869b6c10c84SRafael J. Wysocki 
870b6c10c84SRafael J. Wysocki 		if (--genpd->prepared_count == 0)
871b6c10c84SRafael J. Wysocki 			genpd->suspend_power_off = false;
872b6c10c84SRafael J. Wysocki 
873b6c10c84SRafael J. Wysocki 		mutex_unlock(&genpd->lock);
87417b75ecaSRafael J. Wysocki 		pm_runtime_enable(dev);
875b6c10c84SRafael J. Wysocki 	}
87617b75ecaSRafael J. Wysocki 
87717b75ecaSRafael J. Wysocki 	pm_runtime_put_sync(dev);
878b6c10c84SRafael J. Wysocki 	return ret;
879596ba34bSRafael J. Wysocki }
880596ba34bSRafael J. Wysocki 
881596ba34bSRafael J. Wysocki /**
882596ba34bSRafael J. Wysocki  * pm_genpd_suspend - Suspend a device belonging to an I/O PM domain.
883596ba34bSRafael J. Wysocki  * @dev: Device to suspend.
884596ba34bSRafael J. Wysocki  *
885596ba34bSRafael J. Wysocki  * Suspend a device under the assumption that its pm_domain field points to the
886596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
887596ba34bSRafael J. Wysocki  * a PM domain consisting of I/O devices.
888596ba34bSRafael J. Wysocki  */
889596ba34bSRafael J. Wysocki static int pm_genpd_suspend(struct device *dev)
890596ba34bSRafael J. Wysocki {
891596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
892596ba34bSRafael J. Wysocki 
893596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
894596ba34bSRafael J. Wysocki 
895596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
896596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
897596ba34bSRafael J. Wysocki 		return -EINVAL;
898596ba34bSRafael J. Wysocki 
899d23b9b00SRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_suspend_dev(genpd, dev);
900596ba34bSRafael J. Wysocki }
901596ba34bSRafael J. Wysocki 
902596ba34bSRafael J. Wysocki /**
9030496c8aeSRafael J. Wysocki  * pm_genpd_suspend_late - Late suspend of a device from an I/O PM domain.
904596ba34bSRafael J. Wysocki  * @dev: Device to suspend.
905596ba34bSRafael J. Wysocki  *
906596ba34bSRafael J. Wysocki  * Carry out a late suspend of a device under the assumption that its
907596ba34bSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
908596ba34bSRafael J. Wysocki  * struct generic_pm_domain representing a PM domain consisting of I/O devices.
909596ba34bSRafael J. Wysocki  */
9100496c8aeSRafael J. Wysocki static int pm_genpd_suspend_late(struct device *dev)
911596ba34bSRafael J. Wysocki {
912596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
913596ba34bSRafael J. Wysocki 
914596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
915596ba34bSRafael J. Wysocki 
916596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
917596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
918596ba34bSRafael J. Wysocki 		return -EINVAL;
919596ba34bSRafael J. Wysocki 
9200496c8aeSRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_suspend_late(genpd, dev);
9210496c8aeSRafael J. Wysocki }
922596ba34bSRafael J. Wysocki 
9230496c8aeSRafael J. Wysocki /**
9240496c8aeSRafael J. Wysocki  * pm_genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain.
9250496c8aeSRafael J. Wysocki  * @dev: Device to suspend.
9260496c8aeSRafael J. Wysocki  *
9270496c8aeSRafael J. Wysocki  * Stop the device and remove power from the domain if all devices in it have
9280496c8aeSRafael J. Wysocki  * been stopped.
9290496c8aeSRafael J. Wysocki  */
9300496c8aeSRafael J. Wysocki static int pm_genpd_suspend_noirq(struct device *dev)
9310496c8aeSRafael J. Wysocki {
9320496c8aeSRafael J. Wysocki 	struct generic_pm_domain *genpd;
933596ba34bSRafael J. Wysocki 
9340496c8aeSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
9350496c8aeSRafael J. Wysocki 
9360496c8aeSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
9370496c8aeSRafael J. Wysocki 	if (IS_ERR(genpd))
9380496c8aeSRafael J. Wysocki 		return -EINVAL;
9390496c8aeSRafael J. Wysocki 
9401e78a0c7SRafael J. Wysocki 	if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on
9410496c8aeSRafael J. Wysocki 	    || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
942d4f2d87aSRafael J. Wysocki 		return 0;
943d4f2d87aSRafael J. Wysocki 
944d5e4cbfeSRafael J. Wysocki 	genpd_stop_dev(genpd, dev);
945596ba34bSRafael J. Wysocki 
946596ba34bSRafael J. Wysocki 	/*
947596ba34bSRafael J. Wysocki 	 * Since all of the "noirq" callbacks are executed sequentially, it is
948596ba34bSRafael J. Wysocki 	 * guaranteed that this function will never run twice in parallel for
949596ba34bSRafael J. Wysocki 	 * the same PM domain, so it is not necessary to use locking here.
950596ba34bSRafael J. Wysocki 	 */
951596ba34bSRafael J. Wysocki 	genpd->suspended_count++;
952596ba34bSRafael J. Wysocki 	pm_genpd_sync_poweroff(genpd);
953596ba34bSRafael J. Wysocki 
954596ba34bSRafael J. Wysocki 	return 0;
955596ba34bSRafael J. Wysocki }
956596ba34bSRafael J. Wysocki 
957596ba34bSRafael J. Wysocki /**
9580496c8aeSRafael J. Wysocki  * pm_genpd_resume_noirq - Start of resume of device in an I/O PM domain.
959596ba34bSRafael J. Wysocki  * @dev: Device to resume.
960596ba34bSRafael J. Wysocki  *
9610496c8aeSRafael J. Wysocki  * Restore power to the device's PM domain, if necessary, and start the device.
962596ba34bSRafael J. Wysocki  */
963596ba34bSRafael J. Wysocki static int pm_genpd_resume_noirq(struct device *dev)
964596ba34bSRafael J. Wysocki {
965596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
966596ba34bSRafael J. Wysocki 
967596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
968596ba34bSRafael J. Wysocki 
969596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
970596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
971596ba34bSRafael J. Wysocki 		return -EINVAL;
972596ba34bSRafael J. Wysocki 
9731e78a0c7SRafael J. Wysocki 	if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on
974cc85b207SRafael J. Wysocki 	    || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
975596ba34bSRafael J. Wysocki 		return 0;
976596ba34bSRafael J. Wysocki 
977596ba34bSRafael J. Wysocki 	/*
978596ba34bSRafael J. Wysocki 	 * Since all of the "noirq" callbacks are executed sequentially, it is
979596ba34bSRafael J. Wysocki 	 * guaranteed that this function will never run twice in parallel for
980596ba34bSRafael J. Wysocki 	 * the same PM domain, so it is not necessary to use locking here.
981596ba34bSRafael J. Wysocki 	 */
982596ba34bSRafael J. Wysocki 	pm_genpd_poweron(genpd);
983596ba34bSRafael J. Wysocki 	genpd->suspended_count--;
984596ba34bSRafael J. Wysocki 
9850496c8aeSRafael J. Wysocki 	return genpd_start_dev(genpd, dev);
986596ba34bSRafael J. Wysocki }
987596ba34bSRafael J. Wysocki 
988596ba34bSRafael J. Wysocki /**
9890496c8aeSRafael J. Wysocki  * pm_genpd_resume_early - Early resume of a device in an I/O PM domain.
9900496c8aeSRafael J. Wysocki  * @dev: Device to resume.
9910496c8aeSRafael J. Wysocki  *
9920496c8aeSRafael J. Wysocki  * Carry out an early resume of a device under the assumption that its
9930496c8aeSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
9940496c8aeSRafael J. Wysocki  * struct generic_pm_domain representing a power domain consisting of I/O
9950496c8aeSRafael J. Wysocki  * devices.
9960496c8aeSRafael J. Wysocki  */
9970496c8aeSRafael J. Wysocki static int pm_genpd_resume_early(struct device *dev)
9980496c8aeSRafael J. Wysocki {
9990496c8aeSRafael J. Wysocki 	struct generic_pm_domain *genpd;
10000496c8aeSRafael J. Wysocki 
10010496c8aeSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
10020496c8aeSRafael J. Wysocki 
10030496c8aeSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
10040496c8aeSRafael J. Wysocki 	if (IS_ERR(genpd))
10050496c8aeSRafael J. Wysocki 		return -EINVAL;
10060496c8aeSRafael J. Wysocki 
10070496c8aeSRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_resume_early(genpd, dev);
10080496c8aeSRafael J. Wysocki }
10090496c8aeSRafael J. Wysocki 
10100496c8aeSRafael J. Wysocki /**
10110496c8aeSRafael J. Wysocki  * pm_genpd_resume - Resume of device in an I/O PM domain.
1012596ba34bSRafael J. Wysocki  * @dev: Device to resume.
1013596ba34bSRafael J. Wysocki  *
1014596ba34bSRafael J. Wysocki  * Resume a device under the assumption that its pm_domain field points to the
1015596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
1016596ba34bSRafael J. Wysocki  * a power domain consisting of I/O devices.
1017596ba34bSRafael J. Wysocki  */
1018596ba34bSRafael J. Wysocki static int pm_genpd_resume(struct device *dev)
1019596ba34bSRafael J. Wysocki {
1020596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1021596ba34bSRafael J. Wysocki 
1022596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1023596ba34bSRafael J. Wysocki 
1024596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
1025596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
1026596ba34bSRafael J. Wysocki 		return -EINVAL;
1027596ba34bSRafael J. Wysocki 
1028d23b9b00SRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_resume_dev(genpd, dev);
1029596ba34bSRafael J. Wysocki }
1030596ba34bSRafael J. Wysocki 
1031596ba34bSRafael J. Wysocki /**
10320496c8aeSRafael J. Wysocki  * pm_genpd_freeze - Freezing a device in an I/O PM domain.
1033596ba34bSRafael J. Wysocki  * @dev: Device to freeze.
1034596ba34bSRafael J. Wysocki  *
1035596ba34bSRafael J. Wysocki  * Freeze a device under the assumption that its pm_domain field points to the
1036596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
1037596ba34bSRafael J. Wysocki  * a power domain consisting of I/O devices.
1038596ba34bSRafael J. Wysocki  */
1039596ba34bSRafael J. Wysocki static int pm_genpd_freeze(struct device *dev)
1040596ba34bSRafael J. Wysocki {
1041596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1042596ba34bSRafael J. Wysocki 
1043596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1044596ba34bSRafael J. Wysocki 
1045596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
1046596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
1047596ba34bSRafael J. Wysocki 		return -EINVAL;
1048596ba34bSRafael J. Wysocki 
1049d23b9b00SRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev);
1050596ba34bSRafael J. Wysocki }
1051596ba34bSRafael J. Wysocki 
1052596ba34bSRafael J. Wysocki /**
10530496c8aeSRafael J. Wysocki  * pm_genpd_freeze_late - Late freeze of a device in an I/O PM domain.
10540496c8aeSRafael J. Wysocki  * @dev: Device to freeze.
10550496c8aeSRafael J. Wysocki  *
10560496c8aeSRafael J. Wysocki  * Carry out a late freeze of a device under the assumption that its
10570496c8aeSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
10580496c8aeSRafael J. Wysocki  * struct generic_pm_domain representing a power domain consisting of I/O
10590496c8aeSRafael J. Wysocki  * devices.
10600496c8aeSRafael J. Wysocki  */
10610496c8aeSRafael J. Wysocki static int pm_genpd_freeze_late(struct device *dev)
10620496c8aeSRafael J. Wysocki {
10630496c8aeSRafael J. Wysocki 	struct generic_pm_domain *genpd;
10640496c8aeSRafael J. Wysocki 
10650496c8aeSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
10660496c8aeSRafael J. Wysocki 
10670496c8aeSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
10680496c8aeSRafael J. Wysocki 	if (IS_ERR(genpd))
10690496c8aeSRafael J. Wysocki 		return -EINVAL;
10700496c8aeSRafael J. Wysocki 
10710496c8aeSRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_freeze_late(genpd, dev);
10720496c8aeSRafael J. Wysocki }
10730496c8aeSRafael J. Wysocki 
10740496c8aeSRafael J. Wysocki /**
10750496c8aeSRafael J. Wysocki  * pm_genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain.
1076596ba34bSRafael J. Wysocki  * @dev: Device to freeze.
1077596ba34bSRafael J. Wysocki  *
1078596ba34bSRafael J. Wysocki  * Carry out a late freeze of a device under the assumption that its
1079596ba34bSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
1080596ba34bSRafael J. Wysocki  * struct generic_pm_domain representing a power domain consisting of I/O
1081596ba34bSRafael J. Wysocki  * devices.
1082596ba34bSRafael J. Wysocki  */
1083596ba34bSRafael J. Wysocki static int pm_genpd_freeze_noirq(struct device *dev)
1084596ba34bSRafael J. Wysocki {
1085596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1086596ba34bSRafael J. Wysocki 
1087596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1088596ba34bSRafael J. Wysocki 
1089596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
1090596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
1091596ba34bSRafael J. Wysocki 		return -EINVAL;
1092596ba34bSRafael J. Wysocki 
10931e78a0c7SRafael J. Wysocki 	return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ?
10941e78a0c7SRafael J. Wysocki 		0 : genpd_stop_dev(genpd, dev);
1095596ba34bSRafael J. Wysocki }
1096596ba34bSRafael J. Wysocki 
1097596ba34bSRafael J. Wysocki /**
10980496c8aeSRafael J. Wysocki  * pm_genpd_thaw_noirq - Early thaw of device in an I/O PM domain.
1099596ba34bSRafael J. Wysocki  * @dev: Device to thaw.
1100596ba34bSRafael J. Wysocki  *
11010496c8aeSRafael J. Wysocki  * Start the device, unless power has been removed from the domain already
11020496c8aeSRafael J. Wysocki  * before the system transition.
1103596ba34bSRafael J. Wysocki  */
1104596ba34bSRafael J. Wysocki static int pm_genpd_thaw_noirq(struct device *dev)
1105596ba34bSRafael J. Wysocki {
1106596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1107596ba34bSRafael J. Wysocki 
1108596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1109596ba34bSRafael J. Wysocki 
1110596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
1111596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
1112596ba34bSRafael J. Wysocki 		return -EINVAL;
1113596ba34bSRafael J. Wysocki 
11141e78a0c7SRafael J. Wysocki 	return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ?
11151e78a0c7SRafael J. Wysocki 		0 : genpd_start_dev(genpd, dev);
11160496c8aeSRafael J. Wysocki }
1117596ba34bSRafael J. Wysocki 
11180496c8aeSRafael J. Wysocki /**
11190496c8aeSRafael J. Wysocki  * pm_genpd_thaw_early - Early thaw of device in an I/O PM domain.
11200496c8aeSRafael J. Wysocki  * @dev: Device to thaw.
11210496c8aeSRafael J. Wysocki  *
11220496c8aeSRafael J. Wysocki  * Carry out an early thaw of a device under the assumption that its
11230496c8aeSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
11240496c8aeSRafael J. Wysocki  * struct generic_pm_domain representing a power domain consisting of I/O
11250496c8aeSRafael J. Wysocki  * devices.
11260496c8aeSRafael J. Wysocki  */
11270496c8aeSRafael J. Wysocki static int pm_genpd_thaw_early(struct device *dev)
11280496c8aeSRafael J. Wysocki {
11290496c8aeSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1130596ba34bSRafael J. Wysocki 
11310496c8aeSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
11320496c8aeSRafael J. Wysocki 
11330496c8aeSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
11340496c8aeSRafael J. Wysocki 	if (IS_ERR(genpd))
11350496c8aeSRafael J. Wysocki 		return -EINVAL;
11360496c8aeSRafael J. Wysocki 
11370496c8aeSRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_thaw_early(genpd, dev);
1138596ba34bSRafael J. Wysocki }
1139596ba34bSRafael J. Wysocki 
1140596ba34bSRafael J. Wysocki /**
1141596ba34bSRafael J. Wysocki  * pm_genpd_thaw - Thaw a device belonging to an I/O power domain.
1142596ba34bSRafael J. Wysocki  * @dev: Device to thaw.
1143596ba34bSRafael J. Wysocki  *
1144596ba34bSRafael J. Wysocki  * Thaw a device under the assumption that its pm_domain field points to the
1145596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
1146596ba34bSRafael J. Wysocki  * a power domain consisting of I/O devices.
1147596ba34bSRafael J. Wysocki  */
1148596ba34bSRafael J. Wysocki static int pm_genpd_thaw(struct device *dev)
1149596ba34bSRafael J. Wysocki {
1150596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1151596ba34bSRafael J. Wysocki 
1152596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1153596ba34bSRafael J. Wysocki 
1154596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
1155596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
1156596ba34bSRafael J. Wysocki 		return -EINVAL;
1157596ba34bSRafael J. Wysocki 
1158d23b9b00SRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev);
1159596ba34bSRafael J. Wysocki }
1160596ba34bSRafael J. Wysocki 
1161596ba34bSRafael J. Wysocki /**
11620496c8aeSRafael J. Wysocki  * pm_genpd_restore_noirq - Start of restore of device in an I/O PM domain.
1163596ba34bSRafael J. Wysocki  * @dev: Device to resume.
1164596ba34bSRafael J. Wysocki  *
11650496c8aeSRafael J. Wysocki  * Make sure the domain will be in the same power state as before the
11660496c8aeSRafael J. Wysocki  * hibernation the system is resuming from and start the device if necessary.
1167596ba34bSRafael J. Wysocki  */
1168596ba34bSRafael J. Wysocki static int pm_genpd_restore_noirq(struct device *dev)
1169596ba34bSRafael J. Wysocki {
1170596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1171596ba34bSRafael J. Wysocki 
1172596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1173596ba34bSRafael J. Wysocki 
1174596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
1175596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
1176596ba34bSRafael J. Wysocki 		return -EINVAL;
1177596ba34bSRafael J. Wysocki 
1178596ba34bSRafael J. Wysocki 	/*
1179596ba34bSRafael J. Wysocki 	 * Since all of the "noirq" callbacks are executed sequentially, it is
1180596ba34bSRafael J. Wysocki 	 * guaranteed that this function will never run twice in parallel for
1181596ba34bSRafael J. Wysocki 	 * the same PM domain, so it is not necessary to use locking here.
118265533bbfSRafael J. Wysocki 	 *
118365533bbfSRafael J. Wysocki 	 * At this point suspended_count == 0 means we are being run for the
118465533bbfSRafael J. Wysocki 	 * first time for the given domain in the present cycle.
118565533bbfSRafael J. Wysocki 	 */
118665533bbfSRafael J. Wysocki 	if (genpd->suspended_count++ == 0) {
118765533bbfSRafael J. Wysocki 		/*
118865533bbfSRafael J. Wysocki 		 * The boot kernel might put the domain into arbitrary state,
118965533bbfSRafael J. Wysocki 		 * so make it appear as powered off to pm_genpd_poweron(), so
119065533bbfSRafael J. Wysocki 		 * that it tries to power it on in case it was really off.
1191596ba34bSRafael J. Wysocki 		 */
119217b75ecaSRafael J. Wysocki 		genpd->status = GPD_STATE_POWER_OFF;
1193596ba34bSRafael J. Wysocki 		if (genpd->suspend_power_off) {
1194596ba34bSRafael J. Wysocki 			/*
119565533bbfSRafael J. Wysocki 			 * If the domain was off before the hibernation, make
119665533bbfSRafael J. Wysocki 			 * sure it will be off going forward.
1197596ba34bSRafael J. Wysocki 			 */
1198596ba34bSRafael J. Wysocki 			if (genpd->power_off)
1199596ba34bSRafael J. Wysocki 				genpd->power_off(genpd);
120065533bbfSRafael J. Wysocki 
1201596ba34bSRafael J. Wysocki 			return 0;
1202596ba34bSRafael J. Wysocki 		}
120365533bbfSRafael J. Wysocki 	}
1204596ba34bSRafael J. Wysocki 
120518dd2eceSRafael J. Wysocki 	if (genpd->suspend_power_off)
120618dd2eceSRafael J. Wysocki 		return 0;
120718dd2eceSRafael J. Wysocki 
1208596ba34bSRafael J. Wysocki 	pm_genpd_poweron(genpd);
1209596ba34bSRafael J. Wysocki 
12101e78a0c7SRafael J. Wysocki 	return dev_gpd_data(dev)->always_on ? 0 : genpd_start_dev(genpd, dev);
1211596ba34bSRafael J. Wysocki }
1212596ba34bSRafael J. Wysocki 
1213596ba34bSRafael J. Wysocki /**
1214596ba34bSRafael J. Wysocki  * pm_genpd_complete - Complete power transition of a device in a power domain.
1215596ba34bSRafael J. Wysocki  * @dev: Device to complete the transition of.
1216596ba34bSRafael J. Wysocki  *
1217596ba34bSRafael J. Wysocki  * Complete a power transition of a device (during a system-wide power
1218596ba34bSRafael J. Wysocki  * transition) under the assumption that its pm_domain field points to the
1219596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
1220596ba34bSRafael J. Wysocki  * a power domain consisting of I/O devices.
1221596ba34bSRafael J. Wysocki  */
1222596ba34bSRafael J. Wysocki static void pm_genpd_complete(struct device *dev)
1223596ba34bSRafael J. Wysocki {
1224596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1225596ba34bSRafael J. Wysocki 	bool run_complete;
1226596ba34bSRafael J. Wysocki 
1227596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1228596ba34bSRafael J. Wysocki 
1229596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
1230596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
1231596ba34bSRafael J. Wysocki 		return;
1232596ba34bSRafael J. Wysocki 
1233596ba34bSRafael J. Wysocki 	mutex_lock(&genpd->lock);
1234596ba34bSRafael J. Wysocki 
1235596ba34bSRafael J. Wysocki 	run_complete = !genpd->suspend_power_off;
1236596ba34bSRafael J. Wysocki 	if (--genpd->prepared_count == 0)
1237596ba34bSRafael J. Wysocki 		genpd->suspend_power_off = false;
1238596ba34bSRafael J. Wysocki 
1239596ba34bSRafael J. Wysocki 	mutex_unlock(&genpd->lock);
1240596ba34bSRafael J. Wysocki 
1241596ba34bSRafael J. Wysocki 	if (run_complete) {
1242596ba34bSRafael J. Wysocki 		pm_generic_complete(dev);
12436f00ff78SRafael J. Wysocki 		pm_runtime_set_active(dev);
1244596ba34bSRafael J. Wysocki 		pm_runtime_enable(dev);
12456f00ff78SRafael J. Wysocki 		pm_runtime_idle(dev);
1246596ba34bSRafael J. Wysocki 	}
1247596ba34bSRafael J. Wysocki }
1248596ba34bSRafael J. Wysocki 
1249596ba34bSRafael J. Wysocki #else
1250596ba34bSRafael J. Wysocki 
1251596ba34bSRafael J. Wysocki #define pm_genpd_prepare		NULL
1252596ba34bSRafael J. Wysocki #define pm_genpd_suspend		NULL
12530496c8aeSRafael J. Wysocki #define pm_genpd_suspend_late		NULL
1254596ba34bSRafael J. Wysocki #define pm_genpd_suspend_noirq		NULL
12550496c8aeSRafael J. Wysocki #define pm_genpd_resume_early		NULL
1256596ba34bSRafael J. Wysocki #define pm_genpd_resume_noirq		NULL
1257596ba34bSRafael J. Wysocki #define pm_genpd_resume			NULL
1258596ba34bSRafael J. Wysocki #define pm_genpd_freeze			NULL
12590496c8aeSRafael J. Wysocki #define pm_genpd_freeze_late		NULL
1260596ba34bSRafael J. Wysocki #define pm_genpd_freeze_noirq		NULL
12610496c8aeSRafael J. Wysocki #define pm_genpd_thaw_early		NULL
1262596ba34bSRafael J. Wysocki #define pm_genpd_thaw_noirq		NULL
1263596ba34bSRafael J. Wysocki #define pm_genpd_thaw			NULL
1264596ba34bSRafael J. Wysocki #define pm_genpd_restore_noirq		NULL
1265596ba34bSRafael J. Wysocki #define pm_genpd_complete		NULL
1266596ba34bSRafael J. Wysocki 
1267596ba34bSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
1268596ba34bSRafael J. Wysocki 
1269f721889fSRafael J. Wysocki /**
1270b02c999aSRafael J. Wysocki  * __pm_genpd_add_device - Add a device to an I/O PM domain.
1271f721889fSRafael J. Wysocki  * @genpd: PM domain to add the device to.
1272f721889fSRafael J. Wysocki  * @dev: Device to be added.
1273b02c999aSRafael J. Wysocki  * @td: Set of PM QoS timing parameters to attach to the device.
1274f721889fSRafael J. Wysocki  */
1275b02c999aSRafael J. Wysocki int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1276b02c999aSRafael J. Wysocki 			  struct gpd_timing_data *td)
1277f721889fSRafael J. Wysocki {
1278cd0ea672SRafael J. Wysocki 	struct generic_pm_domain_data *gpd_data;
12794605ab65SRafael J. Wysocki 	struct pm_domain_data *pdd;
1280f721889fSRafael J. Wysocki 	int ret = 0;
1281f721889fSRafael J. Wysocki 
1282f721889fSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1283f721889fSRafael J. Wysocki 
1284f721889fSRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
1285f721889fSRafael J. Wysocki 		return -EINVAL;
1286f721889fSRafael J. Wysocki 
12876ff7bb0dSRafael J. Wysocki 	gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
12886ff7bb0dSRafael J. Wysocki 	if (!gpd_data)
12896ff7bb0dSRafael J. Wysocki 		return -ENOMEM;
12906ff7bb0dSRafael J. Wysocki 
12916ff7bb0dSRafael J. Wysocki 	mutex_init(&gpd_data->lock);
12926ff7bb0dSRafael J. Wysocki 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
12936ff7bb0dSRafael J. Wysocki 	dev_pm_qos_add_notifier(dev, &gpd_data->nb);
12946ff7bb0dSRafael J. Wysocki 
129517b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
1296f721889fSRafael J. Wysocki 
1297596ba34bSRafael J. Wysocki 	if (genpd->prepared_count > 0) {
1298596ba34bSRafael J. Wysocki 		ret = -EAGAIN;
1299596ba34bSRafael J. Wysocki 		goto out;
1300596ba34bSRafael J. Wysocki 	}
1301596ba34bSRafael J. Wysocki 
13024605ab65SRafael J. Wysocki 	list_for_each_entry(pdd, &genpd->dev_list, list_node)
13034605ab65SRafael J. Wysocki 		if (pdd->dev == dev) {
1304f721889fSRafael J. Wysocki 			ret = -EINVAL;
1305f721889fSRafael J. Wysocki 			goto out;
1306f721889fSRafael J. Wysocki 		}
1307f721889fSRafael J. Wysocki 
1308596ba34bSRafael J. Wysocki 	genpd->device_count++;
13096ff7bb0dSRafael J. Wysocki 	genpd->max_off_time_changed = true;
1310f721889fSRafael J. Wysocki 
13114605ab65SRafael J. Wysocki 	dev_pm_get_subsys_data(dev);
13126ff7bb0dSRafael J. Wysocki 
13136ff7bb0dSRafael J. Wysocki 	mutex_lock(&gpd_data->lock);
13146ff7bb0dSRafael J. Wysocki 	spin_lock_irq(&dev->power.lock);
13156ff7bb0dSRafael J. Wysocki 	dev->pm_domain = &genpd->domain;
1316cd0ea672SRafael J. Wysocki 	dev->power.subsys_data->domain_data = &gpd_data->base;
1317cd0ea672SRafael J. Wysocki 	gpd_data->base.dev = dev;
1318cd0ea672SRafael J. Wysocki 	list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
1319ca1d72f0SRafael J. Wysocki 	gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
1320b02c999aSRafael J. Wysocki 	if (td)
1321b02c999aSRafael J. Wysocki 		gpd_data->td = *td;
1322f721889fSRafael J. Wysocki 
13236ff7bb0dSRafael J. Wysocki 	gpd_data->td.constraint_changed = true;
13246ff7bb0dSRafael J. Wysocki 	gpd_data->td.effective_constraint_ns = -1;
13256ff7bb0dSRafael J. Wysocki 	spin_unlock_irq(&dev->power.lock);
13266ff7bb0dSRafael J. Wysocki 	mutex_unlock(&gpd_data->lock);
13276ff7bb0dSRafael J. Wysocki 
13286ff7bb0dSRafael J. Wysocki 	genpd_release_lock(genpd);
13296ff7bb0dSRafael J. Wysocki 
13306ff7bb0dSRafael J. Wysocki 	return 0;
13316ff7bb0dSRafael J. Wysocki 
1332f721889fSRafael J. Wysocki  out:
133317b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
1334f721889fSRafael J. Wysocki 
13356ff7bb0dSRafael J. Wysocki 	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
13366ff7bb0dSRafael J. Wysocki 	kfree(gpd_data);
1337f721889fSRafael J. Wysocki 	return ret;
1338f721889fSRafael J. Wysocki }
1339f721889fSRafael J. Wysocki 
1340f721889fSRafael J. Wysocki /**
1341c8aa130bSThomas Abraham  * __pm_genpd_of_add_device - Add a device to an I/O PM domain.
1342c8aa130bSThomas Abraham  * @genpd_node: Device tree node pointer representing a PM domain to which the
1343c8aa130bSThomas Abraham  *   the device is added to.
1344c8aa130bSThomas Abraham  * @dev: Device to be added.
1345c8aa130bSThomas Abraham  * @td: Set of PM QoS timing parameters to attach to the device.
1346c8aa130bSThomas Abraham  */
1347c8aa130bSThomas Abraham int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev,
1348c8aa130bSThomas Abraham 			     struct gpd_timing_data *td)
1349c8aa130bSThomas Abraham {
1350c8aa130bSThomas Abraham 	struct generic_pm_domain *genpd = NULL, *gpd;
1351c8aa130bSThomas Abraham 
1352c8aa130bSThomas Abraham 	dev_dbg(dev, "%s()\n", __func__);
1353c8aa130bSThomas Abraham 
1354c8aa130bSThomas Abraham 	if (IS_ERR_OR_NULL(genpd_node) || IS_ERR_OR_NULL(dev))
1355c8aa130bSThomas Abraham 		return -EINVAL;
1356c8aa130bSThomas Abraham 
1357c8aa130bSThomas Abraham 	mutex_lock(&gpd_list_lock);
1358c8aa130bSThomas Abraham 	list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
1359c8aa130bSThomas Abraham 		if (gpd->of_node == genpd_node) {
1360c8aa130bSThomas Abraham 			genpd = gpd;
1361c8aa130bSThomas Abraham 			break;
1362c8aa130bSThomas Abraham 		}
1363c8aa130bSThomas Abraham 	}
1364c8aa130bSThomas Abraham 	mutex_unlock(&gpd_list_lock);
1365c8aa130bSThomas Abraham 
1366c8aa130bSThomas Abraham 	if (!genpd)
1367c8aa130bSThomas Abraham 		return -EINVAL;
1368c8aa130bSThomas Abraham 
1369c8aa130bSThomas Abraham 	return __pm_genpd_add_device(genpd, dev, td);
1370c8aa130bSThomas Abraham }
1371c8aa130bSThomas Abraham 
1372c8aa130bSThomas Abraham /**
1373f721889fSRafael J. Wysocki  * pm_genpd_remove_device - Remove a device from an I/O PM domain.
1374f721889fSRafael J. Wysocki  * @genpd: PM domain to remove the device from.
1375f721889fSRafael J. Wysocki  * @dev: Device to be removed.
1376f721889fSRafael J. Wysocki  */
1377f721889fSRafael J. Wysocki int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1378f721889fSRafael J. Wysocki 			   struct device *dev)
1379f721889fSRafael J. Wysocki {
13806ff7bb0dSRafael J. Wysocki 	struct generic_pm_domain_data *gpd_data;
13814605ab65SRafael J. Wysocki 	struct pm_domain_data *pdd;
1382efa69025SRafael J. Wysocki 	int ret = 0;
1383f721889fSRafael J. Wysocki 
1384f721889fSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1385f721889fSRafael J. Wysocki 
1386efa69025SRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
1387efa69025SRafael J. Wysocki 	    ||  IS_ERR_OR_NULL(dev->pm_domain)
1388efa69025SRafael J. Wysocki 	    ||  pd_to_genpd(dev->pm_domain) != genpd)
1389f721889fSRafael J. Wysocki 		return -EINVAL;
1390f721889fSRafael J. Wysocki 
139117b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
1392f721889fSRafael J. Wysocki 
1393596ba34bSRafael J. Wysocki 	if (genpd->prepared_count > 0) {
1394596ba34bSRafael J. Wysocki 		ret = -EAGAIN;
1395596ba34bSRafael J. Wysocki 		goto out;
1396596ba34bSRafael J. Wysocki 	}
1397596ba34bSRafael J. Wysocki 
13986ff7bb0dSRafael J. Wysocki 	genpd->device_count--;
13996ff7bb0dSRafael J. Wysocki 	genpd->max_off_time_changed = true;
14006ff7bb0dSRafael J. Wysocki 
14016ff7bb0dSRafael J. Wysocki 	spin_lock_irq(&dev->power.lock);
1402f721889fSRafael J. Wysocki 	dev->pm_domain = NULL;
1403efa69025SRafael J. Wysocki 	pdd = dev->power.subsys_data->domain_data;
1404efa69025SRafael J. Wysocki 	list_del_init(&pdd->list_node);
1405efa69025SRafael J. Wysocki 	dev->power.subsys_data->domain_data = NULL;
14066ff7bb0dSRafael J. Wysocki 	spin_unlock_irq(&dev->power.lock);
1407f721889fSRafael J. Wysocki 
14086ff7bb0dSRafael J. Wysocki 	gpd_data = to_gpd_data(pdd);
14096ff7bb0dSRafael J. Wysocki 	mutex_lock(&gpd_data->lock);
14106ff7bb0dSRafael J. Wysocki 	pdd->dev = NULL;
14116ff7bb0dSRafael J. Wysocki 	mutex_unlock(&gpd_data->lock);
14126ff7bb0dSRafael J. Wysocki 
14136ff7bb0dSRafael J. Wysocki 	genpd_release_lock(genpd);
14146ff7bb0dSRafael J. Wysocki 
14156ff7bb0dSRafael J. Wysocki 	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
14166ff7bb0dSRafael J. Wysocki 	kfree(gpd_data);
14176ff7bb0dSRafael J. Wysocki 	dev_pm_put_subsys_data(dev);
14186ff7bb0dSRafael J. Wysocki 	return 0;
1419f721889fSRafael J. Wysocki 
1420596ba34bSRafael J. Wysocki  out:
142117b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
1422f721889fSRafael J. Wysocki 
1423f721889fSRafael J. Wysocki 	return ret;
1424f721889fSRafael J. Wysocki }
1425f721889fSRafael J. Wysocki 
1426f721889fSRafael J. Wysocki /**
14271e78a0c7SRafael J. Wysocki  * pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device.
14281e78a0c7SRafael J. Wysocki  * @dev: Device to set/unset the flag for.
14291e78a0c7SRafael J. Wysocki  * @val: The new value of the device's "always on" flag.
14301e78a0c7SRafael J. Wysocki  */
14311e78a0c7SRafael J. Wysocki void pm_genpd_dev_always_on(struct device *dev, bool val)
14321e78a0c7SRafael J. Wysocki {
14331e78a0c7SRafael J. Wysocki 	struct pm_subsys_data *psd;
14341e78a0c7SRafael J. Wysocki 	unsigned long flags;
14351e78a0c7SRafael J. Wysocki 
14361e78a0c7SRafael J. Wysocki 	spin_lock_irqsave(&dev->power.lock, flags);
14371e78a0c7SRafael J. Wysocki 
14381e78a0c7SRafael J. Wysocki 	psd = dev_to_psd(dev);
14391e78a0c7SRafael J. Wysocki 	if (psd && psd->domain_data)
14401e78a0c7SRafael J. Wysocki 		to_gpd_data(psd->domain_data)->always_on = val;
14411e78a0c7SRafael J. Wysocki 
14421e78a0c7SRafael J. Wysocki 	spin_unlock_irqrestore(&dev->power.lock, flags);
14431e78a0c7SRafael J. Wysocki }
14441e78a0c7SRafael J. Wysocki EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
14451e78a0c7SRafael J. Wysocki 
14461e78a0c7SRafael J. Wysocki /**
1447ca1d72f0SRafael J. Wysocki  * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
1448ca1d72f0SRafael J. Wysocki  * @dev: Device to set/unset the flag for.
1449ca1d72f0SRafael J. Wysocki  * @val: The new value of the device's "need restore" flag.
1450ca1d72f0SRafael J. Wysocki  */
1451ca1d72f0SRafael J. Wysocki void pm_genpd_dev_need_restore(struct device *dev, bool val)
1452ca1d72f0SRafael J. Wysocki {
1453ca1d72f0SRafael J. Wysocki 	struct pm_subsys_data *psd;
1454ca1d72f0SRafael J. Wysocki 	unsigned long flags;
1455ca1d72f0SRafael J. Wysocki 
1456ca1d72f0SRafael J. Wysocki 	spin_lock_irqsave(&dev->power.lock, flags);
1457ca1d72f0SRafael J. Wysocki 
1458ca1d72f0SRafael J. Wysocki 	psd = dev_to_psd(dev);
1459ca1d72f0SRafael J. Wysocki 	if (psd && psd->domain_data)
1460ca1d72f0SRafael J. Wysocki 		to_gpd_data(psd->domain_data)->need_restore = val;
1461ca1d72f0SRafael J. Wysocki 
1462ca1d72f0SRafael J. Wysocki 	spin_unlock_irqrestore(&dev->power.lock, flags);
1463ca1d72f0SRafael J. Wysocki }
1464ca1d72f0SRafael J. Wysocki EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);
1465ca1d72f0SRafael J. Wysocki 
1466ca1d72f0SRafael J. Wysocki /**
1467f721889fSRafael J. Wysocki  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
1468f721889fSRafael J. Wysocki  * @genpd: Master PM domain to add the subdomain to.
1469bc0403ffSRafael J. Wysocki  * @subdomain: Subdomain to be added.
1470f721889fSRafael J. Wysocki  */
1471f721889fSRafael J. Wysocki int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
1472bc0403ffSRafael J. Wysocki 			   struct generic_pm_domain *subdomain)
1473f721889fSRafael J. Wysocki {
14745063ce15SRafael J. Wysocki 	struct gpd_link *link;
1475f721889fSRafael J. Wysocki 	int ret = 0;
1476f721889fSRafael J. Wysocki 
1477bc0403ffSRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
1478f721889fSRafael J. Wysocki 		return -EINVAL;
1479f721889fSRafael J. Wysocki 
148017b75ecaSRafael J. Wysocki  start:
148117b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
1482bc0403ffSRafael J. Wysocki 	mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
1483f721889fSRafael J. Wysocki 
1484bc0403ffSRafael J. Wysocki 	if (subdomain->status != GPD_STATE_POWER_OFF
1485bc0403ffSRafael J. Wysocki 	    && subdomain->status != GPD_STATE_ACTIVE) {
1486bc0403ffSRafael J. Wysocki 		mutex_unlock(&subdomain->lock);
148717b75ecaSRafael J. Wysocki 		genpd_release_lock(genpd);
148817b75ecaSRafael J. Wysocki 		goto start;
148917b75ecaSRafael J. Wysocki 	}
149017b75ecaSRafael J. Wysocki 
149117b75ecaSRafael J. Wysocki 	if (genpd->status == GPD_STATE_POWER_OFF
1492bc0403ffSRafael J. Wysocki 	    &&  subdomain->status != GPD_STATE_POWER_OFF) {
1493f721889fSRafael J. Wysocki 		ret = -EINVAL;
1494f721889fSRafael J. Wysocki 		goto out;
1495f721889fSRafael J. Wysocki 	}
1496f721889fSRafael J. Wysocki 
14974fcac10dSHuang Ying 	list_for_each_entry(link, &genpd->master_links, master_node) {
1498bc0403ffSRafael J. Wysocki 		if (link->slave == subdomain && link->master == genpd) {
1499f721889fSRafael J. Wysocki 			ret = -EINVAL;
1500f721889fSRafael J. Wysocki 			goto out;
1501f721889fSRafael J. Wysocki 		}
1502f721889fSRafael J. Wysocki 	}
1503f721889fSRafael J. Wysocki 
15045063ce15SRafael J. Wysocki 	link = kzalloc(sizeof(*link), GFP_KERNEL);
15055063ce15SRafael J. Wysocki 	if (!link) {
15065063ce15SRafael J. Wysocki 		ret = -ENOMEM;
15075063ce15SRafael J. Wysocki 		goto out;
15085063ce15SRafael J. Wysocki 	}
15095063ce15SRafael J. Wysocki 	link->master = genpd;
15105063ce15SRafael J. Wysocki 	list_add_tail(&link->master_node, &genpd->master_links);
1511bc0403ffSRafael J. Wysocki 	link->slave = subdomain;
1512bc0403ffSRafael J. Wysocki 	list_add_tail(&link->slave_node, &subdomain->slave_links);
1513bc0403ffSRafael J. Wysocki 	if (subdomain->status != GPD_STATE_POWER_OFF)
1514c4bb3160SRafael J. Wysocki 		genpd_sd_counter_inc(genpd);
1515f721889fSRafael J. Wysocki 
1516f721889fSRafael J. Wysocki  out:
1517bc0403ffSRafael J. Wysocki 	mutex_unlock(&subdomain->lock);
151817b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
1519f721889fSRafael J. Wysocki 
1520f721889fSRafael J. Wysocki 	return ret;
1521f721889fSRafael J. Wysocki }
1522f721889fSRafael J. Wysocki 
1523f721889fSRafael J. Wysocki /**
1524f721889fSRafael J. Wysocki  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
1525f721889fSRafael J. Wysocki  * @genpd: Master PM domain to remove the subdomain from.
15265063ce15SRafael J. Wysocki  * @subdomain: Subdomain to be removed.
1527f721889fSRafael J. Wysocki  */
1528f721889fSRafael J. Wysocki int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
15295063ce15SRafael J. Wysocki 			      struct generic_pm_domain *subdomain)
1530f721889fSRafael J. Wysocki {
15315063ce15SRafael J. Wysocki 	struct gpd_link *link;
1532f721889fSRafael J. Wysocki 	int ret = -EINVAL;
1533f721889fSRafael J. Wysocki 
15345063ce15SRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
1535f721889fSRafael J. Wysocki 		return -EINVAL;
1536f721889fSRafael J. Wysocki 
153717b75ecaSRafael J. Wysocki  start:
153817b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
1539f721889fSRafael J. Wysocki 
15405063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->master_links, master_node) {
15415063ce15SRafael J. Wysocki 		if (link->slave != subdomain)
1542f721889fSRafael J. Wysocki 			continue;
1543f721889fSRafael J. Wysocki 
1544f721889fSRafael J. Wysocki 		mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
1545f721889fSRafael J. Wysocki 
154617b75ecaSRafael J. Wysocki 		if (subdomain->status != GPD_STATE_POWER_OFF
154717b75ecaSRafael J. Wysocki 		    && subdomain->status != GPD_STATE_ACTIVE) {
154817b75ecaSRafael J. Wysocki 			mutex_unlock(&subdomain->lock);
154917b75ecaSRafael J. Wysocki 			genpd_release_lock(genpd);
155017b75ecaSRafael J. Wysocki 			goto start;
155117b75ecaSRafael J. Wysocki 		}
155217b75ecaSRafael J. Wysocki 
15535063ce15SRafael J. Wysocki 		list_del(&link->master_node);
15545063ce15SRafael J. Wysocki 		list_del(&link->slave_node);
15555063ce15SRafael J. Wysocki 		kfree(link);
155617b75ecaSRafael J. Wysocki 		if (subdomain->status != GPD_STATE_POWER_OFF)
1557f721889fSRafael J. Wysocki 			genpd_sd_counter_dec(genpd);
1558f721889fSRafael J. Wysocki 
1559f721889fSRafael J. Wysocki 		mutex_unlock(&subdomain->lock);
1560f721889fSRafael J. Wysocki 
1561f721889fSRafael J. Wysocki 		ret = 0;
1562f721889fSRafael J. Wysocki 		break;
1563f721889fSRafael J. Wysocki 	}
1564f721889fSRafael J. Wysocki 
156517b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
1566f721889fSRafael J. Wysocki 
1567f721889fSRafael J. Wysocki 	return ret;
1568f721889fSRafael J. Wysocki }
1569f721889fSRafael J. Wysocki 
1570f721889fSRafael J. Wysocki /**
1571d5e4cbfeSRafael J. Wysocki  * pm_genpd_add_callbacks - Add PM domain callbacks to a given device.
1572d5e4cbfeSRafael J. Wysocki  * @dev: Device to add the callbacks to.
1573d5e4cbfeSRafael J. Wysocki  * @ops: Set of callbacks to add.
1574b02c999aSRafael J. Wysocki  * @td: Timing data to add to the device along with the callbacks (optional).
1575d5e4cbfeSRafael J. Wysocki  */
1576b02c999aSRafael J. Wysocki int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops,
1577b02c999aSRafael J. Wysocki 			   struct gpd_timing_data *td)
1578d5e4cbfeSRafael J. Wysocki {
1579d5e4cbfeSRafael J. Wysocki 	struct pm_domain_data *pdd;
1580d5e4cbfeSRafael J. Wysocki 	int ret = 0;
1581d5e4cbfeSRafael J. Wysocki 
1582d5e4cbfeSRafael J. Wysocki 	if (!(dev && dev->power.subsys_data && ops))
1583d5e4cbfeSRafael J. Wysocki 		return -EINVAL;
1584d5e4cbfeSRafael J. Wysocki 
1585d5e4cbfeSRafael J. Wysocki 	pm_runtime_disable(dev);
1586d5e4cbfeSRafael J. Wysocki 	device_pm_lock();
1587d5e4cbfeSRafael J. Wysocki 
1588d5e4cbfeSRafael J. Wysocki 	pdd = dev->power.subsys_data->domain_data;
1589d5e4cbfeSRafael J. Wysocki 	if (pdd) {
1590d5e4cbfeSRafael J. Wysocki 		struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
1591d5e4cbfeSRafael J. Wysocki 
1592d5e4cbfeSRafael J. Wysocki 		gpd_data->ops = *ops;
1593b02c999aSRafael J. Wysocki 		if (td)
1594b02c999aSRafael J. Wysocki 			gpd_data->td = *td;
1595d5e4cbfeSRafael J. Wysocki 	} else {
1596d5e4cbfeSRafael J. Wysocki 		ret = -EINVAL;
1597d5e4cbfeSRafael J. Wysocki 	}
1598d5e4cbfeSRafael J. Wysocki 
1599d5e4cbfeSRafael J. Wysocki 	device_pm_unlock();
1600d5e4cbfeSRafael J. Wysocki 	pm_runtime_enable(dev);
1601d5e4cbfeSRafael J. Wysocki 
1602d5e4cbfeSRafael J. Wysocki 	return ret;
1603d5e4cbfeSRafael J. Wysocki }
1604d5e4cbfeSRafael J. Wysocki EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks);
1605d5e4cbfeSRafael J. Wysocki 
1606d5e4cbfeSRafael J. Wysocki /**
1607b02c999aSRafael J. Wysocki  * __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device.
1608d5e4cbfeSRafael J. Wysocki  * @dev: Device to remove the callbacks from.
1609b02c999aSRafael J. Wysocki  * @clear_td: If set, clear the device's timing data too.
1610d5e4cbfeSRafael J. Wysocki  */
1611b02c999aSRafael J. Wysocki int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
1612d5e4cbfeSRafael J. Wysocki {
1613d5e4cbfeSRafael J. Wysocki 	struct pm_domain_data *pdd;
1614d5e4cbfeSRafael J. Wysocki 	int ret = 0;
1615d5e4cbfeSRafael J. Wysocki 
1616d5e4cbfeSRafael J. Wysocki 	if (!(dev && dev->power.subsys_data))
1617d5e4cbfeSRafael J. Wysocki 		return -EINVAL;
1618d5e4cbfeSRafael J. Wysocki 
1619d5e4cbfeSRafael J. Wysocki 	pm_runtime_disable(dev);
1620d5e4cbfeSRafael J. Wysocki 	device_pm_lock();
1621d5e4cbfeSRafael J. Wysocki 
1622d5e4cbfeSRafael J. Wysocki 	pdd = dev->power.subsys_data->domain_data;
1623d5e4cbfeSRafael J. Wysocki 	if (pdd) {
1624d5e4cbfeSRafael J. Wysocki 		struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
1625d5e4cbfeSRafael J. Wysocki 
1626d5e4cbfeSRafael J. Wysocki 		gpd_data->ops = (struct gpd_dev_ops){ 0 };
1627b02c999aSRafael J. Wysocki 		if (clear_td)
1628b02c999aSRafael J. Wysocki 			gpd_data->td = (struct gpd_timing_data){ 0 };
1629d5e4cbfeSRafael J. Wysocki 	} else {
1630d5e4cbfeSRafael J. Wysocki 		ret = -EINVAL;
1631d5e4cbfeSRafael J. Wysocki 	}
1632d5e4cbfeSRafael J. Wysocki 
1633d5e4cbfeSRafael J. Wysocki 	device_pm_unlock();
1634d5e4cbfeSRafael J. Wysocki 	pm_runtime_enable(dev);
1635d5e4cbfeSRafael J. Wysocki 
1636d5e4cbfeSRafael J. Wysocki 	return ret;
1637d5e4cbfeSRafael J. Wysocki }
1638b02c999aSRafael J. Wysocki EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
1639d5e4cbfeSRafael J. Wysocki 
1640cbc9ef02SRafael J. Wysocki int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
1641cbc9ef02SRafael J. Wysocki {
1642cbc9ef02SRafael J. Wysocki 	struct cpuidle_driver *cpuidle_drv;
1643cbc9ef02SRafael J. Wysocki 	struct gpd_cpu_data *cpu_data;
1644cbc9ef02SRafael J. Wysocki 	struct cpuidle_state *idle_state;
1645cbc9ef02SRafael J. Wysocki 	int ret = 0;
1646cbc9ef02SRafael J. Wysocki 
1647cbc9ef02SRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || state < 0)
1648cbc9ef02SRafael J. Wysocki 		return -EINVAL;
1649cbc9ef02SRafael J. Wysocki 
1650cbc9ef02SRafael J. Wysocki 	genpd_acquire_lock(genpd);
1651cbc9ef02SRafael J. Wysocki 
1652cbc9ef02SRafael J. Wysocki 	if (genpd->cpu_data) {
1653cbc9ef02SRafael J. Wysocki 		ret = -EEXIST;
1654cbc9ef02SRafael J. Wysocki 		goto out;
1655cbc9ef02SRafael J. Wysocki 	}
1656cbc9ef02SRafael J. Wysocki 	cpu_data = kzalloc(sizeof(*cpu_data), GFP_KERNEL);
1657cbc9ef02SRafael J. Wysocki 	if (!cpu_data) {
1658cbc9ef02SRafael J. Wysocki 		ret = -ENOMEM;
1659cbc9ef02SRafael J. Wysocki 		goto out;
1660cbc9ef02SRafael J. Wysocki 	}
1661cbc9ef02SRafael J. Wysocki 	cpuidle_drv = cpuidle_driver_ref();
1662cbc9ef02SRafael J. Wysocki 	if (!cpuidle_drv) {
1663cbc9ef02SRafael J. Wysocki 		ret = -ENODEV;
1664cbc9ef02SRafael J. Wysocki 		goto out;
1665cbc9ef02SRafael J. Wysocki 	}
1666cbc9ef02SRafael J. Wysocki 	if (cpuidle_drv->state_count <= state) {
1667cbc9ef02SRafael J. Wysocki 		ret = -EINVAL;
1668cbc9ef02SRafael J. Wysocki 		goto err;
1669cbc9ef02SRafael J. Wysocki 	}
1670cbc9ef02SRafael J. Wysocki 	idle_state = &cpuidle_drv->states[state];
1671cbc9ef02SRafael J. Wysocki 	if (!idle_state->disabled) {
1672cbc9ef02SRafael J. Wysocki 		ret = -EAGAIN;
1673cbc9ef02SRafael J. Wysocki 		goto err;
1674cbc9ef02SRafael J. Wysocki 	}
1675cbc9ef02SRafael J. Wysocki 	cpu_data->idle_state = idle_state;
1676cbc9ef02SRafael J. Wysocki 	cpu_data->saved_exit_latency = idle_state->exit_latency;
1677cbc9ef02SRafael J. Wysocki 	genpd->cpu_data = cpu_data;
1678cbc9ef02SRafael J. Wysocki 	genpd_recalc_cpu_exit_latency(genpd);
1679cbc9ef02SRafael J. Wysocki 
1680cbc9ef02SRafael J. Wysocki  out:
1681cbc9ef02SRafael J. Wysocki 	genpd_release_lock(genpd);
1682cbc9ef02SRafael J. Wysocki 	return ret;
1683cbc9ef02SRafael J. Wysocki 
1684cbc9ef02SRafael J. Wysocki  err:
1685cbc9ef02SRafael J. Wysocki 	cpuidle_driver_unref();
1686cbc9ef02SRafael J. Wysocki 	goto out;
1687cbc9ef02SRafael J. Wysocki }
1688cbc9ef02SRafael J. Wysocki 
1689cbc9ef02SRafael J. Wysocki int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
1690cbc9ef02SRafael J. Wysocki {
1691cbc9ef02SRafael J. Wysocki 	struct gpd_cpu_data *cpu_data;
1692cbc9ef02SRafael J. Wysocki 	struct cpuidle_state *idle_state;
1693cbc9ef02SRafael J. Wysocki 	int ret = 0;
1694cbc9ef02SRafael J. Wysocki 
1695cbc9ef02SRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd))
1696cbc9ef02SRafael J. Wysocki 		return -EINVAL;
1697cbc9ef02SRafael J. Wysocki 
1698cbc9ef02SRafael J. Wysocki 	genpd_acquire_lock(genpd);
1699cbc9ef02SRafael J. Wysocki 
1700cbc9ef02SRafael J. Wysocki 	cpu_data = genpd->cpu_data;
1701cbc9ef02SRafael J. Wysocki 	if (!cpu_data) {
1702cbc9ef02SRafael J. Wysocki 		ret = -ENODEV;
1703cbc9ef02SRafael J. Wysocki 		goto out;
1704cbc9ef02SRafael J. Wysocki 	}
1705cbc9ef02SRafael J. Wysocki 	idle_state = cpu_data->idle_state;
1706cbc9ef02SRafael J. Wysocki 	if (!idle_state->disabled) {
1707cbc9ef02SRafael J. Wysocki 		ret = -EAGAIN;
1708cbc9ef02SRafael J. Wysocki 		goto out;
1709cbc9ef02SRafael J. Wysocki 	}
1710cbc9ef02SRafael J. Wysocki 	idle_state->exit_latency = cpu_data->saved_exit_latency;
1711cbc9ef02SRafael J. Wysocki 	cpuidle_driver_unref();
1712cbc9ef02SRafael J. Wysocki 	genpd->cpu_data = NULL;
1713cbc9ef02SRafael J. Wysocki 	kfree(cpu_data);
1714cbc9ef02SRafael J. Wysocki 
1715cbc9ef02SRafael J. Wysocki  out:
1716cbc9ef02SRafael J. Wysocki 	genpd_release_lock(genpd);
1717cbc9ef02SRafael J. Wysocki 	return ret;
1718cbc9ef02SRafael J. Wysocki }
1719cbc9ef02SRafael J. Wysocki 
1720d23b9b00SRafael J. Wysocki /* Default device callbacks for generic PM domains. */
1721d23b9b00SRafael J. Wysocki 
1722d5e4cbfeSRafael J. Wysocki /**
1723ecf00475SRafael J. Wysocki  * pm_genpd_default_save_state - Default "save device state" for PM domians.
1724ecf00475SRafael J. Wysocki  * @dev: Device to handle.
1725ecf00475SRafael J. Wysocki  */
1726ecf00475SRafael J. Wysocki static int pm_genpd_default_save_state(struct device *dev)
1727ecf00475SRafael J. Wysocki {
1728ecf00475SRafael J. Wysocki 	int (*cb)(struct device *__dev);
1729ecf00475SRafael J. Wysocki 
1730ecf00475SRafael J. Wysocki 	cb = dev_gpd_data(dev)->ops.save_state;
1731ecf00475SRafael J. Wysocki 	if (cb)
1732ecf00475SRafael J. Wysocki 		return cb(dev);
1733ecf00475SRafael J. Wysocki 
17340b589741SRafael J. Wysocki 	if (dev->type && dev->type->pm)
17350b589741SRafael J. Wysocki 		cb = dev->type->pm->runtime_suspend;
17360b589741SRafael J. Wysocki 	else if (dev->class && dev->class->pm)
17370b589741SRafael J. Wysocki 		cb = dev->class->pm->runtime_suspend;
17380b589741SRafael J. Wysocki 	else if (dev->bus && dev->bus->pm)
17390b589741SRafael J. Wysocki 		cb = dev->bus->pm->runtime_suspend;
17400b589741SRafael J. Wysocki 	else
17410b589741SRafael J. Wysocki 		cb = NULL;
1742ecf00475SRafael J. Wysocki 
17430b589741SRafael J. Wysocki 	if (!cb && dev->driver && dev->driver->pm)
17440b589741SRafael J. Wysocki 		cb = dev->driver->pm->runtime_suspend;
17450b589741SRafael J. Wysocki 
17460b589741SRafael J. Wysocki 	return cb ? cb(dev) : 0;
1747ecf00475SRafael J. Wysocki }
1748ecf00475SRafael J. Wysocki 
1749ecf00475SRafael J. Wysocki /**
1750ecf00475SRafael J. Wysocki  * pm_genpd_default_restore_state - Default PM domians "restore device state".
1751ecf00475SRafael J. Wysocki  * @dev: Device to handle.
1752ecf00475SRafael J. Wysocki  */
1753ecf00475SRafael J. Wysocki static int pm_genpd_default_restore_state(struct device *dev)
1754ecf00475SRafael J. Wysocki {
1755ecf00475SRafael J. Wysocki 	int (*cb)(struct device *__dev);
1756ecf00475SRafael J. Wysocki 
1757ecf00475SRafael J. Wysocki 	cb = dev_gpd_data(dev)->ops.restore_state;
1758ecf00475SRafael J. Wysocki 	if (cb)
1759ecf00475SRafael J. Wysocki 		return cb(dev);
1760ecf00475SRafael J. Wysocki 
17610b589741SRafael J. Wysocki 	if (dev->type && dev->type->pm)
17620b589741SRafael J. Wysocki 		cb = dev->type->pm->runtime_resume;
17630b589741SRafael J. Wysocki 	else if (dev->class && dev->class->pm)
17640b589741SRafael J. Wysocki 		cb = dev->class->pm->runtime_resume;
17650b589741SRafael J. Wysocki 	else if (dev->bus && dev->bus->pm)
17660b589741SRafael J. Wysocki 		cb = dev->bus->pm->runtime_resume;
17670b589741SRafael J. Wysocki 	else
17680b589741SRafael J. Wysocki 		cb = NULL;
1769ecf00475SRafael J. Wysocki 
17700b589741SRafael J. Wysocki 	if (!cb && dev->driver && dev->driver->pm)
17710b589741SRafael J. Wysocki 		cb = dev->driver->pm->runtime_resume;
17720b589741SRafael J. Wysocki 
17730b589741SRafael J. Wysocki 	return cb ? cb(dev) : 0;
1774ecf00475SRafael J. Wysocki }
1775ecf00475SRafael J. Wysocki 
17760f1d6986SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
17770f1d6986SRafael J. Wysocki 
1778ecf00475SRafael J. Wysocki /**
1779d23b9b00SRafael J. Wysocki  * pm_genpd_default_suspend - Default "device suspend" for PM domians.
1780d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1781d23b9b00SRafael J. Wysocki  */
1782d23b9b00SRafael J. Wysocki static int pm_genpd_default_suspend(struct device *dev)
1783d23b9b00SRafael J. Wysocki {
1784c9914854SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend;
1785d23b9b00SRafael J. Wysocki 
1786d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_suspend(dev);
1787d23b9b00SRafael J. Wysocki }
1788d23b9b00SRafael J. Wysocki 
1789d23b9b00SRafael J. Wysocki /**
1790d23b9b00SRafael J. Wysocki  * pm_genpd_default_suspend_late - Default "late device suspend" for PM domians.
1791d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1792d23b9b00SRafael J. Wysocki  */
1793d23b9b00SRafael J. Wysocki static int pm_genpd_default_suspend_late(struct device *dev)
1794d23b9b00SRafael J. Wysocki {
1795c9914854SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late;
1796d23b9b00SRafael J. Wysocki 
17970496c8aeSRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_suspend_late(dev);
1798d23b9b00SRafael J. Wysocki }
1799d23b9b00SRafael J. Wysocki 
1800d23b9b00SRafael J. Wysocki /**
1801d23b9b00SRafael J. Wysocki  * pm_genpd_default_resume_early - Default "early device resume" for PM domians.
1802d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1803d23b9b00SRafael J. Wysocki  */
1804d23b9b00SRafael J. Wysocki static int pm_genpd_default_resume_early(struct device *dev)
1805d23b9b00SRafael J. Wysocki {
1806c9914854SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early;
1807d23b9b00SRafael J. Wysocki 
18080496c8aeSRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_resume_early(dev);
1809d23b9b00SRafael J. Wysocki }
1810d23b9b00SRafael J. Wysocki 
1811d23b9b00SRafael J. Wysocki /**
1812d23b9b00SRafael J. Wysocki  * pm_genpd_default_resume - Default "device resume" for PM domians.
1813d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1814d23b9b00SRafael J. Wysocki  */
1815d23b9b00SRafael J. Wysocki static int pm_genpd_default_resume(struct device *dev)
1816d23b9b00SRafael J. Wysocki {
1817c9914854SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume;
1818d23b9b00SRafael J. Wysocki 
1819d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_resume(dev);
1820d23b9b00SRafael J. Wysocki }
1821d23b9b00SRafael J. Wysocki 
1822d23b9b00SRafael J. Wysocki /**
1823d23b9b00SRafael J. Wysocki  * pm_genpd_default_freeze - Default "device freeze" for PM domians.
1824d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1825d23b9b00SRafael J. Wysocki  */
1826d23b9b00SRafael J. Wysocki static int pm_genpd_default_freeze(struct device *dev)
1827d23b9b00SRafael J. Wysocki {
1828d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze;
1829d23b9b00SRafael J. Wysocki 
1830d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_freeze(dev);
1831d23b9b00SRafael J. Wysocki }
1832d23b9b00SRafael J. Wysocki 
1833d23b9b00SRafael J. Wysocki /**
1834d23b9b00SRafael J. Wysocki  * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians.
1835d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1836d23b9b00SRafael J. Wysocki  */
1837d23b9b00SRafael J. Wysocki static int pm_genpd_default_freeze_late(struct device *dev)
1838d23b9b00SRafael J. Wysocki {
1839d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late;
1840d23b9b00SRafael J. Wysocki 
18410496c8aeSRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_freeze_late(dev);
1842d23b9b00SRafael J. Wysocki }
1843d23b9b00SRafael J. Wysocki 
1844d23b9b00SRafael J. Wysocki /**
1845d23b9b00SRafael J. Wysocki  * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians.
1846d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1847d23b9b00SRafael J. Wysocki  */
1848d23b9b00SRafael J. Wysocki static int pm_genpd_default_thaw_early(struct device *dev)
1849d23b9b00SRafael J. Wysocki {
1850d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early;
1851d23b9b00SRafael J. Wysocki 
18520496c8aeSRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_thaw_early(dev);
1853d23b9b00SRafael J. Wysocki }
1854d23b9b00SRafael J. Wysocki 
1855d23b9b00SRafael J. Wysocki /**
1856d23b9b00SRafael J. Wysocki  * pm_genpd_default_thaw - Default "device thaw" for PM domians.
1857d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1858d23b9b00SRafael J. Wysocki  */
1859d23b9b00SRafael J. Wysocki static int pm_genpd_default_thaw(struct device *dev)
1860d23b9b00SRafael J. Wysocki {
1861d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw;
1862d23b9b00SRafael J. Wysocki 
1863d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_thaw(dev);
1864d23b9b00SRafael J. Wysocki }
1865d23b9b00SRafael J. Wysocki 
18660f1d6986SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP */
18670f1d6986SRafael J. Wysocki 
18680f1d6986SRafael J. Wysocki #define pm_genpd_default_suspend	NULL
18690f1d6986SRafael J. Wysocki #define pm_genpd_default_suspend_late	NULL
18700f1d6986SRafael J. Wysocki #define pm_genpd_default_resume_early	NULL
18710f1d6986SRafael J. Wysocki #define pm_genpd_default_resume		NULL
18720f1d6986SRafael J. Wysocki #define pm_genpd_default_freeze		NULL
18730f1d6986SRafael J. Wysocki #define pm_genpd_default_freeze_late	NULL
18740f1d6986SRafael J. Wysocki #define pm_genpd_default_thaw_early	NULL
18750f1d6986SRafael J. Wysocki #define pm_genpd_default_thaw		NULL
18760f1d6986SRafael J. Wysocki 
18770f1d6986SRafael J. Wysocki #endif /* !CONFIG_PM_SLEEP */
18780f1d6986SRafael J. Wysocki 
1879d23b9b00SRafael J. Wysocki /**
1880f721889fSRafael J. Wysocki  * pm_genpd_init - Initialize a generic I/O PM domain object.
1881f721889fSRafael J. Wysocki  * @genpd: PM domain object to initialize.
1882f721889fSRafael J. Wysocki  * @gov: PM domain governor to associate with the domain (may be NULL).
1883f721889fSRafael J. Wysocki  * @is_off: Initial value of the domain's power_is_off field.
1884f721889fSRafael J. Wysocki  */
1885f721889fSRafael J. Wysocki void pm_genpd_init(struct generic_pm_domain *genpd,
1886f721889fSRafael J. Wysocki 		   struct dev_power_governor *gov, bool is_off)
1887f721889fSRafael J. Wysocki {
1888f721889fSRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd))
1889f721889fSRafael J. Wysocki 		return;
1890f721889fSRafael J. Wysocki 
18915063ce15SRafael J. Wysocki 	INIT_LIST_HEAD(&genpd->master_links);
18925063ce15SRafael J. Wysocki 	INIT_LIST_HEAD(&genpd->slave_links);
1893f721889fSRafael J. Wysocki 	INIT_LIST_HEAD(&genpd->dev_list);
1894f721889fSRafael J. Wysocki 	mutex_init(&genpd->lock);
1895f721889fSRafael J. Wysocki 	genpd->gov = gov;
1896f721889fSRafael J. Wysocki 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
1897f721889fSRafael J. Wysocki 	genpd->in_progress = 0;
1898c4bb3160SRafael J. Wysocki 	atomic_set(&genpd->sd_count, 0);
189917b75ecaSRafael J. Wysocki 	genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
190017b75ecaSRafael J. Wysocki 	init_waitqueue_head(&genpd->status_wait_queue);
1901c6d22b37SRafael J. Wysocki 	genpd->poweroff_task = NULL;
1902c6d22b37SRafael J. Wysocki 	genpd->resume_count = 0;
1903596ba34bSRafael J. Wysocki 	genpd->device_count = 0;
1904221e9b58SRafael J. Wysocki 	genpd->max_off_time_ns = -1;
19056ff7bb0dSRafael J. Wysocki 	genpd->max_off_time_changed = true;
1906f721889fSRafael J. Wysocki 	genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
1907f721889fSRafael J. Wysocki 	genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
1908f721889fSRafael J. Wysocki 	genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
1909596ba34bSRafael J. Wysocki 	genpd->domain.ops.prepare = pm_genpd_prepare;
1910596ba34bSRafael J. Wysocki 	genpd->domain.ops.suspend = pm_genpd_suspend;
19110496c8aeSRafael J. Wysocki 	genpd->domain.ops.suspend_late = pm_genpd_suspend_late;
1912596ba34bSRafael J. Wysocki 	genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq;
1913596ba34bSRafael J. Wysocki 	genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq;
19140496c8aeSRafael J. Wysocki 	genpd->domain.ops.resume_early = pm_genpd_resume_early;
1915596ba34bSRafael J. Wysocki 	genpd->domain.ops.resume = pm_genpd_resume;
1916596ba34bSRafael J. Wysocki 	genpd->domain.ops.freeze = pm_genpd_freeze;
19170496c8aeSRafael J. Wysocki 	genpd->domain.ops.freeze_late = pm_genpd_freeze_late;
1918596ba34bSRafael J. Wysocki 	genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
1919596ba34bSRafael J. Wysocki 	genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
19200496c8aeSRafael J. Wysocki 	genpd->domain.ops.thaw_early = pm_genpd_thaw_early;
1921596ba34bSRafael J. Wysocki 	genpd->domain.ops.thaw = pm_genpd_thaw;
1922d23b9b00SRafael J. Wysocki 	genpd->domain.ops.poweroff = pm_genpd_suspend;
19230496c8aeSRafael J. Wysocki 	genpd->domain.ops.poweroff_late = pm_genpd_suspend_late;
1924d23b9b00SRafael J. Wysocki 	genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq;
1925596ba34bSRafael J. Wysocki 	genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
19260496c8aeSRafael J. Wysocki 	genpd->domain.ops.restore_early = pm_genpd_resume_early;
1927d23b9b00SRafael J. Wysocki 	genpd->domain.ops.restore = pm_genpd_resume;
1928596ba34bSRafael J. Wysocki 	genpd->domain.ops.complete = pm_genpd_complete;
1929ecf00475SRafael J. Wysocki 	genpd->dev_ops.save_state = pm_genpd_default_save_state;
1930ecf00475SRafael J. Wysocki 	genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
1931c9914854SRafael J. Wysocki 	genpd->dev_ops.suspend = pm_genpd_default_suspend;
1932c9914854SRafael J. Wysocki 	genpd->dev_ops.suspend_late = pm_genpd_default_suspend_late;
1933c9914854SRafael J. Wysocki 	genpd->dev_ops.resume_early = pm_genpd_default_resume_early;
1934c9914854SRafael J. Wysocki 	genpd->dev_ops.resume = pm_genpd_default_resume;
1935d23b9b00SRafael J. Wysocki 	genpd->dev_ops.freeze = pm_genpd_default_freeze;
1936d23b9b00SRafael J. Wysocki 	genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late;
1937d23b9b00SRafael J. Wysocki 	genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early;
1938d23b9b00SRafael J. Wysocki 	genpd->dev_ops.thaw = pm_genpd_default_thaw;
19395125bbf3SRafael J. Wysocki 	mutex_lock(&gpd_list_lock);
19405125bbf3SRafael J. Wysocki 	list_add(&genpd->gpd_list_node, &gpd_list);
19415125bbf3SRafael J. Wysocki 	mutex_unlock(&gpd_list_lock);
19425125bbf3SRafael J. Wysocki }
1943