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