diff options
| -rw-r--r-- | arch/x86/kernel/cpu/mcheck/therm_throt.c | 89 |
1 files changed, 71 insertions, 18 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index e1a0a3bf9716..d307f9f64c23 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c | |||
| @@ -37,7 +37,7 @@ | |||
| 37 | /* | 37 | /* |
| 38 | * Current thermal throttling state: | 38 | * Current thermal throttling state: |
| 39 | */ | 39 | */ |
| 40 | struct thermal_state { | 40 | struct _thermal_state { |
| 41 | bool is_throttled; | 41 | bool is_throttled; |
| 42 | 42 | ||
| 43 | u64 next_check; | 43 | u64 next_check; |
| @@ -45,6 +45,11 @@ struct thermal_state { | |||
| 45 | unsigned long last_throttle_count; | 45 | unsigned long last_throttle_count; |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | struct thermal_state { | ||
| 49 | struct _thermal_state core; | ||
| 50 | struct _thermal_state package; | ||
| 51 | }; | ||
| 52 | |||
| 48 | static DEFINE_PER_CPU(struct thermal_state, thermal_state); | 53 | static DEFINE_PER_CPU(struct thermal_state, thermal_state); |
| 49 | 54 | ||
| 50 | static atomic_t therm_throt_en = ATOMIC_INIT(0); | 55 | static atomic_t therm_throt_en = ATOMIC_INIT(0); |
| @@ -53,11 +58,13 @@ static u32 lvtthmr_init __read_mostly; | |||
| 53 | 58 | ||
| 54 | #ifdef CONFIG_SYSFS | 59 | #ifdef CONFIG_SYSFS |
| 55 | #define define_therm_throt_sysdev_one_ro(_name) \ | 60 | #define define_therm_throt_sysdev_one_ro(_name) \ |
| 56 | static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL) | 61 | static SYSDEV_ATTR(_name, 0444, \ |
| 62 | therm_throt_sysdev_show_##_name, \ | ||
| 63 | NULL) \ | ||
| 57 | 64 | ||
| 58 | #define define_therm_throt_sysdev_show_func(name) \ | 65 | #define define_therm_throt_sysdev_show_func(level, name) \ |
| 59 | \ | 66 | \ |
| 60 | static ssize_t therm_throt_sysdev_show_##name( \ | 67 | static ssize_t therm_throt_sysdev_show_##level##_##name( \ |
| 61 | struct sys_device *dev, \ | 68 | struct sys_device *dev, \ |
| 62 | struct sysdev_attribute *attr, \ | 69 | struct sysdev_attribute *attr, \ |
| 63 | char *buf) \ | 70 | char *buf) \ |
| @@ -66,21 +73,24 @@ static ssize_t therm_throt_sysdev_show_##name( \ | |||
| 66 | ssize_t ret; \ | 73 | ssize_t ret; \ |
| 67 | \ | 74 | \ |
| 68 | preempt_disable(); /* CPU hotplug */ \ | 75 | preempt_disable(); /* CPU hotplug */ \ |
| 69 | if (cpu_online(cpu)) \ | 76 | if (cpu_online(cpu)) { \ |
| 70 | ret = sprintf(buf, "%lu\n", \ | 77 | ret = sprintf(buf, "%lu\n", \ |
| 71 | per_cpu(thermal_state, cpu).name); \ | 78 | per_cpu(thermal_state, cpu).level.name); \ |
| 72 | else \ | 79 | } else \ |
| 73 | ret = 0; \ | 80 | ret = 0; \ |
| 74 | preempt_enable(); \ | 81 | preempt_enable(); \ |
| 75 | \ | 82 | \ |
| 76 | return ret; \ | 83 | return ret; \ |
| 77 | } | 84 | } |
| 78 | 85 | ||
| 79 | define_therm_throt_sysdev_show_func(throttle_count); | 86 | define_therm_throt_sysdev_show_func(core, throttle_count); |
| 80 | define_therm_throt_sysdev_one_ro(throttle_count); | 87 | define_therm_throt_sysdev_one_ro(core_throttle_count); |
| 88 | |||
| 89 | define_therm_throt_sysdev_show_func(package, throttle_count); | ||
| 90 | define_therm_throt_sysdev_one_ro(package_throttle_count); | ||
| 81 | 91 | ||
| 82 | static struct attribute *thermal_throttle_attrs[] = { | 92 | static struct attribute *thermal_throttle_attrs[] = { |
| 83 | &attr_throttle_count.attr, | 93 | &attr_core_throttle_count.attr, |
| 84 | NULL | 94 | NULL |
| 85 | }; | 95 | }; |
| 86 | 96 | ||
| @@ -106,16 +116,21 @@ static struct attribute_group thermal_throttle_attr_group = { | |||
| 106 | * 1 : Event should be logged further, and a message has been | 116 | * 1 : Event should be logged further, and a message has been |
| 107 | * printed to the syslog. | 117 | * printed to the syslog. |
| 108 | */ | 118 | */ |
| 109 | static int therm_throt_process(bool is_throttled) | 119 | #define CORE_LEVEL 0 |
| 120 | #define PACKAGE_LEVEL 1 | ||
| 121 | static int therm_throt_process(bool is_throttled, int level) | ||
| 110 | { | 122 | { |
| 111 | struct thermal_state *state; | 123 | struct _thermal_state *state; |
| 112 | unsigned int this_cpu; | 124 | unsigned int this_cpu; |
| 113 | bool was_throttled; | 125 | bool was_throttled; |
| 114 | u64 now; | 126 | u64 now; |
| 115 | 127 | ||
| 116 | this_cpu = smp_processor_id(); | 128 | this_cpu = smp_processor_id(); |
| 117 | now = get_jiffies_64(); | 129 | now = get_jiffies_64(); |
| 118 | state = &per_cpu(thermal_state, this_cpu); | 130 | if (level == CORE_LEVEL) |
| 131 | state = &per_cpu(thermal_state, this_cpu).core; | ||
| 132 | else | ||
| 133 | state = &per_cpu(thermal_state, this_cpu).package; | ||
| 119 | 134 | ||
| 120 | was_throttled = state->is_throttled; | 135 | was_throttled = state->is_throttled; |
| 121 | state->is_throttled = is_throttled; | 136 | state->is_throttled = is_throttled; |
| @@ -132,13 +147,18 @@ static int therm_throt_process(bool is_throttled) | |||
| 132 | 147 | ||
| 133 | /* if we just entered the thermal event */ | 148 | /* if we just entered the thermal event */ |
| 134 | if (is_throttled) { | 149 | if (is_throttled) { |
| 135 | printk(KERN_CRIT "CPU%d: Temperature above threshold, cpu clock throttled (total events = %lu)\n", this_cpu, state->throttle_count); | 150 | printk(KERN_CRIT "CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n", |
| 151 | this_cpu, | ||
| 152 | level == CORE_LEVEL ? "Core" : "Package", | ||
| 153 | state->throttle_count); | ||
| 136 | 154 | ||
| 137 | add_taint(TAINT_MACHINE_CHECK); | 155 | add_taint(TAINT_MACHINE_CHECK); |
| 138 | return 1; | 156 | return 1; |
| 139 | } | 157 | } |
| 140 | if (was_throttled) { | 158 | if (was_throttled) { |
| 141 | printk(KERN_INFO "CPU%d: Temperature/speed normal\n", this_cpu); | 159 | printk(KERN_INFO "CPU%d: %s temperature/speed normal\n", |
| 160 | this_cpu, | ||
| 161 | level == CORE_LEVEL ? "Core" : "Package"); | ||
| 142 | return 1; | 162 | return 1; |
| 143 | } | 163 | } |
| 144 | 164 | ||
| @@ -149,8 +169,19 @@ static int therm_throt_process(bool is_throttled) | |||
| 149 | /* Add/Remove thermal_throttle interface for CPU device: */ | 169 | /* Add/Remove thermal_throttle interface for CPU device: */ |
| 150 | static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev) | 170 | static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev) |
| 151 | { | 171 | { |
| 152 | return sysfs_create_group(&sys_dev->kobj, | 172 | int err; |
| 153 | &thermal_throttle_attr_group); | 173 | struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); |
| 174 | |||
| 175 | err = sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group); | ||
| 176 | if (err) | ||
| 177 | return err; | ||
| 178 | |||
| 179 | if (cpu_has(c, X86_FEATURE_PTS)) | ||
| 180 | err = sysfs_add_file_to_group(&sys_dev->kobj, | ||
| 181 | &attr_package_throttle_count.attr, | ||
| 182 | thermal_throttle_attr_group.name); | ||
| 183 | |||
| 184 | return err; | ||
| 154 | } | 185 | } |
| 155 | 186 | ||
| 156 | static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) | 187 | static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) |
| @@ -230,10 +261,25 @@ device_initcall(thermal_throttle_init_device); | |||
| 230 | static void intel_thermal_interrupt(void) | 261 | static void intel_thermal_interrupt(void) |
| 231 | { | 262 | { |
| 232 | __u64 msr_val; | 263 | __u64 msr_val; |
| 264 | struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); | ||
| 233 | 265 | ||
| 234 | rdmsrl(MSR_IA32_THERM_STATUS, msr_val); | 266 | rdmsrl(MSR_IA32_THERM_STATUS, msr_val); |
| 235 | if (therm_throt_process((msr_val & THERM_STATUS_PROCHOT) != 0)) | 267 | if (therm_throt_process(msr_val & THERM_STATUS_PROCHOT, |
| 268 | CORE_LEVEL) != 0) | ||
| 236 | mce_log_therm_throt_event(msr_val); | 269 | mce_log_therm_throt_event(msr_val); |
| 270 | |||
| 271 | if (cpu_has(c, X86_FEATURE_PTS)) { | ||
| 272 | rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val); | ||
| 273 | if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT, | ||
| 274 | PACKAGE_LEVEL) != 0) | ||
| 275 | /* | ||
| 276 | * Set up the most significant bit to notify mce log | ||
| 277 | * that this thermal event is a package level event. | ||
| 278 | * This is a temp solution. May be changed in the future | ||
| 279 | * with mce log infrasture. | ||
| 280 | */ | ||
| 281 | mce_log_therm_throt_event(((__u64)1 << 63) | msr_val); | ||
| 282 | } | ||
| 237 | } | 283 | } |
| 238 | 284 | ||
| 239 | static void unexpected_thermal_interrupt(void) | 285 | static void unexpected_thermal_interrupt(void) |
| @@ -338,6 +384,13 @@ void intel_init_thermal(struct cpuinfo_x86 *c) | |||
| 338 | wrmsr(MSR_IA32_THERM_INTERRUPT, | 384 | wrmsr(MSR_IA32_THERM_INTERRUPT, |
| 339 | l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h); | 385 | l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h); |
| 340 | 386 | ||
| 387 | if (cpu_has(c, X86_FEATURE_PTS)) { | ||
| 388 | rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); | ||
| 389 | wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, | ||
| 390 | l | (PACKAGE_THERM_INT_LOW_ENABLE | ||
| 391 | | PACKAGE_THERM_INT_HIGH_ENABLE), h); | ||
| 392 | } | ||
| 393 | |||
| 341 | smp_thermal_vector = intel_thermal_interrupt; | 394 | smp_thermal_vector = intel_thermal_interrupt; |
| 342 | 395 | ||
| 343 | rdmsr(MSR_IA32_MISC_ENABLE, l, h); | 396 | rdmsr(MSR_IA32_MISC_ENABLE, l, h); |
