This patch, the second one in the series, enables interrupt handling for core thresholds in coretemp.c
Interrupts are generated when the current temperature crosses the configured thresholds. Whenever an interrupt occurs, it is notified to the user space in the form of a netlink event. This patch has a dependency on the "Adding notification to Thermal framework" patch, that has been submitted to meego. This patch can be downloaded from here: https://patchwork.kernel.org/patch/282042/ This patch is also getting reviewed upstream in lm-sensors. ----------------------------------------------------------- From: Durgadoss R <[email protected]> Date: Tue, 14 Dec 2010 07:48:22 +0530 Subject: [PATCH 2/2] Adding_core_threshold_interrupt_support_to_coretemp This patch adds the interrupt handling support for the Core thermal thresholds. An interrupt is generated, when the current temperature crosses the lower or upper thresholds. This interrupt is notified to the user space (so that it can take some actions like CPU throttling etc..) by a netlink event. Signed-off-by: Durgadoss R <[email protected]> --- arch/x86/include/asm/mce.h | 3 + arch/x86/kernel/cpu/mcheck/therm_throt.c | 40 ++++++++++++++++++ drivers/hwmon/coretemp.c | 65 ++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index f32a430..1dbe697 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -219,6 +219,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 e1a0a3b..65cc522 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) + /* * Current thermal throttling state: */ @@ -45,7 +50,12 @@ struct thermal_state { unsigned long last_throttle_count; }; +/* Callback to handle core/package threshold interrupts */ +int (*platform_thermal_notify)(__u64 msr_val); + static DEFINE_PER_CPU(struct thermal_state, thermal_state); +static DEFINE_PER_CPU(struct thermal_state, thermal_state0); +static DEFINE_PER_CPU(struct thermal_state, thermal_state1); static atomic_t therm_throt_en = ATOMIC_INIT(0); @@ -145,6 +155,25 @@ static int therm_throt_process(bool is_throttled) return 0; } +static int therm_throt_valid(int index) +{ + struct thermal_state *state; + unsigned int this_cpu; + u64 now; + + this_cpu = smp_processor_id(); + now = get_jiffies_64(); + + state = (index) ? &per_cpu(thermal_state1, this_cpu) : + &per_cpu(thermal_state0, this_cpu); + + if (time_before64(now, state->next_check)) + return 0; + + state->next_check = now + CHECK_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) @@ -234,6 +263,17 @@ static void intel_thermal_interrupt(void) rdmsrl(MSR_IA32_THERM_STATUS, msr_val); if (therm_throt_process((msr_val & THERM_STATUS_PROCHOT) != 0)) mce_log_therm_throt_event(msr_val); + + /* check whether the threshold interrupt handler is defined */ + if (platform_thermal_notify) { + /* lower threshold reached */ + if ((msr_val & THERM_LOG_THRESHOLD0) && therm_throt_valid(0)) + platform_thermal_notify(msr_val); + /* higher threshold reached */ + if ((msr_val & THERM_LOG_THRESHOLD1) && therm_throt_valid(1)) + platform_thermal_notify(msr_val); + /* handle other events if any */ + } } static void unexpected_thermal_interrupt(void) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index d97ef59..388f493 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -36,9 +36,17 @@ #include <linux/pci.h> #include <asm/msr.h> #include <asm/processor.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,46 @@ 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 */ @@ -407,6 +455,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; } @@ -687,6 +738,20 @@ static int __init coretemp_init(void) #ifdef CONFIG_HOTPLUG_CPU register_hotcpu_notifier(&coretemp_cpu_notifier); #endif + + /* 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; exit_devices_unreg: -- 1.6.5.2
0002-Adding_core_threshold_interrupt_support_to_coretemp.patch
Description: 0002-Adding_core_threshold_interrupt_support_to_coretemp.patch
_______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
