.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | | - * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h processor hardware monitoring |
---|
| 3 | + * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h/17h |
---|
| 4 | + * processor hardware monitoring |
---|
3 | 5 | * |
---|
4 | 6 | * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de> |
---|
| 7 | + * Copyright (c) 2020 Guenter Roeck <linux@roeck-us.net> |
---|
5 | 8 | * |
---|
6 | | - * |
---|
7 | | - * This driver is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License; either |
---|
9 | | - * version 2 of the License, or (at your option) any later version. |
---|
10 | | - * |
---|
11 | | - * This driver is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
---|
14 | | - * See the GNU General Public License for more details. |
---|
15 | | - * |
---|
16 | | - * You should have received a copy of the GNU General Public License |
---|
17 | | - * along with this driver; if not, see <http://www.gnu.org/licenses/>. |
---|
| 9 | + * Implementation notes: |
---|
| 10 | + * - CCD register address information as well as the calculation to |
---|
| 11 | + * convert raw register values is from https://github.com/ocerman/zenpower. |
---|
| 12 | + * The information is not confirmed from chip datasheets, but experiments |
---|
| 13 | + * suggest that it provides reasonable temperature values. |
---|
18 | 14 | */ |
---|
19 | 15 | |
---|
| 16 | +#include <linux/bitops.h> |
---|
20 | 17 | #include <linux/err.h> |
---|
21 | 18 | #include <linux/hwmon.h> |
---|
22 | | -#include <linux/hwmon-sysfs.h> |
---|
23 | 19 | #include <linux/init.h> |
---|
24 | 20 | #include <linux/module.h> |
---|
25 | 21 | #include <linux/pci.h> |
---|
.. | .. |
---|
43 | 39 | #endif |
---|
44 | 40 | |
---|
45 | 41 | /* CPUID function 0x80000001, ebx */ |
---|
46 | | -#define CPUID_PKGTYPE_MASK 0xf0000000 |
---|
| 42 | +#define CPUID_PKGTYPE_MASK GENMASK(31, 28) |
---|
47 | 43 | #define CPUID_PKGTYPE_F 0x00000000 |
---|
48 | 44 | #define CPUID_PKGTYPE_AM2R2_AM3 0x10000000 |
---|
49 | 45 | |
---|
50 | 46 | /* DRAM controller (PCI function 2) */ |
---|
51 | 47 | #define REG_DCT0_CONFIG_HIGH 0x094 |
---|
52 | | -#define DDR3_MODE 0x00000100 |
---|
| 48 | +#define DDR3_MODE BIT(8) |
---|
53 | 49 | |
---|
54 | 50 | /* miscellaneous (PCI function 3) */ |
---|
55 | 51 | #define REG_HARDWARE_THERMAL_CONTROL 0x64 |
---|
56 | | -#define HTC_ENABLE 0x00000001 |
---|
| 52 | +#define HTC_ENABLE BIT(0) |
---|
57 | 53 | |
---|
58 | 54 | #define REG_REPORTED_TEMPERATURE 0xa4 |
---|
59 | 55 | |
---|
60 | 56 | #define REG_NORTHBRIDGE_CAPABILITIES 0xe8 |
---|
61 | | -#define NB_CAP_HTC 0x00000400 |
---|
| 57 | +#define NB_CAP_HTC BIT(10) |
---|
62 | 58 | |
---|
63 | 59 | /* |
---|
64 | 60 | * For F15h M60h and M70h, REG_HARDWARE_THERMAL_CONTROL |
---|
.. | .. |
---|
69 | 65 | #define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64 |
---|
70 | 66 | #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4 |
---|
71 | 67 | |
---|
72 | | -/* F17h M01h Access througn SMN */ |
---|
73 | | -#define F17H_M01H_REPORTED_TEMP_CTRL_OFFSET 0x00059800 |
---|
| 68 | +/* Common for Zen CPU families (Family 17h and 18h) */ |
---|
| 69 | +#define ZEN_REPORTED_TEMP_CTRL_OFFSET 0x00059800 |
---|
| 70 | + |
---|
| 71 | +#define ZEN_CCD_TEMP(x) (0x00059954 + ((x) * 4)) |
---|
| 72 | +#define ZEN_CCD_TEMP_VALID BIT(11) |
---|
| 73 | +#define ZEN_CCD_TEMP_MASK GENMASK(10, 0) |
---|
| 74 | + |
---|
| 75 | +#define ZEN_CUR_TEMP_SHIFT 21 |
---|
| 76 | +#define ZEN_CUR_TEMP_RANGE_SEL_MASK BIT(19) |
---|
| 77 | +#define ZEN_CUR_TEMP_TJ_SEL_MASK GENMASK(17, 16) |
---|
| 78 | + |
---|
| 79 | +#define ZEN_SVI_BASE 0x0005A000 |
---|
| 80 | + |
---|
| 81 | +/* F17h thermal registers through SMN */ |
---|
| 82 | +#define F17H_M01H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0xc) |
---|
| 83 | +#define F17H_M01H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) |
---|
| 84 | +#define F17H_M31H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) |
---|
| 85 | +#define F17H_M31H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) |
---|
| 86 | + |
---|
| 87 | +#define F17H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ |
---|
| 88 | +#define F17H_M01H_CFACTOR_ISOC 250000 /* 0.25A / LSB */ |
---|
| 89 | +#define F17H_M31H_CFACTOR_ICORE 1000000 /* 1A / LSB */ |
---|
| 90 | +#define F17H_M31H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ |
---|
| 91 | + |
---|
| 92 | +/* F19h thermal registers through SMN */ |
---|
| 93 | +#define F19H_M01_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) |
---|
| 94 | +#define F19H_M01_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) |
---|
| 95 | + |
---|
| 96 | +#define F19H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ |
---|
| 97 | +#define F19H_M01H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ |
---|
74 | 98 | |
---|
75 | 99 | struct k10temp_data { |
---|
76 | 100 | struct pci_dev *pdev; |
---|
.. | .. |
---|
78 | 102 | void (*read_tempreg)(struct pci_dev *pdev, u32 *regval); |
---|
79 | 103 | int temp_offset; |
---|
80 | 104 | u32 temp_adjust_mask; |
---|
81 | | - bool show_tdie; |
---|
| 105 | + u32 show_temp; |
---|
| 106 | + bool is_zen; |
---|
82 | 107 | }; |
---|
| 108 | + |
---|
| 109 | +#define TCTL_BIT 0 |
---|
| 110 | +#define TDIE_BIT 1 |
---|
| 111 | +#define TCCD_BIT(x) ((x) + 2) |
---|
| 112 | + |
---|
| 113 | +#define HAVE_TEMP(d, channel) ((d)->show_temp & BIT(channel)) |
---|
| 114 | +#define HAVE_TDIE(d) HAVE_TEMP(d, TDIE_BIT) |
---|
83 | 115 | |
---|
84 | 116 | struct tctl_offset { |
---|
85 | 117 | u8 model; |
---|
.. | .. |
---|
129 | 161 | F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval); |
---|
130 | 162 | } |
---|
131 | 163 | |
---|
132 | | -static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval) |
---|
| 164 | +static void read_tempreg_nb_zen(struct pci_dev *pdev, u32 *regval) |
---|
133 | 165 | { |
---|
134 | 166 | amd_smn_read(amd_pci_dev_to_node_id(pdev), |
---|
135 | | - F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval); |
---|
| 167 | + ZEN_REPORTED_TEMP_CTRL_OFFSET, regval); |
---|
136 | 168 | } |
---|
137 | 169 | |
---|
138 | | -static unsigned int get_raw_temp(struct k10temp_data *data) |
---|
| 170 | +static long get_raw_temp(struct k10temp_data *data) |
---|
139 | 171 | { |
---|
140 | | - unsigned int temp; |
---|
141 | 172 | u32 regval; |
---|
| 173 | + long temp; |
---|
142 | 174 | |
---|
143 | 175 | data->read_tempreg(data->pdev, ®val); |
---|
144 | | - temp = (regval >> 21) * 125; |
---|
145 | | - if (regval & data->temp_adjust_mask) |
---|
| 176 | + temp = (regval >> ZEN_CUR_TEMP_SHIFT) * 125; |
---|
| 177 | + if ((regval & data->temp_adjust_mask) || |
---|
| 178 | + (regval & ZEN_CUR_TEMP_TJ_SEL_MASK) == ZEN_CUR_TEMP_TJ_SEL_MASK) |
---|
146 | 179 | temp -= 49000; |
---|
147 | 180 | return temp; |
---|
148 | 181 | } |
---|
149 | 182 | |
---|
150 | | -static ssize_t temp1_input_show(struct device *dev, |
---|
151 | | - struct device_attribute *attr, char *buf) |
---|
| 183 | +static const char *k10temp_temp_label[] = { |
---|
| 184 | + "Tctl", |
---|
| 185 | + "Tdie", |
---|
| 186 | + "Tccd1", |
---|
| 187 | + "Tccd2", |
---|
| 188 | + "Tccd3", |
---|
| 189 | + "Tccd4", |
---|
| 190 | + "Tccd5", |
---|
| 191 | + "Tccd6", |
---|
| 192 | + "Tccd7", |
---|
| 193 | + "Tccd8", |
---|
| 194 | +}; |
---|
| 195 | + |
---|
| 196 | +static int k10temp_read_labels(struct device *dev, |
---|
| 197 | + enum hwmon_sensor_types type, |
---|
| 198 | + u32 attr, int channel, const char **str) |
---|
| 199 | +{ |
---|
| 200 | + switch (type) { |
---|
| 201 | + case hwmon_temp: |
---|
| 202 | + *str = k10temp_temp_label[channel]; |
---|
| 203 | + break; |
---|
| 204 | + default: |
---|
| 205 | + return -EOPNOTSUPP; |
---|
| 206 | + } |
---|
| 207 | + return 0; |
---|
| 208 | +} |
---|
| 209 | + |
---|
| 210 | +static int k10temp_read_temp(struct device *dev, u32 attr, int channel, |
---|
| 211 | + long *val) |
---|
152 | 212 | { |
---|
153 | 213 | struct k10temp_data *data = dev_get_drvdata(dev); |
---|
154 | | - unsigned int temp = get_raw_temp(data); |
---|
155 | | - |
---|
156 | | - if (temp > data->temp_offset) |
---|
157 | | - temp -= data->temp_offset; |
---|
158 | | - else |
---|
159 | | - temp = 0; |
---|
160 | | - |
---|
161 | | - return sprintf(buf, "%u\n", temp); |
---|
162 | | -} |
---|
163 | | - |
---|
164 | | -static ssize_t temp2_input_show(struct device *dev, |
---|
165 | | - struct device_attribute *devattr, char *buf) |
---|
166 | | -{ |
---|
167 | | - struct k10temp_data *data = dev_get_drvdata(dev); |
---|
168 | | - unsigned int temp = get_raw_temp(data); |
---|
169 | | - |
---|
170 | | - return sprintf(buf, "%u\n", temp); |
---|
171 | | -} |
---|
172 | | - |
---|
173 | | -static ssize_t temp_label_show(struct device *dev, |
---|
174 | | - struct device_attribute *devattr, char *buf) |
---|
175 | | -{ |
---|
176 | | - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
---|
177 | | - |
---|
178 | | - return sprintf(buf, "%s\n", attr->index ? "Tctl" : "Tdie"); |
---|
179 | | -} |
---|
180 | | - |
---|
181 | | -static ssize_t temp1_max_show(struct device *dev, |
---|
182 | | - struct device_attribute *attr, char *buf) |
---|
183 | | -{ |
---|
184 | | - return sprintf(buf, "%d\n", 70 * 1000); |
---|
185 | | -} |
---|
186 | | - |
---|
187 | | -static ssize_t show_temp_crit(struct device *dev, |
---|
188 | | - struct device_attribute *devattr, char *buf) |
---|
189 | | -{ |
---|
190 | | - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
---|
191 | | - struct k10temp_data *data = dev_get_drvdata(dev); |
---|
192 | | - int show_hyst = attr->index; |
---|
193 | 214 | u32 regval; |
---|
194 | | - int value; |
---|
195 | 215 | |
---|
196 | | - data->read_htcreg(data->pdev, ®val); |
---|
197 | | - value = ((regval >> 16) & 0x7f) * 500 + 52000; |
---|
198 | | - if (show_hyst) |
---|
199 | | - value -= ((regval >> 24) & 0xf) * 500; |
---|
200 | | - return sprintf(buf, "%d\n", value); |
---|
| 216 | + switch (attr) { |
---|
| 217 | + case hwmon_temp_input: |
---|
| 218 | + switch (channel) { |
---|
| 219 | + case 0: /* Tctl */ |
---|
| 220 | + *val = get_raw_temp(data); |
---|
| 221 | + if (*val < 0) |
---|
| 222 | + *val = 0; |
---|
| 223 | + break; |
---|
| 224 | + case 1: /* Tdie */ |
---|
| 225 | + *val = get_raw_temp(data) - data->temp_offset; |
---|
| 226 | + if (*val < 0) |
---|
| 227 | + *val = 0; |
---|
| 228 | + break; |
---|
| 229 | + case 2 ... 9: /* Tccd{1-8} */ |
---|
| 230 | + amd_smn_read(amd_pci_dev_to_node_id(data->pdev), |
---|
| 231 | + ZEN_CCD_TEMP(channel - 2), ®val); |
---|
| 232 | + *val = (regval & ZEN_CCD_TEMP_MASK) * 125 - 49000; |
---|
| 233 | + break; |
---|
| 234 | + default: |
---|
| 235 | + return -EOPNOTSUPP; |
---|
| 236 | + } |
---|
| 237 | + break; |
---|
| 238 | + case hwmon_temp_max: |
---|
| 239 | + *val = 70 * 1000; |
---|
| 240 | + break; |
---|
| 241 | + case hwmon_temp_crit: |
---|
| 242 | + data->read_htcreg(data->pdev, ®val); |
---|
| 243 | + *val = ((regval >> 16) & 0x7f) * 500 + 52000; |
---|
| 244 | + break; |
---|
| 245 | + case hwmon_temp_crit_hyst: |
---|
| 246 | + data->read_htcreg(data->pdev, ®val); |
---|
| 247 | + *val = (((regval >> 16) & 0x7f) |
---|
| 248 | + - ((regval >> 24) & 0xf)) * 500 + 52000; |
---|
| 249 | + break; |
---|
| 250 | + default: |
---|
| 251 | + return -EOPNOTSUPP; |
---|
| 252 | + } |
---|
| 253 | + return 0; |
---|
201 | 254 | } |
---|
202 | 255 | |
---|
203 | | -static DEVICE_ATTR_RO(temp1_input); |
---|
204 | | -static DEVICE_ATTR_RO(temp1_max); |
---|
205 | | -static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); |
---|
206 | | -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1); |
---|
207 | | - |
---|
208 | | -static SENSOR_DEVICE_ATTR(temp1_label, 0444, temp_label_show, NULL, 0); |
---|
209 | | -static DEVICE_ATTR_RO(temp2_input); |
---|
210 | | -static SENSOR_DEVICE_ATTR(temp2_label, 0444, temp_label_show, NULL, 1); |
---|
211 | | - |
---|
212 | | -static umode_t k10temp_is_visible(struct kobject *kobj, |
---|
213 | | - struct attribute *attr, int index) |
---|
| 256 | +static int k10temp_read(struct device *dev, enum hwmon_sensor_types type, |
---|
| 257 | + u32 attr, int channel, long *val) |
---|
214 | 258 | { |
---|
215 | | - struct device *dev = container_of(kobj, struct device, kobj); |
---|
216 | | - struct k10temp_data *data = dev_get_drvdata(dev); |
---|
| 259 | + switch (type) { |
---|
| 260 | + case hwmon_temp: |
---|
| 261 | + return k10temp_read_temp(dev, attr, channel, val); |
---|
| 262 | + default: |
---|
| 263 | + return -EOPNOTSUPP; |
---|
| 264 | + } |
---|
| 265 | +} |
---|
| 266 | + |
---|
| 267 | +static umode_t k10temp_is_visible(const void *_data, |
---|
| 268 | + enum hwmon_sensor_types type, |
---|
| 269 | + u32 attr, int channel) |
---|
| 270 | +{ |
---|
| 271 | + const struct k10temp_data *data = _data; |
---|
217 | 272 | struct pci_dev *pdev = data->pdev; |
---|
218 | 273 | u32 reg; |
---|
219 | 274 | |
---|
220 | | - switch (index) { |
---|
221 | | - case 0 ... 1: /* temp1_input, temp1_max */ |
---|
| 275 | + switch (type) { |
---|
| 276 | + case hwmon_temp: |
---|
| 277 | + switch (attr) { |
---|
| 278 | + case hwmon_temp_input: |
---|
| 279 | + if (!HAVE_TEMP(data, channel)) |
---|
| 280 | + return 0; |
---|
| 281 | + break; |
---|
| 282 | + case hwmon_temp_max: |
---|
| 283 | + if (channel || data->is_zen) |
---|
| 284 | + return 0; |
---|
| 285 | + break; |
---|
| 286 | + case hwmon_temp_crit: |
---|
| 287 | + case hwmon_temp_crit_hyst: |
---|
| 288 | + if (channel || !data->read_htcreg) |
---|
| 289 | + return 0; |
---|
| 290 | + |
---|
| 291 | + pci_read_config_dword(pdev, |
---|
| 292 | + REG_NORTHBRIDGE_CAPABILITIES, |
---|
| 293 | + ®); |
---|
| 294 | + if (!(reg & NB_CAP_HTC)) |
---|
| 295 | + return 0; |
---|
| 296 | + |
---|
| 297 | + data->read_htcreg(data->pdev, ®); |
---|
| 298 | + if (!(reg & HTC_ENABLE)) |
---|
| 299 | + return 0; |
---|
| 300 | + break; |
---|
| 301 | + case hwmon_temp_label: |
---|
| 302 | + /* Show temperature labels only on Zen CPUs */ |
---|
| 303 | + if (!data->is_zen || !HAVE_TEMP(data, channel)) |
---|
| 304 | + return 0; |
---|
| 305 | + break; |
---|
| 306 | + default: |
---|
| 307 | + return 0; |
---|
| 308 | + } |
---|
| 309 | + break; |
---|
222 | 310 | default: |
---|
223 | | - break; |
---|
224 | | - case 2 ... 3: /* temp1_crit, temp1_crit_hyst */ |
---|
225 | | - if (!data->read_htcreg) |
---|
226 | | - return 0; |
---|
227 | | - |
---|
228 | | - pci_read_config_dword(pdev, REG_NORTHBRIDGE_CAPABILITIES, |
---|
229 | | - ®); |
---|
230 | | - if (!(reg & NB_CAP_HTC)) |
---|
231 | | - return 0; |
---|
232 | | - |
---|
233 | | - data->read_htcreg(data->pdev, ®); |
---|
234 | | - if (!(reg & HTC_ENABLE)) |
---|
235 | | - return 0; |
---|
236 | | - break; |
---|
237 | | - case 4 ... 6: /* temp1_label, temp2_input, temp2_label */ |
---|
238 | | - if (!data->show_tdie) |
---|
239 | | - return 0; |
---|
240 | | - break; |
---|
| 311 | + return 0; |
---|
241 | 312 | } |
---|
242 | | - return attr->mode; |
---|
| 313 | + return 0444; |
---|
243 | 314 | } |
---|
244 | | - |
---|
245 | | -static struct attribute *k10temp_attrs[] = { |
---|
246 | | - &dev_attr_temp1_input.attr, |
---|
247 | | - &dev_attr_temp1_max.attr, |
---|
248 | | - &sensor_dev_attr_temp1_crit.dev_attr.attr, |
---|
249 | | - &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, |
---|
250 | | - &sensor_dev_attr_temp1_label.dev_attr.attr, |
---|
251 | | - &dev_attr_temp2_input.attr, |
---|
252 | | - &sensor_dev_attr_temp2_label.dev_attr.attr, |
---|
253 | | - NULL |
---|
254 | | -}; |
---|
255 | | - |
---|
256 | | -static const struct attribute_group k10temp_group = { |
---|
257 | | - .attrs = k10temp_attrs, |
---|
258 | | - .is_visible = k10temp_is_visible, |
---|
259 | | -}; |
---|
260 | | -__ATTRIBUTE_GROUPS(k10temp); |
---|
261 | 315 | |
---|
262 | 316 | static bool has_erratum_319(struct pci_dev *pdev) |
---|
263 | 317 | { |
---|
.. | .. |
---|
293 | 347 | (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2); |
---|
294 | 348 | } |
---|
295 | 349 | |
---|
296 | | -static int k10temp_probe(struct pci_dev *pdev, |
---|
297 | | - const struct pci_device_id *id) |
---|
| 350 | +static const struct hwmon_channel_info *k10temp_info[] = { |
---|
| 351 | + HWMON_CHANNEL_INFO(temp, |
---|
| 352 | + HWMON_T_INPUT | HWMON_T_MAX | |
---|
| 353 | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | |
---|
| 354 | + HWMON_T_LABEL, |
---|
| 355 | + HWMON_T_INPUT | HWMON_T_LABEL, |
---|
| 356 | + HWMON_T_INPUT | HWMON_T_LABEL, |
---|
| 357 | + HWMON_T_INPUT | HWMON_T_LABEL, |
---|
| 358 | + HWMON_T_INPUT | HWMON_T_LABEL, |
---|
| 359 | + HWMON_T_INPUT | HWMON_T_LABEL, |
---|
| 360 | + HWMON_T_INPUT | HWMON_T_LABEL, |
---|
| 361 | + HWMON_T_INPUT | HWMON_T_LABEL, |
---|
| 362 | + HWMON_T_INPUT | HWMON_T_LABEL, |
---|
| 363 | + HWMON_T_INPUT | HWMON_T_LABEL), |
---|
| 364 | + HWMON_CHANNEL_INFO(in, |
---|
| 365 | + HWMON_I_INPUT | HWMON_I_LABEL, |
---|
| 366 | + HWMON_I_INPUT | HWMON_I_LABEL), |
---|
| 367 | + HWMON_CHANNEL_INFO(curr, |
---|
| 368 | + HWMON_C_INPUT | HWMON_C_LABEL, |
---|
| 369 | + HWMON_C_INPUT | HWMON_C_LABEL), |
---|
| 370 | + NULL |
---|
| 371 | +}; |
---|
| 372 | + |
---|
| 373 | +static const struct hwmon_ops k10temp_hwmon_ops = { |
---|
| 374 | + .is_visible = k10temp_is_visible, |
---|
| 375 | + .read = k10temp_read, |
---|
| 376 | + .read_string = k10temp_read_labels, |
---|
| 377 | +}; |
---|
| 378 | + |
---|
| 379 | +static const struct hwmon_chip_info k10temp_chip_info = { |
---|
| 380 | + .ops = &k10temp_hwmon_ops, |
---|
| 381 | + .info = k10temp_info, |
---|
| 382 | +}; |
---|
| 383 | + |
---|
| 384 | +static void k10temp_get_ccd_support(struct pci_dev *pdev, |
---|
| 385 | + struct k10temp_data *data, int limit) |
---|
| 386 | +{ |
---|
| 387 | + u32 regval; |
---|
| 388 | + int i; |
---|
| 389 | + |
---|
| 390 | + for (i = 0; i < limit; i++) { |
---|
| 391 | + amd_smn_read(amd_pci_dev_to_node_id(pdev), |
---|
| 392 | + ZEN_CCD_TEMP(i), ®val); |
---|
| 393 | + if (regval & ZEN_CCD_TEMP_VALID) |
---|
| 394 | + data->show_temp |= BIT(TCCD_BIT(i)); |
---|
| 395 | + } |
---|
| 396 | +} |
---|
| 397 | + |
---|
| 398 | +static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
---|
298 | 399 | { |
---|
299 | 400 | int unreliable = has_erratum_319(pdev); |
---|
300 | 401 | struct device *dev = &pdev->dev; |
---|
.. | .. |
---|
317 | 418 | return -ENOMEM; |
---|
318 | 419 | |
---|
319 | 420 | data->pdev = pdev; |
---|
| 421 | + data->show_temp |= BIT(TCTL_BIT); /* Always show Tctl */ |
---|
320 | 422 | |
---|
321 | 423 | if (boot_cpu_data.x86 == 0x15 && |
---|
322 | 424 | ((boot_cpu_data.x86_model & 0xf0) == 0x60 || |
---|
323 | 425 | (boot_cpu_data.x86_model & 0xf0) == 0x70)) { |
---|
324 | 426 | data->read_htcreg = read_htcreg_nb_f15; |
---|
325 | 427 | data->read_tempreg = read_tempreg_nb_f15; |
---|
326 | | - } else if (boot_cpu_data.x86 == 0x17) { |
---|
327 | | - data->temp_adjust_mask = 0x80000; |
---|
328 | | - data->read_tempreg = read_tempreg_nb_f17; |
---|
329 | | - data->show_tdie = true; |
---|
| 428 | + } else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) { |
---|
| 429 | + data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; |
---|
| 430 | + data->read_tempreg = read_tempreg_nb_zen; |
---|
| 431 | + data->show_temp |= BIT(TDIE_BIT); /* show Tdie */ |
---|
| 432 | + data->is_zen = true; |
---|
| 433 | + |
---|
| 434 | + switch (boot_cpu_data.x86_model) { |
---|
| 435 | + case 0x1: /* Zen */ |
---|
| 436 | + case 0x8: /* Zen+ */ |
---|
| 437 | + case 0x11: /* Zen APU */ |
---|
| 438 | + case 0x18: /* Zen+ APU */ |
---|
| 439 | + k10temp_get_ccd_support(pdev, data, 4); |
---|
| 440 | + break; |
---|
| 441 | + case 0x31: /* Zen2 Threadripper */ |
---|
| 442 | + case 0x71: /* Zen2 */ |
---|
| 443 | + k10temp_get_ccd_support(pdev, data, 8); |
---|
| 444 | + break; |
---|
| 445 | + } |
---|
| 446 | + } else if (boot_cpu_data.x86 == 0x19) { |
---|
| 447 | + data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; |
---|
| 448 | + data->read_tempreg = read_tempreg_nb_zen; |
---|
| 449 | + data->show_temp |= BIT(TDIE_BIT); |
---|
| 450 | + data->is_zen = true; |
---|
| 451 | + |
---|
| 452 | + switch (boot_cpu_data.x86_model) { |
---|
| 453 | + case 0x0 ... 0x1: /* Zen3 */ |
---|
| 454 | + k10temp_get_ccd_support(pdev, data, 8); |
---|
| 455 | + break; |
---|
| 456 | + } |
---|
330 | 457 | } else { |
---|
331 | 458 | data->read_htcreg = read_htcreg_pci; |
---|
332 | 459 | data->read_tempreg = read_tempreg_pci; |
---|
.. | .. |
---|
342 | 469 | } |
---|
343 | 470 | } |
---|
344 | 471 | |
---|
345 | | - hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", data, |
---|
346 | | - k10temp_groups); |
---|
| 472 | + hwmon_dev = devm_hwmon_device_register_with_info(dev, "k10temp", data, |
---|
| 473 | + &k10temp_chip_info, |
---|
| 474 | + NULL); |
---|
347 | 475 | return PTR_ERR_OR_ZERO(hwmon_dev); |
---|
348 | 476 | } |
---|
349 | 477 | |
---|
.. | .. |
---|
360 | 488 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) }, |
---|
361 | 489 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) }, |
---|
362 | 490 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) }, |
---|
| 491 | + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, |
---|
| 492 | + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) }, |
---|
| 493 | + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, |
---|
| 494 | + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) }, |
---|
| 495 | + { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, |
---|
363 | 496 | {} |
---|
364 | 497 | }; |
---|
365 | 498 | MODULE_DEVICE_TABLE(pci, k10temp_id_table); |
---|