[PATCH:hwmon:v4:]Merging_pkgtemp_with_coretemp

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch merges the pkgtemp driver with the coretemp driver.
This merged driver creates one hwmon device per physical CPU.

Changes from v3 of this patch:
Added appropriate support for CONFIG_HOTPLUG_CPU.

Signed-off-by: Durgadoss R <durgadoss.r@xxxxxxxxx>
---
 drivers/hwmon/coretemp.c |  618 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 455 insertions(+), 163 deletions(-)

diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 42de98d..2667828 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -39,119 +39,140 @@
 
 #define DRVNAME	"coretemp"
 
-typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
-		SHOW_NAME } SHOW;
+#define CORES_PER_CPU		16	/* No of Real Cores per CPU */
+#define CORETEMP_NAME_LENGTH	17	/* String Length of attrs */
+#define MAX_ATTRS		5	/* Maximum no of per-core attrs */
 
 /*
- * Functions declaration
+ * Per-Core Temperature Data
+ * @last_updated: The time when the current temperature value was updated
+ *		earlier (in jiffies).
+ * @cpu_core_id: The CPU Core from which temperature values should be read
+ *		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.
+ * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
+ *		Otherwise, temp_data holds coretemp data.
  */
-
-static struct coretemp_data *coretemp_update_device(struct device *dev);
-
-struct coretemp_data {
-	struct device *hwmon_dev;
-	struct mutex update_lock;
-	const char *name;
-	u32 id;
-	u16 core_id;
-	char valid;		/* zero until following fields are valid */
-	unsigned long last_updated;	/* in jiffies */
+struct temp_data {
 	int temp;
-	int tjmax;
 	int ttarget;
-	u8 alarm;
+	int tjmax;
+	u8 crit_alarm;
+	u8 max_alarm;
+	unsigned long last_updated;
+	unsigned int cpu;
+	u32 cpu_core_id;
+	u32 status_reg;
+	bool is_pkg_data;
+	struct sensor_device_attribute sd_attrs[MAX_ATTRS];
+	char attr_name[MAX_ATTRS][CORETEMP_NAME_LENGTH];
+	struct mutex update_lock;
 };
 
 /*
- * Sysfs stuff
+ * Platform Data per Physical CPU
+ * @core_count:		Number of real cores(not HT ones) in a CPU
+ * @phys_proc_id:	The physical CPU id
  */
+struct platform_data {
+	struct device *hwmon_dev;
+	int core_count;
+	u16 phys_proc_id;
+	struct temp_data *core_data[CORES_PER_CPU];
+	struct device_attribute name_attr;
+};
+
+/* Function Declarations */
+static void remove_core(struct platform_data *data, struct device *dev, int i);
+
+static ssize_t show_name(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", DRVNAME);
+}
 
-static ssize_t show_name(struct device *dev, struct device_attribute
-			  *devattr, char *buf)
+static ssize_t show_label(struct device *dev,
+				struct device_attribute *devattr, char *buf)
 {
-	int ret;
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct coretemp_data *data = dev_get_drvdata(dev);
+	struct platform_data *pdata = dev_get_drvdata(dev);
+	struct temp_data *tdata = pdata->core_data[attr->index];
 
-	if (attr->index == SHOW_NAME)
-		ret = sprintf(buf, "%s\n", data->name);
-	else	/* show label */
-		ret = sprintf(buf, "Core %d\n", data->core_id);
-	return ret;
+	if (tdata->is_pkg_data)
+		return sprintf(buf, "Physical id %d\n", pdata->phys_proc_id);
+
+	return sprintf(buf, "Core %d\n", tdata->cpu_core_id);
 }
 
-static ssize_t show_alarm(struct device *dev, struct device_attribute
-			  *devattr, char *buf)
+static ssize_t show_crit_alarm(struct device *dev,
+				struct device_attribute *devattr, char *buf)
 {
-	struct coretemp_data *data = coretemp_update_device(dev);
-	/* read the Out-of-spec log, never clear */
-	return sprintf(buf, "%d\n", data->alarm);
+	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_core_id, tdata->status_reg, &eax, &edx);
+	tdata->crit_alarm = (eax >> 5) & 1;
+
+	return sprintf(buf, "%d\n", tdata->crit_alarm);
 }
 
-static ssize_t show_temp(struct device *dev,
-			 struct device_attribute *devattr, char *buf)
+static ssize_t show_tjmax(struct device *dev,
+				struct device_attribute *devattr, char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct coretemp_data *data = coretemp_update_device(dev);
-	int err;
+	struct platform_data *pdata = dev_get_drvdata(dev);
 
-	if (attr->index == SHOW_TEMP)
-		err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
-	else if (attr->index == SHOW_TJMAX)
-		err = sprintf(buf, "%d\n", data->tjmax);
-	else
-		err = sprintf(buf, "%d\n", data->ttarget);
-	return err;
+	return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax);
 }
 
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
-			  SHOW_TEMP);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
-			  SHOW_TJMAX);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
-			  SHOW_TTARGET);
-static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
-static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
-
-static struct attribute *coretemp_attributes[] = {
-	&sensor_dev_attr_name.dev_attr.attr,
-	&sensor_dev_attr_temp1_label.dev_attr.attr,
-	&dev_attr_temp1_crit_alarm.attr,
-	&sensor_dev_attr_temp1_input.dev_attr.attr,
-	&sensor_dev_attr_temp1_crit.dev_attr.attr,
-	NULL
-};
+static ssize_t show_ttarget(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);
 
-static const struct attribute_group coretemp_group = {
-	.attrs = coretemp_attributes,
-};
+	return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
+}
 
-static struct coretemp_data *coretemp_update_device(struct device *dev)
+static int update_curr_temp(struct temp_data *tdata, u32 eax, int tjmax)
 {
-	struct coretemp_data *data = dev_get_drvdata(dev);
+	int err = -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	mutex_lock(&tdata->update_lock);
+	/*
+	 * Update the current temperature only if:
+	 * 1. The time interval has elapsed _and_
+	 * 2. The data is valid
+	 */
+	if (time_after(jiffies, tdata->last_updated + HZ) &&
+						(eax & 0x80000000)) {
+		tdata->temp = tjmax - (((eax >> 16) & 0x7f) * 1000);
+		tdata->last_updated = jiffies;
+		err = 0;
+	}
 
-	if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
-		u32 eax, edx;
+	mutex_unlock(&tdata->update_lock);
+	return err;
+}
 
-		data->valid = 0;
-		rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
-		data->alarm = (eax >> 5) & 1;
-		/* update only if data has been valid */
-		if (eax & 0x80000000) {
-			data->temp = data->tjmax - (((eax >> 16)
-							& 0x7f) * 1000);
-			data->valid = 1;
-		} else {
-			dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
-		}
-		data->last_updated = jiffies;
-	}
+static ssize_t show_temp(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];
+	int err;
 
-	mutex_unlock(&data->update_lock);
-	return data;
+	rdmsr_on_cpu(tdata->cpu_core_id, tdata->status_reg, &eax, &edx);
+	err = update_curr_temp(tdata, eax, tdata->tjmax);
+	if (err)
+		return err;
+
+	return sprintf(buf, "%d\n", tdata->temp);
 }
 
 static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
@@ -298,115 +319,242 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
 	rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
 }
 
-static int __devinit coretemp_probe(struct platform_device *pdev)
+static int get_pkg_tjmax(int cpu, struct device *dev)
 {
-	struct coretemp_data *data;
-	struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+	int default_tjmax = 100000;	/* 100 degree celsius */
 	int err;
-	u32 eax, edx;
+	u32 eax, edx, val;
 
-	if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) {
-		err = -ENOMEM;
-		dev_err(&pdev->dev, "Out of memory\n");
-		goto exit;
+	err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+	if (!err) {
+		val = (eax >> 16) & 0xff;
+		if ((val > 80) && (val < 120))
+			return val * 1000;
 	}
+	dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%d\n", cpu);
+	return default_tjmax;
+}
 
-	data->id = pdev->id;
-#ifdef CONFIG_SMP
-	data->core_id = c->cpu_core_id;
-#endif
-	data->name = "coretemp";
-	mutex_init(&data->update_lock);
+static int create_name_attr(struct platform_data *pdata, struct device *dev)
+{
+	pdata->name_attr.attr.name = "name";
+	pdata->name_attr.attr.mode = S_IRUGO;
+	pdata->name_attr.show = show_name;
+	return device_create_file(dev, &pdata->name_attr);
+}
 
-	/* test if we can access the THERM_STATUS MSR */
-	err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
-	if (err) {
-		dev_err(&pdev->dev,
-			"Unable to access THERM_STATUS MSR, giving up\n");
-		goto exit_free;
+static int create_core_attrs(struct temp_data *tdata, struct device *dev,
+				int attr_no)
+{
+	int err, i;
+	ssize_t (*rd_ptr[MAX_ATTRS]) (struct device *dev,
+			struct device_attribute *devattr, char *buf) = {
+			show_label, show_crit_alarm, show_ttarget,
+			show_temp, show_tjmax };
+	const char *names[MAX_ATTRS] = { "temp%d_label", "temp%d_crit_alarm",
+					"temp%d_max", "temp%d_input",
+					"temp%d_crit" };
+
+	/* Increment attr_no since the sysfs interfaces start with temp1_* */
+	int sysfs_attr_no = attr_no + 1;
+
+	for (i = 0; i < MAX_ATTRS; i++) {
+		snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
+			sysfs_attr_no);
+		tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
+		tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
+		tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
+		tdata->sd_attrs[i].dev_attr.store = NULL;
+		tdata->sd_attrs[i].index = attr_no;
+		err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
+		if (err)
+			goto exit_free;
 	}
+	return 0;
+
+exit_free:
+	while (--i >= 0)
+		device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+	return err;
+}
+
+static void remove_attrs(struct device *dev, struct temp_data *tdata)
+{
+	int i;
 
-	/* 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).
-	*/
+	/* Remove the sysfs attributes */
+	for (i = 0; i < MAX_ATTRS; i++)
+		device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+}
 
+static void update_ttarget(__u8 cpu_model, struct temp_data *tdata,
+				struct device *dev)
+{
+	int err;
+	u32 eax, edx;
+
+	/*
+	 * Read the still undocumented IA32_TEMPERATURE_TARGET. It exists
+	 * on older CPUs but not in this register,
+	 * Atoms don't have it either.
+	 */
+	if ((cpu_model > 0xe) && (cpu_model != 0x1c)) {
+		err = rdmsr_safe_on_cpu(tdata->cpu_core_id,
+				MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+		if (err) {
+			dev_warn(dev,
+			"Unable to read IA32_TEMPERATURE_TARGET MSR\n");
+
+		} else {
+			tdata->ttarget = tdata->tjmax -
+					(((eax >> 8) & 0xff) * 1000);
+		}
+	}
+}
+
+static int chk_ucode_version(struct cpuinfo_x86 *c,
+				struct platform_device *pdev)
+{
+	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(data->id, get_ucode_rev_on_cpu,
-					       &edx, 1);
+		err = smp_call_function_single(pdev->id, get_ucode_rev_on_cpu,
+								&edx, 1);
 		if (err) {
 			dev_err(&pdev->dev,
 				"Cannot determine microcode revision of "
-				"CPU#%u (%d)!\n", data->id, err);
-			err = -ENODEV;
-			goto exit_free;
+				"CPU#%u (%d)!\n", pdev->id, err);
+			return -ENODEV;
 		} else if (edx < 0x39) {
-			err = -ENODEV;
 			dev_err(&pdev->dev,
 				"Errata AE18 not fixed, update BIOS or "
 				"microcode of the CPU!\n");
-			goto exit_free;
+			return -ENODEV;
 		}
 	}
+	return 0;
+}
 
-	data->tjmax = get_tjmax(c, data->id, &pdev->dev);
-	platform_set_drvdata(pdev, data);
+static struct temp_data *init_temp_data(int cpu, int core_id, int pkg_flag)
+{
+	struct temp_data *tdata;
+
+	tdata = kzalloc(sizeof(struct temp_data), GFP_KERNEL);
+	if (!tdata)
+		return NULL;
+
+	tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
+							MSR_IA32_THERM_STATUS;
+	tdata->is_pkg_data = pkg_flag;
+	tdata->cpu_core_id = core_id;
+	tdata->cpu = cpu;
+	mutex_init(&tdata->update_lock);
+	return tdata;
+}
 
-	/*
-	 * read the still undocumented IA32_TEMPERATURE_TARGET. It exists
-	 * on older CPUs but not in this register,
-	 * Atoms don't have it either.
-	 */
+static int create_core_data(struct platform_data *pdata,
+				struct platform_device *pdev,
+				unsigned int cpu, int pkg_flag)
+{
+	struct temp_data *tdata;
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	u32 eax, edx;
+	int err;
+	int core_id = c->cpu_core_id;
 
-	if ((c->x86_model > 0xe) && (c->x86_model != 0x1c)) {
-		err = rdmsr_safe_on_cpu(data->id, MSR_IA32_TEMPERATURE_TARGET,
-		    &eax, &edx);
-		if (err) {
-			dev_warn(&pdev->dev, "Unable to read"
-					" IA32_TEMPERATURE_TARGET MSR\n");
-		} else {
-			data->ttarget = data->tjmax -
-					(((eax >> 8) & 0xff) * 1000);
-			err = device_create_file(&pdev->dev,
-					&sensor_dev_attr_temp1_max.dev_attr);
-			if (err)
-				goto exit_free;
-		}
+	tdata = init_temp_data(cpu, core_id, pkg_flag);
+	if (!tdata)
+		return -ENOMEM;
+
+	/* Test if we can access the status register */
+	err = rdmsr_safe_on_cpu(core_id, tdata->status_reg, &eax, &edx);
+	if (err)
+		goto exit_free;
+
+	/* Create sysfs interfaces */
+	err = create_core_attrs(tdata, &pdev->dev, pdata->core_count);
+	if (err)
+		goto exit_free;
+
+	/* Get Critical Temperature */
+	if (pkg_flag)
+		tdata->tjmax = get_pkg_tjmax(pdev->id, &pdev->dev);
+	else
+		tdata->tjmax = get_tjmax(c, core_id, &pdev->dev);
+
+	update_ttarget(c->x86_model, tdata, &pdev->dev);
+
+	pdata->core_data[pdata->core_count] = tdata;
+	pdata->core_count++;
+
+	return 0;
+exit_free:
+	kfree(tdata);
+	return err;
+}
+
+static int __devinit coretemp_probe(struct platform_device *pdev)
+{
+	struct platform_data *pdata;
+	struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+	int err;
+
+	/* Initialize the per-package data structures */
+	pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&pdev->dev, "Out of memory\n");
+		return -ENOMEM;
 	}
 
-	if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
-		goto exit_dev;
+	pdata->core_count = 0;
+	pdata->phys_proc_id = c->phys_proc_id;
 
-	data->hwmon_dev = hwmon_device_register(&pdev->dev);
-	if (IS_ERR(data->hwmon_dev)) {
-		err = PTR_ERR(data->hwmon_dev);
-		dev_err(&pdev->dev, "Class registration failed (%d)\n",
-			err);
-		goto exit_class;
+	err = create_name_attr(pdata, &pdev->dev);
+	if (err)
+		goto exit_free;
+
+	/* Check the microcode version of the CPU */
+	err = chk_ucode_version(c, pdev);
+	if (err)
+		goto exit_name;
+
+	platform_set_drvdata(pdev, pdata);
+
+	pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(pdata->hwmon_dev)) {
+		err = PTR_ERR(pdata->hwmon_dev);
+		dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
+		goto exit_name;
 	}
 
 	return 0;
 
-exit_class:
-	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
-exit_dev:
-	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
+exit_name:
+	device_remove_file(&pdev->dev, &pdata->name_attr);
 exit_free:
-	kfree(data);
-exit:
+	kfree(pdata);
 	return err;
 }
 
 static int __devexit coretemp_remove(struct platform_device *pdev)
 {
-	struct coretemp_data *data = platform_get_drvdata(pdev);
+	struct platform_data *pdata = platform_get_drvdata(pdev);
+	int i;
 
-	hwmon_device_unregister(data->hwmon_dev);
-	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
-	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
+	for (i = pdata->core_count - 1; i >= 0; --i)
+		remove_core(pdata, &pdev->dev, i);
+
+	device_remove_file(&pdev->dev, &pdata->name_attr);
+	hwmon_device_unregister(pdata->hwmon_dev);
 	platform_set_drvdata(pdev, NULL);
-	kfree(data);
+	kfree(pdata);
 	return 0;
 }
 
@@ -432,6 +580,96 @@ struct pdev_entry {
 static LIST_HEAD(pdev_list);
 static DEFINE_MUTEX(pdev_list_mutex);
 
+static struct platform_device *get_pdev(int phys_proc_id)
+{
+	struct pdev_entry *p;
+
+	mutex_lock(&pdev_list_mutex);
+
+	list_for_each_entry(p, &pdev_list, list)
+		if (p->phys_proc_id == phys_proc_id) {
+			mutex_unlock(&pdev_list_mutex);
+			return p->pdev;
+		}
+
+	mutex_unlock(&pdev_list_mutex);
+	return NULL;
+}
+
+static int get_core_indx(struct platform_data *pdata, int core_id)
+{
+	int i;
+
+	for (i = 0; i < pdata->core_count; i++) {
+		if (pdata->core_data[i]->cpu_core_id == core_id &&
+			!pdata->core_data[i]->is_pkg_data)
+			return i;
+	}
+	return -ENODEV;
+}
+
+static void add_core(unsigned int cpu, int pkg_flag)
+{
+	int indx, err;
+	struct platform_data *pdata;
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	struct platform_device *pdev = get_pdev(c->phys_proc_id);
+
+	if (!pdev)
+		return;
+
+	pdata = platform_get_drvdata(pdev);
+
+	/* If this core is a HT one, do not create any interfaces */
+	indx = get_core_indx(pdata, c->cpu_core_id);
+	if (indx >= 0) {
+		dev_info(&pdev->dev, "A HT core (%u) is onlined\n", cpu);
+		return;
+	}
+
+	err = create_core_data(pdata, pdev, cpu, pkg_flag);
+	if (err) {
+		dev_err(&pdev->dev, "Onlining Core %u on Pkg %d failed\n",
+			cpu, c->phys_proc_id);
+	}
+}
+
+static void remove_core(struct platform_data *pdata, struct device *dev,
+			int indx)
+{
+	int i;
+	int max = pdata->core_count - 1;
+
+	/* Remove all sysfs attrs for this core */
+	remove_attrs(dev, pdata->core_data[indx]);
+
+	/* Shift the core_data elements */
+	for (i = indx; i < max; i++)
+		pdata->core_data[i] = pdata->core_data[i + 1];
+
+	/* Free the _last_ element */
+	kfree(pdata->core_data[max]);
+	pdata->core_data[max] = NULL;
+
+	pdata->core_count--;
+
+	/*
+	 * If count is _only_ one and the device is pkg temp
+	 * remove those interfaces and get rid off this 'pdev' entry
+	 * in the pdev_entry list.
+	 *
+	 * The pkg temp is alive as long as atleast one of the
+	 * cores inside the pkg is online. And it is removed
+	 * when all cores in a pkg go offline.
+	 */
+	if (pdata->core_count == 1 && pdata->core_data[0]->is_pkg_data) {
+		remove_attrs(dev, pdata->core_data[0]);
+		kfree(pdata->core_data[0]);
+		pdata->core_data[0] = NULL;
+		pdata->core_count--;
+	}
+}
+
 static int __cpuinit coretemp_device_add(unsigned int cpu)
 {
 	int err;
@@ -503,28 +741,81 @@ exit:
 	return err;
 }
 
-static void __cpuinit coretemp_device_remove(unsigned int cpu)
+static void __cpuinit coretemp_device_remove(int phys_proc_id)
 {
 	struct pdev_entry *p;
-	unsigned int i;
 
 	mutex_lock(&pdev_list_mutex);
 	list_for_each_entry(p, &pdev_list, list) {
-		if (p->cpu != cpu)
+		if (p->phys_proc_id != phys_proc_id)
 			continue;
 
 		platform_device_unregister(p->pdev);
 		list_del(&p->list);
 		mutex_unlock(&pdev_list_mutex);
 		kfree(p);
-		for_each_cpu(i, cpu_sibling_mask(cpu))
-			if (i != cpu && !coretemp_device_add(i))
-				break;
 		return;
 	}
 	mutex_unlock(&pdev_list_mutex);
 }
 
+static void get_core_online(unsigned int cpu)
+{
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	struct platform_device *pdev = get_pdev(c->phys_proc_id);
+
+	if (!pdev) {
+		/*
+		 * We are bringing the _first_ core in this pkg
+		 * online. So initialize per-pkg data structures and
+		 * then bring this core online.
+		 */
+		coretemp_device_add(cpu);
+		if (cpu_has(c, X86_FEATURE_PTS))
+			add_core(cpu, 1);
+	}
+	/*
+	 * Physical CPU device already exists.
+	 * So, just bring this core online.
+	 */
+	add_core(cpu, 0);
+}
+
+
+static void put_core_offline(unsigned int cpu)
+{
+	int indx;
+	struct platform_data *pdata;
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	struct platform_device *pdev = get_pdev(c->phys_proc_id);
+
+	/* If the physical CPU device does not exist, just return */
+	if (!pdev)
+		return;
+
+	pdata = platform_get_drvdata(pdev);
+
+	indx = get_core_indx(pdata, c->cpu_core_id);
+	if (indx < 0) {
+		dev_info(&pdev->dev, "Core %d does not exist\n",
+			c->cpu_core_id);
+		return;
+	}
+
+	if (pdata->core_data[indx]->cpu == cpu)
+		remove_core(pdata, &pdev->dev, indx);
+	else
+		dev_info(&pdev->dev, "A HT CPU (%u) is offlined\n", cpu);
+
+	/*
+	 * If all cores in this pkg are offline,
+	 * remove this device from the pdev_entry list and
+	 * do pkg level clean ups
+	 */
+	if (pdata->core_count == 0)
+		coretemp_device_remove(c->phys_proc_id);
+}
+
 static int __cpuinit coretemp_cpu_callback(struct notifier_block *nfb,
 				 unsigned long action, void *hcpu)
 {
@@ -533,10 +824,10 @@ static int __cpuinit coretemp_cpu_callback(struct notifier_block *nfb,
 	switch (action) {
 	case CPU_ONLINE:
 	case CPU_DOWN_FAILED:
-		coretemp_device_add(cpu);
+		get_core_online(cpu);
 		break;
 	case CPU_DOWN_PREPARE:
-		coretemp_device_remove(cpu);
+		put_core_offline(cpu);
 		break;
 	}
 	return NOTIFY_OK;
@@ -546,6 +837,7 @@ static struct notifier_block coretemp_cpu_notifier __refdata = {
 	.notifier_call = coretemp_cpu_callback,
 };
 
+
 static int __init coretemp_init(void)
 {
 	int i, err = -ENODEV;
@@ -559,7 +851,7 @@ static int __init coretemp_init(void)
 		goto exit;
 
 	for_each_online_cpu(i)
-		coretemp_device_add(i);
+		get_core_online(i);
 
 #ifndef CONFIG_HOTPLUG_CPU
 	if (list_empty(&pdev_list)) {
-- 
1.7.4


_______________________________________________
lm-sensors mailing list
lm-sensors@xxxxxxxxxxxxxx
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors


[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux