
Cpuidle governor only suggests the state to enter using the governor->select() interface, but allows the low level driver to override the recommended state. The actual entered state may be different because of software or hardware demotion. Software demotion is done by the back-end cpuidle driver and can be accounted correctly. Current cpuidle code uses last_state field to capture the actual state entered and based on that updates the statistics for the state entered. Ideally the driver enter routine should update the counters, and it should return the state actually entered rather than the time spent there. The generic cpuidle code should simply handle where the counters live in the sysfs namespace, not updating the counters. Reference: https://lkml.org/lkml/2011/3/25/52 Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com> Tested-by: Jean Pihet <j-pihet@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Acked-by: Arjan van de Ven <arjan@linux.intel.com> Acked-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Len Brown <len.brown@intel.com>
195 lines
5 KiB
C
195 lines
5 KiB
C
/*
|
|
* cpuidle.h - a generic framework for CPU idle power management
|
|
*
|
|
* (C) 2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
|
|
* Shaohua Li <shaohua.li@intel.com>
|
|
* Adam Belay <abelay@novell.com>
|
|
*
|
|
* This code is licenced under the GPL.
|
|
*/
|
|
|
|
#ifndef _LINUX_CPUIDLE_H
|
|
#define _LINUX_CPUIDLE_H
|
|
|
|
#include <linux/percpu.h>
|
|
#include <linux/list.h>
|
|
#include <linux/module.h>
|
|
#include <linux/kobject.h>
|
|
#include <linux/completion.h>
|
|
|
|
#define CPUIDLE_STATE_MAX 8
|
|
#define CPUIDLE_NAME_LEN 16
|
|
#define CPUIDLE_DESC_LEN 32
|
|
|
|
struct cpuidle_device;
|
|
|
|
|
|
/****************************
|
|
* CPUIDLE DEVICE INTERFACE *
|
|
****************************/
|
|
|
|
struct cpuidle_state {
|
|
char name[CPUIDLE_NAME_LEN];
|
|
char desc[CPUIDLE_DESC_LEN];
|
|
void *driver_data;
|
|
|
|
unsigned int flags;
|
|
unsigned int exit_latency; /* in US */
|
|
unsigned int power_usage; /* in mW */
|
|
unsigned int target_residency; /* in US */
|
|
|
|
unsigned long long usage;
|
|
unsigned long long time; /* in US */
|
|
|
|
int (*enter) (struct cpuidle_device *dev,
|
|
int index);
|
|
};
|
|
|
|
/* Idle State Flags */
|
|
#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
|
|
#define CPUIDLE_FLAG_IGNORE (0x100) /* ignore during this idle period */
|
|
|
|
#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
|
|
|
|
/**
|
|
* cpuidle_get_statedata - retrieves private driver state data
|
|
* @state: the state
|
|
*/
|
|
static inline void * cpuidle_get_statedata(struct cpuidle_state *state)
|
|
{
|
|
return state->driver_data;
|
|
}
|
|
|
|
/**
|
|
* cpuidle_set_statedata - stores private driver state data
|
|
* @state: the state
|
|
* @data: the private data
|
|
*/
|
|
static inline void
|
|
cpuidle_set_statedata(struct cpuidle_state *state, void *data)
|
|
{
|
|
state->driver_data = data;
|
|
}
|
|
|
|
struct cpuidle_state_kobj {
|
|
struct cpuidle_state *state;
|
|
struct completion kobj_unregister;
|
|
struct kobject kobj;
|
|
};
|
|
|
|
struct cpuidle_device {
|
|
unsigned int registered:1;
|
|
unsigned int enabled:1;
|
|
unsigned int power_specified:1;
|
|
unsigned int cpu;
|
|
|
|
int last_residency;
|
|
int state_count;
|
|
struct cpuidle_state states[CPUIDLE_STATE_MAX];
|
|
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
|
|
|
|
struct list_head device_list;
|
|
struct kobject kobj;
|
|
struct completion kobj_unregister;
|
|
void *governor_data;
|
|
int safe_state_index;
|
|
|
|
int (*prepare) (struct cpuidle_device *dev);
|
|
};
|
|
|
|
DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
|
|
|
|
/**
|
|
* cpuidle_get_last_residency - retrieves the last state's residency time
|
|
* @dev: the target CPU
|
|
*
|
|
* NOTE: this value is invalid if CPUIDLE_FLAG_TIME_VALID isn't set
|
|
*/
|
|
static inline int cpuidle_get_last_residency(struct cpuidle_device *dev)
|
|
{
|
|
return dev->last_residency;
|
|
}
|
|
|
|
|
|
/****************************
|
|
* CPUIDLE DRIVER INTERFACE *
|
|
****************************/
|
|
|
|
struct cpuidle_driver {
|
|
char name[CPUIDLE_NAME_LEN];
|
|
struct module *owner;
|
|
};
|
|
|
|
#ifdef CONFIG_CPU_IDLE
|
|
extern void disable_cpuidle(void);
|
|
extern int cpuidle_idle_call(void);
|
|
|
|
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
|
|
struct cpuidle_driver *cpuidle_get_driver(void);
|
|
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
|
|
extern int cpuidle_register_device(struct cpuidle_device *dev);
|
|
extern void cpuidle_unregister_device(struct cpuidle_device *dev);
|
|
|
|
extern void cpuidle_pause_and_lock(void);
|
|
extern void cpuidle_resume_and_unlock(void);
|
|
extern int cpuidle_enable_device(struct cpuidle_device *dev);
|
|
extern void cpuidle_disable_device(struct cpuidle_device *dev);
|
|
|
|
#else
|
|
static inline void disable_cpuidle(void) { }
|
|
static inline int cpuidle_idle_call(void) { return -ENODEV; }
|
|
|
|
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
|
|
{return -ENODEV; }
|
|
static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
|
|
static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
|
|
static inline int cpuidle_register_device(struct cpuidle_device *dev)
|
|
{return -ENODEV; }
|
|
static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
|
|
|
|
static inline void cpuidle_pause_and_lock(void) { }
|
|
static inline void cpuidle_resume_and_unlock(void) { }
|
|
static inline int cpuidle_enable_device(struct cpuidle_device *dev)
|
|
{return -ENODEV; }
|
|
static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
|
|
|
|
#endif
|
|
|
|
/******************************
|
|
* CPUIDLE GOVERNOR INTERFACE *
|
|
******************************/
|
|
|
|
struct cpuidle_governor {
|
|
char name[CPUIDLE_NAME_LEN];
|
|
struct list_head governor_list;
|
|
unsigned int rating;
|
|
|
|
int (*enable) (struct cpuidle_device *dev);
|
|
void (*disable) (struct cpuidle_device *dev);
|
|
|
|
int (*select) (struct cpuidle_device *dev);
|
|
void (*reflect) (struct cpuidle_device *dev, int index);
|
|
|
|
struct module *owner;
|
|
};
|
|
|
|
#ifdef CONFIG_CPU_IDLE
|
|
|
|
extern int cpuidle_register_governor(struct cpuidle_governor *gov);
|
|
extern void cpuidle_unregister_governor(struct cpuidle_governor *gov);
|
|
|
|
#else
|
|
|
|
static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
|
|
{return 0;}
|
|
static inline void cpuidle_unregister_governor(struct cpuidle_governor *gov) { }
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
|
|
#define CPUIDLE_DRIVER_STATE_START 1
|
|
#else
|
|
#define CPUIDLE_DRIVER_STATE_START 0
|
|
#endif
|
|
|
|
#endif /* _LINUX_CPUIDLE_H */
|