162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * coretemp.c - Linux kernel module for hardware monitoring
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Inspired from many hwmon drivers
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/jiffies.h>
1662306a36Sopenharmony_ci#include <linux/hwmon.h>
1762306a36Sopenharmony_ci#include <linux/sysfs.h>
1862306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h>
1962306a36Sopenharmony_ci#include <linux/err.h>
2062306a36Sopenharmony_ci#include <linux/mutex.h>
2162306a36Sopenharmony_ci#include <linux/list.h>
2262306a36Sopenharmony_ci#include <linux/platform_device.h>
2362306a36Sopenharmony_ci#include <linux/cpu.h>
2462306a36Sopenharmony_ci#include <linux/smp.h>
2562306a36Sopenharmony_ci#include <linux/moduleparam.h>
2662306a36Sopenharmony_ci#include <linux/pci.h>
2762306a36Sopenharmony_ci#include <asm/msr.h>
2862306a36Sopenharmony_ci#include <asm/processor.h>
2962306a36Sopenharmony_ci#include <asm/cpu_device_id.h>
3062306a36Sopenharmony_ci#include <linux/sched/isolation.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define DRVNAME	"coretemp"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * force_tjmax only matters when TjMax can't be read from the CPU itself.
3662306a36Sopenharmony_ci * When set, it replaces the driver's suboptimal heuristic.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_cistatic int force_tjmax;
3962306a36Sopenharmony_cimodule_param_named(tjmax, force_tjmax, int, 0444);
4062306a36Sopenharmony_ciMODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define PKG_SYSFS_ATTR_NO	1	/* Sysfs attribute for package temp */
4362306a36Sopenharmony_ci#define BASE_SYSFS_ATTR_NO	2	/* Sysfs Base attr no for coretemp */
4462306a36Sopenharmony_ci#define NUM_REAL_CORES		512	/* Number of Real cores per cpu */
4562306a36Sopenharmony_ci#define CORETEMP_NAME_LENGTH	28	/* String Length of attrs */
4662306a36Sopenharmony_ci#define MAX_CORE_ATTRS		4	/* Maximum no of basic attrs */
4762306a36Sopenharmony_ci#define TOTAL_ATTRS		(MAX_CORE_ATTRS + 1)
4862306a36Sopenharmony_ci#define MAX_CORE_DATA		(NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#ifdef CONFIG_SMP
5162306a36Sopenharmony_ci#define for_each_sibling(i, cpu) \
5262306a36Sopenharmony_ci	for_each_cpu(i, topology_sibling_cpumask(cpu))
5362306a36Sopenharmony_ci#else
5462306a36Sopenharmony_ci#define for_each_sibling(i, cpu)	for (i = 0; false; )
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/*
5862306a36Sopenharmony_ci * Per-Core Temperature Data
5962306a36Sopenharmony_ci * @tjmax: The static tjmax value when tjmax cannot be retrieved from
6062306a36Sopenharmony_ci *		IA32_TEMPERATURE_TARGET MSR.
6162306a36Sopenharmony_ci * @last_updated: The time when the current temperature value was updated
6262306a36Sopenharmony_ci *		earlier (in jiffies).
6362306a36Sopenharmony_ci * @cpu_core_id: The CPU Core from which temperature values should be read
6462306a36Sopenharmony_ci *		This value is passed as "id" field to rdmsr/wrmsr functions.
6562306a36Sopenharmony_ci * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
6662306a36Sopenharmony_ci *		from where the temperature values should be read.
6762306a36Sopenharmony_ci * @attr_size:  Total number of pre-core attrs displayed in the sysfs.
6862306a36Sopenharmony_ci * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
6962306a36Sopenharmony_ci *		Otherwise, temp_data holds coretemp data.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cistruct temp_data {
7262306a36Sopenharmony_ci	int temp;
7362306a36Sopenharmony_ci	int tjmax;
7462306a36Sopenharmony_ci	unsigned long last_updated;
7562306a36Sopenharmony_ci	unsigned int cpu;
7662306a36Sopenharmony_ci	u32 cpu_core_id;
7762306a36Sopenharmony_ci	u32 status_reg;
7862306a36Sopenharmony_ci	int attr_size;
7962306a36Sopenharmony_ci	bool is_pkg_data;
8062306a36Sopenharmony_ci	struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
8162306a36Sopenharmony_ci	char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
8262306a36Sopenharmony_ci	struct attribute *attrs[TOTAL_ATTRS + 1];
8362306a36Sopenharmony_ci	struct attribute_group attr_group;
8462306a36Sopenharmony_ci	struct mutex update_lock;
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* Platform Data per Physical CPU */
8862306a36Sopenharmony_cistruct platform_data {
8962306a36Sopenharmony_ci	struct device		*hwmon_dev;
9062306a36Sopenharmony_ci	u16			pkg_id;
9162306a36Sopenharmony_ci	u16			cpu_map[NUM_REAL_CORES];
9262306a36Sopenharmony_ci	struct ida		ida;
9362306a36Sopenharmony_ci	struct cpumask		cpumask;
9462306a36Sopenharmony_ci	struct temp_data	*core_data[MAX_CORE_DATA];
9562306a36Sopenharmony_ci	struct device_attribute name_attr;
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistruct tjmax_pci {
9962306a36Sopenharmony_ci	unsigned int device;
10062306a36Sopenharmony_ci	int tjmax;
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic const struct tjmax_pci tjmax_pci_table[] = {
10462306a36Sopenharmony_ci	{ 0x0708, 110000 },	/* CE41x0 (Sodaville ) */
10562306a36Sopenharmony_ci	{ 0x0c72, 102000 },	/* Atom S1240 (Centerton) */
10662306a36Sopenharmony_ci	{ 0x0c73, 95000 },	/* Atom S1220 (Centerton) */
10762306a36Sopenharmony_ci	{ 0x0c75, 95000 },	/* Atom S1260 (Centerton) */
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistruct tjmax {
11162306a36Sopenharmony_ci	char const *id;
11262306a36Sopenharmony_ci	int tjmax;
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const struct tjmax tjmax_table[] = {
11662306a36Sopenharmony_ci	{ "CPU  230", 100000 },		/* Model 0x1c, stepping 2	*/
11762306a36Sopenharmony_ci	{ "CPU  330", 125000 },		/* Model 0x1c, stepping 2	*/
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct tjmax_model {
12162306a36Sopenharmony_ci	u8 model;
12262306a36Sopenharmony_ci	u8 mask;
12362306a36Sopenharmony_ci	int tjmax;
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define ANY 0xff
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic const struct tjmax_model tjmax_model_table[] = {
12962306a36Sopenharmony_ci	{ 0x1c, 10, 100000 },	/* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */
13062306a36Sopenharmony_ci	{ 0x1c, ANY, 90000 },	/* Z5xx, N2xx, possibly others
13162306a36Sopenharmony_ci				 * Note: Also matches 230 and 330,
13262306a36Sopenharmony_ci				 * which are covered by tjmax_table
13362306a36Sopenharmony_ci				 */
13462306a36Sopenharmony_ci	{ 0x26, ANY, 90000 },	/* Atom Tunnel Creek (Exx), Lincroft (Z6xx)
13562306a36Sopenharmony_ci				 * Note: TjMax for E6xxT is 110C, but CPU type
13662306a36Sopenharmony_ci				 * is undetectable by software
13762306a36Sopenharmony_ci				 */
13862306a36Sopenharmony_ci	{ 0x27, ANY, 90000 },	/* Atom Medfield (Z2460) */
13962306a36Sopenharmony_ci	{ 0x35, ANY, 90000 },	/* Atom Clover Trail/Cloverview (Z27x0) */
14062306a36Sopenharmony_ci	{ 0x36, ANY, 100000 },	/* Atom Cedar Trail/Cedarview (N2xxx, D2xxx)
14162306a36Sopenharmony_ci				 * Also matches S12x0 (stepping 9), covered by
14262306a36Sopenharmony_ci				 * PCI table
14362306a36Sopenharmony_ci				 */
14462306a36Sopenharmony_ci};
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	/* The 100C is default for both mobile and non mobile CPUs */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	int tjmax = 100000;
15162306a36Sopenharmony_ci	int tjmax_ee = 85000;
15262306a36Sopenharmony_ci	int usemsr_ee = 1;
15362306a36Sopenharmony_ci	int err;
15462306a36Sopenharmony_ci	u32 eax, edx;
15562306a36Sopenharmony_ci	int i;
15662306a36Sopenharmony_ci	u16 devfn = PCI_DEVFN(0, 0);
15762306a36Sopenharmony_ci	struct pci_dev *host_bridge = pci_get_domain_bus_and_slot(0, 0, devfn);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/*
16062306a36Sopenharmony_ci	 * Explicit tjmax table entries override heuristics.
16162306a36Sopenharmony_ci	 * First try PCI host bridge IDs, followed by model ID strings
16262306a36Sopenharmony_ci	 * and model/stepping information.
16362306a36Sopenharmony_ci	 */
16462306a36Sopenharmony_ci	if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL) {
16562306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(tjmax_pci_table); i++) {
16662306a36Sopenharmony_ci			if (host_bridge->device == tjmax_pci_table[i].device) {
16762306a36Sopenharmony_ci				pci_dev_put(host_bridge);
16862306a36Sopenharmony_ci				return tjmax_pci_table[i].tjmax;
16962306a36Sopenharmony_ci			}
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci	pci_dev_put(host_bridge);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tjmax_table); i++) {
17562306a36Sopenharmony_ci		if (strstr(c->x86_model_id, tjmax_table[i].id))
17662306a36Sopenharmony_ci			return tjmax_table[i].tjmax;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) {
18062306a36Sopenharmony_ci		const struct tjmax_model *tm = &tjmax_model_table[i];
18162306a36Sopenharmony_ci		if (c->x86_model == tm->model &&
18262306a36Sopenharmony_ci		    (tm->mask == ANY || c->x86_stepping == tm->mask))
18362306a36Sopenharmony_ci			return tm->tjmax;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* Early chips have no MSR for TjMax */
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (c->x86_model == 0xf && c->x86_stepping < 4)
18962306a36Sopenharmony_ci		usemsr_ee = 0;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (c->x86_model > 0xe && usemsr_ee) {
19262306a36Sopenharmony_ci		u8 platform_id;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		/*
19562306a36Sopenharmony_ci		 * Now we can detect the mobile CPU using Intel provided table
19662306a36Sopenharmony_ci		 * http://softwarecommunity.intel.com/Wiki/Mobility/720.htm
19762306a36Sopenharmony_ci		 * For Core2 cores, check MSR 0x17, bit 28 1 = Mobile CPU
19862306a36Sopenharmony_ci		 */
19962306a36Sopenharmony_ci		err = rdmsr_safe_on_cpu(id, 0x17, &eax, &edx);
20062306a36Sopenharmony_ci		if (err) {
20162306a36Sopenharmony_ci			dev_warn(dev,
20262306a36Sopenharmony_ci				 "Unable to access MSR 0x17, assuming desktop"
20362306a36Sopenharmony_ci				 " CPU\n");
20462306a36Sopenharmony_ci			usemsr_ee = 0;
20562306a36Sopenharmony_ci		} else if (c->x86_model < 0x17 && !(eax & 0x10000000)) {
20662306a36Sopenharmony_ci			/*
20762306a36Sopenharmony_ci			 * Trust bit 28 up to Penryn, I could not find any
20862306a36Sopenharmony_ci			 * documentation on that; if you happen to know
20962306a36Sopenharmony_ci			 * someone at Intel please ask
21062306a36Sopenharmony_ci			 */
21162306a36Sopenharmony_ci			usemsr_ee = 0;
21262306a36Sopenharmony_ci		} else {
21362306a36Sopenharmony_ci			/* Platform ID bits 52:50 (EDX starts at bit 32) */
21462306a36Sopenharmony_ci			platform_id = (edx >> 18) & 0x7;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci			/*
21762306a36Sopenharmony_ci			 * Mobile Penryn CPU seems to be platform ID 7 or 5
21862306a36Sopenharmony_ci			 * (guesswork)
21962306a36Sopenharmony_ci			 */
22062306a36Sopenharmony_ci			if (c->x86_model == 0x17 &&
22162306a36Sopenharmony_ci			    (platform_id == 5 || platform_id == 7)) {
22262306a36Sopenharmony_ci				/*
22362306a36Sopenharmony_ci				 * If MSR EE bit is set, set it to 90 degrees C,
22462306a36Sopenharmony_ci				 * otherwise 105 degrees C
22562306a36Sopenharmony_ci				 */
22662306a36Sopenharmony_ci				tjmax_ee = 90000;
22762306a36Sopenharmony_ci				tjmax = 105000;
22862306a36Sopenharmony_ci			}
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (usemsr_ee) {
23362306a36Sopenharmony_ci		err = rdmsr_safe_on_cpu(id, 0xee, &eax, &edx);
23462306a36Sopenharmony_ci		if (err) {
23562306a36Sopenharmony_ci			dev_warn(dev,
23662306a36Sopenharmony_ci				 "Unable to access MSR 0xEE, for Tjmax, left"
23762306a36Sopenharmony_ci				 " at default\n");
23862306a36Sopenharmony_ci		} else if (eax & 0x40000000) {
23962306a36Sopenharmony_ci			tjmax = tjmax_ee;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci	} else if (tjmax == 100000) {
24262306a36Sopenharmony_ci		/*
24362306a36Sopenharmony_ci		 * If we don't use msr EE it means we are desktop CPU
24462306a36Sopenharmony_ci		 * (with exeception of Atom)
24562306a36Sopenharmony_ci		 */
24662306a36Sopenharmony_ci		dev_warn(dev, "Using relative temperature scale!\n");
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return tjmax;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic bool cpu_has_tjmax(struct cpuinfo_x86 *c)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	u8 model = c->x86_model;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return model > 0xe &&
25762306a36Sopenharmony_ci	       model != 0x1c &&
25862306a36Sopenharmony_ci	       model != 0x26 &&
25962306a36Sopenharmony_ci	       model != 0x27 &&
26062306a36Sopenharmony_ci	       model != 0x35 &&
26162306a36Sopenharmony_ci	       model != 0x36;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int get_tjmax(struct temp_data *tdata, struct device *dev)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct cpuinfo_x86 *c = &cpu_data(tdata->cpu);
26762306a36Sopenharmony_ci	int err;
26862306a36Sopenharmony_ci	u32 eax, edx;
26962306a36Sopenharmony_ci	u32 val;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* use static tjmax once it is set */
27262306a36Sopenharmony_ci	if (tdata->tjmax)
27362306a36Sopenharmony_ci		return tdata->tjmax;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/*
27662306a36Sopenharmony_ci	 * A new feature of current Intel(R) processors, the
27762306a36Sopenharmony_ci	 * IA32_TEMPERATURE_TARGET contains the TjMax value
27862306a36Sopenharmony_ci	 */
27962306a36Sopenharmony_ci	err = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
28062306a36Sopenharmony_ci	if (err) {
28162306a36Sopenharmony_ci		if (cpu_has_tjmax(c))
28262306a36Sopenharmony_ci			dev_warn(dev, "Unable to read TjMax from CPU %u\n", tdata->cpu);
28362306a36Sopenharmony_ci	} else {
28462306a36Sopenharmony_ci		val = (eax >> 16) & 0xff;
28562306a36Sopenharmony_ci		if (val)
28662306a36Sopenharmony_ci			return val * 1000;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (force_tjmax) {
29062306a36Sopenharmony_ci		dev_notice(dev, "TjMax forced to %d degrees C by user\n",
29162306a36Sopenharmony_ci			   force_tjmax);
29262306a36Sopenharmony_ci		tdata->tjmax = force_tjmax * 1000;
29362306a36Sopenharmony_ci	} else {
29462306a36Sopenharmony_ci		/*
29562306a36Sopenharmony_ci		 * An assumption is made for early CPUs and unreadable MSR.
29662306a36Sopenharmony_ci		 * NOTE: the calculated value may not be correct.
29762306a36Sopenharmony_ci		 */
29862306a36Sopenharmony_ci		tdata->tjmax = adjust_tjmax(c, tdata->cpu, dev);
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	return tdata->tjmax;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic int get_ttarget(struct temp_data *tdata, struct device *dev)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	u32 eax, edx;
30662306a36Sopenharmony_ci	int tjmax, ttarget_offset, ret;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/*
30962306a36Sopenharmony_ci	 * ttarget is valid only if tjmax can be retrieved from
31062306a36Sopenharmony_ci	 * MSR_IA32_TEMPERATURE_TARGET
31162306a36Sopenharmony_ci	 */
31262306a36Sopenharmony_ci	if (tdata->tjmax)
31362306a36Sopenharmony_ci		return -ENODEV;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	ret = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
31662306a36Sopenharmony_ci	if (ret)
31762306a36Sopenharmony_ci		return ret;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	tjmax = (eax >> 16) & 0xff;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/* Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. */
32262306a36Sopenharmony_ci	ttarget_offset = (eax >> 8) & 0xff;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	return (tjmax - ttarget_offset) * 1000;
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci/* Keep track of how many zone pointers we allocated in init() */
32862306a36Sopenharmony_cistatic int max_zones __read_mostly;
32962306a36Sopenharmony_ci/* Array of zone pointers. Serialized by cpu hotplug lock */
33062306a36Sopenharmony_cistatic struct platform_device **zone_devices;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic ssize_t show_label(struct device *dev,
33362306a36Sopenharmony_ci				struct device_attribute *devattr, char *buf)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
33662306a36Sopenharmony_ci	struct platform_data *pdata = dev_get_drvdata(dev);
33762306a36Sopenharmony_ci	struct temp_data *tdata = pdata->core_data[attr->index];
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (tdata->is_pkg_data)
34062306a36Sopenharmony_ci		return sprintf(buf, "Package id %u\n", pdata->pkg_id);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return sprintf(buf, "Core %u\n", tdata->cpu_core_id);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic ssize_t show_crit_alarm(struct device *dev,
34662306a36Sopenharmony_ci				struct device_attribute *devattr, char *buf)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	u32 eax, edx;
34962306a36Sopenharmony_ci	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
35062306a36Sopenharmony_ci	struct platform_data *pdata = dev_get_drvdata(dev);
35162306a36Sopenharmony_ci	struct temp_data *tdata = pdata->core_data[attr->index];
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	mutex_lock(&tdata->update_lock);
35462306a36Sopenharmony_ci	rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
35562306a36Sopenharmony_ci	mutex_unlock(&tdata->update_lock);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return sprintf(buf, "%d\n", (eax >> 5) & 1);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic ssize_t show_tjmax(struct device *dev,
36162306a36Sopenharmony_ci			struct device_attribute *devattr, char *buf)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
36462306a36Sopenharmony_ci	struct platform_data *pdata = dev_get_drvdata(dev);
36562306a36Sopenharmony_ci	struct temp_data *tdata = pdata->core_data[attr->index];
36662306a36Sopenharmony_ci	int tjmax;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	mutex_lock(&tdata->update_lock);
36962306a36Sopenharmony_ci	tjmax = get_tjmax(tdata, dev);
37062306a36Sopenharmony_ci	mutex_unlock(&tdata->update_lock);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	return sprintf(buf, "%d\n", tjmax);
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic ssize_t show_ttarget(struct device *dev,
37662306a36Sopenharmony_ci				struct device_attribute *devattr, char *buf)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
37962306a36Sopenharmony_ci	struct platform_data *pdata = dev_get_drvdata(dev);
38062306a36Sopenharmony_ci	struct temp_data *tdata = pdata->core_data[attr->index];
38162306a36Sopenharmony_ci	int ttarget;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	mutex_lock(&tdata->update_lock);
38462306a36Sopenharmony_ci	ttarget = get_ttarget(tdata, dev);
38562306a36Sopenharmony_ci	mutex_unlock(&tdata->update_lock);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (ttarget < 0)
38862306a36Sopenharmony_ci		return ttarget;
38962306a36Sopenharmony_ci	return sprintf(buf, "%d\n", ttarget);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic ssize_t show_temp(struct device *dev,
39362306a36Sopenharmony_ci			struct device_attribute *devattr, char *buf)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	u32 eax, edx;
39662306a36Sopenharmony_ci	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
39762306a36Sopenharmony_ci	struct platform_data *pdata = dev_get_drvdata(dev);
39862306a36Sopenharmony_ci	struct temp_data *tdata = pdata->core_data[attr->index];
39962306a36Sopenharmony_ci	int tjmax;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	mutex_lock(&tdata->update_lock);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	tjmax = get_tjmax(tdata, dev);
40462306a36Sopenharmony_ci	/* Check whether the time interval has elapsed */
40562306a36Sopenharmony_ci	if (time_after(jiffies, tdata->last_updated + HZ)) {
40662306a36Sopenharmony_ci		rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
40762306a36Sopenharmony_ci		/*
40862306a36Sopenharmony_ci		 * Ignore the valid bit. In all observed cases the register
40962306a36Sopenharmony_ci		 * value is either low or zero if the valid bit is 0.
41062306a36Sopenharmony_ci		 * Return it instead of reporting an error which doesn't
41162306a36Sopenharmony_ci		 * really help at all.
41262306a36Sopenharmony_ci		 */
41362306a36Sopenharmony_ci		tdata->temp = tjmax - ((eax >> 16) & 0x7f) * 1000;
41462306a36Sopenharmony_ci		tdata->last_updated = jiffies;
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	mutex_unlock(&tdata->update_lock);
41862306a36Sopenharmony_ci	return sprintf(buf, "%d\n", tdata->temp);
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic int create_core_attrs(struct temp_data *tdata, struct device *dev,
42262306a36Sopenharmony_ci			     int index)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	int i;
42562306a36Sopenharmony_ci	static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
42662306a36Sopenharmony_ci			struct device_attribute *devattr, char *buf) = {
42762306a36Sopenharmony_ci			show_label, show_crit_alarm, show_temp, show_tjmax,
42862306a36Sopenharmony_ci			show_ttarget };
42962306a36Sopenharmony_ci	static const char *const suffixes[TOTAL_ATTRS] = {
43062306a36Sopenharmony_ci		"label", "crit_alarm", "input", "crit", "max"
43162306a36Sopenharmony_ci	};
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	for (i = 0; i < tdata->attr_size; i++) {
43462306a36Sopenharmony_ci		/*
43562306a36Sopenharmony_ci		 * We map the attr number to core id of the CPU
43662306a36Sopenharmony_ci		 * The attr number is always core id + 2
43762306a36Sopenharmony_ci		 * The Pkgtemp will always show up as temp1_*, if available
43862306a36Sopenharmony_ci		 */
43962306a36Sopenharmony_ci		int attr_no = tdata->is_pkg_data ? 1 : tdata->cpu_core_id + 2;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH,
44262306a36Sopenharmony_ci			 "temp%d_%s", attr_no, suffixes[i]);
44362306a36Sopenharmony_ci		sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
44462306a36Sopenharmony_ci		tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
44562306a36Sopenharmony_ci		tdata->sd_attrs[i].dev_attr.attr.mode = 0444;
44662306a36Sopenharmony_ci		tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
44762306a36Sopenharmony_ci		tdata->sd_attrs[i].index = index;
44862306a36Sopenharmony_ci		tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci	tdata->attr_group.attrs = tdata->attrs;
45162306a36Sopenharmony_ci	return sysfs_create_group(&dev->kobj, &tdata->attr_group);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic int chk_ucode_version(unsigned int cpu)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct cpuinfo_x86 *c = &cpu_data(cpu);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/*
46062306a36Sopenharmony_ci	 * Check if we have problem with errata AE18 of Core processors:
46162306a36Sopenharmony_ci	 * Readings might stop update when processor visited too deep sleep,
46262306a36Sopenharmony_ci	 * fixed for stepping D0 (6EC).
46362306a36Sopenharmony_ci	 */
46462306a36Sopenharmony_ci	if (c->x86_model == 0xe && c->x86_stepping < 0xc && c->microcode < 0x39) {
46562306a36Sopenharmony_ci		pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
46662306a36Sopenharmony_ci		return -ENODEV;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci	return 0;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic struct platform_device *coretemp_get_pdev(unsigned int cpu)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	int id = topology_logical_die_id(cpu);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (id >= 0 && id < max_zones)
47662306a36Sopenharmony_ci		return zone_devices[id];
47762306a36Sopenharmony_ci	return NULL;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct temp_data *tdata;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	tdata = kzalloc(sizeof(struct temp_data), GFP_KERNEL);
48562306a36Sopenharmony_ci	if (!tdata)
48662306a36Sopenharmony_ci		return NULL;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
48962306a36Sopenharmony_ci							MSR_IA32_THERM_STATUS;
49062306a36Sopenharmony_ci	tdata->is_pkg_data = pkg_flag;
49162306a36Sopenharmony_ci	tdata->cpu = cpu;
49262306a36Sopenharmony_ci	tdata->cpu_core_id = topology_core_id(cpu);
49362306a36Sopenharmony_ci	tdata->attr_size = MAX_CORE_ATTRS;
49462306a36Sopenharmony_ci	mutex_init(&tdata->update_lock);
49562306a36Sopenharmony_ci	return tdata;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic int create_core_data(struct platform_device *pdev, unsigned int cpu,
49962306a36Sopenharmony_ci			    int pkg_flag)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct temp_data *tdata;
50262306a36Sopenharmony_ci	struct platform_data *pdata = platform_get_drvdata(pdev);
50362306a36Sopenharmony_ci	struct cpuinfo_x86 *c = &cpu_data(cpu);
50462306a36Sopenharmony_ci	u32 eax, edx;
50562306a36Sopenharmony_ci	int err, index;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
50862306a36Sopenharmony_ci		return 0;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/*
51162306a36Sopenharmony_ci	 * Get the index of tdata in pdata->core_data[]
51262306a36Sopenharmony_ci	 * tdata for package: pdata->core_data[1]
51362306a36Sopenharmony_ci	 * tdata for core: pdata->core_data[2] .. pdata->core_data[NUM_REAL_CORES + 1]
51462306a36Sopenharmony_ci	 */
51562306a36Sopenharmony_ci	if (pkg_flag) {
51662306a36Sopenharmony_ci		index = PKG_SYSFS_ATTR_NO;
51762306a36Sopenharmony_ci	} else {
51862306a36Sopenharmony_ci		index = ida_alloc_max(&pdata->ida, NUM_REAL_CORES - 1, GFP_KERNEL);
51962306a36Sopenharmony_ci		if (index < 0)
52062306a36Sopenharmony_ci			return index;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		pdata->cpu_map[index] = topology_core_id(cpu);
52362306a36Sopenharmony_ci		index += BASE_SYSFS_ATTR_NO;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	tdata = init_temp_data(cpu, pkg_flag);
52762306a36Sopenharmony_ci	if (!tdata) {
52862306a36Sopenharmony_ci		err = -ENOMEM;
52962306a36Sopenharmony_ci		goto ida_free;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* Test if we can access the status register */
53362306a36Sopenharmony_ci	err = rdmsr_safe_on_cpu(cpu, tdata->status_reg, &eax, &edx);
53462306a36Sopenharmony_ci	if (err)
53562306a36Sopenharmony_ci		goto exit_free;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* Make sure tdata->tjmax is a valid indicator for dynamic/static tjmax */
53862306a36Sopenharmony_ci	get_tjmax(tdata, &pdev->dev);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	/*
54162306a36Sopenharmony_ci	 * The target temperature is available on older CPUs but not in the
54262306a36Sopenharmony_ci	 * MSR_IA32_TEMPERATURE_TARGET register. Atoms don't have the register
54362306a36Sopenharmony_ci	 * at all.
54462306a36Sopenharmony_ci	 */
54562306a36Sopenharmony_ci	if (c->x86_model > 0xe && c->x86_model != 0x1c)
54662306a36Sopenharmony_ci		if (get_ttarget(tdata, &pdev->dev) >= 0)
54762306a36Sopenharmony_ci			tdata->attr_size++;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	pdata->core_data[index] = tdata;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* Create sysfs interfaces */
55262306a36Sopenharmony_ci	err = create_core_attrs(tdata, pdata->hwmon_dev, index);
55362306a36Sopenharmony_ci	if (err)
55462306a36Sopenharmony_ci		goto exit_free;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	return 0;
55762306a36Sopenharmony_ciexit_free:
55862306a36Sopenharmony_ci	pdata->core_data[index] = NULL;
55962306a36Sopenharmony_ci	kfree(tdata);
56062306a36Sopenharmony_ciida_free:
56162306a36Sopenharmony_ci	if (!pkg_flag)
56262306a36Sopenharmony_ci		ida_free(&pdata->ida, index - BASE_SYSFS_ATTR_NO);
56362306a36Sopenharmony_ci	return err;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic void
56762306a36Sopenharmony_cicoretemp_add_core(struct platform_device *pdev, unsigned int cpu, int pkg_flag)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	if (create_core_data(pdev, cpu, pkg_flag))
57062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Adding Core %u failed\n", cpu);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic void coretemp_remove_core(struct platform_data *pdata, int indx)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct temp_data *tdata = pdata->core_data[indx];
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/* if we errored on add then this is already gone */
57862306a36Sopenharmony_ci	if (!tdata)
57962306a36Sopenharmony_ci		return;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* Remove the sysfs attributes */
58262306a36Sopenharmony_ci	sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	kfree(pdata->core_data[indx]);
58562306a36Sopenharmony_ci	pdata->core_data[indx] = NULL;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (indx >= BASE_SYSFS_ATTR_NO)
58862306a36Sopenharmony_ci		ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO);
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic int coretemp_device_add(int zoneid)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct platform_device *pdev;
59462306a36Sopenharmony_ci	struct platform_data *pdata;
59562306a36Sopenharmony_ci	int err;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* Initialize the per-zone data structures */
59862306a36Sopenharmony_ci	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
59962306a36Sopenharmony_ci	if (!pdata)
60062306a36Sopenharmony_ci		return -ENOMEM;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	pdata->pkg_id = zoneid;
60362306a36Sopenharmony_ci	ida_init(&pdata->ida);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	pdev = platform_device_alloc(DRVNAME, zoneid);
60662306a36Sopenharmony_ci	if (!pdev) {
60762306a36Sopenharmony_ci		err = -ENOMEM;
60862306a36Sopenharmony_ci		goto err_free_pdata;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	err = platform_device_add(pdev);
61262306a36Sopenharmony_ci	if (err)
61362306a36Sopenharmony_ci		goto err_put_dev;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	platform_set_drvdata(pdev, pdata);
61662306a36Sopenharmony_ci	zone_devices[zoneid] = pdev;
61762306a36Sopenharmony_ci	return 0;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cierr_put_dev:
62062306a36Sopenharmony_ci	platform_device_put(pdev);
62162306a36Sopenharmony_cierr_free_pdata:
62262306a36Sopenharmony_ci	kfree(pdata);
62362306a36Sopenharmony_ci	return err;
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic void coretemp_device_remove(int zoneid)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct platform_device *pdev = zone_devices[zoneid];
62962306a36Sopenharmony_ci	struct platform_data *pdata = platform_get_drvdata(pdev);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	ida_destroy(&pdata->ida);
63262306a36Sopenharmony_ci	kfree(pdata);
63362306a36Sopenharmony_ci	platform_device_unregister(pdev);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic int coretemp_cpu_online(unsigned int cpu)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct platform_device *pdev = coretemp_get_pdev(cpu);
63962306a36Sopenharmony_ci	struct cpuinfo_x86 *c = &cpu_data(cpu);
64062306a36Sopenharmony_ci	struct platform_data *pdata;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	/*
64362306a36Sopenharmony_ci	 * Don't execute this on resume as the offline callback did
64462306a36Sopenharmony_ci	 * not get executed on suspend.
64562306a36Sopenharmony_ci	 */
64662306a36Sopenharmony_ci	if (cpuhp_tasks_frozen)
64762306a36Sopenharmony_ci		return 0;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	/*
65062306a36Sopenharmony_ci	 * CPUID.06H.EAX[0] indicates whether the CPU has thermal
65162306a36Sopenharmony_ci	 * sensors. We check this bit only, all the early CPUs
65262306a36Sopenharmony_ci	 * without thermal sensors will be filtered out.
65362306a36Sopenharmony_ci	 */
65462306a36Sopenharmony_ci	if (!cpu_has(c, X86_FEATURE_DTHERM))
65562306a36Sopenharmony_ci		return -ENODEV;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	pdata = platform_get_drvdata(pdev);
65862306a36Sopenharmony_ci	if (!pdata->hwmon_dev) {
65962306a36Sopenharmony_ci		struct device *hwmon;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		/* Check the microcode version of the CPU */
66262306a36Sopenharmony_ci		if (chk_ucode_version(cpu))
66362306a36Sopenharmony_ci			return -EINVAL;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		/*
66662306a36Sopenharmony_ci		 * Alright, we have DTS support.
66762306a36Sopenharmony_ci		 * We are bringing the _first_ core in this pkg
66862306a36Sopenharmony_ci		 * online. So, initialize per-pkg data structures and
66962306a36Sopenharmony_ci		 * then bring this core online.
67062306a36Sopenharmony_ci		 */
67162306a36Sopenharmony_ci		hwmon = hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
67262306a36Sopenharmony_ci							  pdata, NULL);
67362306a36Sopenharmony_ci		if (IS_ERR(hwmon))
67462306a36Sopenharmony_ci			return PTR_ERR(hwmon);
67562306a36Sopenharmony_ci		pdata->hwmon_dev = hwmon;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci		/*
67862306a36Sopenharmony_ci		 * Check whether pkgtemp support is available.
67962306a36Sopenharmony_ci		 * If so, add interfaces for pkgtemp.
68062306a36Sopenharmony_ci		 */
68162306a36Sopenharmony_ci		if (cpu_has(c, X86_FEATURE_PTS))
68262306a36Sopenharmony_ci			coretemp_add_core(pdev, cpu, 1);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/*
68662306a36Sopenharmony_ci	 * Check whether a thread sibling is already online. If not add the
68762306a36Sopenharmony_ci	 * interface for this CPU core.
68862306a36Sopenharmony_ci	 */
68962306a36Sopenharmony_ci	if (!cpumask_intersects(&pdata->cpumask, topology_sibling_cpumask(cpu)))
69062306a36Sopenharmony_ci		coretemp_add_core(pdev, cpu, 0);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	cpumask_set_cpu(cpu, &pdata->cpumask);
69362306a36Sopenharmony_ci	return 0;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic int coretemp_cpu_offline(unsigned int cpu)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	struct platform_device *pdev = coretemp_get_pdev(cpu);
69962306a36Sopenharmony_ci	struct platform_data *pd;
70062306a36Sopenharmony_ci	struct temp_data *tdata;
70162306a36Sopenharmony_ci	int i, indx = -1, target;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/* No need to tear down any interfaces for suspend */
70462306a36Sopenharmony_ci	if (cpuhp_tasks_frozen)
70562306a36Sopenharmony_ci		return 0;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	/* If the physical CPU device does not exist, just return */
70862306a36Sopenharmony_ci	pd = platform_get_drvdata(pdev);
70962306a36Sopenharmony_ci	if (!pd->hwmon_dev)
71062306a36Sopenharmony_ci		return 0;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	for (i = 0; i < NUM_REAL_CORES; i++) {
71362306a36Sopenharmony_ci		if (pd->cpu_map[i] == topology_core_id(cpu)) {
71462306a36Sopenharmony_ci			indx = i + BASE_SYSFS_ATTR_NO;
71562306a36Sopenharmony_ci			break;
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/* Too many cores and this core is not populated, just return */
72062306a36Sopenharmony_ci	if (indx < 0)
72162306a36Sopenharmony_ci		return 0;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	tdata = pd->core_data[indx];
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	cpumask_clear_cpu(cpu, &pd->cpumask);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/*
72862306a36Sopenharmony_ci	 * If this is the last thread sibling, remove the CPU core
72962306a36Sopenharmony_ci	 * interface, If there is still a sibling online, transfer the
73062306a36Sopenharmony_ci	 * target cpu of that core interface to it.
73162306a36Sopenharmony_ci	 */
73262306a36Sopenharmony_ci	target = cpumask_any_and(&pd->cpumask, topology_sibling_cpumask(cpu));
73362306a36Sopenharmony_ci	if (target >= nr_cpu_ids) {
73462306a36Sopenharmony_ci		coretemp_remove_core(pd, indx);
73562306a36Sopenharmony_ci	} else if (tdata && tdata->cpu == cpu) {
73662306a36Sopenharmony_ci		mutex_lock(&tdata->update_lock);
73762306a36Sopenharmony_ci		tdata->cpu = target;
73862306a36Sopenharmony_ci		mutex_unlock(&tdata->update_lock);
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/*
74262306a36Sopenharmony_ci	 * If all cores in this pkg are offline, remove the interface.
74362306a36Sopenharmony_ci	 */
74462306a36Sopenharmony_ci	tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
74562306a36Sopenharmony_ci	if (cpumask_empty(&pd->cpumask)) {
74662306a36Sopenharmony_ci		if (tdata)
74762306a36Sopenharmony_ci			coretemp_remove_core(pd, PKG_SYSFS_ATTR_NO);
74862306a36Sopenharmony_ci		hwmon_device_unregister(pd->hwmon_dev);
74962306a36Sopenharmony_ci		pd->hwmon_dev = NULL;
75062306a36Sopenharmony_ci		return 0;
75162306a36Sopenharmony_ci	}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	/*
75462306a36Sopenharmony_ci	 * Check whether this core is the target for the package
75562306a36Sopenharmony_ci	 * interface. We need to assign it to some other cpu.
75662306a36Sopenharmony_ci	 */
75762306a36Sopenharmony_ci	if (tdata && tdata->cpu == cpu) {
75862306a36Sopenharmony_ci		target = cpumask_first(&pd->cpumask);
75962306a36Sopenharmony_ci		mutex_lock(&tdata->update_lock);
76062306a36Sopenharmony_ci		tdata->cpu = target;
76162306a36Sopenharmony_ci		mutex_unlock(&tdata->update_lock);
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci	return 0;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_cistatic const struct x86_cpu_id __initconst coretemp_ids[] = {
76662306a36Sopenharmony_ci	X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_DTHERM, NULL),
76762306a36Sopenharmony_ci	{}
76862306a36Sopenharmony_ci};
76962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, coretemp_ids);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic enum cpuhp_state coretemp_hp_online;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic int __init coretemp_init(void)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	int i, err;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	/*
77862306a36Sopenharmony_ci	 * CPUID.06H.EAX[0] indicates whether the CPU has thermal
77962306a36Sopenharmony_ci	 * sensors. We check this bit only, all the early CPUs
78062306a36Sopenharmony_ci	 * without thermal sensors will be filtered out.
78162306a36Sopenharmony_ci	 */
78262306a36Sopenharmony_ci	if (!x86_match_cpu(coretemp_ids))
78362306a36Sopenharmony_ci		return -ENODEV;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	max_zones = topology_max_packages() * topology_max_die_per_package();
78662306a36Sopenharmony_ci	zone_devices = kcalloc(max_zones, sizeof(struct platform_device *),
78762306a36Sopenharmony_ci			      GFP_KERNEL);
78862306a36Sopenharmony_ci	if (!zone_devices)
78962306a36Sopenharmony_ci		return -ENOMEM;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	for (i = 0; i < max_zones; i++) {
79262306a36Sopenharmony_ci		err = coretemp_device_add(i);
79362306a36Sopenharmony_ci		if (err)
79462306a36Sopenharmony_ci			goto outzone;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
79862306a36Sopenharmony_ci				coretemp_cpu_online, coretemp_cpu_offline);
79962306a36Sopenharmony_ci	if (err < 0)
80062306a36Sopenharmony_ci		goto outzone;
80162306a36Sopenharmony_ci	coretemp_hp_online = err;
80262306a36Sopenharmony_ci	return 0;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cioutzone:
80562306a36Sopenharmony_ci	while (i--)
80662306a36Sopenharmony_ci		coretemp_device_remove(i);
80762306a36Sopenharmony_ci	kfree(zone_devices);
80862306a36Sopenharmony_ci	return err;
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_cimodule_init(coretemp_init)
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic void __exit coretemp_exit(void)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	int i;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	cpuhp_remove_state(coretemp_hp_online);
81762306a36Sopenharmony_ci	for (i = 0; i < max_zones; i++)
81862306a36Sopenharmony_ci		coretemp_device_remove(i);
81962306a36Sopenharmony_ci	kfree(zone_devices);
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_cimodule_exit(coretemp_exit)
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ciMODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
82462306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel Core temperature monitor");
82562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
826