From cd5bd3df1a6e7a68454734fb109c409101c20f42 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 14 Sep 2011 04:43:07 -0400 Subject: hwmon: (coretemp) Initialize tmin ttarget is initialized when the driver is loaded, but tmin is not. As a result, tempX_max_hyst attributes read 0. Fix this. Also use THERM_*_THRESHOLD* constants in these initializations instead of hard-coding the constants. Signed-off-by: Jean Delvare Cc: "R, Durgadoss" Cc: Guenter Roeck Cc: Fenghua Yu Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 59d83e83da7f..411257676133 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -601,7 +601,12 @@ static int create_core_data(struct platform_data *pdata, err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx); if (!err) { tdata->attr_size += MAX_THRESH_ATTRS; - tdata->ttarget = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; + tdata->tmin = tdata->tjmax - + ((eax & THERM_MASK_THRESHOLD0) >> + THERM_SHIFT_THRESHOLD0) * 1000; + tdata->ttarget = tdata->tjmax - + ((eax & THERM_MASK_THRESHOLD1) >> + THERM_SHIFT_THRESHOLD1) * 1000; } pdata->core_data[attr_no] = tdata; -- cgit v1.2.3 From 6bf9e9b09c3abb5447bbbf16c2d0cbe721e44f3f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 16 Sep 2011 21:21:43 +0200 Subject: hwmon: (coretemp) Drop duplicate function get_pkg_tjmax Function get_pkg_tjmax is a simplified copy of get_tjmax. Drop it and always use get_tjmax, result is the same and this avoids code duplication. Also make get_tjmax less verbose: don't warn about MSR read failure when failure was expected, and don't report TjMax in the logs unless debugging is enabled. Signed-off-by: Jean Delvare Cc: Fenghua Yu Cc: Guenter Roeck Cc: Durgadoss R Acked-by: Fenghua Yu Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 411257676133..256f70803eb3 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -374,7 +374,6 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) { - /* The 100C is default for both mobile and non mobile CPUs */ int err; u32 eax, edx; u32 val; @@ -385,7 +384,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) */ err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); if (err) { - dev_warn(dev, "Unable to read TjMax from CPU.\n"); + if (c->x86_model > 0xe && c->x86_model != 0x1c) + dev_warn(dev, "Unable to read TjMax from CPU %u\n", id); } else { val = (eax >> 16) & 0xff; /* @@ -393,7 +393,7 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) * will be used */ if (val) { - dev_info(dev, "TjMax is %d C.\n", val); + dev_dbg(dev, "TjMax is %d degrees C\n", val); return val * 1000; } } @@ -414,21 +414,6 @@ static void __devinit get_ucode_rev_on_cpu(void *edx) rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx); } -static int get_pkg_tjmax(unsigned int cpu, struct device *dev) -{ - int err; - u32 eax, edx, val; - - err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); - if (!err) { - val = (eax >> 16) & 0xff; - if (val) - return val * 1000; - } - dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%u\n", cpu); - return 100000; /* Default TjMax: 100 degree celsius */ -} - static int create_name_attr(struct platform_data *pdata, struct device *dev) { sysfs_attr_init(&pdata->name_attr.attr); @@ -588,10 +573,7 @@ static int create_core_data(struct platform_data *pdata, goto exit_free; /* We can access status register. Get Critical Temperature */ - if (pkg_flag) - tdata->tjmax = get_pkg_tjmax(pdev->id, &pdev->dev); - else - tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); + tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); /* * Test if we can access the intrpt register. If so, increase the -- cgit v1.2.3 From a45a8c8571c0be6a6bd72ae5a14255c26b14b504 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 16 Sep 2011 21:24:02 +0200 Subject: hwmon: (coretemp) Let the user force TjMax On old CPUs (and even some recent Atom CPUs) TjMax can't be read from the CPU registers, so it is guessed by the driver using a complex heuristic which isn't reliable. So let users who know their CPU's TjMax pass it as a module parameter. Signed-off-by: Jean Delvare Cc: Fenghua Yu Cc: "R, Durgadoss" Cc: Guenter Roeck Cc: Alexander Stein Acked-by: Fenghua Yu Signed-off-by: Guenter Roeck --- Documentation/hwmon/coretemp | 7 ++++--- drivers/hwmon/coretemp.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp index fa8776ab9b18..49c0d42dde86 100644 --- a/Documentation/hwmon/coretemp +++ b/Documentation/hwmon/coretemp @@ -49,9 +49,10 @@ tempX_label - Contains string "Core X", where X is processor number. For Package temp, this will be "Physical id Y", where Y is the package number. -The TjMax temperature is set to 85 degrees C if undocumented model specific -register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as -(sometimes) documented in processor datasheet. +On CPU models which support it, TjMax is read from a model-specific register. +On other models, it is set to an arbitrary value based on weak heuristics. +If these heuristics don't work for you, you can pass the correct TjMax value +as a module parameter (tjmax). Appendix A. Known TjMax lists (TBD): Some information comes from ark.intel.com diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 256f70803eb3..5a41e9dda909 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -36,11 +36,20 @@ #include #include #include +#include #include #include #define DRVNAME "coretemp" +/* + * force_tjmax only matters when TjMax can't be read from the CPU itself. + * When set, it replaces the driver's suboptimal heuristic. + */ +static int force_tjmax; +module_param_named(tjmax, force_tjmax, int, 0444); +MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); + #define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */ #define NUM_REAL_CORES 16 /* Number of Real cores per cpu */ #define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */ @@ -398,6 +407,12 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) } } + if (force_tjmax) { + dev_notice(dev, "TjMax forced to %d degrees C by user\n", + force_tjmax); + return force_tjmax * 1000; + } + /* * An assumption is made for early CPUs and unreadable MSR. * NOTE: the calculated value may not be correct. -- cgit v1.2.3 From f4af6fd6e21792ca4deca3d29c113a575594078e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 19 Sep 2011 21:41:16 -0700 Subject: hwmon: (coretemp) Don't use threshold registers for tempX_max With commit c814a4c7c4aad795835583344353963a0a673eb0, the meaning of tempX_max was changed. It no longer returns the value of bits 8:15 of MSR_IA32_TEMPERATURE_TARGET, but instead returns the value of CPU threshold register T1. tempX_max_hyst was added to reflect the value of temperature threshold register T0. As it turns out, T0 and T1 are used on some systems, presumably by the BIOS. Also, T0 and T1 don't have a well defined meaning. The thresholds may be used as upper or lower limits, and it is not guaranteed that T0 <= T1. Thus, the new attribute mapping does not reflect the actual usage of the threshold registers. Also, register contents are changed during runtime by an entity other than the hwmon driver, meaning the values cached by the driver do not reflect actual register contents. Revert most of c814a4c7c4aad795835583344353963a0a673eb0 to address the problem. Support for T0 and T1 will be added back in with a separate commit, using new attribute names. Signed-off-by: Guenter Roeck Cc: Fenghua Yu Cc: Durgadoss R Acked-by: Jean Delvare --- Documentation/hwmon/coretemp | 7 --- drivers/hwmon/coretemp.c | 135 +++++-------------------------------------- 2 files changed, 14 insertions(+), 128 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp index 49c0d42dde86..84d46c0c71a3 100644 --- a/Documentation/hwmon/coretemp +++ b/Documentation/hwmon/coretemp @@ -35,13 +35,6 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files: All Sysfs entries are named with their core_id (represented here by 'X'). tempX_input - Core temperature (in millidegrees Celsius). tempX_max - All cooling devices should be turned on (on Core2). - Initialized with IA32_THERM_INTERRUPT. When the CPU - temperature reaches this temperature, an interrupt is - generated and tempX_max_alarm is set. -tempX_max_hyst - If the CPU temperature falls below than temperature, - an interrupt is generated and tempX_max_alarm is reset. -tempX_max_alarm - Set if the temperature reaches or exceeds tempX_max. - Reset if the temperature drops to or below tempX_max_hyst. tempX_crit - Maximum junction temperature (in millidegrees Celsius). tempX_crit_alarm - Set when Out-of-spec bit is set, never clears. Correct CPU operation is no longer guaranteed. diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 5a41e9dda909..47364151e67a 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -54,8 +54,7 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); #define NUM_REAL_CORES 16 /* Number of Real cores per cpu */ #define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */ #define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */ -#define MAX_THRESH_ATTRS 3 /* Maximum no of Threshold attrs */ -#define TOTAL_ATTRS (MAX_CORE_ATTRS + MAX_THRESH_ATTRS) +#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) #ifdef CONFIG_SMP @@ -78,8 +77,6 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); * This value is passed as "id" field to rdmsr/wrmsr functions. * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS, * from where the temperature values should be read. - * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT, - * from where the thresholds are read. * @attr_size: Total number of pre-core attrs displayed in the sysfs. * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data. * Otherwise, temp_data holds coretemp data. @@ -88,13 +85,11 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); struct temp_data { int temp; int ttarget; - int tmin; int tjmax; unsigned long last_updated; unsigned int cpu; u32 cpu_core_id; u32 status_reg; - u32 intrpt_reg; int attr_size; bool is_pkg_data; bool valid; @@ -152,19 +147,6 @@ static ssize_t show_crit_alarm(struct device *dev, return sprintf(buf, "%d\n", (eax >> 5) & 1); } -static ssize_t show_max_alarm(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - u32 eax, edx; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - struct temp_data *tdata = pdata->core_data[attr->index]; - - rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); - - return sprintf(buf, "%d\n", !!(eax & THERM_STATUS_THRESHOLD1)); -} - static ssize_t show_tjmax(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -183,83 +165,6 @@ static ssize_t show_ttarget(struct device *dev, return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget); } -static ssize_t store_ttarget(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct platform_data *pdata = dev_get_drvdata(dev); - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct temp_data *tdata = pdata->core_data[attr->index]; - u32 eax, edx; - unsigned long val; - int diff; - - if (strict_strtoul(buf, 10, &val)) - return -EINVAL; - - /* - * THERM_MASK_THRESHOLD1 is 7 bits wide. Values are entered in terms - * of milli degree celsius. Hence don't accept val > (127 * 1000) - */ - if (val > tdata->tjmax || val > 127000) - return -EINVAL; - - diff = (tdata->tjmax - val) / 1000; - - mutex_lock(&tdata->update_lock); - rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx); - eax = (eax & ~THERM_MASK_THRESHOLD1) | - (diff << THERM_SHIFT_THRESHOLD1); - wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx); - tdata->ttarget = val; - mutex_unlock(&tdata->update_lock); - - return count; -} - -static ssize_t show_tmin(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin); -} - -static ssize_t store_tmin(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct platform_data *pdata = dev_get_drvdata(dev); - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct temp_data *tdata = pdata->core_data[attr->index]; - u32 eax, edx; - unsigned long val; - int diff; - - if (strict_strtoul(buf, 10, &val)) - return -EINVAL; - - /* - * THERM_MASK_THRESHOLD0 is 7 bits wide. Values are entered in terms - * of milli degree celsius. Hence don't accept val > (127 * 1000) - */ - if (val > tdata->tjmax || val > 127000) - return -EINVAL; - - diff = (tdata->tjmax - val) / 1000; - - mutex_lock(&tdata->update_lock); - rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx); - eax = (eax & ~THERM_MASK_THRESHOLD0) | - (diff << THERM_SHIFT_THRESHOLD0); - wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx); - tdata->tmin = val; - mutex_unlock(&tdata->update_lock); - - return count; -} - static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -445,16 +350,11 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev, struct device_attribute *devattr, char *buf) = { show_label, show_crit_alarm, show_temp, show_tjmax, - show_max_alarm, show_ttarget, show_tmin }; - static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev, - struct device_attribute *devattr, const char *buf, - size_t count) = { NULL, NULL, NULL, NULL, NULL, - store_ttarget, store_tmin }; + show_ttarget }; static const char *names[TOTAL_ATTRS] = { "temp%d_label", "temp%d_crit_alarm", "temp%d_input", "temp%d_crit", - "temp%d_max_alarm", "temp%d_max", - "temp%d_max_hyst" }; + "temp%d_max" }; for (i = 0; i < tdata->attr_size; i++) { snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i], @@ -462,10 +362,6 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr); tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i]; tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO; - if (rw_ptr[i]) { - tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR; - tdata->sd_attrs[i].dev_attr.store = rw_ptr[i]; - } tdata->sd_attrs[i].dev_attr.show = rd_ptr[i]; tdata->sd_attrs[i].index = attr_no; err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr); @@ -538,8 +434,6 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS; - tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT : - MSR_IA32_THERM_INTERRUPT; tdata->is_pkg_data = pkg_flag; tdata->cpu = cpu; tdata->cpu_core_id = TO_CORE_ID(cpu); @@ -591,19 +485,18 @@ static int create_core_data(struct platform_data *pdata, tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); /* - * Test if we can access the intrpt register. If so, increase the - * 'size' enough to have ttarget/tmin/max_alarm interfaces. - * Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT + * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. + * The target temperature is available on older CPUs but not in this + * register. Atoms don't have the register at all. */ - err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx); - if (!err) { - tdata->attr_size += MAX_THRESH_ATTRS; - tdata->tmin = tdata->tjmax - - ((eax & THERM_MASK_THRESHOLD0) >> - THERM_SHIFT_THRESHOLD0) * 1000; - tdata->ttarget = tdata->tjmax - - ((eax & THERM_MASK_THRESHOLD1) >> - THERM_SHIFT_THRESHOLD1) * 1000; + if (c->x86_model > 0xe && c->x86_model != 0x1c) { + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, + &eax, &edx); + if (!err) { + tdata->ttarget + = tdata->tjmax - ((eax >> 8) & 0xff) * 1000; + tdata->attr_size++; + } } pdata->core_data[attr_no] = tdata; -- cgit v1.2.3 From b3a242a6e4b8c09dbb466ab7a9d2c724e75faa67 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 23 Sep 2011 06:35:00 -0400 Subject: hwmon: (coretemp) don't use kernel assigned CPU number as platform device ID ... as that has the potential to conflict with (particularly soft) CPU hot removal and re-adding. Signed-off-by: Jan Beulich [guenter.roeck@ericsson.com: use platform device ID as physical CPU id] Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 47364151e67a..6420c3be07b8 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -561,7 +561,7 @@ static int __devinit coretemp_probe(struct platform_device *pdev) if (err) goto exit_free; - pdata->phys_proc_id = TO_PHYS_ID(pdev->id); + pdata->phys_proc_id = pdev->id; platform_set_drvdata(pdev, pdata); pdata->hwmon_dev = hwmon_device_register(&pdev->dev); @@ -613,7 +613,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) mutex_lock(&pdev_list_mutex); - pdev = platform_device_alloc(DRVNAME, cpu); + pdev = platform_device_alloc(DRVNAME, TO_PHYS_ID(cpu)); if (!pdev) { err = -ENOMEM; pr_err("Device allocation failed\n"); -- cgit v1.2.3 From e3204ed3a4a78ca4d10eee8b661b94429bd38da8 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 23 Sep 2011 06:36:53 -0400 Subject: hwmon: (coretemp) constify static data These arrays won't ever be written to, so protect them from unintentional modification. Signed-off-by: Jan Beulich Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 6420c3be07b8..ac1c81f1d593 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -347,11 +347,11 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, int attr_no) { int err, i; - static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev, + static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev, struct device_attribute *devattr, char *buf) = { show_label, show_crit_alarm, show_temp, show_tjmax, show_ttarget }; - static const char *names[TOTAL_ATTRS] = { + static const char *const names[TOTAL_ATTRS] = { "temp%d_label", "temp%d_crit_alarm", "temp%d_input", "temp%d_crit", "temp%d_max" }; -- cgit v1.2.3 From 2f1c3db0a6adcfd12d556afa3605d4923658b307 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 23 Sep 2011 06:40:08 -0400 Subject: hwmon: (coretemp) remove struct platform_data * parameter from create_core_data() The only caller of the function obtained the pointer solely for the purpose of passing it to this function, while it can be easily determined from the struct platform_device * parameter also passed. Signed-off-by: Jan Beulich Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index ac1c81f1d593..44b23917d4cc 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -442,11 +442,11 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) return tdata; } -static int create_core_data(struct platform_data *pdata, - struct platform_device *pdev, +static int create_core_data(struct platform_device *pdev, unsigned int cpu, int pkg_flag) { struct temp_data *tdata; + struct platform_data *pdata = platform_get_drvdata(pdev); struct cpuinfo_x86 *c = &cpu_data(cpu); u32 eax, edx; int err, attr_no; @@ -514,16 +514,13 @@ exit_free: static void coretemp_add_core(unsigned int cpu, int pkg_flag) { - struct platform_data *pdata; struct platform_device *pdev = coretemp_get_pdev(cpu); int err; if (!pdev) return; - pdata = platform_get_drvdata(pdev); - - err = create_core_data(pdata, pdev, cpu, pkg_flag); + err = create_core_data(pdev, cpu, pkg_flag); if (err) dev_err(&pdev->dev, "Adding Core %u failed\n", cpu); } -- cgit v1.2.3 From 0eb9782ad9b1bd496ba61cd5ea27ccb8db21e885 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 28 Sep 2011 08:11:00 -0700 Subject: hwmon: (coretemp) Fixup platform device ID change With recent change "hwmon: (coretemp) don't use kernel assigned CPU number as platform device ID", the microcode check is now running on random CPU. Fix that by checking the microcode before creating the platform device rather than at probe time. Also avoid calling TO_PHYS_ID(cpu) twice in the same function, it's expensive. Signed-off-by: Jean Delvare Cc: Jan Beulich Cc: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 44b23917d4cc..cf5b1de32c0a 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -377,9 +377,9 @@ exit_free: } -static int __devinit chk_ucode_version(struct platform_device *pdev) +static int __cpuinit chk_ucode_version(unsigned int cpu) { - struct cpuinfo_x86 *c = &cpu_data(pdev->id); + struct cpuinfo_x86 *c = &cpu_data(cpu); int err; u32 edx; @@ -390,17 +390,15 @@ static int __devinit chk_ucode_version(struct platform_device *pdev) */ if (c->x86_model == 0xe && c->x86_mask < 0xc) { /* check for microcode update */ - err = smp_call_function_single(pdev->id, get_ucode_rev_on_cpu, + err = smp_call_function_single(cpu, get_ucode_rev_on_cpu, &edx, 1); if (err) { - dev_err(&pdev->dev, - "Cannot determine microcode revision of " - "CPU#%u (%d)!\n", pdev->id, err); + pr_err("Cannot determine microcode revision of " + "CPU#%u (%d)!\n", cpu, err); return -ENODEV; } else if (edx < 0x39) { - dev_err(&pdev->dev, - "Errata AE18 not fixed, update BIOS or " - "microcode of the CPU!\n"); + pr_err("Errata AE18 not fixed, update BIOS or " + "microcode of the CPU!\n"); return -ENODEV; } } @@ -544,11 +542,6 @@ static int __devinit coretemp_probe(struct platform_device *pdev) struct platform_data *pdata; int err; - /* Check the microcode version of the CPU */ - err = chk_ucode_version(pdev); - if (err) - return err; - /* Initialize the per-package data structures */ pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL); if (!pdata) @@ -630,7 +623,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) } pdev_entry->pdev = pdev; - pdev_entry->phys_proc_id = TO_PHYS_ID(cpu); + pdev_entry->phys_proc_id = pdev->id; list_add_tail(&pdev_entry->list, &pdev_list); mutex_unlock(&pdev_list_mutex); @@ -691,6 +684,10 @@ static void __cpuinit get_core_online(unsigned int cpu) return; if (!pdev) { + /* Check the microcode version of the CPU */ + if (chk_ucode_version(cpu)) + return; + /* * Alright, we have DTS support. * We are bringing the _first_ core in this pkg -- cgit v1.2.3 From 20ecb499f64a7e8e7fe03f6098ab25c71b7a6481 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 24 Sep 2011 15:27:04 -0700 Subject: hwmon: (coretemp) Avoid leaving around dangling pointer Storing the struct temp_data pointer allocated from create_core_data() when returning an error has the potential of leaving around a pointer to freed memory. Reset it to NULL for error returns. Reported-by: Jan Beulich Signed-off-by: Guenter Roeck Acked-by: Jean Delvare --- drivers/hwmon/coretemp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index cf5b1de32c0a..932383786642 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -506,6 +506,7 @@ static int create_core_data(struct platform_device *pdev, return 0; exit_free: + pdata->core_data[attr_no] = NULL; kfree(tdata); return err; } -- cgit v1.2.3 From ca8bc8dc044793ee4d59ff7fe40138eee27d0325 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 12 Oct 2011 17:46:35 -0700 Subject: coretemp: Get microcode revision from cpu_data Now that the ucode revision is available in cpu_data remove the existing code in coretemp.c to query it manually. Read the ucode revision from cpu_data instead Signed-off-by: Andi Kleen Acked-by: H. Peter Anvin Cc: jbeulich@novell.com Cc: fenghua.yu@intel.com Cc: khali@linux-fr.org Link: http://lkml.kernel.org/r/1318466795-7393-3-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar --- drivers/hwmon/coretemp.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 932383786642..ce18c046f728 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -325,15 +325,6 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) return adjust_tjmax(c, id, dev); } -static void __devinit get_ucode_rev_on_cpu(void *edx) -{ - u32 eax; - - wrmsr(MSR_IA32_UCODE_REV, 0, 0); - sync_core(); - rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx); -} - static int create_name_attr(struct platform_data *pdata, struct device *dev) { sysfs_attr_init(&pdata->name_attr.attr); @@ -380,27 +371,16 @@ exit_free: static int __cpuinit chk_ucode_version(unsigned int cpu) { struct cpuinfo_x86 *c = &cpu_data(cpu); - int err; - u32 edx; /* * Check if we have problem with errata AE18 of Core processors: * Readings might stop update when processor visited too deep sleep, * fixed for stepping D0 (6EC). */ - if (c->x86_model == 0xe && c->x86_mask < 0xc) { - /* check for microcode update */ - err = smp_call_function_single(cpu, get_ucode_rev_on_cpu, - &edx, 1); - if (err) { - pr_err("Cannot determine microcode revision of " - "CPU#%u (%d)!\n", cpu, err); - return -ENODEV; - } else if (edx < 0x39) { - pr_err("Errata AE18 not fixed, update BIOS or " - "microcode of the CPU!\n"); - return -ENODEV; - } + if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) { + pr_err("Errata AE18 not fixed, update BIOS or " + "microcode of the CPU!\n"); + return -ENODEV; } return 0; } -- cgit v1.2.3 From 2aba6cac2a84f3b80e11a680c34d55e7739b474d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 6 Nov 2011 20:25:18 +0100 Subject: hwmon: (coretemp) Fix for non-SMP builds The definition of TO_ATTR_NO in the non-SMP case is wrong. As the SMP definition resolves to the correct value, just use this for both cases. Without this fix the temperature attributes are named temp0_* instead of temp2_*, so libsensors won't pick them. Broken since kernel 3.0. Signed-off-by: Jean Delvare Tested-by: Phil Sutter Cc: stable@kernel.org Acked-by: Durgadoss R Acked-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/hwmon/coretemp.c') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index ce18c046f728..104b3767516c 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -60,14 +60,13 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); #ifdef CONFIG_SMP #define TO_PHYS_ID(cpu) cpu_data(cpu).phys_proc_id #define TO_CORE_ID(cpu) cpu_data(cpu).cpu_core_id -#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) #define for_each_sibling(i, cpu) for_each_cpu(i, cpu_sibling_mask(cpu)) #else #define TO_PHYS_ID(cpu) (cpu) #define TO_CORE_ID(cpu) (cpu) -#define TO_ATTR_NO(cpu) (cpu) #define for_each_sibling(i, cpu) for (i = 0; false; ) #endif +#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) /* * Per-Core Temperature Data -- cgit v1.2.3