13e8c4d31SAmit Kucheria /* 23e8c4d31SAmit Kucheria * x86_pkg_temp_thermal driver 33e8c4d31SAmit Kucheria * Copyright (c) 2013, Intel Corporation. 43e8c4d31SAmit Kucheria * 53e8c4d31SAmit Kucheria * This program is free software; you can redistribute it and/or modify it 63e8c4d31SAmit Kucheria * under the terms and conditions of the GNU General Public License, 73e8c4d31SAmit Kucheria * version 2, as published by the Free Software Foundation. 83e8c4d31SAmit Kucheria * 93e8c4d31SAmit Kucheria * This program is distributed in the hope it will be useful, but WITHOUT 103e8c4d31SAmit Kucheria * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 113e8c4d31SAmit Kucheria * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 123e8c4d31SAmit Kucheria * more details. 133e8c4d31SAmit Kucheria * 143e8c4d31SAmit Kucheria * You should have received a copy of the GNU General Public License along with 153e8c4d31SAmit Kucheria * this program; if not, write to the Free Software Foundation, Inc. 163e8c4d31SAmit Kucheria * 173e8c4d31SAmit Kucheria */ 183e8c4d31SAmit Kucheria #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 193e8c4d31SAmit Kucheria 203e8c4d31SAmit Kucheria #include <linux/module.h> 213e8c4d31SAmit Kucheria #include <linux/init.h> 223e8c4d31SAmit Kucheria #include <linux/err.h> 233e8c4d31SAmit Kucheria #include <linux/param.h> 243e8c4d31SAmit Kucheria #include <linux/device.h> 253e8c4d31SAmit Kucheria #include <linux/platform_device.h> 263e8c4d31SAmit Kucheria #include <linux/cpu.h> 273e8c4d31SAmit Kucheria #include <linux/smp.h> 283e8c4d31SAmit Kucheria #include <linux/slab.h> 293e8c4d31SAmit Kucheria #include <linux/pm.h> 303e8c4d31SAmit Kucheria #include <linux/thermal.h> 313e8c4d31SAmit Kucheria #include <linux/debugfs.h> 323e8c4d31SAmit Kucheria #include <asm/cpu_device_id.h> 333e8c4d31SAmit Kucheria #include <asm/mce.h> 343e8c4d31SAmit Kucheria 353e8c4d31SAmit Kucheria /* 363e8c4d31SAmit Kucheria * Rate control delay: Idea is to introduce denounce effect 373e8c4d31SAmit Kucheria * This should be long enough to avoid reduce events, when 383e8c4d31SAmit Kucheria * threshold is set to a temperature, which is constantly 393e8c4d31SAmit Kucheria * violated, but at the short enough to take any action. 403e8c4d31SAmit Kucheria * The action can be remove threshold or change it to next 413e8c4d31SAmit Kucheria * interesting setting. Based on experiments, in around 423e8c4d31SAmit Kucheria * every 5 seconds under load will give us a significant 433e8c4d31SAmit Kucheria * temperature change. 443e8c4d31SAmit Kucheria */ 453e8c4d31SAmit Kucheria #define PKG_TEMP_THERMAL_NOTIFY_DELAY 5000 463e8c4d31SAmit Kucheria static int notify_delay_ms = PKG_TEMP_THERMAL_NOTIFY_DELAY; 473e8c4d31SAmit Kucheria module_param(notify_delay_ms, int, 0644); 483e8c4d31SAmit Kucheria MODULE_PARM_DESC(notify_delay_ms, 493e8c4d31SAmit Kucheria "User space notification delay in milli seconds."); 503e8c4d31SAmit Kucheria 513e8c4d31SAmit Kucheria /* Number of trip points in thermal zone. Currently it can't 523e8c4d31SAmit Kucheria * be more than 2. MSR can allow setting and getting notifications 533e8c4d31SAmit Kucheria * for only 2 thresholds. This define enforces this, if there 543e8c4d31SAmit Kucheria * is some wrong values returned by cpuid for number of thresholds. 553e8c4d31SAmit Kucheria */ 563e8c4d31SAmit Kucheria #define MAX_NUMBER_OF_TRIPS 2 573e8c4d31SAmit Kucheria 583e8c4d31SAmit Kucheria struct pkg_device { 593e8c4d31SAmit Kucheria int cpu; 603e8c4d31SAmit Kucheria bool work_scheduled; 613e8c4d31SAmit Kucheria u32 tj_max; 623e8c4d31SAmit Kucheria u32 msr_pkg_therm_low; 633e8c4d31SAmit Kucheria u32 msr_pkg_therm_high; 643e8c4d31SAmit Kucheria struct delayed_work work; 653e8c4d31SAmit Kucheria struct thermal_zone_device *tzone; 663e8c4d31SAmit Kucheria struct cpumask cpumask; 673e8c4d31SAmit Kucheria }; 683e8c4d31SAmit Kucheria 693e8c4d31SAmit Kucheria static struct thermal_zone_params pkg_temp_tz_params = { 703e8c4d31SAmit Kucheria .no_hwmon = true, 713e8c4d31SAmit Kucheria }; 723e8c4d31SAmit Kucheria 733e8c4d31SAmit Kucheria /* Keep track of how many package pointers we allocated in init() */ 743e8c4d31SAmit Kucheria static int max_packages __read_mostly; 753e8c4d31SAmit Kucheria /* Array of package pointers */ 763e8c4d31SAmit Kucheria static struct pkg_device **packages; 773e8c4d31SAmit Kucheria /* Serializes interrupt notification, work and hotplug */ 783e8c4d31SAmit Kucheria static DEFINE_SPINLOCK(pkg_temp_lock); 793e8c4d31SAmit Kucheria /* Protects zone operation in the work function against hotplug removal */ 803e8c4d31SAmit Kucheria static DEFINE_MUTEX(thermal_zone_mutex); 813e8c4d31SAmit Kucheria 823e8c4d31SAmit Kucheria /* The dynamically assigned cpu hotplug state for module_exit() */ 833e8c4d31SAmit Kucheria static enum cpuhp_state pkg_thermal_hp_state __read_mostly; 843e8c4d31SAmit Kucheria 853e8c4d31SAmit Kucheria /* Debug counters to show using debugfs */ 863e8c4d31SAmit Kucheria static struct dentry *debugfs; 873e8c4d31SAmit Kucheria static unsigned int pkg_interrupt_cnt; 883e8c4d31SAmit Kucheria static unsigned int pkg_work_cnt; 893e8c4d31SAmit Kucheria 9072c9f26bSGreg Kroah-Hartman static void pkg_temp_debugfs_init(void) 913e8c4d31SAmit Kucheria { 923e8c4d31SAmit Kucheria debugfs = debugfs_create_dir("pkg_temp_thermal", NULL); 933e8c4d31SAmit Kucheria 9472c9f26bSGreg Kroah-Hartman debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs, 953e8c4d31SAmit Kucheria &pkg_interrupt_cnt); 9672c9f26bSGreg Kroah-Hartman debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs, 973e8c4d31SAmit Kucheria &pkg_work_cnt); 983e8c4d31SAmit Kucheria } 993e8c4d31SAmit Kucheria 1003e8c4d31SAmit Kucheria /* 1013e8c4d31SAmit Kucheria * Protection: 1023e8c4d31SAmit Kucheria * 1033e8c4d31SAmit Kucheria * - cpu hotplug: Read serialized by cpu hotplug lock 1043e8c4d31SAmit Kucheria * Write must hold pkg_temp_lock 1053e8c4d31SAmit Kucheria * 1063e8c4d31SAmit Kucheria * - Other callsites: Must hold pkg_temp_lock 1073e8c4d31SAmit Kucheria */ 1083e8c4d31SAmit Kucheria static struct pkg_device *pkg_temp_thermal_get_dev(unsigned int cpu) 1093e8c4d31SAmit Kucheria { 1103e8c4d31SAmit Kucheria int pkgid = topology_logical_package_id(cpu); 1113e8c4d31SAmit Kucheria 1123e8c4d31SAmit Kucheria if (pkgid >= 0 && pkgid < max_packages) 1133e8c4d31SAmit Kucheria return packages[pkgid]; 1143e8c4d31SAmit Kucheria return NULL; 1153e8c4d31SAmit Kucheria } 1163e8c4d31SAmit Kucheria 1173e8c4d31SAmit Kucheria /* 1183e8c4d31SAmit Kucheria * tj-max is is interesting because threshold is set relative to this 1193e8c4d31SAmit Kucheria * temperature. 1203e8c4d31SAmit Kucheria */ 1213e8c4d31SAmit Kucheria static int get_tj_max(int cpu, u32 *tj_max) 1223e8c4d31SAmit Kucheria { 1233e8c4d31SAmit Kucheria u32 eax, edx, val; 1243e8c4d31SAmit Kucheria int err; 1253e8c4d31SAmit Kucheria 1263e8c4d31SAmit Kucheria err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); 1273e8c4d31SAmit Kucheria if (err) 1283e8c4d31SAmit Kucheria return err; 1293e8c4d31SAmit Kucheria 1303e8c4d31SAmit Kucheria val = (eax >> 16) & 0xff; 1313e8c4d31SAmit Kucheria *tj_max = val * 1000; 1323e8c4d31SAmit Kucheria 1333e8c4d31SAmit Kucheria return val ? 0 : -EINVAL; 1343e8c4d31SAmit Kucheria } 1353e8c4d31SAmit Kucheria 1363e8c4d31SAmit Kucheria static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp) 1373e8c4d31SAmit Kucheria { 1383e8c4d31SAmit Kucheria struct pkg_device *pkgdev = tzd->devdata; 1393e8c4d31SAmit Kucheria u32 eax, edx; 1403e8c4d31SAmit Kucheria 1413e8c4d31SAmit Kucheria rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_STATUS, &eax, &edx); 1423e8c4d31SAmit Kucheria if (eax & 0x80000000) { 1433e8c4d31SAmit Kucheria *temp = pkgdev->tj_max - ((eax >> 16) & 0x7f) * 1000; 1443e8c4d31SAmit Kucheria pr_debug("sys_get_curr_temp %d\n", *temp); 1453e8c4d31SAmit Kucheria return 0; 1463e8c4d31SAmit Kucheria } 1473e8c4d31SAmit Kucheria return -EINVAL; 1483e8c4d31SAmit Kucheria } 1493e8c4d31SAmit Kucheria 1503e8c4d31SAmit Kucheria static int sys_get_trip_temp(struct thermal_zone_device *tzd, 1513e8c4d31SAmit Kucheria int trip, int *temp) 1523e8c4d31SAmit Kucheria { 1533e8c4d31SAmit Kucheria struct pkg_device *pkgdev = tzd->devdata; 1543e8c4d31SAmit Kucheria unsigned long thres_reg_value; 1553e8c4d31SAmit Kucheria u32 mask, shift, eax, edx; 1563e8c4d31SAmit Kucheria int ret; 1573e8c4d31SAmit Kucheria 1583e8c4d31SAmit Kucheria if (trip >= MAX_NUMBER_OF_TRIPS) 1593e8c4d31SAmit Kucheria return -EINVAL; 1603e8c4d31SAmit Kucheria 1613e8c4d31SAmit Kucheria if (trip) { 1623e8c4d31SAmit Kucheria mask = THERM_MASK_THRESHOLD1; 1633e8c4d31SAmit Kucheria shift = THERM_SHIFT_THRESHOLD1; 1643e8c4d31SAmit Kucheria } else { 1653e8c4d31SAmit Kucheria mask = THERM_MASK_THRESHOLD0; 1663e8c4d31SAmit Kucheria shift = THERM_SHIFT_THRESHOLD0; 1673e8c4d31SAmit Kucheria } 1683e8c4d31SAmit Kucheria 1693e8c4d31SAmit Kucheria ret = rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, 1703e8c4d31SAmit Kucheria &eax, &edx); 1713e8c4d31SAmit Kucheria if (ret < 0) 1723e8c4d31SAmit Kucheria return ret; 1733e8c4d31SAmit Kucheria 1743e8c4d31SAmit Kucheria thres_reg_value = (eax & mask) >> shift; 1753e8c4d31SAmit Kucheria if (thres_reg_value) 1763e8c4d31SAmit Kucheria *temp = pkgdev->tj_max - thres_reg_value * 1000; 1773e8c4d31SAmit Kucheria else 1783e8c4d31SAmit Kucheria *temp = 0; 1793e8c4d31SAmit Kucheria pr_debug("sys_get_trip_temp %d\n", *temp); 1803e8c4d31SAmit Kucheria 1813e8c4d31SAmit Kucheria return 0; 1823e8c4d31SAmit Kucheria } 1833e8c4d31SAmit Kucheria 1843e8c4d31SAmit Kucheria static int 1853e8c4d31SAmit Kucheria sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp) 1863e8c4d31SAmit Kucheria { 1873e8c4d31SAmit Kucheria struct pkg_device *pkgdev = tzd->devdata; 1883e8c4d31SAmit Kucheria u32 l, h, mask, shift, intr; 1893e8c4d31SAmit Kucheria int ret; 1903e8c4d31SAmit Kucheria 1913e8c4d31SAmit Kucheria if (trip >= MAX_NUMBER_OF_TRIPS || temp >= pkgdev->tj_max) 1923e8c4d31SAmit Kucheria return -EINVAL; 1933e8c4d31SAmit Kucheria 1943e8c4d31SAmit Kucheria ret = rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, 1953e8c4d31SAmit Kucheria &l, &h); 1963e8c4d31SAmit Kucheria if (ret < 0) 1973e8c4d31SAmit Kucheria return ret; 1983e8c4d31SAmit Kucheria 1993e8c4d31SAmit Kucheria if (trip) { 2003e8c4d31SAmit Kucheria mask = THERM_MASK_THRESHOLD1; 2013e8c4d31SAmit Kucheria shift = THERM_SHIFT_THRESHOLD1; 2023e8c4d31SAmit Kucheria intr = THERM_INT_THRESHOLD1_ENABLE; 2033e8c4d31SAmit Kucheria } else { 2043e8c4d31SAmit Kucheria mask = THERM_MASK_THRESHOLD0; 2053e8c4d31SAmit Kucheria shift = THERM_SHIFT_THRESHOLD0; 2063e8c4d31SAmit Kucheria intr = THERM_INT_THRESHOLD0_ENABLE; 2073e8c4d31SAmit Kucheria } 2083e8c4d31SAmit Kucheria l &= ~mask; 2093e8c4d31SAmit Kucheria /* 2103e8c4d31SAmit Kucheria * When users space sets a trip temperature == 0, which is indication 2113e8c4d31SAmit Kucheria * that, it is no longer interested in receiving notifications. 2123e8c4d31SAmit Kucheria */ 2133e8c4d31SAmit Kucheria if (!temp) { 2143e8c4d31SAmit Kucheria l &= ~intr; 2153e8c4d31SAmit Kucheria } else { 2163e8c4d31SAmit Kucheria l |= (pkgdev->tj_max - temp)/1000 << shift; 2173e8c4d31SAmit Kucheria l |= intr; 2183e8c4d31SAmit Kucheria } 2193e8c4d31SAmit Kucheria 2203e8c4d31SAmit Kucheria return wrmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); 2213e8c4d31SAmit Kucheria } 2223e8c4d31SAmit Kucheria 2233e8c4d31SAmit Kucheria static int sys_get_trip_type(struct thermal_zone_device *thermal, int trip, 2243e8c4d31SAmit Kucheria enum thermal_trip_type *type) 2253e8c4d31SAmit Kucheria { 2263e8c4d31SAmit Kucheria *type = THERMAL_TRIP_PASSIVE; 2273e8c4d31SAmit Kucheria return 0; 2283e8c4d31SAmit Kucheria } 2293e8c4d31SAmit Kucheria 2303e8c4d31SAmit Kucheria /* Thermal zone callback registry */ 2313e8c4d31SAmit Kucheria static struct thermal_zone_device_ops tzone_ops = { 2323e8c4d31SAmit Kucheria .get_temp = sys_get_curr_temp, 2333e8c4d31SAmit Kucheria .get_trip_temp = sys_get_trip_temp, 2343e8c4d31SAmit Kucheria .get_trip_type = sys_get_trip_type, 2353e8c4d31SAmit Kucheria .set_trip_temp = sys_set_trip_temp, 2363e8c4d31SAmit Kucheria }; 2373e8c4d31SAmit Kucheria 2383e8c4d31SAmit Kucheria static bool pkg_thermal_rate_control(void) 2393e8c4d31SAmit Kucheria { 2403e8c4d31SAmit Kucheria return true; 2413e8c4d31SAmit Kucheria } 2423e8c4d31SAmit Kucheria 2433e8c4d31SAmit Kucheria /* Enable threshold interrupt on local package/cpu */ 2443e8c4d31SAmit Kucheria static inline void enable_pkg_thres_interrupt(void) 2453e8c4d31SAmit Kucheria { 2463e8c4d31SAmit Kucheria u8 thres_0, thres_1; 2473e8c4d31SAmit Kucheria u32 l, h; 2483e8c4d31SAmit Kucheria 2493e8c4d31SAmit Kucheria rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); 2503e8c4d31SAmit Kucheria /* only enable/disable if it had valid threshold value */ 2513e8c4d31SAmit Kucheria thres_0 = (l & THERM_MASK_THRESHOLD0) >> THERM_SHIFT_THRESHOLD0; 2523e8c4d31SAmit Kucheria thres_1 = (l & THERM_MASK_THRESHOLD1) >> THERM_SHIFT_THRESHOLD1; 2533e8c4d31SAmit Kucheria if (thres_0) 2543e8c4d31SAmit Kucheria l |= THERM_INT_THRESHOLD0_ENABLE; 2553e8c4d31SAmit Kucheria if (thres_1) 2563e8c4d31SAmit Kucheria l |= THERM_INT_THRESHOLD1_ENABLE; 2573e8c4d31SAmit Kucheria wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); 2583e8c4d31SAmit Kucheria } 2593e8c4d31SAmit Kucheria 2603e8c4d31SAmit Kucheria /* Disable threshold interrupt on local package/cpu */ 2613e8c4d31SAmit Kucheria static inline void disable_pkg_thres_interrupt(void) 2623e8c4d31SAmit Kucheria { 2633e8c4d31SAmit Kucheria u32 l, h; 2643e8c4d31SAmit Kucheria 2653e8c4d31SAmit Kucheria rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); 2663e8c4d31SAmit Kucheria 2673e8c4d31SAmit Kucheria l &= ~(THERM_INT_THRESHOLD0_ENABLE | THERM_INT_THRESHOLD1_ENABLE); 2683e8c4d31SAmit Kucheria wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); 2693e8c4d31SAmit Kucheria } 2703e8c4d31SAmit Kucheria 2713e8c4d31SAmit Kucheria static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work) 2723e8c4d31SAmit Kucheria { 2733e8c4d31SAmit Kucheria struct thermal_zone_device *tzone = NULL; 2743e8c4d31SAmit Kucheria int cpu = smp_processor_id(); 2753e8c4d31SAmit Kucheria struct pkg_device *pkgdev; 2763e8c4d31SAmit Kucheria u64 msr_val, wr_val; 2773e8c4d31SAmit Kucheria 2783e8c4d31SAmit Kucheria mutex_lock(&thermal_zone_mutex); 2793e8c4d31SAmit Kucheria spin_lock_irq(&pkg_temp_lock); 2803e8c4d31SAmit Kucheria ++pkg_work_cnt; 2813e8c4d31SAmit Kucheria 2823e8c4d31SAmit Kucheria pkgdev = pkg_temp_thermal_get_dev(cpu); 2833e8c4d31SAmit Kucheria if (!pkgdev) { 2843e8c4d31SAmit Kucheria spin_unlock_irq(&pkg_temp_lock); 2853e8c4d31SAmit Kucheria mutex_unlock(&thermal_zone_mutex); 2863e8c4d31SAmit Kucheria return; 2873e8c4d31SAmit Kucheria } 2883e8c4d31SAmit Kucheria pkgdev->work_scheduled = false; 2893e8c4d31SAmit Kucheria 2903e8c4d31SAmit Kucheria rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val); 2913e8c4d31SAmit Kucheria wr_val = msr_val & ~(THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1); 2923e8c4d31SAmit Kucheria if (wr_val != msr_val) { 2933e8c4d31SAmit Kucheria wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, wr_val); 2943e8c4d31SAmit Kucheria tzone = pkgdev->tzone; 2953e8c4d31SAmit Kucheria } 2963e8c4d31SAmit Kucheria 2973e8c4d31SAmit Kucheria enable_pkg_thres_interrupt(); 2983e8c4d31SAmit Kucheria spin_unlock_irq(&pkg_temp_lock); 2993e8c4d31SAmit Kucheria 3003e8c4d31SAmit Kucheria /* 3013e8c4d31SAmit Kucheria * If tzone is not NULL, then thermal_zone_mutex will prevent the 3023e8c4d31SAmit Kucheria * concurrent removal in the cpu offline callback. 3033e8c4d31SAmit Kucheria */ 3043e8c4d31SAmit Kucheria if (tzone) 3053e8c4d31SAmit Kucheria thermal_zone_device_update(tzone, THERMAL_EVENT_UNSPECIFIED); 3063e8c4d31SAmit Kucheria 3073e8c4d31SAmit Kucheria mutex_unlock(&thermal_zone_mutex); 3083e8c4d31SAmit Kucheria } 3093e8c4d31SAmit Kucheria 3103e8c4d31SAmit Kucheria static void pkg_thermal_schedule_work(int cpu, struct delayed_work *work) 3113e8c4d31SAmit Kucheria { 3123e8c4d31SAmit Kucheria unsigned long ms = msecs_to_jiffies(notify_delay_ms); 3133e8c4d31SAmit Kucheria 3143e8c4d31SAmit Kucheria schedule_delayed_work_on(cpu, work, ms); 3153e8c4d31SAmit Kucheria } 3163e8c4d31SAmit Kucheria 3173e8c4d31SAmit Kucheria static int pkg_thermal_notify(u64 msr_val) 3183e8c4d31SAmit Kucheria { 3193e8c4d31SAmit Kucheria int cpu = smp_processor_id(); 3203e8c4d31SAmit Kucheria struct pkg_device *pkgdev; 3213e8c4d31SAmit Kucheria unsigned long flags; 3223e8c4d31SAmit Kucheria 3233e8c4d31SAmit Kucheria spin_lock_irqsave(&pkg_temp_lock, flags); 3243e8c4d31SAmit Kucheria ++pkg_interrupt_cnt; 3253e8c4d31SAmit Kucheria 3263e8c4d31SAmit Kucheria disable_pkg_thres_interrupt(); 3273e8c4d31SAmit Kucheria 3283e8c4d31SAmit Kucheria /* Work is per package, so scheduling it once is enough. */ 3293e8c4d31SAmit Kucheria pkgdev = pkg_temp_thermal_get_dev(cpu); 3303e8c4d31SAmit Kucheria if (pkgdev && !pkgdev->work_scheduled) { 3313e8c4d31SAmit Kucheria pkgdev->work_scheduled = true; 3323e8c4d31SAmit Kucheria pkg_thermal_schedule_work(pkgdev->cpu, &pkgdev->work); 3333e8c4d31SAmit Kucheria } 3343e8c4d31SAmit Kucheria 3353e8c4d31SAmit Kucheria spin_unlock_irqrestore(&pkg_temp_lock, flags); 3363e8c4d31SAmit Kucheria return 0; 3373e8c4d31SAmit Kucheria } 3383e8c4d31SAmit Kucheria 3393e8c4d31SAmit Kucheria static int pkg_temp_thermal_device_add(unsigned int cpu) 3403e8c4d31SAmit Kucheria { 3413e8c4d31SAmit Kucheria int pkgid = topology_logical_package_id(cpu); 3423e8c4d31SAmit Kucheria u32 tj_max, eax, ebx, ecx, edx; 3433e8c4d31SAmit Kucheria struct pkg_device *pkgdev; 3443e8c4d31SAmit Kucheria int thres_count, err; 3453e8c4d31SAmit Kucheria 3463e8c4d31SAmit Kucheria if (pkgid >= max_packages) 3473e8c4d31SAmit Kucheria return -ENOMEM; 3483e8c4d31SAmit Kucheria 3493e8c4d31SAmit Kucheria cpuid(6, &eax, &ebx, &ecx, &edx); 3503e8c4d31SAmit Kucheria thres_count = ebx & 0x07; 3513e8c4d31SAmit Kucheria if (!thres_count) 3523e8c4d31SAmit Kucheria return -ENODEV; 3533e8c4d31SAmit Kucheria 3543e8c4d31SAmit Kucheria thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS); 3553e8c4d31SAmit Kucheria 3563e8c4d31SAmit Kucheria err = get_tj_max(cpu, &tj_max); 3573e8c4d31SAmit Kucheria if (err) 3583e8c4d31SAmit Kucheria return err; 3593e8c4d31SAmit Kucheria 3603e8c4d31SAmit Kucheria pkgdev = kzalloc(sizeof(*pkgdev), GFP_KERNEL); 3613e8c4d31SAmit Kucheria if (!pkgdev) 3623e8c4d31SAmit Kucheria return -ENOMEM; 3633e8c4d31SAmit Kucheria 3643e8c4d31SAmit Kucheria INIT_DELAYED_WORK(&pkgdev->work, pkg_temp_thermal_threshold_work_fn); 3653e8c4d31SAmit Kucheria pkgdev->cpu = cpu; 3663e8c4d31SAmit Kucheria pkgdev->tj_max = tj_max; 3673e8c4d31SAmit Kucheria pkgdev->tzone = thermal_zone_device_register("x86_pkg_temp", 3683e8c4d31SAmit Kucheria thres_count, 3693e8c4d31SAmit Kucheria (thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01, 3703e8c4d31SAmit Kucheria pkgdev, &tzone_ops, &pkg_temp_tz_params, 0, 0); 3713e8c4d31SAmit Kucheria if (IS_ERR(pkgdev->tzone)) { 3723e8c4d31SAmit Kucheria err = PTR_ERR(pkgdev->tzone); 3733e8c4d31SAmit Kucheria kfree(pkgdev); 3743e8c4d31SAmit Kucheria return err; 3753e8c4d31SAmit Kucheria } 3763e8c4d31SAmit Kucheria /* Store MSR value for package thermal interrupt, to restore at exit */ 3773e8c4d31SAmit Kucheria rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, pkgdev->msr_pkg_therm_low, 3783e8c4d31SAmit Kucheria pkgdev->msr_pkg_therm_high); 3793e8c4d31SAmit Kucheria 3803e8c4d31SAmit Kucheria cpumask_set_cpu(cpu, &pkgdev->cpumask); 3813e8c4d31SAmit Kucheria spin_lock_irq(&pkg_temp_lock); 3823e8c4d31SAmit Kucheria packages[pkgid] = pkgdev; 3833e8c4d31SAmit Kucheria spin_unlock_irq(&pkg_temp_lock); 3843e8c4d31SAmit Kucheria return 0; 3853e8c4d31SAmit Kucheria } 3863e8c4d31SAmit Kucheria 3873e8c4d31SAmit Kucheria static int pkg_thermal_cpu_offline(unsigned int cpu) 3883e8c4d31SAmit Kucheria { 3893e8c4d31SAmit Kucheria struct pkg_device *pkgdev = pkg_temp_thermal_get_dev(cpu); 3903e8c4d31SAmit Kucheria bool lastcpu, was_target; 3913e8c4d31SAmit Kucheria int target; 3923e8c4d31SAmit Kucheria 3933e8c4d31SAmit Kucheria if (!pkgdev) 3943e8c4d31SAmit Kucheria return 0; 3953e8c4d31SAmit Kucheria 3963e8c4d31SAmit Kucheria target = cpumask_any_but(&pkgdev->cpumask, cpu); 3973e8c4d31SAmit Kucheria cpumask_clear_cpu(cpu, &pkgdev->cpumask); 3983e8c4d31SAmit Kucheria lastcpu = target >= nr_cpu_ids; 3993e8c4d31SAmit Kucheria /* 4003e8c4d31SAmit Kucheria * Remove the sysfs files, if this is the last cpu in the package 4013e8c4d31SAmit Kucheria * before doing further cleanups. 4023e8c4d31SAmit Kucheria */ 4033e8c4d31SAmit Kucheria if (lastcpu) { 4043e8c4d31SAmit Kucheria struct thermal_zone_device *tzone = pkgdev->tzone; 4053e8c4d31SAmit Kucheria 4063e8c4d31SAmit Kucheria /* 4073e8c4d31SAmit Kucheria * We must protect against a work function calling 4083e8c4d31SAmit Kucheria * thermal_zone_update, after/while unregister. We null out 4093e8c4d31SAmit Kucheria * the pointer under the zone mutex, so the worker function 4103e8c4d31SAmit Kucheria * won't try to call. 4113e8c4d31SAmit Kucheria */ 4123e8c4d31SAmit Kucheria mutex_lock(&thermal_zone_mutex); 4133e8c4d31SAmit Kucheria pkgdev->tzone = NULL; 4143e8c4d31SAmit Kucheria mutex_unlock(&thermal_zone_mutex); 4153e8c4d31SAmit Kucheria 4163e8c4d31SAmit Kucheria thermal_zone_device_unregister(tzone); 4173e8c4d31SAmit Kucheria } 4183e8c4d31SAmit Kucheria 4193e8c4d31SAmit Kucheria /* Protect against work and interrupts */ 4203e8c4d31SAmit Kucheria spin_lock_irq(&pkg_temp_lock); 4213e8c4d31SAmit Kucheria 4223e8c4d31SAmit Kucheria /* 4233e8c4d31SAmit Kucheria * Check whether this cpu was the current target and store the new 4243e8c4d31SAmit Kucheria * one. When we drop the lock, then the interrupt notify function 4253e8c4d31SAmit Kucheria * will see the new target. 4263e8c4d31SAmit Kucheria */ 4273e8c4d31SAmit Kucheria was_target = pkgdev->cpu == cpu; 4283e8c4d31SAmit Kucheria pkgdev->cpu = target; 4293e8c4d31SAmit Kucheria 4303e8c4d31SAmit Kucheria /* 4313e8c4d31SAmit Kucheria * If this is the last CPU in the package remove the package 4323e8c4d31SAmit Kucheria * reference from the array and restore the interrupt MSR. When we 4333e8c4d31SAmit Kucheria * drop the lock neither the interrupt notify function nor the 4343e8c4d31SAmit Kucheria * worker will see the package anymore. 4353e8c4d31SAmit Kucheria */ 4363e8c4d31SAmit Kucheria if (lastcpu) { 4373e8c4d31SAmit Kucheria packages[topology_logical_package_id(cpu)] = NULL; 4383e8c4d31SAmit Kucheria /* After this point nothing touches the MSR anymore. */ 4393e8c4d31SAmit Kucheria wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, 4403e8c4d31SAmit Kucheria pkgdev->msr_pkg_therm_low, pkgdev->msr_pkg_therm_high); 4413e8c4d31SAmit Kucheria } 4423e8c4d31SAmit Kucheria 4433e8c4d31SAmit Kucheria /* 4443e8c4d31SAmit Kucheria * Check whether there is work scheduled and whether the work is 4453e8c4d31SAmit Kucheria * targeted at the outgoing CPU. 4463e8c4d31SAmit Kucheria */ 4473e8c4d31SAmit Kucheria if (pkgdev->work_scheduled && was_target) { 4483e8c4d31SAmit Kucheria /* 4493e8c4d31SAmit Kucheria * To cancel the work we need to drop the lock, otherwise 4503e8c4d31SAmit Kucheria * we might deadlock if the work needs to be flushed. 4513e8c4d31SAmit Kucheria */ 4523e8c4d31SAmit Kucheria spin_unlock_irq(&pkg_temp_lock); 4533e8c4d31SAmit Kucheria cancel_delayed_work_sync(&pkgdev->work); 4543e8c4d31SAmit Kucheria spin_lock_irq(&pkg_temp_lock); 4553e8c4d31SAmit Kucheria /* 4563e8c4d31SAmit Kucheria * If this is not the last cpu in the package and the work 4573e8c4d31SAmit Kucheria * did not run after we dropped the lock above, then we 4583e8c4d31SAmit Kucheria * need to reschedule the work, otherwise the interrupt 4593e8c4d31SAmit Kucheria * stays disabled forever. 4603e8c4d31SAmit Kucheria */ 4613e8c4d31SAmit Kucheria if (!lastcpu && pkgdev->work_scheduled) 4623e8c4d31SAmit Kucheria pkg_thermal_schedule_work(target, &pkgdev->work); 4633e8c4d31SAmit Kucheria } 4643e8c4d31SAmit Kucheria 4653e8c4d31SAmit Kucheria spin_unlock_irq(&pkg_temp_lock); 4663e8c4d31SAmit Kucheria 4673e8c4d31SAmit Kucheria /* Final cleanup if this is the last cpu */ 4683e8c4d31SAmit Kucheria if (lastcpu) 4693e8c4d31SAmit Kucheria kfree(pkgdev); 4703e8c4d31SAmit Kucheria return 0; 4713e8c4d31SAmit Kucheria } 4723e8c4d31SAmit Kucheria 4733e8c4d31SAmit Kucheria static int pkg_thermal_cpu_online(unsigned int cpu) 4743e8c4d31SAmit Kucheria { 4753e8c4d31SAmit Kucheria struct pkg_device *pkgdev = pkg_temp_thermal_get_dev(cpu); 4763e8c4d31SAmit Kucheria struct cpuinfo_x86 *c = &cpu_data(cpu); 4773e8c4d31SAmit Kucheria 4783e8c4d31SAmit Kucheria /* Paranoia check */ 4793e8c4d31SAmit Kucheria if (!cpu_has(c, X86_FEATURE_DTHERM) || !cpu_has(c, X86_FEATURE_PTS)) 4803e8c4d31SAmit Kucheria return -ENODEV; 4813e8c4d31SAmit Kucheria 4823e8c4d31SAmit Kucheria /* If the package exists, nothing to do */ 4833e8c4d31SAmit Kucheria if (pkgdev) { 4843e8c4d31SAmit Kucheria cpumask_set_cpu(cpu, &pkgdev->cpumask); 4853e8c4d31SAmit Kucheria return 0; 4863e8c4d31SAmit Kucheria } 4873e8c4d31SAmit Kucheria return pkg_temp_thermal_device_add(cpu); 4883e8c4d31SAmit Kucheria } 4893e8c4d31SAmit Kucheria 4903e8c4d31SAmit Kucheria static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = { 4913e8c4d31SAmit Kucheria { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_PTS }, 4923e8c4d31SAmit Kucheria {} 4933e8c4d31SAmit Kucheria }; 4943e8c4d31SAmit Kucheria MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids); 4953e8c4d31SAmit Kucheria 4963e8c4d31SAmit Kucheria static int __init pkg_temp_thermal_init(void) 4973e8c4d31SAmit Kucheria { 4983e8c4d31SAmit Kucheria int ret; 4993e8c4d31SAmit Kucheria 5003e8c4d31SAmit Kucheria if (!x86_match_cpu(pkg_temp_thermal_ids)) 5013e8c4d31SAmit Kucheria return -ENODEV; 5023e8c4d31SAmit Kucheria 5033e8c4d31SAmit Kucheria max_packages = topology_max_packages(); 5043e8c4d31SAmit Kucheria packages = kcalloc(max_packages, sizeof(struct pkg_device *), 5053e8c4d31SAmit Kucheria GFP_KERNEL); 5063e8c4d31SAmit Kucheria if (!packages) 5073e8c4d31SAmit Kucheria return -ENOMEM; 5083e8c4d31SAmit Kucheria 5093e8c4d31SAmit Kucheria ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "thermal/x86_pkg:online", 5103e8c4d31SAmit Kucheria pkg_thermal_cpu_online, pkg_thermal_cpu_offline); 5113e8c4d31SAmit Kucheria if (ret < 0) 5123e8c4d31SAmit Kucheria goto err; 5133e8c4d31SAmit Kucheria 5143e8c4d31SAmit Kucheria /* Store the state for module exit */ 5153e8c4d31SAmit Kucheria pkg_thermal_hp_state = ret; 5163e8c4d31SAmit Kucheria 5173e8c4d31SAmit Kucheria platform_thermal_package_notify = pkg_thermal_notify; 5183e8c4d31SAmit Kucheria platform_thermal_package_rate_control = pkg_thermal_rate_control; 5193e8c4d31SAmit Kucheria 5203e8c4d31SAmit Kucheria /* Don't care if it fails */ 5213e8c4d31SAmit Kucheria pkg_temp_debugfs_init(); 5223e8c4d31SAmit Kucheria return 0; 5233e8c4d31SAmit Kucheria 5243e8c4d31SAmit Kucheria err: 5253e8c4d31SAmit Kucheria kfree(packages); 5263e8c4d31SAmit Kucheria return ret; 5273e8c4d31SAmit Kucheria } 5283e8c4d31SAmit Kucheria module_init(pkg_temp_thermal_init) 5293e8c4d31SAmit Kucheria 5303e8c4d31SAmit Kucheria static void __exit pkg_temp_thermal_exit(void) 5313e8c4d31SAmit Kucheria { 5323e8c4d31SAmit Kucheria platform_thermal_package_notify = NULL; 5333e8c4d31SAmit Kucheria platform_thermal_package_rate_control = NULL; 5343e8c4d31SAmit Kucheria 5353e8c4d31SAmit Kucheria cpuhp_remove_state(pkg_thermal_hp_state); 5363e8c4d31SAmit Kucheria debugfs_remove_recursive(debugfs); 5373e8c4d31SAmit Kucheria kfree(packages); 5383e8c4d31SAmit Kucheria } 5393e8c4d31SAmit Kucheria module_exit(pkg_temp_thermal_exit) 5403e8c4d31SAmit Kucheria 5413e8c4d31SAmit Kucheria MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver"); 5423e8c4d31SAmit Kucheria MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 5433e8c4d31SAmit Kucheria MODULE_LICENSE("GPL v2"); 544