diff options
Diffstat (limited to 'drivers/hwmon/coretemp.c')
| -rw-r--r-- | drivers/hwmon/coretemp.c | 141 | 
1 files changed, 64 insertions, 77 deletions
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 78be6617684..d76f0b70c6e 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -36,6 +36,7 @@  #include <linux/cpu.h>  #include <linux/smp.h>  #include <linux/moduleparam.h> +#include <linux/pci.h>  #include <asm/msr.h>  #include <asm/processor.h>  #include <asm/cpu_device_id.h> @@ -52,7 +53,7 @@ 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	17	/* String Length of attrs */ +#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) @@ -93,6 +94,8 @@ struct temp_data {  	bool valid;  	struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];  	char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH]; +	struct attribute *attrs[TOTAL_ATTRS + 1]; +	struct attribute_group attr_group;  	struct mutex update_lock;  }; @@ -113,12 +116,6 @@ struct pdev_entry {  static LIST_HEAD(pdev_list);  static DEFINE_MUTEX(pdev_list_mutex); -static ssize_t show_name(struct device *dev, -			struct device_attribute *devattr, char *buf) -{ -	return sprintf(buf, "%s\n", DRVNAME); -} -  static ssize_t show_label(struct device *dev,  				struct device_attribute *devattr, char *buf)  { @@ -176,20 +173,33 @@ static ssize_t show_temp(struct device *dev,  	/* Check whether the time interval has elapsed */  	if (!tdata->valid || time_after(jiffies, tdata->last_updated + HZ)) {  		rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); -		tdata->valid = 0; -		/* Check whether the data is valid */ -		if (eax & 0x80000000) { -			tdata->temp = tdata->tjmax - -					((eax >> 16) & 0x7f) * 1000; -			tdata->valid = 1; -		} +		/* +		 * Ignore the valid bit. In all observed cases the register +		 * value is either low or zero if the valid bit is 0. +		 * Return it instead of reporting an error which doesn't +		 * really help at all. +		 */ +		tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; +		tdata->valid = 1;  		tdata->last_updated = jiffies;  	}  	mutex_unlock(&tdata->update_lock); -	return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN; +	return sprintf(buf, "%d\n", tdata->temp);  } +struct tjmax_pci { +	unsigned int device; +	int tjmax; +}; + +static const struct tjmax_pci tjmax_pci_table[] = { +	{ 0x0708, 110000 },	/* CE41x0 (Sodaville ) */ +	{ 0x0c72, 102000 },	/* Atom S1240 (Centerton) */ +	{ 0x0c73, 95000 },	/* Atom S1220 (Centerton) */ +	{ 0x0c75, 95000 },	/* Atom S1260 (Centerton) */ +}; +  struct tjmax {  	char const *id;  	int tjmax; @@ -198,9 +208,6 @@ struct tjmax {  static const struct tjmax tjmax_table[] = {  	{ "CPU  230", 100000 },		/* Model 0x1c, stepping 2	*/  	{ "CPU  330", 125000 },		/* Model 0x1c, stepping 2	*/ -	{ "CPU CE4110", 110000 },	/* Model 0x1c, stepping 10 Sodaville */ -	{ "CPU CE4150", 110000 },	/* Model 0x1c, stepping 10	*/ -	{ "CPU CE4170", 110000 },	/* Model 0x1c, stepping 10	*/  };  struct tjmax_model { @@ -222,8 +229,11 @@ static const struct tjmax_model tjmax_model_table[] = {  				 * is undetectable by software  				 */  	{ 0x27, ANY, 90000 },	/* Atom Medfield (Z2460) */ -	{ 0x35, ANY, 90000 },	/* Atom Clover Trail/Cloverview (Z2760) */ -	{ 0x36, ANY, 100000 },	/* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */ +	{ 0x35, ANY, 90000 },	/* Atom Clover Trail/Cloverview (Z27x0) */ +	{ 0x36, ANY, 100000 },	/* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) +				 * Also matches S12x0 (stepping 9), covered by +				 * PCI table +				 */  };  static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) @@ -236,8 +246,20 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)  	int err;  	u32 eax, edx;  	int i; +	struct pci_dev *host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); + +	/* +	 * Explicit tjmax table entries override heuristics. +	 * First try PCI host bridge IDs, followed by model ID strings +	 * and model/stepping information. +	 */ +	if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL) { +		for (i = 0; i < ARRAY_SIZE(tjmax_pci_table); i++) { +			if (host_bridge->device == tjmax_pci_table[i].device) +				return tjmax_pci_table[i].tjmax; +		} +	} -	/* explicit tjmax table entries override heuristics */  	for (i = 0; i < ARRAY_SIZE(tjmax_table); i++) {  		if (strstr(c->x86_model_id, tjmax_table[i].id))  			return tjmax_table[i].tjmax; @@ -367,20 +389,10 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)  	return adjust_tjmax(c, id, dev);  } -static int create_name_attr(struct platform_data *pdata, -				      struct device *dev) -{ -	sysfs_attr_init(&pdata->name_attr.attr); -	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); -} -  static int create_core_attrs(struct temp_data *tdata, struct device *dev,  			     int attr_no)  { -	int err, i; +	int i;  	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, @@ -398,16 +410,10 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,  		tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;  		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); -		if (err) -			goto exit_free; +		tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;  	} -	return 0; - -exit_free: -	while (--i >= 0) -		device_remove_file(dev, &tdata->sd_attrs[i].dev_attr); -	return err; +	tdata->attr_group.attrs = tdata->attrs; +	return sysfs_create_group(&dev->kobj, &tdata->attr_group);  } @@ -522,7 +528,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,  	pdata->core_data[attr_no] = tdata;  	/* Create sysfs interfaces */ -	err = create_core_attrs(tdata, &pdev->dev, attr_no); +	err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);  	if (err)  		goto exit_free; @@ -547,14 +553,12 @@ static void coretemp_add_core(unsigned int cpu, int pkg_flag)  }  static void coretemp_remove_core(struct platform_data *pdata, -				struct device *dev, int indx) +				 int indx)  { -	int i;  	struct temp_data *tdata = pdata->core_data[indx];  	/* Remove the sysfs attributes */ -	for (i = 0; i < tdata->attr_size; i++) -		device_remove_file(dev, &tdata->sd_attrs[i].dev_attr); +	sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);  	kfree(pdata->core_data[indx]);  	pdata->core_data[indx] = NULL; @@ -562,34 +566,20 @@ static void coretemp_remove_core(struct platform_data *pdata,  static int coretemp_probe(struct platform_device *pdev)  { +	struct device *dev = &pdev->dev;  	struct platform_data *pdata; -	int err;  	/* Initialize the per-package data structures */ -	pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL); +	pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);  	if (!pdata)  		return -ENOMEM; -	err = create_name_attr(pdata, &pdev->dev); -	if (err) -		goto exit_free; -  	pdata->phys_proc_id = pdev->id;  	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_name: -	device_remove_file(&pdev->dev, &pdata->name_attr); -exit_free: -	kfree(pdata); -	return err; +	pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, +								  pdata, NULL); +	return PTR_ERR_OR_ZERO(pdata->hwmon_dev);  }  static int coretemp_remove(struct platform_device *pdev) @@ -599,11 +589,8 @@ static int coretemp_remove(struct platform_device *pdev)  	for (i = MAX_CORE_DATA - 1; i >= 0; --i)  		if (pdata->core_data[i]) -			coretemp_remove_core(pdata, &pdev->dev, i); +			coretemp_remove_core(pdata, i); -	device_remove_file(&pdev->dev, &pdata->name_attr); -	hwmon_device_unregister(pdata->hwmon_dev); -	kfree(pdata);  	return 0;  } @@ -751,7 +738,7 @@ static void put_core_offline(unsigned int cpu)  		return;  	if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu) -		coretemp_remove_core(pdata, &pdev->dev, indx); +		coretemp_remove_core(pdata, indx);  	/*  	 * If a HT sibling of a core is taken offline, but another HT sibling @@ -823,20 +810,20 @@ static int __init coretemp_init(void)  	if (err)  		goto exit; -	get_online_cpus(); +	cpu_notifier_register_begin();  	for_each_online_cpu(i)  		get_core_online(i);  #ifndef CONFIG_HOTPLUG_CPU  	if (list_empty(&pdev_list)) { -		put_online_cpus(); +		cpu_notifier_register_done();  		err = -ENODEV;  		goto exit_driver_unreg;  	}  #endif -	register_hotcpu_notifier(&coretemp_cpu_notifier); -	put_online_cpus(); +	__register_hotcpu_notifier(&coretemp_cpu_notifier); +	cpu_notifier_register_done();  	return 0;  #ifndef CONFIG_HOTPLUG_CPU @@ -851,8 +838,8 @@ static void __exit coretemp_exit(void)  {  	struct pdev_entry *p, *n; -	get_online_cpus(); -	unregister_hotcpu_notifier(&coretemp_cpu_notifier); +	cpu_notifier_register_begin(); +	__unregister_hotcpu_notifier(&coretemp_cpu_notifier);  	mutex_lock(&pdev_list_mutex);  	list_for_each_entry_safe(p, n, &pdev_list, list) {  		platform_device_unregister(p->pdev); @@ -860,7 +847,7 @@ static void __exit coretemp_exit(void)  		kfree(p);  	}  	mutex_unlock(&pdev_list_mutex); -	put_online_cpus(); +	cpu_notifier_register_done();  	platform_driver_unregister(&coretemp_driver);  }  | 
