Subversion Repositories Kolibri OS

Rev

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
}