Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 205465
b: refs/heads/master
c: 0199114
h: refs/heads/master
i:
  205463: 5a62e8a
v: v3
  • Loading branch information
Fenghua Yu authored and H. Peter Anvin committed Aug 3, 2010
1 parent 5075277 commit 1269803
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 55 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 55d435a227bd28c77afab326de44dfacc0b15059
refs/heads/master: 0199114c31798af5b83841b21759b64171060d9b
183 changes: 129 additions & 54 deletions trunk/arch/x86/kernel/cpu/mcheck/therm_throt.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,25 @@
/* How long to wait between reporting thermal events */
#define CHECK_INTERVAL (300 * HZ)

#define THERMAL_THROTTLING_EVENT 0
#define POWER_LIMIT_EVENT 1

/*
* Current thermal throttling state:
* Current thermal event state:
*/
struct _thermal_state {
bool is_throttled;

bool new_event;
int event;
u64 next_check;
unsigned long throttle_count;
unsigned long last_throttle_count;
unsigned long count;
unsigned long last_count;
};

struct thermal_state {
struct _thermal_state core;
struct _thermal_state package;
struct _thermal_state core_throttle;
struct _thermal_state core_power_limit;
struct _thermal_state package_throttle;
struct _thermal_state package_power_limit;
};

static DEFINE_PER_CPU(struct thermal_state, thermal_state);
Expand All @@ -62,9 +67,9 @@ static u32 lvtthmr_init __read_mostly;
therm_throt_sysdev_show_##_name, \
NULL) \

#define define_therm_throt_sysdev_show_func(level, name) \
#define define_therm_throt_sysdev_show_func(event, name) \
\
static ssize_t therm_throt_sysdev_show_##level##_##name( \
static ssize_t therm_throt_sysdev_show_##event##_##name( \
struct sys_device *dev, \
struct sysdev_attribute *attr, \
char *buf) \
Expand All @@ -75,31 +80,40 @@ static ssize_t therm_throt_sysdev_show_##level##_##name( \
preempt_disable(); /* CPU hotplug */ \
if (cpu_online(cpu)) { \
ret = sprintf(buf, "%lu\n", \
per_cpu(thermal_state, cpu).level.name); \
per_cpu(thermal_state, cpu).event.name); \
} else \
ret = 0; \
preempt_enable(); \
\
return ret; \
}

define_therm_throt_sysdev_show_func(core, throttle_count);
define_therm_throt_sysdev_show_func(core_throttle, count);
define_therm_throt_sysdev_one_ro(core_throttle_count);

define_therm_throt_sysdev_show_func(package, throttle_count);
define_therm_throt_sysdev_show_func(core_power_limit, count);
define_therm_throt_sysdev_one_ro(core_power_limit_count);

define_therm_throt_sysdev_show_func(package_throttle, count);
define_therm_throt_sysdev_one_ro(package_throttle_count);

define_therm_throt_sysdev_show_func(package_power_limit, count);
define_therm_throt_sysdev_one_ro(package_power_limit_count);

static struct attribute *thermal_throttle_attrs[] = {
&attr_core_throttle_count.attr,
NULL
};

static struct attribute_group thermal_throttle_attr_group = {
static struct attribute_group thermal_attr_group = {
.attrs = thermal_throttle_attrs,
.name = "thermal_throttle"
};
#endif /* CONFIG_SYSFS */

#define CORE_LEVEL 0
#define PACKAGE_LEVEL 1

/***
* therm_throt_process - Process thermal throttling event from interrupt
* @curr: Whether the condition is current or not (boolean), since the
Expand All @@ -116,49 +130,70 @@ static struct attribute_group thermal_throttle_attr_group = {
* 1 : Event should be logged further, and a message has been
* printed to the syslog.
*/
#define CORE_LEVEL 0
#define PACKAGE_LEVEL 1
static int therm_throt_process(bool is_throttled, int level)
static int therm_throt_process(bool new_event, int event, int level)
{
struct _thermal_state *state;
unsigned int this_cpu;
bool was_throttled;
unsigned int this_cpu = smp_processor_id();
bool old_event;
u64 now;
struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu);

this_cpu = smp_processor_id();
now = get_jiffies_64();
if (level == CORE_LEVEL)
state = &per_cpu(thermal_state, this_cpu).core;
else
state = &per_cpu(thermal_state, this_cpu).package;
if (level == CORE_LEVEL) {
if (event == THERMAL_THROTTLING_EVENT)
state = &pstate->core_throttle;
else if (event == POWER_LIMIT_EVENT)
state = &pstate->core_power_limit;
else
return 0;
} else if (level == PACKAGE_LEVEL) {
if (event == THERMAL_THROTTLING_EVENT)
state = &pstate->package_throttle;
else if (event == POWER_LIMIT_EVENT)
state = &pstate->package_power_limit;
else
return 0;
} else
return 0;

was_throttled = state->is_throttled;
state->is_throttled = is_throttled;
old_event = state->new_event;
state->new_event = new_event;

if (is_throttled)
state->throttle_count++;
if (new_event)
state->count++;

if (time_before64(now, state->next_check) &&
state->throttle_count != state->last_throttle_count)
state->count != state->last_count)
return 0;

state->next_check = now + CHECK_INTERVAL;
state->last_throttle_count = state->throttle_count;
state->last_count = state->count;

/* if we just entered the thermal event */
if (is_throttled) {
printk(KERN_CRIT "CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
this_cpu,
level == CORE_LEVEL ? "Core" : "Package",
state->throttle_count);
if (new_event) {
if (event == THERMAL_THROTTLING_EVENT)
printk(KERN_CRIT "CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
this_cpu,
level == CORE_LEVEL ? "Core" : "Package",
state->count);
else
printk(KERN_CRIT "CPU%d: %s power limit notification (total events = %lu)\n",
this_cpu,
level == CORE_LEVEL ? "Core" : "Package",
state->count);

add_taint(TAINT_MACHINE_CHECK);
return 1;
}
if (was_throttled) {
printk(KERN_INFO "CPU%d: %s temperature/speed normal\n",
this_cpu,
level == CORE_LEVEL ? "Core" : "Package");
if (old_event) {
if (event == THERMAL_THROTTLING_EVENT)
printk(KERN_INFO "CPU%d: %s temperature/speed normal\n",
this_cpu,
level == CORE_LEVEL ? "Core" : "Package");
else
printk(KERN_INFO "CPU%d: %s power limit normal\n",
this_cpu,
level == CORE_LEVEL ? "Core" : "Package");
return 1;
}

Expand All @@ -172,21 +207,29 @@ static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev)
int err;
struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());

err = sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group);
err = sysfs_create_group(&sys_dev->kobj, &thermal_attr_group);
if (err)
return err;

if (cpu_has(c, X86_FEATURE_PLN))
err = sysfs_add_file_to_group(&sys_dev->kobj,
&attr_core_power_limit_count.attr,
thermal_attr_group.name);
if (cpu_has(c, X86_FEATURE_PTS))
err = sysfs_add_file_to_group(&sys_dev->kobj,
&attr_package_throttle_count.attr,
thermal_throttle_attr_group.name);
thermal_attr_group.name);
if (cpu_has(c, X86_FEATURE_PLN))
err = sysfs_add_file_to_group(&sys_dev->kobj,
&attr_package_power_limit_count.attr,
thermal_attr_group.name);

return err;
}

static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
{
sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group);
sysfs_remove_group(&sys_dev->kobj, &thermal_attr_group);
}

/* Mutex protecting device creation against CPU hotplug: */
Expand Down Expand Up @@ -257,28 +300,49 @@ device_initcall(thermal_throttle_init_device);

#endif /* CONFIG_SYSFS */

/*
* Set up the most two significant bit to notify mce log that this thermal
* event type.
* This is a temp solution. May be changed in the future with mce log
* infrasture.
*/
#define CORE_THROTTLED (0)
#define CORE_POWER_LIMIT ((__u64)1 << 62)
#define PACKAGE_THROTTLED ((__u64)2 << 62)
#define PACKAGE_POWER_LIMIT ((__u64)3 << 62)

/* Thermal transition interrupt handler */
static void intel_thermal_interrupt(void)
{
__u64 msr_val;
struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());

rdmsrl(MSR_IA32_THERM_STATUS, msr_val);

if (therm_throt_process(msr_val & THERM_STATUS_PROCHOT,
THERMAL_THROTTLING_EVENT,
CORE_LEVEL) != 0)
mce_log_therm_throt_event(msr_val);
mce_log_therm_throt_event(CORE_THROTTLED | msr_val);

if (cpu_has(c, X86_FEATURE_PLN))
if (therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT,
POWER_LIMIT_EVENT,
CORE_LEVEL) != 0)
mce_log_therm_throt_event(CORE_POWER_LIMIT | msr_val);

if (cpu_has(c, X86_FEATURE_PTS)) {
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
THERMAL_THROTTLING_EVENT,
PACKAGE_LEVEL) != 0)
/*
* Set up the most significant bit to notify mce log
* that this thermal event is a package level event.
* This is a temp solution. May be changed in the future
* with mce log infrasture.
*/
mce_log_therm_throt_event(((__u64)1 << 63) | msr_val);
mce_log_therm_throt_event(PACKAGE_THROTTLED | msr_val);
if (cpu_has(c, X86_FEATURE_PLN))
if (therm_throt_process(msr_val &
PACKAGE_THERM_STATUS_POWER_LIMIT,
POWER_LIMIT_EVENT,
PACKAGE_LEVEL) != 0)
mce_log_therm_throt_event(PACKAGE_POWER_LIMIT
| msr_val);
}
}

Expand Down Expand Up @@ -381,14 +445,25 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
apic_write(APIC_LVTTHMR, h);

rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
wrmsr(MSR_IA32_THERM_INTERRUPT,
l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h);
if (cpu_has(c, X86_FEATURE_PLN))
wrmsr(MSR_IA32_THERM_INTERRUPT,
l | (THERM_INT_LOW_ENABLE
| THERM_INT_HIGH_ENABLE | THERM_INT_PLN_ENABLE), h);
else
wrmsr(MSR_IA32_THERM_INTERRUPT,
l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h);

if (cpu_has(c, X86_FEATURE_PTS)) {
rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
l | (PACKAGE_THERM_INT_LOW_ENABLE
| PACKAGE_THERM_INT_HIGH_ENABLE), h);
if (cpu_has(c, X86_FEATURE_PLN))
wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
l | (PACKAGE_THERM_INT_LOW_ENABLE
| PACKAGE_THERM_INT_HIGH_ENABLE
| PACKAGE_THERM_INT_PLN_ENABLE), h);
else
wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
l | (PACKAGE_THERM_INT_LOW_ENABLE
| PACKAGE_THERM_INT_HIGH_ENABLE), h);
}

smp_thermal_vector = intel_thermal_interrupt;
Expand Down

0 comments on commit 1269803

Please sign in to comment.