[PATCH 1/1] hwmon: coretemp: use dynamically allocated array to store per core data

From: Lukasz Odzioba
Date: Fri Sep 11 2015 - 09:57:24 EST


Removes arbitrary limit of supported CPU cores and max core ID.
Replaces fixed size array storing per core information with dynamically allocated one.

Currently coretemp is not able to handle cores with core ID greater than 32.
Such attempt ends up with the following error in dmesg:
coretemp coretemp.0: Adding Core XXX failed

Signed-off-by: Lukasz Odzioba <lukasz.odzioba@xxxxxxxxx>
---
drivers/hwmon/coretemp.c | 94 +++++++++++++++++++++++++++++++++++++---------
1 files changed, 76 insertions(+), 18 deletions(-)

diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 3e03379..1e60039 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -52,11 +52,9 @@ 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 32 /* Number of Real cores per cpu */
#define CORETEMP_NAME_LENGTH 19 /* String Length of attrs */
#define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */
#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
-#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)

#define TO_PHYS_ID(cpu) (cpu_data(cpu).phys_proc_id)
#define TO_CORE_ID(cpu) (cpu_data(cpu).cpu_core_id)
@@ -104,7 +102,9 @@ struct temp_data {
struct platform_data {
struct device *hwmon_dev;
u16 phys_proc_id;
- struct temp_data *core_data[MAX_CORE_DATA];
+ u32 core_data_size;
+ struct temp_data **core_data;
+ struct mutex core_data_lock;
struct device_attribute name_attr;
};

@@ -117,12 +117,25 @@ struct pdev_entry {
static LIST_HEAD(pdev_list);
static DEFINE_MUTEX(pdev_list_mutex);

+static struct temp_data *get_core_data(struct platform_data *pdata, int index)
+{
+ struct temp_data *tdata;
+
+ mutex_lock(&pdata->core_data_lock);
+ if (index >= pdata->core_data_size)
+ tdata = NULL;
+ else
+ tdata = pdata->core_data[index];
+ mutex_unlock(&pdata->core_data_lock);
+ return tdata;
+}
+
static ssize_t show_label(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);
- struct temp_data *tdata = pdata->core_data[attr->index];
+ struct temp_data *tdata = get_core_data(pdata, attr->index);

if (tdata->is_pkg_data)
return sprintf(buf, "Physical id %u\n", pdata->phys_proc_id);
@@ -136,7 +149,7 @@ static ssize_t show_crit_alarm(struct device *dev,
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];
+ struct temp_data *tdata = get_core_data(pdata, attr->index);

rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);

@@ -148,8 +161,9 @@ static ssize_t show_tjmax(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
+ struct temp_data *tdata = get_core_data(pdata, attr->index);

- return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax);
+ return sprintf(buf, "%d\n", tdata->tjmax);
}

static ssize_t show_ttarget(struct device *dev,
@@ -157,8 +171,9 @@ static ssize_t show_ttarget(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
+ struct temp_data *tdata = get_core_data(pdata, attr->index);

- return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
+ return sprintf(buf, "%d\n", tdata->ttarget);
}

static ssize_t show_temp(struct device *dev,
@@ -167,7 +182,8 @@ static ssize_t show_temp(struct device *dev,
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];
+ struct temp_data *tdata = get_core_data(pdata, attr->index);
+

mutex_lock(&tdata->update_lock);

@@ -485,8 +501,23 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
*/
attr_no = pkg_flag ? 1 : TO_ATTR_NO(cpu);

- if (attr_no > MAX_CORE_DATA - 1)
- return -ERANGE;
+ if (attr_no >= pdata->core_data_size) {
+ struct temp_data **tmp;
+ u32 new_size = attr_no + 1;
+
+ get_online_cpus();
+ mutex_lock(&pdata->core_data_lock);
+ tmp = krealloc(pdata->core_data, new_size * sizeof(struct temp_data*), GFP_ATOMIC | __GFP_ZERO);
+ if (tmp == NULL) {
+ mutex_unlock(&pdata->core_data_lock);
+ put_online_cpus();
+ return -ENOMEM;
+ }
+ pdata->core_data = tmp;
+ pdata->core_data_size = new_size;
+ mutex_unlock(&pdata->core_data_lock);
+ put_online_cpus();
+ }

/*
* Provide a single set of attributes for all HT siblings of a core
@@ -495,7 +526,8 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
* Skip if a HT sibling of this core is already registered.
* This is not an error.
*/
- if (pdata->core_data[attr_no] != NULL)
+ tdata = get_core_data(pdata, attr_no);
+ if (tdata)
return 0;

tdata = init_temp_data(cpu, pkg_flag);
@@ -525,7 +557,9 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
}
}

+ mutex_lock(&pdata->core_data_lock);
pdata->core_data[attr_no] = tdata;
+ mutex_unlock(&pdata->core_data_lock);

/* Create sysfs interfaces */
err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
@@ -534,7 +568,9 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,

return 0;
exit_free:
+ mutex_lock(&pdata->core_data_lock);
pdata->core_data[attr_no] = NULL;
+ mutex_unlock(&pdata->core_data_lock);
kfree(tdata);
return err;
}
@@ -555,26 +591,35 @@ static void coretemp_add_core(unsigned int cpu, int pkg_flag)
static void coretemp_remove_core(struct platform_data *pdata,
int indx)
{
- struct temp_data *tdata = pdata->core_data[indx];
+ struct temp_data *tdata = get_core_data(pdata, indx);

/* Remove the sysfs attributes */
sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);

- kfree(pdata->core_data[indx]);
+ mutex_lock(&pdata->core_data_lock);
+ kfree(tdata);
pdata->core_data[indx] = NULL;
+ mutex_unlock(&pdata->core_data_lock);
}

static int coretemp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct platform_data *pdata;
+ const u32 init_size = 4;

/* Initialize the per-package data structures */
pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
if (!pdata)
return -ENOMEM;

+ pdata->core_data = kcalloc(init_size, sizeof(struct temp_data*), GFP_KERNEL);
+ if (!pdata->core_data)
+ return -ENOMEM;
+
pdata->phys_proc_id = pdev->id;
+ mutex_init(&pdata->core_data_lock);
+ pdata->core_data_size = init_size;
platform_set_drvdata(pdev, pdata);

pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
@@ -587,9 +632,12 @@ static int coretemp_remove(struct platform_device *pdev)
struct platform_data *pdata = platform_get_drvdata(pdev);
int i;

- for (i = MAX_CORE_DATA - 1; i >= 0; --i)
+ get_online_cpus();
+ for (i = pdata->core_data_size - 1; i >= 0; --i)
if (pdata->core_data[i])
coretemp_remove_core(pdata, i);
+ put_online_cpus();
+ kfree(pdata->core_data);

return 0;
}
@@ -667,12 +715,15 @@ static bool is_any_core_online(struct platform_data *pdata)
int i;

/* Find online cores, except pkgtemp data */
- for (i = MAX_CORE_DATA - 1; i >= 0; --i) {
+ mutex_lock(&pdata->core_data_lock);
+ for (i = pdata->core_data_size - 1; i >= 0; --i) {
if (pdata->core_data[i] &&
!pdata->core_data[i]->is_pkg_data) {
+ mutex_unlock(&pdata->core_data_lock);
return true;
}
}
+ mutex_unlock(&pdata->core_data_lock);
return false;
}

@@ -723,6 +774,7 @@ static void put_core_offline(unsigned int cpu)
int i, indx;
struct platform_data *pdata;
struct platform_device *pdev = coretemp_get_pdev(cpu);
+ struct temp_data *tdata;

/* If the physical CPU device does not exist, just return */
if (!pdev)
@@ -732,12 +784,18 @@ static void put_core_offline(unsigned int cpu)

indx = TO_ATTR_NO(cpu);

- /* The core id is too big, just return */
- if (indx > MAX_CORE_DATA - 1)
+ if (indx >= pdata->core_data_size)
return;

- if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
+ get_online_cpus();
+ tdata = get_core_data(pdata, indx);
+ if (!tdata) {
+ put_online_cpus();
+ return;
+ }
+ if (tdata->cpu == cpu)
coretemp_remove_core(pdata, indx);
+ put_online_cpus();

/*
* If a HT sibling of a core is taken offline, but another HT sibling
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/