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); } |
