linux/drivers/devfreq/devfreq.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
 *	    for Non-CPU Devices.
 *
 * Copyright (C) 2011 Samsung Electronics
 *	MyungJoo Ham <[email protected]>
 */

#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/devfreq_cooling.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/pm_opp.h>
#include <linux/devfreq.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/hrtimer.h>
#include <linux/of.h>
#include <linux/pm_qos.h>
#include <linux/units.h>
#include "governor.h"

#define CREATE_TRACE_POINTS
#include <trace/events/devfreq.h>

#define IS_SUPPORTED_FLAG(f, name)
#define IS_SUPPORTED_ATTR(f, name)

static struct class *devfreq_class;
static struct dentry *devfreq_debugfs;

/*
 * devfreq core provides delayed work based load monitoring helper
 * functions. Governors can use these or can implement their own
 * monitoring mechanism.
 */
static struct workqueue_struct *devfreq_wq;

/* The list of all device-devfreq governors */
static LIST_HEAD(devfreq_governor_list);
/* The list of all device-devfreq */
static LIST_HEAD(devfreq_list);
static DEFINE_MUTEX(devfreq_list_lock);

static const char timer_name[][DEVFREQ_NAME_LEN] =;

/**
 * find_device_devfreq() - find devfreq struct using device pointer
 * @dev:	device pointer used to lookup device devfreq.
 *
 * Search the list of device devfreqs and return the matched device's
 * devfreq info. devfreq_list_lock should be held by the caller.
 */
static struct devfreq *find_device_devfreq(struct device *dev)
{}

static unsigned long find_available_min_freq(struct devfreq *devfreq)
{}

static unsigned long find_available_max_freq(struct devfreq *devfreq)
{}

/**
 * devfreq_get_freq_range() - Get the current freq range
 * @devfreq:	the devfreq instance
 * @min_freq:	the min frequency
 * @max_freq:	the max frequency
 *
 * This takes into consideration all constraints.
 */
void devfreq_get_freq_range(struct devfreq *devfreq,
			    unsigned long *min_freq,
			    unsigned long *max_freq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_get_freq_level() - Lookup freq_table for the frequency
 * @devfreq:	the devfreq instance
 * @freq:	the target frequency
 */
static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
{}

static int set_freq_table(struct devfreq *devfreq)
{}

/**
 * devfreq_update_status() - Update statistics of devfreq behavior
 * @devfreq:	the devfreq instance
 * @freq:	the update target frequency
 */
int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
{}
EXPORT_SYMBOL();

/**
 * find_devfreq_governor() - find devfreq governor from name
 * @name:	name of the governor
 *
 * Search the list of devfreq governors and return the matched
 * governor's pointer. devfreq_list_lock should be held by the caller.
 */
static struct devfreq_governor *find_devfreq_governor(const char *name)
{}

/**
 * try_then_request_governor() - Try to find the governor and request the
 *                               module if is not found.
 * @name:	name of the governor
 *
 * Search the list of devfreq governors and request the module and try again
 * if is not found. This can happen when both drivers (the governor driver
 * and the driver that call devfreq_add_device) are built as modules.
 * devfreq_list_lock should be held by the caller. Returns the matched
 * governor's pointer or an error pointer.
 */
static struct devfreq_governor *try_then_request_governor(const char *name)
{}

static int devfreq_notify_transition(struct devfreq *devfreq,
		struct devfreq_freqs *freqs, unsigned int state)
{}

static int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq,
			      u32 flags)
{}

/**
 * devfreq_update_target() - Reevaluate the device and configure frequency
 *			   on the final stage.
 * @devfreq:	the devfreq instance.
 * @freq:	the new frequency of parent device. This argument
 *		is only used for devfreq device using passive governor.
 *
 * Note: Lock devfreq->lock before calling devfreq_update_target. This function
 *	 should be only used by both update_devfreq() and devfreq governors.
 */
int devfreq_update_target(struct devfreq *devfreq, unsigned long freq)
{}
EXPORT_SYMBOL();

/* Load monitoring helper functions for governors use */

/**
 * update_devfreq() - Reevaluate the device and configure frequency.
 * @devfreq:	the devfreq instance.
 *
 * Note: Lock devfreq->lock before calling update_devfreq
 *	 This function is exported for governors.
 */
int update_devfreq(struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_monitor() - Periodically poll devfreq objects.
 * @work:	the work struct used to run devfreq_monitor periodically.
 *
 */
static void devfreq_monitor(struct work_struct *work)
{}

/**
 * devfreq_monitor_start() - Start load monitoring of devfreq instance
 * @devfreq:	the devfreq instance.
 *
 * Helper function for starting devfreq device load monitoring. By default,
 * deferrable timer is used for load monitoring. But the users can change this
 * behavior using the "timer" type in devfreq_dev_profile. This function will be
 * called by devfreq governor in response to the DEVFREQ_GOV_START event
 * generated while adding a device to the devfreq framework.
 */
void devfreq_monitor_start(struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance
 * @devfreq:	the devfreq instance.
 *
 * Helper function to stop devfreq device load monitoring. Function
 * to be called from governor in response to DEVFREQ_GOV_STOP
 * event when device is removed from devfreq framework.
 */
void devfreq_monitor_stop(struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance
 * @devfreq:	the devfreq instance.
 *
 * Helper function to suspend devfreq device load monitoring. Function
 * to be called from governor in response to DEVFREQ_GOV_SUSPEND
 * event or when polling interval is set to zero.
 *
 * Note: Though this function is same as devfreq_monitor_stop(),
 * intentionally kept separate to provide hooks for collecting
 * transition statistics.
 */
void devfreq_monitor_suspend(struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance
 * @devfreq:    the devfreq instance.
 *
 * Helper function to resume devfreq device load monitoring. Function
 * to be called from governor in response to DEVFREQ_GOV_RESUME
 * event or when polling interval is set to non-zero.
 */
void devfreq_monitor_resume(struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_update_interval() - Update device devfreq monitoring interval
 * @devfreq:    the devfreq instance.
 * @delay:      new polling interval to be set.
 *
 * Helper function to set new load monitoring polling interval. Function
 * to be called from governor in response to DEVFREQ_GOV_UPDATE_INTERVAL event.
 */
void devfreq_update_interval(struct devfreq *devfreq, unsigned int *delay)
{}
EXPORT_SYMBOL();

/**
 * devfreq_notifier_call() - Notify that the device frequency requirements
 *			     has been changed out of devfreq framework.
 * @nb:		the notifier_block (supposed to be devfreq->nb)
 * @type:	not used
 * @devp:	not used
 *
 * Called by a notifier that uses devfreq->nb.
 */
static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
				 void *devp)
{}

/**
 * qos_notifier_call() - Common handler for QoS constraints.
 * @devfreq:    the devfreq instance.
 */
static int qos_notifier_call(struct devfreq *devfreq)
{}

/**
 * qos_min_notifier_call() - Callback for QoS min_freq changes.
 * @nb:		Should be devfreq->nb_min
 * @val:	not used
 * @ptr:	not used
 */
static int qos_min_notifier_call(struct notifier_block *nb,
					 unsigned long val, void *ptr)
{}

/**
 * qos_max_notifier_call() - Callback for QoS max_freq changes.
 * @nb:		Should be devfreq->nb_max
 * @val:	not used
 * @ptr:	not used
 */
static int qos_max_notifier_call(struct notifier_block *nb,
					 unsigned long val, void *ptr)
{}

/**
 * devfreq_dev_release() - Callback for struct device to release the device.
 * @dev:	the devfreq device
 *
 * Remove devfreq from the list and release its resources.
 */
static void devfreq_dev_release(struct device *dev)
{}

static void create_sysfs_files(struct devfreq *devfreq,
				const struct devfreq_governor *gov);
static void remove_sysfs_files(struct devfreq *devfreq,
				const struct devfreq_governor *gov);

/**
 * devfreq_add_device() - Add devfreq feature to the device
 * @dev:	the device to add devfreq feature.
 * @profile:	device-specific profile to run devfreq.
 * @governor_name:	name of the policy to choose frequency.
 * @data:	devfreq driver pass to governors, governor should not change it.
 */
struct devfreq *devfreq_add_device(struct device *dev,
				   struct devfreq_dev_profile *profile,
				   const char *governor_name,
				   void *data)
{}
EXPORT_SYMBOL();

/**
 * devfreq_remove_device() - Remove devfreq feature from a device.
 * @devfreq:	the devfreq instance to be removed
 *
 * The opposite of devfreq_add_device().
 */
int devfreq_remove_device(struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

static int devm_devfreq_dev_match(struct device *dev, void *res, void *data)
{}

static void devm_devfreq_dev_release(struct device *dev, void *res)
{}

/**
 * devm_devfreq_add_device() - Resource-managed devfreq_add_device()
 * @dev:	the device to add devfreq feature.
 * @profile:	device-specific profile to run devfreq.
 * @governor_name:	name of the policy to choose frequency.
 * @data:	 devfreq driver pass to governors, governor should not change it.
 *
 * This function manages automatically the memory of devfreq device using device
 * resource management and simplify the free operation for memory of devfreq
 * device.
 */
struct devfreq *devm_devfreq_add_device(struct device *dev,
					struct devfreq_dev_profile *profile,
					const char *governor_name,
					void *data)
{}
EXPORT_SYMBOL();

#ifdef CONFIG_OF
/*
 * devfreq_get_devfreq_by_node - Get the devfreq device from devicetree
 * @node - pointer to device_node
 *
 * return the instance of devfreq device
 */
struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
{}

/*
 * devfreq_get_devfreq_by_phandle - Get the devfreq device from devicetree
 * @dev - instance to the given device
 * @phandle_name - name of property holding a phandle value
 * @index - index into list of devfreq
 *
 * return the instance of devfreq device
 */
struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
					const char *phandle_name, int index)
{}

#else
struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
{
	return ERR_PTR(-ENODEV);
}

struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
					const char *phandle_name, int index)
{
	return ERR_PTR(-ENODEV);
}
#endif /* CONFIG_OF */
EXPORT_SYMBOL_GPL();
EXPORT_SYMBOL_GPL();

/**
 * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device()
 * @dev:	the device from which to remove devfreq feature.
 * @devfreq:	the devfreq instance to be removed
 */
void devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_suspend_device() - Suspend devfreq of a device.
 * @devfreq: the devfreq instance to be suspended
 *
 * This function is intended to be called by the pm callbacks
 * (e.g., runtime_suspend, suspend) of the device driver that
 * holds the devfreq.
 */
int devfreq_suspend_device(struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_resume_device() - Resume devfreq of a device.
 * @devfreq: the devfreq instance to be resumed
 *
 * This function is intended to be called by the pm callbacks
 * (e.g., runtime_resume, resume) of the device driver that
 * holds the devfreq.
 */
int devfreq_resume_device(struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_suspend() - Suspend devfreq governors and devices
 *
 * Called during system wide Suspend/Hibernate cycles for suspending governors
 * and devices preserving the state for resume. On some platforms the devfreq
 * device must have precise state (frequency) after resume in order to provide
 * fully operating setup.
 */
void devfreq_suspend(void)
{}

/**
 * devfreq_resume() - Resume devfreq governors and devices
 *
 * Called during system wide Suspend/Hibernate cycle for resuming governors and
 * devices that are suspended with devfreq_suspend().
 */
void devfreq_resume(void)
{}

/**
 * devfreq_add_governor() - Add devfreq governor
 * @governor:	the devfreq governor to be added
 */
int devfreq_add_governor(struct devfreq_governor *governor)
{}
EXPORT_SYMBOL();

static void devm_devfreq_remove_governor(void *governor)
{}

/**
 * devm_devfreq_add_governor() - Add devfreq governor
 * @dev:	device which adds devfreq governor
 * @governor:	the devfreq governor to be added
 *
 * This is a resource-managed variant of devfreq_add_governor().
 */
int devm_devfreq_add_governor(struct device *dev,
			      struct devfreq_governor *governor)
{}
EXPORT_SYMBOL();

/**
 * devfreq_remove_governor() - Remove devfreq feature from a device.
 * @governor:	the devfreq governor to be removed
 */
int devfreq_remove_governor(struct devfreq_governor *governor)
{}
EXPORT_SYMBOL();

static ssize_t name_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{}
static DEVICE_ATTR_RO(name);

static ssize_t governor_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
			      const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(governor);

static ssize_t available_governors_show(struct device *d,
					struct device_attribute *attr,
					char *buf)
{}
static DEVICE_ATTR_RO(available_governors);

static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{}
static DEVICE_ATTR_RO(cur_freq);

static ssize_t target_freq_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{}
static DEVICE_ATTR_RO(target_freq);

static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
			      const char *buf, size_t count)
{}

static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{}
static DEVICE_ATTR_RW(min_freq);

static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
			      const char *buf, size_t count)
{}

static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{}
static DEVICE_ATTR_RW(max_freq);

static ssize_t available_frequencies_show(struct device *d,
					  struct device_attribute *attr,
					  char *buf)
{}
static DEVICE_ATTR_RO(available_frequencies);

static ssize_t trans_stat_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{}

static ssize_t trans_stat_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(trans_stat);

static struct attribute *devfreq_attrs[] =;
ATTRIBUTE_GROUPS();

static ssize_t polling_interval_show(struct device *dev,
				     struct device_attribute *attr, char *buf)
{}

static ssize_t polling_interval_store(struct device *dev,
				      struct device_attribute *attr,
				      const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(polling_interval);

static ssize_t timer_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

static ssize_t timer_store(struct device *dev, struct device_attribute *attr,
			      const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(timer);

#define CREATE_SYSFS_FILE(df, name)									\

/* Create the specific sysfs files which depend on each governor. */
static void create_sysfs_files(struct devfreq *devfreq,
				const struct devfreq_governor *gov)
{}

/* Remove the specific sysfs files which depend on each governor. */
static void remove_sysfs_files(struct devfreq *devfreq,
				const struct devfreq_governor *gov)
{}

/**
 * devfreq_summary_show() - Show the summary of the devfreq devices
 * @s:		seq_file instance to show the summary of devfreq devices
 * @data:	not used
 *
 * Show the summary of the devfreq devices via 'devfreq_summary' debugfs file.
 * It helps that user can know the detailed information of the devfreq devices.
 *
 * Return 0 always because it shows the information without any data change.
 */
static int devfreq_summary_show(struct seq_file *s, void *data)
{}
DEFINE_SHOW_ATTRIBUTE();

static int __init devfreq_init(void)
{}
subsys_initcall(devfreq_init);

/*
 * The following are helper functions for devfreq user device drivers with
 * OPP framework.
 */

/**
 * devfreq_recommended_opp() - Helper function to get proper OPP for the
 *			     freq value given to target callback.
 * @dev:	The devfreq user device. (parent of devfreq)
 * @freq:	The frequency given to target function
 * @flags:	Flags handed from devfreq framework.
 *
 * The callers are required to call dev_pm_opp_put() for the returned OPP after
 * use.
 */
struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
					   unsigned long *freq,
					   u32 flags)
{}
EXPORT_SYMBOL();

/**
 * devfreq_register_opp_notifier() - Helper function to get devfreq notified
 *				     for any changes in the OPP availability
 *				     changes
 * @dev:	The devfreq user device. (parent of devfreq)
 * @devfreq:	The devfreq object.
 */
int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
 *				       notified for any changes in the OPP
 *				       availability changes anymore.
 * @dev:	The devfreq user device. (parent of devfreq)
 * @devfreq:	The devfreq object.
 *
 * At exit() callback of devfreq_dev_profile, this must be included if
 * devfreq_recommended_opp is used.
 */
int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

static void devm_devfreq_opp_release(struct device *dev, void *res)
{}

/**
 * devm_devfreq_register_opp_notifier() - Resource-managed
 *					  devfreq_register_opp_notifier()
 * @dev:	The devfreq user device. (parent of devfreq)
 * @devfreq:	The devfreq object.
 */
int devm_devfreq_register_opp_notifier(struct device *dev,
				       struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devm_devfreq_unregister_opp_notifier() - Resource-managed
 *					    devfreq_unregister_opp_notifier()
 * @dev:	The devfreq user device. (parent of devfreq)
 * @devfreq:	The devfreq object.
 */
void devm_devfreq_unregister_opp_notifier(struct device *dev,
					 struct devfreq *devfreq)
{}
EXPORT_SYMBOL();

/**
 * devfreq_register_notifier() - Register a driver with devfreq
 * @devfreq:	The devfreq object.
 * @nb:		The notifier block to register.
 * @list:	DEVFREQ_TRANSITION_NOTIFIER.
 */
int devfreq_register_notifier(struct devfreq *devfreq,
			      struct notifier_block *nb,
			      unsigned int list)
{}
EXPORT_SYMBOL();

/*
 * devfreq_unregister_notifier() - Unregister a driver with devfreq
 * @devfreq:	The devfreq object.
 * @nb:		The notifier block to be unregistered.
 * @list:	DEVFREQ_TRANSITION_NOTIFIER.
 */
int devfreq_unregister_notifier(struct devfreq *devfreq,
				struct notifier_block *nb,
				unsigned int list)
{}
EXPORT_SYMBOL();

struct devfreq_notifier_devres {};

static void devm_devfreq_notifier_release(struct device *dev, void *res)
{}

/**
 * devm_devfreq_register_notifier()
 *	- Resource-managed devfreq_register_notifier()
 * @dev:	The devfreq user device. (parent of devfreq)
 * @devfreq:	The devfreq object.
 * @nb:		The notifier block to be unregistered.
 * @list:	DEVFREQ_TRANSITION_NOTIFIER.
 */
int devm_devfreq_register_notifier(struct device *dev,
				struct devfreq *devfreq,
				struct notifier_block *nb,
				unsigned int list)
{}
EXPORT_SYMBOL();

/**
 * devm_devfreq_unregister_notifier()
 *	- Resource-managed devfreq_unregister_notifier()
 * @dev:	The devfreq user device. (parent of devfreq)
 * @devfreq:	The devfreq object.
 * @nb:		The notifier block to be unregistered.
 * @list:	DEVFREQ_TRANSITION_NOTIFIER.
 */
void devm_devfreq_unregister_notifier(struct device *dev,
				      struct devfreq *devfreq,
				      struct notifier_block *nb,
				      unsigned int list)
{}
EXPORT_SYMBOL();