cpuidle: add poll_limit_ns to cpuidle_device structure
Add a poll_limit_ns variable to cpuidle_device structure. Calculate and configure it in the new cpuidle_poll_time function, in case its zero. Individual governors are allowed to override this value. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
fa86ee90eb
commit
259231a045
@ -361,6 +361,36 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index)
|
|||||||
cpuidle_curr_governor->reflect(dev, index);
|
cpuidle_curr_governor->reflect(dev, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpuidle_poll_time - return amount of time to poll for,
|
||||||
|
* governors can override dev->poll_limit_ns if necessary
|
||||||
|
*
|
||||||
|
* @drv: the cpuidle driver tied with the cpu
|
||||||
|
* @dev: the cpuidle device
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
u64 cpuidle_poll_time(struct cpuidle_driver *drv,
|
||||||
|
struct cpuidle_device *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u64 limit_ns;
|
||||||
|
|
||||||
|
if (dev->poll_limit_ns)
|
||||||
|
return dev->poll_limit_ns;
|
||||||
|
|
||||||
|
limit_ns = TICK_NSEC;
|
||||||
|
for (i = 1; i < drv->state_count; i++) {
|
||||||
|
if (drv->states[i].disabled || dev->states_usage[i].disable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
limit_ns = (u64)drv->states[i].target_residency * NSEC_PER_USEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->poll_limit_ns = limit_ns;
|
||||||
|
|
||||||
|
return dev->poll_limit_ns;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cpuidle_install_idle_handler - installs the cpuidle idle loop handler
|
* cpuidle_install_idle_handler - installs the cpuidle idle loop handler
|
||||||
*/
|
*/
|
||||||
|
@ -20,16 +20,9 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev,
|
|||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
if (!current_set_polling_and_test()) {
|
if (!current_set_polling_and_test()) {
|
||||||
unsigned int loop_count = 0;
|
unsigned int loop_count = 0;
|
||||||
u64 limit = TICK_NSEC;
|
u64 limit;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 1; i < drv->state_count; i++) {
|
limit = cpuidle_poll_time(drv, dev);
|
||||||
if (drv->states[i].disabled || dev->states_usage[i].disable)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
limit = (u64)drv->states[i].target_residency * NSEC_PER_USEC;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!need_resched()) {
|
while (!need_resched()) {
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
|
@ -334,6 +334,7 @@ struct cpuidle_state_kobj {
|
|||||||
struct cpuidle_state_usage *state_usage;
|
struct cpuidle_state_usage *state_usage;
|
||||||
struct completion kobj_unregister;
|
struct completion kobj_unregister;
|
||||||
struct kobject kobj;
|
struct kobject kobj;
|
||||||
|
struct cpuidle_device *device;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_SUSPEND
|
#ifdef CONFIG_SUSPEND
|
||||||
@ -391,6 +392,7 @@ static inline void cpuidle_remove_s2idle_attr_group(struct cpuidle_state_kobj *k
|
|||||||
#define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
|
#define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
|
||||||
#define kobj_to_state(k) (kobj_to_state_obj(k)->state)
|
#define kobj_to_state(k) (kobj_to_state_obj(k)->state)
|
||||||
#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
|
#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
|
||||||
|
#define kobj_to_device(k) (kobj_to_state_obj(k)->device)
|
||||||
#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
|
#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
|
||||||
|
|
||||||
static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr,
|
static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr,
|
||||||
@ -414,10 +416,14 @@ static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr,
|
|||||||
struct cpuidle_state *state = kobj_to_state(kobj);
|
struct cpuidle_state *state = kobj_to_state(kobj);
|
||||||
struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
|
struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
|
||||||
struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
|
struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
|
||||||
|
struct cpuidle_device *dev = kobj_to_device(kobj);
|
||||||
|
|
||||||
if (cattr->store)
|
if (cattr->store)
|
||||||
ret = cattr->store(state, state_usage, buf, size);
|
ret = cattr->store(state, state_usage, buf, size);
|
||||||
|
|
||||||
|
/* reset poll time cache */
|
||||||
|
dev->poll_limit_ns = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,6 +474,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
|
|||||||
}
|
}
|
||||||
kobj->state = &drv->states[i];
|
kobj->state = &drv->states[i];
|
||||||
kobj->state_usage = &device->states_usage[i];
|
kobj->state_usage = &device->states_usage[i];
|
||||||
|
kobj->device = device;
|
||||||
init_completion(&kobj->kobj_unregister);
|
init_completion(&kobj->kobj_unregister);
|
||||||
|
|
||||||
ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
|
ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
|
||||||
|
@ -86,6 +86,7 @@ struct cpuidle_device {
|
|||||||
ktime_t next_hrtimer;
|
ktime_t next_hrtimer;
|
||||||
|
|
||||||
int last_residency;
|
int last_residency;
|
||||||
|
u64 poll_limit_ns;
|
||||||
struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX];
|
struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX];
|
||||||
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
|
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
|
||||||
struct cpuidle_driver_kobj *kobj_driver;
|
struct cpuidle_driver_kobj *kobj_driver;
|
||||||
@ -132,6 +133,8 @@ extern int cpuidle_select(struct cpuidle_driver *drv,
|
|||||||
extern int cpuidle_enter(struct cpuidle_driver *drv,
|
extern int cpuidle_enter(struct cpuidle_driver *drv,
|
||||||
struct cpuidle_device *dev, int index);
|
struct cpuidle_device *dev, int index);
|
||||||
extern void cpuidle_reflect(struct cpuidle_device *dev, int index);
|
extern void cpuidle_reflect(struct cpuidle_device *dev, int index);
|
||||||
|
extern u64 cpuidle_poll_time(struct cpuidle_driver *drv,
|
||||||
|
struct cpuidle_device *dev);
|
||||||
|
|
||||||
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
|
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
|
||||||
extern struct cpuidle_driver *cpuidle_get_driver(void);
|
extern struct cpuidle_driver *cpuidle_get_driver(void);
|
||||||
@ -166,6 +169,9 @@ static inline int cpuidle_enter(struct cpuidle_driver *drv,
|
|||||||
struct cpuidle_device *dev, int index)
|
struct cpuidle_device *dev, int index)
|
||||||
{return -ENODEV; }
|
{return -ENODEV; }
|
||||||
static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { }
|
static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { }
|
||||||
|
extern u64 cpuidle_poll_time(struct cpuidle_driver *drv,
|
||||||
|
struct cpuidle_device *dev)
|
||||||
|
{return 0; }
|
||||||
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
|
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
|
||||||
{return -ENODEV; }
|
{return -ENODEV; }
|
||||||
static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
|
static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user