Rev 9079 | Rev 9144 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
9079 | turbocat | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
||
3 | * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h/17h |
||
4 | * processor hardware monitoring |
||
5 | * |
||
6 | * Copyright (c) 2009 Clemens Ladisch |
||
7 | * Copyright (c) 2020 Guenter Roeck |
||
8 | * |
||
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. |
||
14 | */ |
||
15 | |||
9100 | turbocat | 16 | /* Ported for Kolibri OS by turbocat (Maxim Logaeav). 2021 */ |
17 | /* Thanks: dunkaist, punk_joker, doczom. */ |
||
18 | |||
9079 | turbocat | 19 | #include |
20 | #include |
||
21 | #include |
||
22 | #include |
||
23 | #include |
||
24 | #include |
||
25 | #include |
||
26 | #include |
||
27 | #include |
||
28 | #include |
||
29 | |||
30 | struct cpuinfo_x86 boot_cpu_data; |
||
31 | bool force; |
||
32 | |||
33 | /* CPUID function 0x80000001, ebx */ |
||
34 | #define CPUID_PKGTYPE_MASK GENMASK(31, 28) |
||
35 | #define CPUID_PKGTYPE_F 0x00000000 |
||
36 | #define CPUID_PKGTYPE_AM2R2_AM3 0x10000000 |
||
37 | |||
38 | /* DRAM controller (PCI function 2) */ |
||
39 | #define REG_DCT0_CONFIG_HIGH 0x094 |
||
40 | #define DDR3_MODE BIT(8) |
||
41 | |||
42 | /* miscellaneous (PCI function 3) */ |
||
43 | #define REG_HARDWARE_THERMAL_CONTROL 0x64 |
||
44 | #define HTC_ENABLE BIT(0) |
||
45 | |||
46 | #define REG_REPORTED_TEMPERATURE 0xa4 |
||
47 | |||
48 | #define REG_NORTHBRIDGE_CAPABILITIES 0xe8 |
||
49 | #define NB_CAP_HTC BIT(10) |
||
50 | |||
51 | /* |
||
52 | * For F15h M60h and M70h, REG_HARDWARE_THERMAL_CONTROL |
||
53 | * and REG_REPORTED_TEMPERATURE have been moved to |
||
54 | * D0F0xBC_xD820_0C64 [Hardware Temperature Control] |
||
55 | * D0F0xBC_xD820_0CA4 [Reported Temperature Control] |
||
56 | */ |
||
57 | #define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64 |
||
58 | #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4 |
||
59 | |||
60 | /* Common for Zen CPU families (Family 17h and 18h) */ |
||
61 | #define ZEN_REPORTED_TEMP_CTRL_OFFSET 0x00059800 |
||
62 | |||
63 | #define ZEN_CCD_TEMP(x) (0x00059954 + ((x) * 4)) |
||
64 | #define ZEN_CCD_TEMP_VALID BIT(11) |
||
65 | #define ZEN_CCD_TEMP_MASK GENMASK(10, 0) |
||
66 | |||
67 | #define ZEN_CUR_TEMP_SHIFT 21 |
||
68 | #define ZEN_CUR_TEMP_RANGE_SEL_MASK BIT(19) |
||
69 | |||
70 | #define ZEN_SVI_BASE 0x0005A000 |
||
71 | |||
72 | /* F17h thermal registers through SMN */ |
||
73 | #define F17H_M01H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0xc) |
||
74 | #define F17H_M01H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) |
||
75 | #define F17H_M31H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) |
||
76 | #define F17H_M31H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) |
||
77 | |||
78 | #define F17H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ |
||
79 | #define F17H_M01H_CFACTOR_ISOC 250000 /* 0.25A / LSB */ |
||
80 | #define F17H_M31H_CFACTOR_ICORE 1000000 /* 1A / LSB */ |
||
81 | #define F17H_M31H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ |
||
82 | |||
83 | /* F19h thermal registers through SMN */ |
||
84 | #define F19H_M01_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) |
||
85 | #define F19H_M01_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) |
||
86 | |||
87 | #define F19H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ |
||
88 | #define F19H_M01H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ |
||
89 | |||
90 | /* Provide lock for writing to NB_SMU_IND_ADDR */ |
||
91 | DEFINE_MUTEX(nb_smu_ind_mutex); |
||
92 | DEFINE_MUTEX(smn_mutex); |
||
93 | |||
94 | struct k10temp_data { |
||
95 | struct pci_dev *pdev; |
||
96 | void (*read_htcreg)(struct pci_dev *pdev, u32 *regval); |
||
97 | void (*read_tempreg)(struct pci_dev *pdev, u32 *regval); |
||
98 | int temp_offset; |
||
99 | u32 temp_adjust_mask; |
||
100 | u32 show_temp; |
||
101 | bool is_zen; |
||
102 | }; |
||
103 | |||
104 | #define TCTL_BIT 0 |
||
105 | #define TDIE_BIT 1 |
||
106 | #define TCCD_BIT(x) ((x) + 2) |
||
107 | |||
108 | #define HAVE_TEMP(d, channel) ((d)->show_temp & BIT(channel)) |
||
109 | #define HAVE_TDIE(d) HAVE_TEMP(d, TDIE_BIT) |
||
110 | |||
111 | struct tctl_offset { |
||
112 | u8 model; |
||
113 | char const *id; |
||
114 | int offset; |
||
115 | }; |
||
116 | |||
117 | const struct tctl_offset tctl_offset_table[] = { |
||
118 | { 0x17, "AMD Ryzen 5 1600X", 20000 }, |
||
119 | { 0x17, "AMD Ryzen 7 1700X", 20000 }, |
||
120 | { 0x17, "AMD Ryzen 7 1800X", 20000 }, |
||
121 | { 0x17, "AMD Ryzen 7 2700X", 10000 }, |
||
122 | { 0x17, "AMD Ryzen Threadripper 19", 27000 }, /* 19{00,20,50}X */ |
||
123 | { 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */ |
||
124 | }; |
||
125 | |||
126 | void read_htcreg_pci(struct pci_dev *pdev, u32 *regval) |
||
127 | { |
||
128 | pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL, regval); |
||
129 | } |
||
130 | |||
131 | void read_tempreg_pci(struct pci_dev *pdev, u32 *regval) |
||
132 | { |
||
133 | pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, regval); |
||
134 | } |
||
135 | |||
136 | void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn, |
||
137 | unsigned int base, int offset, u32 *val) |
||
138 | { |
||
139 | mutex_lock(&nb_smu_ind_mutex); |
||
140 | pci_bus_write_config_dword(pdev->bus, devfn, |
||
141 | base, offset); |
||
142 | pci_bus_read_config_dword(pdev->bus, devfn, |
||
143 | base + 4, val); |
||
144 | mutex_unlock(&nb_smu_ind_mutex); |
||
145 | } |
||
146 | |||
147 | void read_htcreg_nb_f15(struct pci_dev *pdev, u32 *regval) |
||
148 | { |
||
149 | amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8, |
||
150 | F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET, regval); |
||
151 | } |
||
152 | |||
153 | void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval) |
||
154 | { |
||
155 | amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8, |
||
156 | F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval); |
||
157 | } |
||
158 | |||
159 | void read_tempreg_nb_zen(struct pci_dev *pdev, u32 *regval) |
||
160 | { |
||
161 | amd_smn_read(amd_pci_dev_to_node_id(pdev), |
||
162 | ZEN_REPORTED_TEMP_CTRL_OFFSET, regval); |
||
163 | } |
||
164 | |||
165 | long get_raw_temp(struct k10temp_data *data) |
||
166 | { |
||
167 | u32 regval; |
||
168 | long temp; |
||
169 | //printk("b30\n"); |
||
170 | data->read_tempreg(data->pdev, ®val); |
||
171 | temp = (regval >> ZEN_CUR_TEMP_SHIFT) * 125; |
||
172 | if (regval & data->temp_adjust_mask) |
||
173 | temp -= 49000; |
||
174 | return temp; |
||
175 | } |
||
9100 | turbocat | 176 | #if 0 |
9079 | turbocat | 177 | const char *k10temp_temp_label[] = { |
178 | "Tctl", |
||
179 | "Tdie", |
||
180 | "Tccd1", |
||
181 | "Tccd2", |
||
182 | "Tccd3", |
||
183 | "Tccd4", |
||
184 | "Tccd5", |
||
185 | "Tccd6", |
||
186 | "Tccd7", |
||
187 | "Tccd8", |
||
188 | }; |
||
189 | |||
190 | int k10temp_read_labels(struct device *dev, |
||
191 | enum hwmon_sensor_types type, |
||
192 | u32 attr, int channel, const char **str) |
||
193 | { |
||
194 | switch (type) { |
||
195 | case hwmon_temp: |
||
196 | *str = k10temp_temp_label[channel]; |
||
197 | break; |
||
198 | default: |
||
199 | return -EOPNOTSUPP; |
||
200 | } |
||
201 | return 0; |
||
202 | } |
||
9100 | turbocat | 203 | #endif |
9079 | turbocat | 204 | |
205 | int k10temp_read_temp(struct device *dev, u32 attr, int channel, |
||
206 | long *val) |
||
207 | { |
||
208 | struct k10temp_data *data = dev_get_drvdata(dev); |
||
209 | u32 regval; |
||
210 | |||
211 | switch (attr) { |
||
212 | case hwmon_temp_input: |
||
213 | switch (channel) { |
||
214 | case 0: /* Tctl */ |
||
215 | *val = get_raw_temp(data); |
||
216 | if (*val < 0) |
||
217 | *val = 0; |
||
218 | break; |
||
219 | case 1: /* Tdie */ |
||
220 | *val = get_raw_temp(data) - data->temp_offset; |
||
221 | if (*val < 0) |
||
222 | *val = 0; |
||
223 | break; |
||
224 | case 2 ... 9: /* Tccd{1-8} */ |
||
225 | amd_smn_read(amd_pci_dev_to_node_id(data->pdev), |
||
226 | ZEN_CCD_TEMP(channel - 2), ®val); |
||
227 | *val = (regval & ZEN_CCD_TEMP_MASK) * 125 - 49000; |
||
228 | break; |
||
229 | default: |
||
230 | return -EOPNOTSUPP; |
||
231 | } |
||
232 | break; |
||
233 | case hwmon_temp_max: |
||
234 | *val = 70 * 1000; |
||
235 | break; |
||
236 | case hwmon_temp_crit: |
||
237 | data->read_htcreg(data->pdev, ®val); |
||
238 | *val = ((regval >> 16) & 0x7f) * 500 + 52000; |
||
239 | break; |
||
240 | case hwmon_temp_crit_hyst: |
||
241 | data->read_htcreg(data->pdev, ®val); |
||
242 | *val = (((regval >> 16) & 0x7f) |
||
243 | - ((regval >> 24) & 0xf)) * 500 + 52000; |
||
244 | break; |
||
245 | default: |
||
246 | return -EOPNOTSUPP; |
||
247 | } |
||
248 | return 0; |
||
249 | } |
||
250 | |||
251 | int k10temp_read(struct device *dev, enum hwmon_sensor_types type, |
||
252 | u32 attr, int channel, long *val) |
||
253 | { |
||
254 | switch (type) { |
||
255 | case hwmon_temp: |
||
256 | return k10temp_read_temp(dev, attr, channel, val); |
||
257 | default: |
||
258 | return -EOPNOTSUPP; |
||
259 | } |
||
260 | } |
||
261 | |||
262 | umode_t k10temp_is_visible(const void *_data, |
||
263 | enum hwmon_sensor_types type, |
||
264 | u32 attr, int channel) |
||
265 | { |
||
266 | const struct k10temp_data *data = _data; |
||
267 | struct pci_dev *pdev = data->pdev; |
||
268 | u32 reg; |
||
269 | |||
270 | switch (type) { |
||
271 | case hwmon_temp: |
||
272 | switch (attr) { |
||
273 | case hwmon_temp_input: |
||
274 | if (!HAVE_TEMP(data, channel)){ |
||
275 | return 0; |
||
276 | } |
||
277 | break; |
||
278 | case hwmon_temp_max: |
||
279 | if (channel || data->is_zen) |
||
280 | return 0; |
||
281 | break; |
||
282 | case hwmon_temp_crit: |
||
283 | case hwmon_temp_crit_hyst: |
||
284 | if (channel || !data->read_htcreg) |
||
285 | return 0; |
||
286 | |||
287 | pci_read_config_dword(pdev, |
||
288 | REG_NORTHBRIDGE_CAPABILITIES, |
||
289 | ®); |
||
290 | if (!(reg & NB_CAP_HTC)) |
||
291 | return 0; |
||
292 | |||
293 | data->read_htcreg(data->pdev, ®); |
||
294 | if (!(reg & HTC_ENABLE)) |
||
295 | return 0; |
||
296 | break; |
||
9100 | turbocat | 297 | // case hwmon_temp_label: |
298 | // /* Show temperature labels only on Zen CPUs */ |
||
299 | // if (!data->is_zen || !HAVE_TEMP(data, channel)) |
||
300 | // return 0; |
||
301 | // break; |
||
9079 | turbocat | 302 | default: |
303 | return 0; |
||
304 | } |
||
305 | break; |
||
306 | default: |
||
307 | return 0; |
||
308 | } |
||
309 | return 0444; |
||
310 | } |
||
9100 | turbocat | 311 | #if 0 |
9079 | turbocat | 312 | bool has_erratum_319(struct pci_dev *pdev) |
313 | { |
||
314 | u32 pkg_type, reg_dram_cfg; |
||
315 | |||
316 | if (boot_cpu_data.x86 != 0x10) |
||
317 | return false; |
||
318 | |||
319 | /* |
||
320 | * Erratum 319: The thermal sensor of Socket F/AM2+ processors |
||
321 | * may be unreliable. |
||
322 | */ |
||
323 | pkg_type = cpuid_ebx(0x80000001) & CPUID_PKGTYPE_MASK; |
||
324 | if (pkg_type == CPUID_PKGTYPE_F) |
||
325 | return true; |
||
326 | if (pkg_type != CPUID_PKGTYPE_AM2R2_AM3) |
||
327 | return false; |
||
328 | |||
329 | /* DDR3 memory implies socket AM3, which is good */ |
||
330 | pci_bus_read_config_dword(pdev->bus, |
||
331 | PCI_DEVFN(PCI_SLOT(pdev->devfn), 2), |
||
332 | REG_DCT0_CONFIG_HIGH, ®_dram_cfg); |
||
333 | if (reg_dram_cfg & DDR3_MODE) |
||
334 | return false; |
||
335 | |||
336 | /* |
||
337 | * Unfortunately it is possible to run a socket AM3 CPU with DDR2 |
||
338 | * memory. We blacklist all the cores which do exist in socket AM2+ |
||
339 | * format. It still isn't perfect, as RB-C2 cores exist in both AM2+ |
||
340 | * and AM3 formats, but that's the best we can do. |
||
341 | */ |
||
342 | |||
343 | return boot_cpu_data.x86_model < 4; |
||
344 | } |
||
9100 | turbocat | 345 | #endif |
9079 | turbocat | 346 | |
347 | const struct hwmon_channel_info *k10temp_info[] = { |
||
348 | HWMON_CHANNEL_INFO(temp, |
||
349 | HWMON_T_INPUT | HWMON_T_MAX | |
||
350 | HWMON_T_CRIT | HWMON_T_CRIT_HYST | |
||
351 | HWMON_T_LABEL, |
||
352 | HWMON_T_INPUT | HWMON_T_LABEL, |
||
353 | HWMON_T_INPUT | HWMON_T_LABEL, |
||
354 | HWMON_T_INPUT | 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_CHANNEL_INFO(in, |
||
362 | HWMON_I_INPUT | HWMON_I_LABEL, |
||
363 | HWMON_I_INPUT | HWMON_I_LABEL), |
||
364 | HWMON_CHANNEL_INFO(curr, |
||
365 | HWMON_C_INPUT | HWMON_C_LABEL, |
||
366 | HWMON_C_INPUT | HWMON_C_LABEL), |
||
367 | NULL |
||
368 | }; |
||
369 | /* |
||
370 | const struct hwmon_ops k10temp_hwmon_ops = { |
||
371 | .is_visible = k10temp_is_visible, |
||
372 | .read = k10temp_read, |
||
373 | .read_string = k10temp_read_labels, |
||
374 | };*/ |
||
375 | /* |
||
376 | const struct hwmon_chip_info k10temp_chip_info = { |
||
377 | .ops = &k10temp_hwmon_ops, |
||
378 | .info = k10temp_info, |
||
379 | };*/ |
||
380 | |||
381 | void k10temp_get_ccd_support(struct pci_dev *pdev, |
||
382 | struct k10temp_data *data, int limit) |
||
383 | { |
||
384 | |||
385 | u32 regval; |
||
386 | int i; |
||
387 | |||
388 | for (i = 0; i < limit; i++) { |
||
389 | amd_smn_read(amd_pci_dev_to_node_id(pdev), |
||
390 | ZEN_CCD_TEMP(i), ®val); |
||
391 | if (regval & ZEN_CCD_TEMP_VALID) |
||
392 | data->show_temp |= BIT(TCCD_BIT(i)); |
||
393 | } |
||
394 | } |
||
395 | |||
396 | int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id, struct device *hwmon_dev) |
||
397 | { |
||
9100 | turbocat | 398 | // int unreliable = has_erratum_319(pdev); |
9079 | turbocat | 399 | struct device *dev = &pdev->dev; |
400 | struct k10temp_data *data; |
||
401 | int i; |
||
9100 | turbocat | 402 | /* if (unreliable) { |
9079 | turbocat | 403 | if (!force) { |
404 | dev_err(dev,"unreliable CPU thermal sensor; monitoring disabled\n"); |
||
405 | return -ENODEV; |
||
406 | } |
||
407 | dev_warn(dev, |
||
408 | "unreliable CPU thermal sensor; check erratum 319\n"); |
||
409 | } |
||
9100 | turbocat | 410 | */ |
9079 | turbocat | 411 | data = kzalloc(sizeof(struct k10temp_data), GFP_KERNEL); |
412 | memset(data, 0x0, sizeof(struct k10temp_data)); |
||
413 | if (!data) |
||
414 | return -ENOMEM; |
||
415 | |||
416 | data->pdev = pdev; |
||
417 | data->show_temp |= BIT(TCTL_BIT); /* Always show Tctl */ |
||
418 | |||
419 | if (boot_cpu_data.x86 == 0x15 && |
||
420 | ((boot_cpu_data.x86_model & 0xf0) == 0x60 || |
||
421 | (boot_cpu_data.x86_model & 0xf0) == 0x70)) { |
||
422 | data->read_htcreg = read_htcreg_nb_f15; |
||
423 | data->read_tempreg = read_tempreg_nb_f15; |
||
424 | |||
425 | } else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) { |
||
426 | data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; |
||
427 | data->read_tempreg = read_tempreg_nb_zen; |
||
428 | data->show_temp |= BIT(TDIE_BIT); /* show Tdie */ |
||
429 | data->is_zen = true; |
||
430 | |||
431 | switch (boot_cpu_data.x86_model) { |
||
432 | case 0x1: /* Zen */ |
||
433 | case 0x8: /* Zen+ */ |
||
434 | case 0x11: /* Zen APU */ |
||
435 | case 0x18: /* Zen+ APU */ |
||
436 | k10temp_get_ccd_support(pdev, data, 4); |
||
437 | break; |
||
438 | case 0x31: /* Zen2 Threadripper */ |
||
439 | case 0x71: /* Zen2 */ |
||
440 | k10temp_get_ccd_support(pdev, data, 8); |
||
441 | break; |
||
442 | } |
||
443 | } else if (boot_cpu_data.x86 == 0x19) { |
||
444 | data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; |
||
445 | data->read_tempreg = read_tempreg_nb_zen; |
||
446 | data->show_temp |= BIT(TDIE_BIT); |
||
447 | data->is_zen = true; |
||
448 | switch (boot_cpu_data.x86_model) { |
||
449 | case 0x0 ... 0x1: /* Zen3 SP3/TR */ |
||
450 | case 0x21: /* Zen3 Ryzen Desktop */ |
||
451 | k10temp_get_ccd_support(pdev, data, 8); |
||
452 | break; |
||
453 | } |
||
454 | } else { |
||
455 | data->read_htcreg = read_htcreg_pci; |
||
456 | data->read_tempreg = read_tempreg_pci; |
||
457 | } |
||
458 | |||
459 | for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) { |
||
460 | const struct tctl_offset *entry = &tctl_offset_table[i]; |
||
461 | if (boot_cpu_data.x86 == entry->model && |
||
462 | strstr(boot_cpu_data.x86_model_id, entry->id)) { |
||
463 | data->temp_offset = entry->offset; |
||
464 | break; |
||
465 | } |
||
466 | } |
||
467 | |||
468 | hwmon_dev->driver_data=data; |
||
469 | return PTR_ERR_OR_ZERO(hwmon_dev); |
||
470 | } |
||
471 | |||
472 | const struct pci_device_id k10temp_id_table[] = { |
||
473 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, |
||
474 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, |
||
475 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, |
||
476 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, |
||
477 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, |
||
478 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, |
||
479 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) }, |
||
480 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F3) }, |
||
481 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, |
||
482 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) }, |
||
483 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) }, |
||
484 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) }, |
||
485 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, |
||
486 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) }, |
||
487 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, |
||
488 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) }, |
||
489 | { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, |
||
490 | {} |
||
491 | }; |
||
492 | |||
9100 | turbocat | 493 | #define K10TEMP_NA (~0) |
494 | #define CHANEL_MAX 9 |
||
495 | |||
496 | #pragma pack(push, 1) |
||
497 | struct{ |
||
498 | int Tctl; |
||
499 | int Tdie; |
||
500 | int Tccd1; |
||
501 | int Tccd2; |
||
502 | int Tccd3; |
||
503 | int Tccd4; |
||
504 | int Tccd5; |
||
505 | int Tccd6; |
||
506 | int Tccd7; |
||
507 | int Tccd8; |
||
508 | |||
509 | int Tmax; |
||
510 | int Tcrit; |
||
511 | int Tcrit_hyst; |
||
512 | }k10temp_out; |
||
513 | #pragma pack(pop) |
||
514 | |||
515 | struct device k10temp_device; |
||
516 | |||
517 | void read_temp_info(struct device *dev, u32 attr, int channel, int *val){ |
||
518 | long temp=0; |
||
519 | if(k10temp_is_visible(dev->driver_data, hwmon_temp, attr, channel)){ |
||
520 | k10temp_read_temp(dev, attr, channel, &temp); |
||
521 | *val=temp; |
||
522 | }else{ |
||
523 | *val=K10TEMP_NA; |
||
524 | } |
||
9079 | turbocat | 525 | } |
526 | |||
9100 | turbocat | 527 | void read_all_info(struct device* dev){ |
528 | for(int c=0; c<=CHANEL_MAX; c++){ |
||
529 | read_temp_info(dev, hwmon_temp_input, c, (int*)&k10temp_out+c); |
||
530 | } |
||
531 | read_temp_info(dev, hwmon_temp_max, 0, &k10temp_out.Tmax); |
||
532 | read_temp_info(dev, hwmon_temp_crit, 0, &k10temp_out.Tcrit); |
||
533 | read_temp_info(dev, hwmon_temp_crit_hyst, 0, &k10temp_out.Tcrit_hyst); |
||
9079 | turbocat | 534 | } |
535 | |||
9100 | turbocat | 536 | int __stdcall service_proc(ioctl_t *my_ctl){ |
537 | if(!my_ctl || !my_ctl->output){ |
||
538 | return 1; |
||
9079 | turbocat | 539 | } |
9100 | turbocat | 540 | read_all_info(&k10temp_device); |
541 | if(my_ctl->out_size == sizeof(k10temp_out)){ |
||
542 | memcpy(my_ctl->output, &k10temp_out, sizeof(k10temp_out)); |
||
543 | return 0; |
||
544 | } |
||
545 | return 1; |
||
9079 | turbocat | 546 | } |
547 | |||
9100 | turbocat | 548 | extern void init_amd_nbs(void); |
9079 | turbocat | 549 | |
550 | uint32_t drvEntry(int action, char *cmdline){ |
||
551 | if(action != 1){ |
||
552 | return 0; |
||
553 | } |
||
9100 | turbocat | 554 | pci_dev_t device; |
555 | const struct pci_device_id *k10temp_id; |
||
9079 | turbocat | 556 | int err; |
557 | |||
558 | cpu_detect(&boot_cpu_data); |
||
559 | |||
560 | err = enum_pci_devices(); |
||
561 | if(unlikely(err != 0)) { |
||
9100 | turbocat | 562 | printk("k10temp: Device enumeration failed!\n"); |
9079 | turbocat | 563 | return -1; |
564 | } |
||
565 | |||
566 | k10temp_id = find_pci_device(&device, k10temp_id_table); |
||
9100 | turbocat | 567 | |
568 | if(unlikely(k10temp_id == NULL)){ |
||
569 | printk("k10temp: Device not found!\n"); |
||
9079 | turbocat | 570 | return -ENODEV; |
571 | } |
||
9100 | turbocat | 572 | |
9079 | turbocat | 573 | init_amd_nbs(); |
9100 | turbocat | 574 | k10temp_probe(&device.pci_dev, k10temp_id, &k10temp_device); |
9079 | turbocat | 575 | return RegService("k10temp", service_proc); |
576 | }=CHANEL_MAX;>>>>>> |