Hi Jean/Fenghua, This patch, the second one in the series adds the interrupt Handling support for the thermal thresholds. When an interrupt occurs, this is notified to the user space(so that the user space can take some action) by a netlink event. This patch is generated against the stable Linux-2.6 tree. This patch depends on the "Adding notification to thermal Framework" patch, which can be downloaded from here: https://patchwork.kernel.org/patch/282042/ Kindly review and merge. ------------------------------------------------------------ From: Durgadoss R <durgadoss.r@xxxxxxxxx> Date: Tue, 14 Dec 2010 06:31:09 +0530 Subject: [PATCH 2/2] Adding_core_threshold_interrupt_handling_to_coretemp This patch adds the interrupt handling support for the Core thermal thresholds. When an interrupt occurs, this is notified to the user space(so that the user space can take some action) by a netlink event. Signed-off-by: Durgadoss R <durgadoss.r@xxxxxxxxx> --- arch/x86/include/asm/mce.h | 3 + arch/x86/kernel/cpu/mcheck/therm_throt.c | 56 ++++++++++++++++++++++++++ drivers/hwmon/coretemp.c | 64 ++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index c62c13c..eb16e94 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -223,6 +223,9 @@ void intel_init_thermal(struct cpuinfo_x86 *c); void mce_log_therm_throt_event(__u64 status); +/* Interrupt Handler for core thermal thresholds */ +extern int (*platform_thermal_notify)(__u64 msr_val); + #ifdef CONFIG_X86_THERMAL_VECTOR extern void mcheck_intel_therm_init(void); #else diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 4b68326..d1148cc 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -34,6 +34,11 @@ /* How long to wait between reporting thermal events */ #define CHECK_INTERVAL (300 * HZ) +/* Similar to CHECK_INTERVAL. But interval is reduced because + * these lower and upper threhsolds will be crossed frequently. + * Hence the reporting should be quick enough to handle the event */ +#define THRES_INTERVAL (25 * HZ) + #define THERMAL_THROTTLING_EVENT 0 #define POWER_LIMIT_EVENT 1 @@ -53,8 +58,13 @@ struct thermal_state { struct _thermal_state core_power_limit; struct _thermal_state package_throttle; struct _thermal_state package_power_limit; + struct _thermal_state core_thresh0; + struct _thermal_state core_thresh1; }; +/* Callback to handle core threshold interrupts */ +int (*platform_thermal_notify)(__u64 msr_val); + static DEFINE_PER_CPU(struct thermal_state, thermal_state); static atomic_t therm_throt_en = ATOMIC_INIT(0); @@ -200,6 +210,32 @@ static int therm_throt_process(bool new_event, int event, int level) return 0; } +static int thresh_event_valid(int event) +{ + struct _thermal_state *state = NULL; + + unsigned int this_cpu = smp_processor_id(); + struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu); + u64 now = get_jiffies_64(); + + switch (event) { + case 0: + state = &pstate->core_thresh0; + break; + case 1: + state = &pstate->core_thresh1; + break; + default: + WARN_ON(1); + } + + if (time_before64(now, state->next_check)) + return 0; + + state->next_check = now + THRES_INTERVAL; + return 1; +} + #ifdef CONFIG_SYSFS /* Add/Remove thermal_throttle interface for CPU device: */ static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev, @@ -313,6 +349,22 @@ device_initcall(thermal_throttle_init_device); #define PACKAGE_THROTTLED ((__u64)2 << 62) #define PACKAGE_POWER_LIMIT ((__u64)3 << 62) +static void notify_thresholds(__u64 msr_val) +{ + /* check whether the interrupt handler is defined; + * otherwise simply return + */ + if (!platform_thermal_notify) + return; + + /* lower threshold reached */ + if ((msr_val & THERM_LOG_THRESHOLD0) && thresh_event_valid(0)) + platform_thermal_notify(msr_val); + /* higher threshold reached */ + if ((msr_val & THERM_LOG_THRESHOLD1) && thresh_event_valid(1)) + platform_thermal_notify(msr_val); +} + /* Thermal transition interrupt handler */ static void intel_thermal_interrupt(void) { @@ -321,6 +373,10 @@ static void intel_thermal_interrupt(void) rdmsrl(MSR_IA32_THERM_STATUS, msr_val); + /* Check for violation of core thermal thresholds + * If so, send notification */ + notify_thresholds(msr_val); + if (therm_throt_process(msr_val & THERM_STATUS_PROCHOT, THERMAL_THROTTLING_EVENT, CORE_LEVEL) != 0) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 4c221b8..c53228c 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -36,9 +36,17 @@ #include <asm/msr.h> #include <asm/processor.h> #include <asm/smp.h> +#include <asm/mce.h> +#include <linux/thermal.h> #define DRVNAME "coretemp" +/* An identification number to the DTS sensor. + * This will help the user space to figure out which + * sensor caused the event + */ +#define DTS_ID 0 + typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL, SHOW_NAME } SHOW; @@ -69,6 +77,45 @@ struct coretemp_data { static int set_core_threshold(struct coretemp_data *data, int val, enum thresholds thresh); +/* Interrupt Handlers for core/package thresholds */ +struct work_struct *t0_netlink_handlr; +struct work_struct *t1_netlink_handlr; + +/* Send netlink event for DTS sensor reaching threshold0 */ +static void gen_netlink_t0(struct work_struct *work) +{ + generate_netlink_event(DTS_ID, THERMAL_AUX0); +} + +/* Send netlink event for DTS sensor reaching threshold1 */ +static void gen_netlink_t1(struct work_struct *work) +{ + generate_netlink_event(DTS_ID, THERMAL_AUX1); +} + +/* Platform thermal Interrupt Handler */ +static int coretemp_interrupt(__u64 msr_val) +{ + + if (msr_val & THERM_LOG_THRESHOLD0) { + if (!(msr_val & THERM_STATUS_THRESHOLD0)) + schedule_work(t0_netlink_handlr); + + /* Reset the Threshold0 interrupt */ + wrmsrl(MSR_IA32_THERM_STATUS, msr_val & ~THERM_LOG_THRESHOLD0); + } + + if (msr_val & THERM_LOG_THRESHOLD1) { + if (msr_val & THERM_STATUS_THRESHOLD1) + schedule_work(t1_netlink_handlr); + + /* Reset the Threshold1 interrupt */ + wrmsrl(MSR_IA32_THERM_STATUS, msr_val & ~THERM_LOG_THRESHOLD1); + } + + return 0; +} + /* * Sysfs stuff */ @@ -415,6 +462,9 @@ static int __devinit enable_thresh_support(struct coretemp_data *data) flag = 0; /*Flag should be zero to unmask the apic */ smp_call_function_single(data->id, &configure_apic, &flag, 1); + /* Enable the Interrupt Handling Support */ + platform_thermal_notify = coretemp_interrupt; + return 0; } @@ -702,6 +752,20 @@ static int __init coretemp_init(void) #endif register_hotcpu_notifier(&coretemp_cpu_notifier); + + /* Initialize the Interrupt Handlers */ + t0_netlink_handlr = kzalloc(sizeof(struct work_struct), GFP_KERNEL); + if (!t0_netlink_handlr) + return -ENOMEM; + + t1_netlink_handlr = kzalloc(sizeof(struct work_struct), GFP_KERNEL); + if (!t1_netlink_handlr) { + kfree(t0_netlink_handlr); + return -ENOMEM; + } + INIT_WORK(t0_netlink_handlr, (void *)gen_netlink_t0); + INIT_WORK(t1_netlink_handlr, (void *)gen_netlink_t1); + return 0; #ifndef CONFIG_HOTPLUG_CPU -- 1.6.5.2
Attachment:
0002-Adding_core_threshold_interrupt_handling_to_coretemp.patch
Description: 0002-Adding_core_threshold_interrupt_handling_to_coretemp.patch