4160 lines · 106.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * drivers/base/power/domain.c - Common code related to device power domains. * * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp. */#define pr_fmt(fmt) "PM: " fmt #include <linux/delay.h>#include <linux/idr.h>#include <linux/kernel.h>#include <linux/io.h>#include <linux/platform_device.h>#include <linux/pm_opp.h>#include <linux/pm_runtime.h>#include <linux/pm_domain.h>#include <linux/pm_qos.h>#include <linux/pm_clock.h>#include <linux/slab.h>#include <linux/err.h>#include <linux/sched.h>#include <linux/suspend.h>#include <linux/export.h>#include <linux/cpu.h>#include <linux/debugfs.h> /* Provides a unique ID for each genpd device */static DEFINE_IDA(genpd_ida); /* The bus for genpd_providers. */static const struct bus_type genpd_provider_bus_type = {	.name		= "genpd_provider",}; #define GENPD_RETRY_MAX_MS	250		/* Approximate */ #define GENPD_DEV_CALLBACK(genpd, type, callback, dev)		\({								\	type (*__routine)(struct device *__d); 			\	type __ret = (type)0;					\								\	__routine = genpd->dev_ops.callback; 			\	if (__routine) {					\		__ret = __routine(dev); 			\	}							\	__ret;							\}) static LIST_HEAD(gpd_list);static DEFINE_MUTEX(gpd_list_lock); struct genpd_lock_ops {	void (*lock)(struct generic_pm_domain *genpd);	void (*lock_nested)(struct generic_pm_domain *genpd, int depth);	int (*lock_interruptible)(struct generic_pm_domain *genpd);	void (*unlock)(struct generic_pm_domain *genpd);}; static void genpd_lock_mtx(struct generic_pm_domain *genpd){	mutex_lock(&genpd->mlock);} static void genpd_lock_nested_mtx(struct generic_pm_domain *genpd,					int depth){	mutex_lock_nested(&genpd->mlock, depth);} static int genpd_lock_interruptible_mtx(struct generic_pm_domain *genpd){	return mutex_lock_interruptible(&genpd->mlock);} static void genpd_unlock_mtx(struct generic_pm_domain *genpd){	return mutex_unlock(&genpd->mlock);} static const struct genpd_lock_ops genpd_mtx_ops = {	.lock = genpd_lock_mtx,	.lock_nested = genpd_lock_nested_mtx,	.lock_interruptible = genpd_lock_interruptible_mtx,	.unlock = genpd_unlock_mtx,}; static void genpd_lock_spin(struct generic_pm_domain *genpd)	__acquires(&genpd->slock){	unsigned long flags; 	spin_lock_irqsave(&genpd->slock, flags);	genpd->lock_flags = flags;} static void genpd_lock_nested_spin(struct generic_pm_domain *genpd,					int depth)	__acquires(&genpd->slock){	unsigned long flags; 	spin_lock_irqsave_nested(&genpd->slock, flags, depth);	genpd->lock_flags = flags;} static int genpd_lock_interruptible_spin(struct generic_pm_domain *genpd)	__acquires(&genpd->slock){	unsigned long flags; 	spin_lock_irqsave(&genpd->slock, flags);	genpd->lock_flags = flags;	return 0;} static void genpd_unlock_spin(struct generic_pm_domain *genpd)	__releases(&genpd->slock){	spin_unlock_irqrestore(&genpd->slock, genpd->lock_flags);} static const struct genpd_lock_ops genpd_spin_ops = {	.lock = genpd_lock_spin,	.lock_nested = genpd_lock_nested_spin,	.lock_interruptible = genpd_lock_interruptible_spin,	.unlock = genpd_unlock_spin,}; static void genpd_lock_raw_spin(struct generic_pm_domain *genpd)	__acquires(&genpd->raw_slock){	unsigned long flags; 	raw_spin_lock_irqsave(&genpd->raw_slock, flags);	genpd->raw_lock_flags = flags;} static void genpd_lock_nested_raw_spin(struct generic_pm_domain *genpd,					int depth)	__acquires(&genpd->raw_slock){	unsigned long flags; 	raw_spin_lock_irqsave_nested(&genpd->raw_slock, flags, depth);	genpd->raw_lock_flags = flags;} static int genpd_lock_interruptible_raw_spin(struct generic_pm_domain *genpd)	__acquires(&genpd->raw_slock){	unsigned long flags; 	raw_spin_lock_irqsave(&genpd->raw_slock, flags);	genpd->raw_lock_flags = flags;	return 0;} static void genpd_unlock_raw_spin(struct generic_pm_domain *genpd)	__releases(&genpd->raw_slock){	raw_spin_unlock_irqrestore(&genpd->raw_slock, genpd->raw_lock_flags);} static const struct genpd_lock_ops genpd_raw_spin_ops = {	.lock = genpd_lock_raw_spin,	.lock_nested = genpd_lock_nested_raw_spin,	.lock_interruptible = genpd_lock_interruptible_raw_spin,	.unlock = genpd_unlock_raw_spin,}; #define genpd_lock(p)			p->lock_ops->lock(p)#define genpd_lock_nested(p, d)		p->lock_ops->lock_nested(p, d)#define genpd_lock_interruptible(p)	p->lock_ops->lock_interruptible(p)#define genpd_unlock(p)			p->lock_ops->unlock(p) #define genpd_status_on(genpd)		(genpd->status == GENPD_STATE_ON)#define genpd_is_irq_safe(genpd)	(genpd->flags & GENPD_FLAG_IRQ_SAFE)#define genpd_is_always_on(genpd)	(genpd->flags & GENPD_FLAG_ALWAYS_ON)#define genpd_is_active_wakeup(genpd)	(genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP)#define genpd_is_cpu_domain(genpd)	(genpd->flags & GENPD_FLAG_CPU_DOMAIN)#define genpd_is_rpm_always_on(genpd)	(genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON)#define genpd_is_opp_table_fw(genpd)	(genpd->flags & GENPD_FLAG_OPP_TABLE_FW)#define genpd_is_dev_name_fw(genpd)	(genpd->flags & GENPD_FLAG_DEV_NAME_FW)#define genpd_is_no_sync_state(genpd)	(genpd->flags & GENPD_FLAG_NO_SYNC_STATE)#define genpd_is_no_stay_on(genpd)	(genpd->flags & GENPD_FLAG_NO_STAY_ON) static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,		const struct generic_pm_domain *genpd){	bool ret; 	ret = pm_runtime_is_irq_safe(dev) && !genpd_is_irq_safe(genpd); 	/*	 * Warn once if an IRQ safe device is attached to a domain, which	 * callbacks are allowed to sleep. This indicates a suboptimal	 * configuration for PM, but it doesn't matter for an always on domain.	 */	if (genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd))		return ret; 	if (ret)		dev_warn_once(dev, "PM domain %s will not be powered off\n",			      dev_name(&genpd->dev)); 	return ret;} static int genpd_runtime_suspend(struct device *dev); /* * Get the generic PM domain for a particular struct device. * This validates the struct device pointer, the PM domain pointer, * and checks that the PM domain pointer is a real generic PM domain. * Any failure results in NULL being returned. */static struct generic_pm_domain *dev_to_genpd_safe(struct device *dev){	if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(dev->pm_domain))		return NULL; 	/* A genpd's always have its ->runtime_suspend() callback assigned. */	if (dev->pm_domain->ops.runtime_suspend == genpd_runtime_suspend)		return pd_to_genpd(dev->pm_domain); 	return NULL;} /* * This should only be used where we are certain that the pm_domain * attached to the device is a genpd domain. */static struct generic_pm_domain *dev_to_genpd(struct device *dev){	if (IS_ERR_OR_NULL(dev->pm_domain))		return ERR_PTR(-EINVAL); 	return pd_to_genpd(dev->pm_domain);} struct device *dev_to_genpd_dev(struct device *dev){	struct generic_pm_domain *genpd = dev_to_genpd(dev); 	if (IS_ERR(genpd))		return ERR_CAST(genpd); 	return &genpd->dev;} static int genpd_stop_dev(const struct generic_pm_domain *genpd,			  struct device *dev){	return GENPD_DEV_CALLBACK(genpd, int, stop, dev);} static int genpd_start_dev(const struct generic_pm_domain *genpd,			   struct device *dev){	return GENPD_DEV_CALLBACK(genpd, int, start, dev);} static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd){	bool ret = false; 	if (!WARN_ON(atomic_read(&genpd->sd_count) == 0))		ret = !!atomic_dec_and_test(&genpd->sd_count); 	return ret;} static void genpd_sd_counter_inc(struct generic_pm_domain *genpd){	atomic_inc(&genpd->sd_count);	smp_mb__after_atomic();} #ifdef CONFIG_DEBUG_FSstatic struct dentry *genpd_debugfs_dir; static void genpd_debug_add(struct generic_pm_domain *genpd); static void genpd_debug_remove(struct generic_pm_domain *genpd){	if (!genpd_debugfs_dir)		return; 	debugfs_lookup_and_remove(dev_name(&genpd->dev), genpd_debugfs_dir);} static void genpd_update_accounting(struct generic_pm_domain *genpd){	u64 delta, now; 	now = ktime_get_mono_fast_ns();	if (now <= genpd->accounting_time)		return; 	delta = now - genpd->accounting_time; 	/*	 * If genpd->status is active, it means we are just	 * out of off and so update the idle time and vice	 * versa.	 */	if (genpd->status == GENPD_STATE_ON)		genpd->states[genpd->state_idx].idle_time += delta;	else		genpd->on_time += delta; 	genpd->accounting_time = now;} static void genpd_reflect_residency(struct generic_pm_domain *genpd){	struct genpd_governor_data *gd = genpd->gd;	struct genpd_power_state *state, *next_state;	unsigned int state_idx;	s64 sleep_ns, target_ns; 	if (!gd || !gd->reflect_residency)		return; 	sleep_ns = ktime_to_ns(ktime_sub(ktime_get(), gd->last_enter));	state_idx = genpd->state_idx;	state = &genpd->states[state_idx];	target_ns = state->power_off_latency_ns + state->residency_ns; 	if (sleep_ns < target_ns) {		state->above++;	} else if (state_idx < (genpd->state_count -1)) {		next_state = &genpd->states[state_idx + 1];		target_ns = next_state->power_off_latency_ns +			next_state->residency_ns; 		if (sleep_ns >= target_ns)			state->below++;	} 	gd->reflect_residency = false;}#elsestatic inline void genpd_debug_add(struct generic_pm_domain *genpd) {}static inline void genpd_debug_remove(struct generic_pm_domain *genpd) {}static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}static inline void genpd_reflect_residency(struct generic_pm_domain *genpd) {}#endif static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd,					   unsigned int state){	struct generic_pm_domain_data *pd_data;	struct pm_domain_data *pdd;	struct gpd_link *link; 	/* New requested state is same as Max requested state */	if (state == genpd->performance_state)		return state; 	/* New requested state is higher than Max requested state */	if (state > genpd->performance_state)		return state; 	/* Traverse all devices within the domain */	list_for_each_entry(pdd, &genpd->dev_list, list_node) {		pd_data = to_gpd_data(pdd); 		if (pd_data->performance_state > state)			state = pd_data->performance_state;	} 	/*	 * Traverse all sub-domains within the domain. This can be	 * done without any additional locking as the link->performance_state	 * field is protected by the parent genpd->lock, which is already taken.	 *	 * Also note that link->performance_state (subdomain's performance state	 * requirement to parent domain) is different from	 * link->child->performance_state (current performance state requirement	 * of the devices/sub-domains of the subdomain) and so can have a	 * different value.	 *	 * Note that we also take vote from powered-off sub-domains into account	 * as the same is done for devices right now.	 */	list_for_each_entry(link, &genpd->parent_links, parent_node) {		if (link->performance_state > state)			state = link->performance_state;	} 	return state;} static int genpd_xlate_performance_state(struct generic_pm_domain *genpd,					 struct generic_pm_domain *parent,					 unsigned int pstate){	if (!parent->set_performance_state)		return pstate; 	return dev_pm_opp_xlate_performance_state(genpd->opp_table,						  parent->opp_table,						  pstate);} static int _genpd_set_performance_state(struct generic_pm_domain *genpd,					unsigned int state, int depth); static void _genpd_rollback_parent_state(struct gpd_link *link, int depth){	struct generic_pm_domain *parent = link->parent;	int parent_state; 	genpd_lock_nested(parent, depth + 1); 	parent_state = link->prev_performance_state;	link->performance_state = parent_state; 	parent_state = _genpd_reeval_performance_state(parent, parent_state);	if (_genpd_set_performance_state(parent, parent_state, depth + 1)) {		pr_err("%s: Failed to roll back to %d performance state\n",		       parent->name, parent_state);	} 	genpd_unlock(parent);} static int _genpd_set_parent_state(struct generic_pm_domain *genpd,				   struct gpd_link *link,				   unsigned int state, int depth){	struct generic_pm_domain *parent = link->parent;	int parent_state, ret; 	/* Find parent's performance state */	ret = genpd_xlate_performance_state(genpd, parent, state);	if (unlikely(ret < 0))		return ret; 	parent_state = ret; 	genpd_lock_nested(parent, depth + 1); 	link->prev_performance_state = link->performance_state;	link->performance_state = parent_state; 	parent_state = _genpd_reeval_performance_state(parent, parent_state);	ret = _genpd_set_performance_state(parent, parent_state, depth + 1);	if (ret)		link->performance_state = link->prev_performance_state; 	genpd_unlock(parent); 	return ret;} static int _genpd_set_performance_state(struct generic_pm_domain *genpd,					unsigned int state, int depth){	struct gpd_link *link = NULL;	int ret; 	if (state == genpd->performance_state)		return 0; 	/* When scaling up, propagate to parents first in normal order */	if (state > genpd->performance_state) {		list_for_each_entry(link, &genpd->child_links, child_node) {			ret = _genpd_set_parent_state(genpd, link, state, depth);			if (ret)				goto rollback_parents_up;		}	} 	if (genpd->set_performance_state) {		ret = genpd->set_performance_state(genpd, state);		if (ret) {			if (link)				goto rollback_parents_up;			return ret;		}	} 	/* When scaling down, propagate to parents last in reverse order */	if (state < genpd->performance_state) {		list_for_each_entry_reverse(link, &genpd->child_links, child_node) {			ret = _genpd_set_parent_state(genpd, link, state, depth);			if (ret)				goto rollback_parents_down;		}	} 	genpd->performance_state = state;	return 0; rollback_parents_up:	list_for_each_entry_continue_reverse(link, &genpd->child_links, child_node)		_genpd_rollback_parent_state(link, depth);	return ret;

Lines 1–500 of 4160.