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