forked from luck/tmp_suning_uos_patched
Merge branch 'pm-cpuidle'
This commit is contained in:
commit
3db0bc9767
@ -427,18 +427,11 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
|
||||
* Initialize missing things
|
||||
*/
|
||||
if (pr->flags.need_hotplug_init) {
|
||||
struct cpuidle_driver *idle_driver =
|
||||
cpuidle_get_driver();
|
||||
|
||||
printk(KERN_INFO "Will online and init hotplugged "
|
||||
"CPU: %d\n", pr->id);
|
||||
WARN(acpi_processor_start(pr), "Failed to start CPU:"
|
||||
" %d\n", pr->id);
|
||||
pr->flags.need_hotplug_init = 0;
|
||||
if (idle_driver && !strcmp(idle_driver->name,
|
||||
"intel_idle")) {
|
||||
intel_idle_cpu_init(pr->id);
|
||||
}
|
||||
/* Normal CPU soft online event */
|
||||
} else {
|
||||
acpi_processor_ppc_has_changed(pr, 0);
|
||||
|
@ -221,10 +221,6 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Suspend / resume control
|
||||
*/
|
||||
static int acpi_idle_suspend;
|
||||
static u32 saved_bm_rld;
|
||||
|
||||
static void acpi_idle_bm_rld_save(void)
|
||||
@ -243,21 +239,13 @@ static void acpi_idle_bm_rld_restore(void)
|
||||
|
||||
int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
|
||||
{
|
||||
if (acpi_idle_suspend == 1)
|
||||
return 0;
|
||||
|
||||
acpi_idle_bm_rld_save();
|
||||
acpi_idle_suspend = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpi_processor_resume(struct acpi_device * device)
|
||||
{
|
||||
if (acpi_idle_suspend == 0)
|
||||
return 0;
|
||||
|
||||
acpi_idle_bm_rld_restore();
|
||||
acpi_idle_suspend = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -595,7 +583,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
|
||||
*/
|
||||
cx->valid = 1;
|
||||
|
||||
cx->latency_ticks = cx->latency;
|
||||
/*
|
||||
* On older chipsets, BM_RLD needs to be set
|
||||
* in order for Bus Master activity to wake the
|
||||
@ -628,7 +615,6 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
|
||||
if (!cx->address)
|
||||
break;
|
||||
cx->valid = 1;
|
||||
cx->latency_ticks = cx->latency; /* Normalize latency */
|
||||
break;
|
||||
|
||||
case ACPI_STATE_C3:
|
||||
@ -763,11 +749,6 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
if (acpi_idle_suspend) {
|
||||
local_irq_enable();
|
||||
cpu_relax();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
lapic_timer_state_broadcast(pr, cx, 1);
|
||||
kt1 = ktime_get_real();
|
||||
@ -779,7 +760,6 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
|
||||
dev->last_residency = (int)idle_time;
|
||||
|
||||
local_irq_enable();
|
||||
cx->usage++;
|
||||
lapic_timer_state_broadcast(pr, cx, 0);
|
||||
|
||||
return index;
|
||||
@ -838,11 +818,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
if (acpi_idle_suspend) {
|
||||
local_irq_enable();
|
||||
cpu_relax();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (cx->entry_method != ACPI_CSTATE_FFH) {
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
@ -887,10 +862,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
|
||||
if (cx->entry_method != ACPI_CSTATE_FFH)
|
||||
current_thread_info()->status |= TS_POLLING;
|
||||
|
||||
cx->usage++;
|
||||
|
||||
lapic_timer_state_broadcast(pr, cx, 0);
|
||||
cx->time += idle_time;
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -928,8 +900,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
||||
drv, drv->safe_state_index);
|
||||
} else {
|
||||
local_irq_disable();
|
||||
if (!acpi_idle_suspend)
|
||||
acpi_safe_halt();
|
||||
acpi_safe_halt();
|
||||
local_irq_enable();
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -937,11 +908,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
if (acpi_idle_suspend) {
|
||||
local_irq_enable();
|
||||
cpu_relax();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (cx->entry_method != ACPI_CSTATE_FFH) {
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
@ -1014,10 +980,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
||||
if (cx->entry_method != ACPI_CSTATE_FFH)
|
||||
current_thread_info()->status |= TS_POLLING;
|
||||
|
||||
cx->usage++;
|
||||
|
||||
lapic_timer_state_broadcast(pr, cx, 0);
|
||||
cx->time += idle_time;
|
||||
return index;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/async.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include <linux/cpuidle.h>
|
||||
#include "../base.h"
|
||||
#include "power.h"
|
||||
|
||||
@ -467,6 +467,7 @@ static void dpm_resume_noirq(pm_message_t state)
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
dpm_show_time(starttime, state, "noirq");
|
||||
resume_device_irqs();
|
||||
cpuidle_resume();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -867,6 +868,7 @@ static int dpm_suspend_noirq(pm_message_t state)
|
||||
ktime_t starttime = ktime_get();
|
||||
int error = 0;
|
||||
|
||||
cpuidle_pause();
|
||||
suspend_device_irqs();
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
while (!list_empty(&dpm_late_early_list)) {
|
||||
|
@ -201,6 +201,22 @@ void cpuidle_resume_and_unlock(void)
|
||||
|
||||
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
|
||||
|
||||
/* Currently used in suspend/resume path to suspend cpuidle */
|
||||
void cpuidle_pause(void)
|
||||
{
|
||||
mutex_lock(&cpuidle_lock);
|
||||
cpuidle_uninstall_idle_handler();
|
||||
mutex_unlock(&cpuidle_lock);
|
||||
}
|
||||
|
||||
/* Currently used in suspend/resume path to resume cpuidle */
|
||||
void cpuidle_resume(void)
|
||||
{
|
||||
mutex_lock(&cpuidle_lock);
|
||||
cpuidle_install_idle_handler();
|
||||
mutex_unlock(&cpuidle_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* cpuidle_wrap_enter - performs timekeeping and irqen around enter function
|
||||
* @dev: pointer to a valid cpuidle_device object
|
||||
@ -265,7 +281,6 @@ static void poll_idle_init(struct cpuidle_driver *drv)
|
||||
state->power_usage = -1;
|
||||
state->flags = 0;
|
||||
state->enter = poll_idle;
|
||||
state->disable = 0;
|
||||
}
|
||||
#else
|
||||
static void poll_idle_init(struct cpuidle_driver *drv) {}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
static struct cpuidle_driver *cpuidle_curr_driver;
|
||||
DEFINE_SPINLOCK(cpuidle_driver_lock);
|
||||
int cpuidle_driver_refcount;
|
||||
|
||||
static void __cpuidle_register_driver(struct cpuidle_driver *drv)
|
||||
{
|
||||
@ -89,8 +90,34 @@ void cpuidle_unregister_driver(struct cpuidle_driver *drv)
|
||||
}
|
||||
|
||||
spin_lock(&cpuidle_driver_lock);
|
||||
cpuidle_curr_driver = NULL;
|
||||
|
||||
if (!WARN_ON(cpuidle_driver_refcount > 0))
|
||||
cpuidle_curr_driver = NULL;
|
||||
|
||||
spin_unlock(&cpuidle_driver_lock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
|
||||
|
||||
struct cpuidle_driver *cpuidle_driver_ref(void)
|
||||
{
|
||||
struct cpuidle_driver *drv;
|
||||
|
||||
spin_lock(&cpuidle_driver_lock);
|
||||
|
||||
drv = cpuidle_curr_driver;
|
||||
cpuidle_driver_refcount++;
|
||||
|
||||
spin_unlock(&cpuidle_driver_lock);
|
||||
return drv;
|
||||
}
|
||||
|
||||
void cpuidle_driver_unref(void)
|
||||
{
|
||||
spin_lock(&cpuidle_driver_lock);
|
||||
|
||||
if (!WARN_ON(cpuidle_driver_refcount <= 0))
|
||||
cpuidle_driver_refcount--;
|
||||
|
||||
spin_unlock(&cpuidle_driver_lock);
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
||||
* unless the timer is happening really really soon.
|
||||
*/
|
||||
if (data->expected_us > 5 &&
|
||||
drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0)
|
||||
dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
|
||||
data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
|
||||
|
||||
/*
|
||||
@ -290,8 +290,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
||||
*/
|
||||
for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
|
||||
struct cpuidle_state *s = &drv->states[i];
|
||||
struct cpuidle_state_usage *su = &dev->states_usage[i];
|
||||
|
||||
if (s->disable)
|
||||
if (su->disable)
|
||||
continue;
|
||||
if (s->target_residency > data->predicted_us)
|
||||
continue;
|
||||
|
@ -217,7 +217,8 @@ struct cpuidle_state_attr {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct cpuidle_state *, \
|
||||
struct cpuidle_state_usage *, char *);
|
||||
ssize_t (*store)(struct cpuidle_state *, const char *, size_t);
|
||||
ssize_t (*store)(struct cpuidle_state *, \
|
||||
struct cpuidle_state_usage *, const char *, size_t);
|
||||
};
|
||||
|
||||
#define define_one_state_ro(_name, show) \
|
||||
@ -233,21 +234,22 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \
|
||||
return sprintf(buf, "%u\n", state->_name);\
|
||||
}
|
||||
|
||||
#define define_store_state_function(_name) \
|
||||
#define define_store_state_ull_function(_name) \
|
||||
static ssize_t store_state_##_name(struct cpuidle_state *state, \
|
||||
struct cpuidle_state_usage *state_usage, \
|
||||
const char *buf, size_t size) \
|
||||
{ \
|
||||
long value; \
|
||||
unsigned long long value; \
|
||||
int err; \
|
||||
if (!capable(CAP_SYS_ADMIN)) \
|
||||
return -EPERM; \
|
||||
err = kstrtol(buf, 0, &value); \
|
||||
err = kstrtoull(buf, 0, &value); \
|
||||
if (err) \
|
||||
return err; \
|
||||
if (value) \
|
||||
state->disable = 1; \
|
||||
state_usage->_name = 1; \
|
||||
else \
|
||||
state->disable = 0; \
|
||||
state_usage->_name = 0; \
|
||||
return size; \
|
||||
}
|
||||
|
||||
@ -273,8 +275,8 @@ define_show_state_ull_function(usage)
|
||||
define_show_state_ull_function(time)
|
||||
define_show_state_str_function(name)
|
||||
define_show_state_str_function(desc)
|
||||
define_show_state_function(disable)
|
||||
define_store_state_function(disable)
|
||||
define_show_state_ull_function(disable)
|
||||
define_store_state_ull_function(disable)
|
||||
|
||||
define_one_state_ro(name, show_state_name);
|
||||
define_one_state_ro(desc, show_state_desc);
|
||||
@ -318,10 +320,11 @@ static ssize_t cpuidle_state_store(struct kobject *kobj,
|
||||
{
|
||||
int ret = -EIO;
|
||||
struct cpuidle_state *state = kobj_to_state(kobj);
|
||||
struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
|
||||
struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
|
||||
|
||||
if (cattr->store)
|
||||
ret = cattr->store(state, buf, size);
|
||||
ret = cattr->store(state, state_usage, buf, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ static const struct idle_cpu *icpu;
|
||||
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
|
||||
static int intel_idle(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv, int index);
|
||||
static int intel_idle_cpu_init(int cpu);
|
||||
|
||||
static struct cpuidle_state *cpuidle_state_table;
|
||||
|
||||
@ -302,22 +303,35 @@ static void __setup_broadcast_timer(void *arg)
|
||||
clockevents_notify(reason, &cpu);
|
||||
}
|
||||
|
||||
static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
|
||||
unsigned long action, void *hcpu)
|
||||
static int cpu_hotplug_notify(struct notifier_block *n,
|
||||
unsigned long action, void *hcpu)
|
||||
{
|
||||
int hotcpu = (unsigned long)hcpu;
|
||||
struct cpuidle_device *dev;
|
||||
|
||||
switch (action & 0xf) {
|
||||
case CPU_ONLINE:
|
||||
smp_call_function_single(hotcpu, __setup_broadcast_timer,
|
||||
(void *)true, 1);
|
||||
|
||||
if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
|
||||
smp_call_function_single(hotcpu, __setup_broadcast_timer,
|
||||
(void *)true, 1);
|
||||
|
||||
/*
|
||||
* Some systems can hotplug a cpu at runtime after
|
||||
* the kernel has booted, we have to initialize the
|
||||
* driver in this case
|
||||
*/
|
||||
dev = per_cpu_ptr(intel_idle_cpuidle_devices, hotcpu);
|
||||
if (!dev->registered)
|
||||
intel_idle_cpu_init(hotcpu);
|
||||
|
||||
break;
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block setup_broadcast_notifier = {
|
||||
.notifier_call = setup_broadcast_cpuhp_notify,
|
||||
static struct notifier_block cpu_hotplug_notifier = {
|
||||
.notifier_call = cpu_hotplug_notify,
|
||||
};
|
||||
|
||||
static void auto_demotion_disable(void *dummy)
|
||||
@ -405,10 +419,10 @@ static int intel_idle_probe(void)
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
|
||||
lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
|
||||
else {
|
||||
else
|
||||
on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
|
||||
register_cpu_notifier(&setup_broadcast_notifier);
|
||||
}
|
||||
|
||||
register_cpu_notifier(&cpu_hotplug_notifier);
|
||||
|
||||
pr_debug(PREFIX "v" INTEL_IDLE_VERSION
|
||||
" model 0x%X\n", boot_cpu_data.x86_model);
|
||||
@ -494,7 +508,7 @@ static int intel_idle_cpuidle_driver_init(void)
|
||||
* allocate, initialize, register cpuidle_devices
|
||||
* @cpu: cpu/core to initialize
|
||||
*/
|
||||
int intel_idle_cpu_init(int cpu)
|
||||
static int intel_idle_cpu_init(int cpu)
|
||||
{
|
||||
int cstate;
|
||||
struct cpuidle_device *dev;
|
||||
@ -539,7 +553,6 @@ int intel_idle_cpu_init(int cpu)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(intel_idle_cpu_init);
|
||||
|
||||
static int __init intel_idle_init(void)
|
||||
{
|
||||
@ -581,10 +594,10 @@ static void __exit intel_idle_exit(void)
|
||||
intel_idle_cpuidle_devices_uninit();
|
||||
cpuidle_unregister_driver(&intel_idle_driver);
|
||||
|
||||
if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) {
|
||||
|
||||
if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
|
||||
on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
|
||||
unregister_cpu_notifier(&setup_broadcast_notifier);
|
||||
}
|
||||
unregister_cpu_notifier(&cpu_hotplug_notifier);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -59,10 +59,7 @@ struct acpi_processor_cx {
|
||||
u8 entry_method;
|
||||
u8 index;
|
||||
u32 latency;
|
||||
u32 latency_ticks;
|
||||
u32 power;
|
||||
u32 usage;
|
||||
u64 time;
|
||||
u8 bm_sts_skip;
|
||||
char desc[ACPI_CX_DESC_LEN];
|
||||
};
|
||||
|
@ -34,6 +34,7 @@ struct cpuidle_driver;
|
||||
struct cpuidle_state_usage {
|
||||
void *driver_data;
|
||||
|
||||
unsigned long long disable;
|
||||
unsigned long long usage;
|
||||
unsigned long long time; /* in US */
|
||||
};
|
||||
@ -46,7 +47,6 @@ struct cpuidle_state {
|
||||
unsigned int exit_latency; /* in US */
|
||||
int power_usage; /* in mW */
|
||||
unsigned int target_residency; /* in US */
|
||||
unsigned int disable;
|
||||
|
||||
int (*enter) (struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
@ -136,13 +136,17 @@ struct cpuidle_driver {
|
||||
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 struct cpuidle_driver *cpuidle_get_driver(void);
|
||||
extern struct cpuidle_driver *cpuidle_driver_ref(void);
|
||||
extern void cpuidle_driver_unref(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 void cpuidle_pause(void);
|
||||
extern void cpuidle_resume(void);
|
||||
extern int cpuidle_enable_device(struct cpuidle_device *dev);
|
||||
extern void cpuidle_disable_device(struct cpuidle_device *dev);
|
||||
extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
|
||||
@ -157,6 +161,8 @@ 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 struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; }
|
||||
static inline void cpuidle_driver_unref(void) {}
|
||||
static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
|
||||
static inline int cpuidle_register_device(struct cpuidle_device *dev)
|
||||
{return -ENODEV; }
|
||||
@ -164,6 +170,8 @@ 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 void cpuidle_pause(void) { }
|
||||
static inline void cpuidle_resume(void) { }
|
||||
static inline int cpuidle_enable_device(struct cpuidle_device *dev)
|
||||
{return -ENODEV; }
|
||||
static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
|
||||
@ -202,14 +210,7 @@ struct cpuidle_governor {
|
||||
extern int cpuidle_register_governor(struct cpuidle_governor *gov);
|
||||
extern void cpuidle_unregister_governor(struct cpuidle_governor *gov);
|
||||
|
||||
#ifdef CONFIG_INTEL_IDLE
|
||||
extern int intel_idle_cpu_init(int cpu);
|
||||
#else
|
||||
static inline int intel_idle_cpu_init(int cpu) { return -1; }
|
||||
#endif
|
||||
|
||||
#else
|
||||
static inline int intel_idle_cpu_init(int cpu) { return -1; }
|
||||
|
||||
static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
|
||||
{return 0;}
|
||||
|
Loading…
Reference in New Issue
Block a user