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