Commit 7108b80a authored by Zhang Rui's avatar Zhang Rui Committed by Dave Hansen

hwmon/coretemp: Handle large core ID value

The coretemp driver supports up to a hard-coded limit of 128 cores.

Today, the driver can not support a core with an ID above that limit.
Yet, the encoding of core ID's is arbitrary (BIOS APIC-ID) and so they
may be sparse and they may be large.

Update the driver to map arbitrary core ID numbers into appropriate
array indexes so that 128 cores can be supported, no matter the encoding
of core ID's.
Signed-off-by: default avatarZhang Rui <rui.zhang@intel.com>
Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Acked-by: default avatarLen Brown <len.brown@intel.com>
Acked-by: default avatarGuenter Roeck <linux@roeck-us.net>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/20221014090147.1836-3-rui.zhang@intel.com
parent 33806e7c
...@@ -46,9 +46,6 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); ...@@ -46,9 +46,6 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) #define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
#define TO_CORE_ID(cpu) (cpu_data(cpu).cpu_core_id)
#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#define for_each_sibling(i, cpu) \ #define for_each_sibling(i, cpu) \
for_each_cpu(i, topology_sibling_cpumask(cpu)) for_each_cpu(i, topology_sibling_cpumask(cpu))
...@@ -91,6 +88,8 @@ struct temp_data { ...@@ -91,6 +88,8 @@ struct temp_data {
struct platform_data { struct platform_data {
struct device *hwmon_dev; struct device *hwmon_dev;
u16 pkg_id; u16 pkg_id;
u16 cpu_map[NUM_REAL_CORES];
struct ida ida;
struct cpumask cpumask; struct cpumask cpumask;
struct temp_data *core_data[MAX_CORE_DATA]; struct temp_data *core_data[MAX_CORE_DATA];
struct device_attribute name_attr; struct device_attribute name_attr;
...@@ -441,7 +440,7 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) ...@@ -441,7 +440,7 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
MSR_IA32_THERM_STATUS; MSR_IA32_THERM_STATUS;
tdata->is_pkg_data = pkg_flag; tdata->is_pkg_data = pkg_flag;
tdata->cpu = cpu; tdata->cpu = cpu;
tdata->cpu_core_id = TO_CORE_ID(cpu); tdata->cpu_core_id = topology_core_id(cpu);
tdata->attr_size = MAX_CORE_ATTRS; tdata->attr_size = MAX_CORE_ATTRS;
mutex_init(&tdata->update_lock); mutex_init(&tdata->update_lock);
return tdata; return tdata;
...@@ -454,7 +453,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, ...@@ -454,7 +453,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
struct platform_data *pdata = platform_get_drvdata(pdev); struct platform_data *pdata = platform_get_drvdata(pdev);
struct cpuinfo_x86 *c = &cpu_data(cpu); struct cpuinfo_x86 *c = &cpu_data(cpu);
u32 eax, edx; u32 eax, edx;
int err, attr_no; int err, index, attr_no;
/* /*
* Find attr number for sysfs: * Find attr number for sysfs:
...@@ -462,14 +461,26 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, ...@@ -462,14 +461,26 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
* The attr number is always core id + 2 * The attr number is always core id + 2
* The Pkgtemp will always show up as temp1_*, if available * The Pkgtemp will always show up as temp1_*, if available
*/ */
attr_no = pkg_flag ? PKG_SYSFS_ATTR_NO : TO_ATTR_NO(cpu); if (pkg_flag) {
attr_no = PKG_SYSFS_ATTR_NO;
} else {
index = ida_alloc(&pdata->ida, GFP_KERNEL);
if (index < 0)
return index;
pdata->cpu_map[index] = topology_core_id(cpu);
attr_no = index + BASE_SYSFS_ATTR_NO;
}
if (attr_no > MAX_CORE_DATA - 1) if (attr_no > MAX_CORE_DATA - 1) {
return -ERANGE; err = -ERANGE;
goto ida_free;
}
tdata = init_temp_data(cpu, pkg_flag); tdata = init_temp_data(cpu, pkg_flag);
if (!tdata) if (!tdata) {
return -ENOMEM; err = -ENOMEM;
goto ida_free;
}
/* Test if we can access the status register */ /* Test if we can access the status register */
err = rdmsr_safe_on_cpu(cpu, tdata->status_reg, &eax, &edx); err = rdmsr_safe_on_cpu(cpu, tdata->status_reg, &eax, &edx);
...@@ -505,6 +516,9 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, ...@@ -505,6 +516,9 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
exit_free: exit_free:
pdata->core_data[attr_no] = NULL; pdata->core_data[attr_no] = NULL;
kfree(tdata); kfree(tdata);
ida_free:
if (!pkg_flag)
ida_free(&pdata->ida, index);
return err; return err;
} }
...@@ -524,6 +538,9 @@ static void coretemp_remove_core(struct platform_data *pdata, int indx) ...@@ -524,6 +538,9 @@ static void coretemp_remove_core(struct platform_data *pdata, int indx)
kfree(pdata->core_data[indx]); kfree(pdata->core_data[indx]);
pdata->core_data[indx] = NULL; pdata->core_data[indx] = NULL;
if (indx >= BASE_SYSFS_ATTR_NO)
ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO);
} }
static int coretemp_probe(struct platform_device *pdev) static int coretemp_probe(struct platform_device *pdev)
...@@ -537,6 +554,7 @@ static int coretemp_probe(struct platform_device *pdev) ...@@ -537,6 +554,7 @@ static int coretemp_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
pdata->pkg_id = pdev->id; pdata->pkg_id = pdev->id;
ida_init(&pdata->ida);
platform_set_drvdata(pdev, pdata); platform_set_drvdata(pdev, pdata);
pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
...@@ -553,6 +571,7 @@ static int coretemp_remove(struct platform_device *pdev) ...@@ -553,6 +571,7 @@ static int coretemp_remove(struct platform_device *pdev)
if (pdata->core_data[i]) if (pdata->core_data[i])
coretemp_remove_core(pdata, i); coretemp_remove_core(pdata, i);
ida_destroy(&pdata->ida);
return 0; return 0;
} }
...@@ -647,7 +666,7 @@ static int coretemp_cpu_offline(unsigned int cpu) ...@@ -647,7 +666,7 @@ static int coretemp_cpu_offline(unsigned int cpu)
struct platform_device *pdev = coretemp_get_pdev(cpu); struct platform_device *pdev = coretemp_get_pdev(cpu);
struct platform_data *pd; struct platform_data *pd;
struct temp_data *tdata; struct temp_data *tdata;
int indx, target; int i, indx = -1, target;
/* /*
* Don't execute this on suspend as the device remove locks * Don't execute this on suspend as the device remove locks
...@@ -660,12 +679,19 @@ static int coretemp_cpu_offline(unsigned int cpu) ...@@ -660,12 +679,19 @@ static int coretemp_cpu_offline(unsigned int cpu)
if (!pdev) if (!pdev)
return 0; return 0;
/* The core id is too big, just return */ pd = platform_get_drvdata(pdev);
indx = TO_ATTR_NO(cpu);
if (indx > MAX_CORE_DATA - 1) for (i = 0; i < NUM_REAL_CORES; i++) {
if (pd->cpu_map[i] == topology_core_id(cpu)) {
indx = i + BASE_SYSFS_ATTR_NO;
break;
}
}
/* Too many cores and this core is not populated, just return */
if (indx < 0)
return 0; return 0;
pd = platform_get_drvdata(pdev);
tdata = pd->core_data[indx]; tdata = pd->core_data[indx];
cpumask_clear_cpu(cpu, &pd->cpumask); cpumask_clear_cpu(cpu, &pd->cpumask);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment