0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0012
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/slab.h>
0016 #include <linux/hwmon.h>
0017 #include <linux/hwmon-vid.h>
0018 #include <linux/sysfs.h>
0019 #include <linux/hwmon-sysfs.h>
0020 #include <linux/err.h>
0021 #include <linux/mutex.h>
0022 #include <linux/list.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/cpu.h>
0025 #include <asm/msr.h>
0026 #include <asm/processor.h>
0027 #include <asm/cpu_device_id.h>
0028
0029 #define DRVNAME "via_cputemp"
0030
0031 enum { SHOW_TEMP, SHOW_LABEL, SHOW_NAME };
0032
0033
0034
0035
0036
0037 struct via_cputemp_data {
0038 struct device *hwmon_dev;
0039 const char *name;
0040 u8 vrm;
0041 u32 id;
0042 u32 msr_temp;
0043 u32 msr_vid;
0044 };
0045
0046
0047
0048
0049
0050 static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
0051 char *buf)
0052 {
0053 int ret;
0054 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
0055 struct via_cputemp_data *data = dev_get_drvdata(dev);
0056
0057 if (attr->index == SHOW_NAME)
0058 ret = sprintf(buf, "%s\n", data->name);
0059 else
0060 ret = sprintf(buf, "Core %d\n", data->id);
0061 return ret;
0062 }
0063
0064 static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
0065 char *buf)
0066 {
0067 struct via_cputemp_data *data = dev_get_drvdata(dev);
0068 u32 eax, edx;
0069 int err;
0070
0071 err = rdmsr_safe_on_cpu(data->id, data->msr_temp, &eax, &edx);
0072 if (err)
0073 return -EAGAIN;
0074
0075 return sprintf(buf, "%lu\n", ((unsigned long)eax & 0xffffff) * 1000);
0076 }
0077
0078 static ssize_t cpu0_vid_show(struct device *dev,
0079 struct device_attribute *devattr, char *buf)
0080 {
0081 struct via_cputemp_data *data = dev_get_drvdata(dev);
0082 u32 eax, edx;
0083 int err;
0084
0085 err = rdmsr_safe_on_cpu(data->id, data->msr_vid, &eax, &edx);
0086 if (err)
0087 return -EAGAIN;
0088
0089 return sprintf(buf, "%d\n", vid_from_reg(~edx & 0x7f, data->vrm));
0090 }
0091
0092 static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, SHOW_TEMP);
0093 static SENSOR_DEVICE_ATTR_RO(temp1_label, name, SHOW_LABEL);
0094 static SENSOR_DEVICE_ATTR_RO(name, name, SHOW_NAME);
0095
0096 static struct attribute *via_cputemp_attributes[] = {
0097 &sensor_dev_attr_name.dev_attr.attr,
0098 &sensor_dev_attr_temp1_label.dev_attr.attr,
0099 &sensor_dev_attr_temp1_input.dev_attr.attr,
0100 NULL
0101 };
0102
0103 static const struct attribute_group via_cputemp_group = {
0104 .attrs = via_cputemp_attributes,
0105 };
0106
0107
0108 static DEVICE_ATTR_RO(cpu0_vid);
0109
0110 static int via_cputemp_probe(struct platform_device *pdev)
0111 {
0112 struct via_cputemp_data *data;
0113 struct cpuinfo_x86 *c = &cpu_data(pdev->id);
0114 int err;
0115 u32 eax, edx;
0116
0117 data = devm_kzalloc(&pdev->dev, sizeof(struct via_cputemp_data),
0118 GFP_KERNEL);
0119 if (!data)
0120 return -ENOMEM;
0121
0122 data->id = pdev->id;
0123 data->name = "via_cputemp";
0124
0125 if (c->x86 == 7) {
0126 data->msr_temp = 0x1423;
0127 } else {
0128 switch (c->x86_model) {
0129 case 0xA:
0130
0131 case 0xD:
0132
0133 data->msr_temp = 0x1169;
0134 data->msr_vid = 0x198;
0135 break;
0136 case 0xF:
0137
0138 data->msr_temp = 0x1423;
0139 break;
0140 default:
0141 return -ENODEV;
0142 }
0143 }
0144
0145
0146 err = rdmsr_safe_on_cpu(data->id, data->msr_temp, &eax, &edx);
0147 if (err) {
0148 dev_err(&pdev->dev,
0149 "Unable to access TEMPERATURE MSR, giving up\n");
0150 return err;
0151 }
0152
0153 platform_set_drvdata(pdev, data);
0154
0155 err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group);
0156 if (err)
0157 return err;
0158
0159 if (data->msr_vid)
0160 data->vrm = vid_which_vrm();
0161
0162 if (data->vrm) {
0163 err = device_create_file(&pdev->dev, &dev_attr_cpu0_vid);
0164 if (err)
0165 goto exit_remove;
0166 }
0167
0168 data->hwmon_dev = hwmon_device_register(&pdev->dev);
0169 if (IS_ERR(data->hwmon_dev)) {
0170 err = PTR_ERR(data->hwmon_dev);
0171 dev_err(&pdev->dev, "Class registration failed (%d)\n",
0172 err);
0173 goto exit_remove;
0174 }
0175
0176 return 0;
0177
0178 exit_remove:
0179 if (data->vrm)
0180 device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
0181 sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
0182 return err;
0183 }
0184
0185 static int via_cputemp_remove(struct platform_device *pdev)
0186 {
0187 struct via_cputemp_data *data = platform_get_drvdata(pdev);
0188
0189 hwmon_device_unregister(data->hwmon_dev);
0190 if (data->vrm)
0191 device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
0192 sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
0193 return 0;
0194 }
0195
0196 static struct platform_driver via_cputemp_driver = {
0197 .driver = {
0198 .name = DRVNAME,
0199 },
0200 .probe = via_cputemp_probe,
0201 .remove = via_cputemp_remove,
0202 };
0203
0204 struct pdev_entry {
0205 struct list_head list;
0206 struct platform_device *pdev;
0207 unsigned int cpu;
0208 };
0209
0210 static LIST_HEAD(pdev_list);
0211 static DEFINE_MUTEX(pdev_list_mutex);
0212
0213 static int via_cputemp_online(unsigned int cpu)
0214 {
0215 int err;
0216 struct platform_device *pdev;
0217 struct pdev_entry *pdev_entry;
0218
0219 pdev = platform_device_alloc(DRVNAME, cpu);
0220 if (!pdev) {
0221 err = -ENOMEM;
0222 pr_err("Device allocation failed\n");
0223 goto exit;
0224 }
0225
0226 pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
0227 if (!pdev_entry) {
0228 err = -ENOMEM;
0229 goto exit_device_put;
0230 }
0231
0232 err = platform_device_add(pdev);
0233 if (err) {
0234 pr_err("Device addition failed (%d)\n", err);
0235 goto exit_device_free;
0236 }
0237
0238 pdev_entry->pdev = pdev;
0239 pdev_entry->cpu = cpu;
0240 mutex_lock(&pdev_list_mutex);
0241 list_add_tail(&pdev_entry->list, &pdev_list);
0242 mutex_unlock(&pdev_list_mutex);
0243
0244 return 0;
0245
0246 exit_device_free:
0247 kfree(pdev_entry);
0248 exit_device_put:
0249 platform_device_put(pdev);
0250 exit:
0251 return err;
0252 }
0253
0254 static int via_cputemp_down_prep(unsigned int cpu)
0255 {
0256 struct pdev_entry *p;
0257
0258 mutex_lock(&pdev_list_mutex);
0259 list_for_each_entry(p, &pdev_list, list) {
0260 if (p->cpu == cpu) {
0261 platform_device_unregister(p->pdev);
0262 list_del(&p->list);
0263 mutex_unlock(&pdev_list_mutex);
0264 kfree(p);
0265 return 0;
0266 }
0267 }
0268 mutex_unlock(&pdev_list_mutex);
0269 return 0;
0270 }
0271
0272 static const struct x86_cpu_id __initconst cputemp_ids[] = {
0273 X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 6, X86_CENTAUR_FAM6_C7_A, NULL),
0274 X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 6, X86_CENTAUR_FAM6_C7_D, NULL),
0275 X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 6, X86_CENTAUR_FAM6_NANO, NULL),
0276 X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, X86_MODEL_ANY, NULL),
0277 {}
0278 };
0279 MODULE_DEVICE_TABLE(x86cpu, cputemp_ids);
0280
0281 static enum cpuhp_state via_temp_online;
0282
0283 static int __init via_cputemp_init(void)
0284 {
0285 int err;
0286
0287 if (!x86_match_cpu(cputemp_ids))
0288 return -ENODEV;
0289
0290 err = platform_driver_register(&via_cputemp_driver);
0291 if (err)
0292 goto exit;
0293
0294 err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/via:online",
0295 via_cputemp_online, via_cputemp_down_prep);
0296 if (err < 0)
0297 goto exit_driver_unreg;
0298 via_temp_online = err;
0299
0300 #ifndef CONFIG_HOTPLUG_CPU
0301 if (list_empty(&pdev_list)) {
0302 err = -ENODEV;
0303 goto exit_hp_unreg;
0304 }
0305 #endif
0306 return 0;
0307
0308 #ifndef CONFIG_HOTPLUG_CPU
0309 exit_hp_unreg:
0310 cpuhp_remove_state_nocalls(via_temp_online);
0311 #endif
0312 exit_driver_unreg:
0313 platform_driver_unregister(&via_cputemp_driver);
0314 exit:
0315 return err;
0316 }
0317
0318 static void __exit via_cputemp_exit(void)
0319 {
0320 cpuhp_remove_state(via_temp_online);
0321 platform_driver_unregister(&via_cputemp_driver);
0322 }
0323
0324 MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
0325 MODULE_DESCRIPTION("VIA CPU temperature monitor");
0326 MODULE_LICENSE("GPL");
0327
0328 module_init(via_cputemp_init)
0329 module_exit(via_cputemp_exit)