aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/k8temp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/k8temp.c')
-rw-r--r--drivers/hwmon/k8temp.c55
1 files changed, 46 insertions, 9 deletions
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index bd2bde0ef95e..1fe995111841 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -31,6 +31,7 @@
31#include <linux/hwmon-sysfs.h> 31#include <linux/hwmon-sysfs.h>
32#include <linux/err.h> 32#include <linux/err.h>
33#include <linux/mutex.h> 33#include <linux/mutex.h>
34#include <asm/processor.h>
34 35
35#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000) 36#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000)
36#define REG_TEMP 0xe4 37#define REG_TEMP 0xe4
@@ -47,6 +48,8 @@ struct k8temp_data {
47 /* registers values */ 48 /* registers values */
48 u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */ 49 u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */
49 u32 temp[2][2]; /* core, place */ 50 u32 temp[2][2]; /* core, place */
51 u8 swap_core_select; /* meaning of SEL_CORE is inverted */
52 u32 temp_offset;
50}; 53};
51 54
52static struct k8temp_data *k8temp_update_device(struct device *dev) 55static struct k8temp_data *k8temp_update_device(struct device *dev)
@@ -114,10 +117,15 @@ static ssize_t show_temp(struct device *dev,
114 to_sensor_dev_attr_2(devattr); 117 to_sensor_dev_attr_2(devattr);
115 int core = attr->nr; 118 int core = attr->nr;
116 int place = attr->index; 119 int place = attr->index;
120 int temp;
117 struct k8temp_data *data = k8temp_update_device(dev); 121 struct k8temp_data *data = k8temp_update_device(dev);
118 122
119 return sprintf(buf, "%d\n", 123 if (data->swap_core_select)
120 TEMP_FROM_REG(data->temp[core][place])); 124 core = core ? 0 : 1;
125
126 temp = TEMP_FROM_REG(data->temp[core][place]) + data->temp_offset;
127
128 return sprintf(buf, "%d\n", temp);
121} 129}
122 130
123/* core, place */ 131/* core, place */
@@ -141,20 +149,49 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
141 int err; 149 int err;
142 u8 scfg; 150 u8 scfg;
143 u32 temp; 151 u32 temp;
152 u8 model, stepping;
144 struct k8temp_data *data; 153 struct k8temp_data *data;
145 u32 cpuid = cpuid_eax(1);
146
147 /* this feature should be available since SH-C0 core */
148 if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) {
149 err = -ENODEV;
150 goto exit;
151 }
152 154
153 if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) { 155 if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) {
154 err = -ENOMEM; 156 err = -ENOMEM;
155 goto exit; 157 goto exit;
156 } 158 }
157 159
160 model = boot_cpu_data.x86_model;
161 stepping = boot_cpu_data.x86_mask;
162
163 switch (boot_cpu_data.x86) {
164 case 0xf:
165 /* feature available since SH-C0, exclude older revisions */
166 if (((model == 4) && (stepping == 0)) ||
167 ((model == 5) && (stepping <= 1))) {
168 err = -ENODEV;
169 goto exit_free;
170 }
171
172 /*
173 * AMD NPT family 0fh, i.e. RevF and RevG:
174 * meaning of SEL_CORE bit is inverted
175 */
176 if (model >= 0x40) {
177 data->swap_core_select = 1;
178 dev_warn(&pdev->dev, "Temperature readouts might be "
179 "wrong - check erratum #141\n");
180 }
181
182 if ((model >= 0x69) &&
183 !(model == 0xc1 || model == 0x6c || model == 0x7c)) {
184 /*
185 * RevG desktop CPUs (i.e. no socket S1G1 parts)
186 * need additional offset, otherwise reported
187 * temperature is below ambient temperature
188 */
189 data->temp_offset = 21000;
190 }
191
192 break;
193 }
194
158 pci_read_config_byte(pdev, REG_TEMP, &scfg); 195 pci_read_config_byte(pdev, REG_TEMP, &scfg);
159 scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ 196 scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
160 pci_write_config_byte(pdev, REG_TEMP, scfg); 197 pci_write_config_byte(pdev, REG_TEMP, scfg);