Blame view

drivers/hwmon/fam15h_power.c 12.5 KB
6e7c10944   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
512d1027a   Andreas Herrmann   hwmon: Add driver...
2
3
4
  /*
   * fam15h_power.c - AMD Family 15h processor power monitoring
   *
a6e232f78   Huang Rui   hwmon: (fam15h_po...
5
   * Copyright (c) 2011-2016 Advanced Micro Devices, Inc.
d034fbf08   Andreas Herrmann   hwmon, fam15h_pow...
6
   * Author: Andreas Herrmann <herrmann.der.user@googlemail.com>
512d1027a   Andreas Herrmann   hwmon: Add driver...
7
8
9
10
11
12
13
14
15
   */
  
  #include <linux/err.h>
  #include <linux/hwmon.h>
  #include <linux/hwmon-sysfs.h>
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/pci.h>
  #include <linux/bitops.h>
fa7943449   Huang Rui   hwmon: (fam15h_po...
16
17
  #include <linux/cpu.h>
  #include <linux/cpumask.h>
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
18
19
  #include <linux/time.h>
  #include <linux/sched.h>
512d1027a   Andreas Herrmann   hwmon: Add driver...
20
  #include <asm/processor.h>
3b5ea47db   Huang Rui   hwmon: (fam15h_po...
21
  #include <asm/msr.h>
512d1027a   Andreas Herrmann   hwmon: Add driver...
22
23
  
  MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
d034fbf08   Andreas Herrmann   hwmon, fam15h_pow...
24
  MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
512d1027a   Andreas Herrmann   hwmon: Add driver...
25
26
27
28
29
30
31
32
33
34
35
  MODULE_LICENSE("GPL");
  
  /* D18F3 */
  #define REG_NORTHBRIDGE_CAP		0xe8
  
  /* D18F4 */
  #define REG_PROCESSOR_TDP		0x1b8
  
  /* D18F5 */
  #define REG_TDP_RUNNING_AVERAGE		0xe0
  #define REG_TDP_LIMIT3			0xe8
7deb14b13   Huang Rui   hwmon: (fam15h_po...
36
37
  #define FAM15H_MIN_NUM_ATTRS		2
  #define FAM15H_NUM_GROUPS		2
fa7943449   Huang Rui   hwmon: (fam15h_po...
38
  #define MAX_CUS				8
7deb14b13   Huang Rui   hwmon: (fam15h_po...
39

11bf0d78c   Huang Rui   hwmon: (fam15h_po...
40
41
  /* set maximum interval as 1 second */
  #define MAX_INTERVAL			1000
fa7943449   Huang Rui   hwmon: (fam15h_po...
42
  #define MSR_F15H_CU_PWR_ACCUMULATOR	0xc001007a
3b5ea47db   Huang Rui   hwmon: (fam15h_po...
43
  #define MSR_F15H_CU_MAX_PWR_ACCUMULATOR	0xc001007b
cdb9e110b   Huang Rui   hwmon: (fam15h_po...
44
  #define MSR_F15H_PTSC			0xc0010280
3b5ea47db   Huang Rui   hwmon: (fam15h_po...
45

eff2a9459   Huang Rui   hwmon: (fam15h_po...
46
  #define PCI_DEVICE_ID_AMD_15H_M70H_NB_F4 0x15b4
512d1027a   Andreas Herrmann   hwmon: Add driver...
47
  struct fam15h_power_data {
562dc9732   Axel Lin   hwmon: (fam15h_po...
48
  	struct pci_dev *pdev;
512d1027a   Andreas Herrmann   hwmon: Add driver...
49
50
51
  	unsigned int tdp_to_watts;
  	unsigned int base_tdp;
  	unsigned int processor_pwr_watts;
1ed32160d   Huang Rui   hwmon: (fam15h_po...
52
  	unsigned int cpu_pwr_sample_ratio;
7deb14b13   Huang Rui   hwmon: (fam15h_po...
53
54
  	const struct attribute_group *groups[FAM15H_NUM_GROUPS];
  	struct attribute_group group;
3b5ea47db   Huang Rui   hwmon: (fam15h_po...
55
56
  	/* maximum accumulated power of a compute unit */
  	u64 max_cu_acc_power;
fa7943449   Huang Rui   hwmon: (fam15h_po...
57
58
  	/* accumulated power of the compute units */
  	u64 cu_acc_power[MAX_CUS];
cdb9e110b   Huang Rui   hwmon: (fam15h_po...
59
60
  	/* performance timestamp counter */
  	u64 cpu_sw_pwr_ptsc[MAX_CUS];
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
61
62
63
  	/* online/offline status of current compute unit */
  	int cu_on[MAX_CUS];
  	unsigned long power_period;
512d1027a   Andreas Herrmann   hwmon: Add driver...
64
  };
1d28e0162   Huang Rui   hwmon: (fam15h_po...
65
66
67
68
  static bool is_carrizo_or_later(void)
  {
  	return boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model >= 0x60;
  }
d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
69
70
  static ssize_t power1_input_show(struct device *dev,
  				 struct device_attribute *attr, char *buf)
512d1027a   Andreas Herrmann   hwmon: Add driver...
71
72
73
74
  {
  	u32 val, tdp_limit, running_avg_range;
  	s32 running_avg_capture;
  	u64 curr_pwr_watts;
512d1027a   Andreas Herrmann   hwmon: Add driver...
75
  	struct fam15h_power_data *data = dev_get_drvdata(dev);
562dc9732   Axel Lin   hwmon: (fam15h_po...
76
  	struct pci_dev *f4 = data->pdev;
512d1027a   Andreas Herrmann   hwmon: Add driver...
77
78
79
  
  	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
  				  REG_TDP_RUNNING_AVERAGE, &val);
e9cd4d55d   Huang Rui   hwmon: (fam15h_po...
80
81
82
83
84
  
  	/*
  	 * On Carrizo and later platforms, TdpRunAvgAccCap bit field
  	 * is extended to 4:31 from 4:25.
  	 */
1d28e0162   Huang Rui   hwmon: (fam15h_po...
85
  	if (is_carrizo_or_later()) {
e9cd4d55d   Huang Rui   hwmon: (fam15h_po...
86
87
88
89
90
91
  		running_avg_capture = val >> 4;
  		running_avg_capture = sign_extend32(running_avg_capture, 27);
  	} else {
  		running_avg_capture = (val >> 4) & 0x3fffff;
  		running_avg_capture = sign_extend32(running_avg_capture, 21);
  	}
941a956b0   Andre Przywara   hwmon: (fam15h_po...
92
  	running_avg_range = (val & 0xf) + 1;
512d1027a   Andreas Herrmann   hwmon: Add driver...
93
94
95
  
  	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
  				  REG_TDP_LIMIT3, &val);
60dee3ca2   Gioh Kim   hwmon: (fam15h_po...
96
97
98
99
  	/*
  	 * On Carrizo and later platforms, ApmTdpLimit bit field
  	 * is extended to 16:31 from 16:28.
  	 */
1d28e0162   Huang Rui   hwmon: (fam15h_po...
100
  	if (is_carrizo_or_later())
60dee3ca2   Gioh Kim   hwmon: (fam15h_po...
101
102
103
  		tdp_limit = val >> 16;
  	else
  		tdp_limit = (val >> 16) & 0x1fff;
62867d491   Guenter Roeck   hwmon: (fam15h_po...
104
105
  	curr_pwr_watts = ((u64)(tdp_limit +
  				data->base_tdp)) << running_avg_range;
941a956b0   Andre Przywara   hwmon: (fam15h_po...
106
  	curr_pwr_watts -= running_avg_capture;
512d1027a   Andreas Herrmann   hwmon: Add driver...
107
108
109
110
111
112
113
114
115
  	curr_pwr_watts *= data->tdp_to_watts;
  
  	/*
  	 * Convert to microWatt
  	 *
  	 * power is in Watt provided as fixed point integer with
  	 * scaling factor 1/(2^16).  For conversion we use
  	 * (10^6)/(2^16) = 15625/(2^10)
  	 */
941a956b0   Andre Przywara   hwmon: (fam15h_po...
116
  	curr_pwr_watts = (curr_pwr_watts * 15625) >> (10 + running_avg_range);
512d1027a   Andreas Herrmann   hwmon: Add driver...
117
118
119
  	return sprintf(buf, "%u
  ", (unsigned int) curr_pwr_watts);
  }
d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
120
  static DEVICE_ATTR_RO(power1_input);
512d1027a   Andreas Herrmann   hwmon: Add driver...
121

d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
122
123
  static ssize_t power1_crit_show(struct device *dev,
  				struct device_attribute *attr, char *buf)
512d1027a   Andreas Herrmann   hwmon: Add driver...
124
125
126
127
128
129
  {
  	struct fam15h_power_data *data = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%u
  ", data->processor_pwr_watts);
  }
d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
130
  static DEVICE_ATTR_RO(power1_crit);
512d1027a   Andreas Herrmann   hwmon: Add driver...
131

fa7943449   Huang Rui   hwmon: (fam15h_po...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  static void do_read_registers_on_cu(void *_data)
  {
  	struct fam15h_power_data *data = _data;
  	int cpu, cu;
  
  	cpu = smp_processor_id();
  
  	/*
  	 * With the new x86 topology modelling, cpu core id actually
  	 * is compute unit id.
  	 */
  	cu = cpu_data(cpu).cpu_core_id;
  
  	rdmsrl_safe(MSR_F15H_CU_PWR_ACCUMULATOR, &data->cu_acc_power[cu]);
cdb9e110b   Huang Rui   hwmon: (fam15h_po...
146
  	rdmsrl_safe(MSR_F15H_PTSC, &data->cpu_sw_pwr_ptsc[cu]);
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
147
148
  
  	data->cu_on[cu] = 1;
fa7943449   Huang Rui   hwmon: (fam15h_po...
149
150
151
152
153
154
155
156
  }
  
  /*
   * This function is only able to be called when CPUID
   * Fn8000_0007:EDX[12] is set.
   */
  static int read_registers(struct fam15h_power_data *data)
  {
fa7943449   Huang Rui   hwmon: (fam15h_po...
157
158
  	int core, this_core;
  	cpumask_var_t mask;
7be488184   Borislav Petkov   hwmon: (fam15h_po...
159
  	int ret, cpu;
fa7943449   Huang Rui   hwmon: (fam15h_po...
160
161
162
163
  
  	ret = zalloc_cpumask_var(&mask, GFP_KERNEL);
  	if (!ret)
  		return -ENOMEM;
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
164
  	memset(data->cu_on, 0, sizeof(int) * MAX_CUS);
fa7943449   Huang Rui   hwmon: (fam15h_po...
165
  	get_online_cpus();
fa7943449   Huang Rui   hwmon: (fam15h_po...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  
  	/*
  	 * Choose the first online core of each compute unit, and then
  	 * read their MSR value of power and ptsc in a single IPI,
  	 * because the MSR value of CPU core represent the compute
  	 * unit's.
  	 */
  	core = -1;
  
  	for_each_online_cpu(cpu) {
  		this_core = topology_core_id(cpu);
  
  		if (this_core == core)
  			continue;
  
  		core = this_core;
  
  		/* get any CPU on this compute unit */
  		cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(cpu)), mask);
  	}
7be488184   Borislav Petkov   hwmon: (fam15h_po...
186
  	on_each_cpu_mask(mask, do_read_registers_on_cu, data, true);
fa7943449   Huang Rui   hwmon: (fam15h_po...
187

fa7943449   Huang Rui   hwmon: (fam15h_po...
188
  	put_online_cpus();
fa7943449   Huang Rui   hwmon: (fam15h_po...
189
190
191
192
  	free_cpumask_var(mask);
  
  	return 0;
  }
d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
193
194
  static ssize_t power1_average_show(struct device *dev,
  				   struct device_attribute *attr, char *buf)
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  {
  	struct fam15h_power_data *data = dev_get_drvdata(dev);
  	u64 prev_cu_acc_power[MAX_CUS], prev_ptsc[MAX_CUS],
  	    jdelta[MAX_CUS];
  	u64 tdelta, avg_acc;
  	int cu, cu_num, ret;
  	signed long leftover;
  
  	/*
  	 * With the new x86 topology modelling, x86_max_cores is the
  	 * compute unit number.
  	 */
  	cu_num = boot_cpu_data.x86_max_cores;
  
  	ret = read_registers(data);
  	if (ret)
  		return 0;
  
  	for (cu = 0; cu < cu_num; cu++) {
  		prev_cu_acc_power[cu] = data->cu_acc_power[cu];
  		prev_ptsc[cu] = data->cpu_sw_pwr_ptsc[cu];
  	}
  
  	leftover = schedule_timeout_interruptible(msecs_to_jiffies(data->power_period));
  	if (leftover)
  		return 0;
  
  	ret = read_registers(data);
  	if (ret)
  		return 0;
  
  	for (cu = 0, avg_acc = 0; cu < cu_num; cu++) {
  		/* check if current compute unit is online */
  		if (data->cu_on[cu] == 0)
  			continue;
  
  		if (data->cu_acc_power[cu] < prev_cu_acc_power[cu]) {
  			jdelta[cu] = data->max_cu_acc_power + data->cu_acc_power[cu];
  			jdelta[cu] -= prev_cu_acc_power[cu];
  		} else {
  			jdelta[cu] = data->cu_acc_power[cu] - prev_cu_acc_power[cu];
  		}
  		tdelta = data->cpu_sw_pwr_ptsc[cu] - prev_ptsc[cu];
  		jdelta[cu] *= data->cpu_pwr_sample_ratio * 1000;
  		do_div(jdelta[cu], tdelta);
  
  		/* the unit is microWatt */
  		avg_acc += jdelta[cu];
  	}
  
  	return sprintf(buf, "%llu
  ", (unsigned long long)avg_acc);
  }
d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
248
  static DEVICE_ATTR_RO(power1_average);
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
249

d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
250
251
252
  static ssize_t power1_average_interval_show(struct device *dev,
  					    struct device_attribute *attr,
  					    char *buf)
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
253
254
255
256
257
258
  {
  	struct fam15h_power_data *data = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%lu
  ", data->power_period);
  }
d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
259
260
261
  static ssize_t power1_average_interval_store(struct device *dev,
  					     struct device_attribute *attr,
  					     const char *buf, size_t count)
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  {
  	struct fam15h_power_data *data = dev_get_drvdata(dev);
  	unsigned long temp;
  	int ret;
  
  	ret = kstrtoul(buf, 10, &temp);
  	if (ret)
  		return ret;
  
  	if (temp > MAX_INTERVAL)
  		return -EINVAL;
  
  	/* the interval value should be greater than 0 */
  	if (temp <= 0)
  		return -EINVAL;
  
  	data->power_period = temp;
  
  	return count;
  }
d013f7f5b   Julia Lawall   hwmon: (fam15h_po...
282
  static DEVICE_ATTR_RW(power1_average_interval);
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
283

7deb14b13   Huang Rui   hwmon: (fam15h_po...
284
285
  static int fam15h_power_init_attrs(struct pci_dev *pdev,
  				   struct fam15h_power_data *data)
961a23788   Aravind Gopalakrishnan   hwmon: (fam15h_po...
286
  {
7deb14b13   Huang Rui   hwmon: (fam15h_po...
287
288
  	int n = FAM15H_MIN_NUM_ATTRS;
  	struct attribute **fam15h_power_attrs;
46f29c2b4   Huang Rui   hwmon: (fam15h_po...
289
  	struct cpuinfo_x86 *c = &boot_cpu_data;
961a23788   Aravind Gopalakrishnan   hwmon: (fam15h_po...
290

46f29c2b4   Huang Rui   hwmon: (fam15h_po...
291
292
  	if (c->x86 == 0x15 &&
  	    (c->x86_model <= 0xf ||
eff2a9459   Huang Rui   hwmon: (fam15h_po...
293
  	     (c->x86_model >= 0x60 && c->x86_model <= 0x7f)))
7deb14b13   Huang Rui   hwmon: (fam15h_po...
294
  		n += 1;
961a23788   Aravind Gopalakrishnan   hwmon: (fam15h_po...
295

11bf0d78c   Huang Rui   hwmon: (fam15h_po...
296
297
298
  	/* check if processor supports accumulated power */
  	if (boot_cpu_has(X86_FEATURE_ACC_POWER))
  		n += 2;
7deb14b13   Huang Rui   hwmon: (fam15h_po...
299
300
301
  	fam15h_power_attrs = devm_kcalloc(&pdev->dev, n,
  					  sizeof(*fam15h_power_attrs),
  					  GFP_KERNEL);
512d1027a   Andreas Herrmann   hwmon: Add driver...
302

7deb14b13   Huang Rui   hwmon: (fam15h_po...
303
304
305
306
307
  	if (!fam15h_power_attrs)
  		return -ENOMEM;
  
  	n = 0;
  	fam15h_power_attrs[n++] = &dev_attr_power1_crit.attr;
46f29c2b4   Huang Rui   hwmon: (fam15h_po...
308
309
  	if (c->x86 == 0x15 &&
  	    (c->x86_model <= 0xf ||
eff2a9459   Huang Rui   hwmon: (fam15h_po...
310
  	     (c->x86_model >= 0x60 && c->x86_model <= 0x7f)))
7deb14b13   Huang Rui   hwmon: (fam15h_po...
311
  		fam15h_power_attrs[n++] = &dev_attr_power1_input.attr;
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
312
313
314
315
  	if (boot_cpu_has(X86_FEATURE_ACC_POWER)) {
  		fam15h_power_attrs[n++] = &dev_attr_power1_average.attr;
  		fam15h_power_attrs[n++] = &dev_attr_power1_average_interval.attr;
  	}
7deb14b13   Huang Rui   hwmon: (fam15h_po...
316
317
318
319
  	data->group.attrs = fam15h_power_attrs;
  
  	return 0;
  }
512d1027a   Andreas Herrmann   hwmon: Add driver...
320

d83e92b3a   Huang Rui   hwmon: (fam15h_po...
321
  static bool should_load_on_this_node(struct pci_dev *f4)
512d1027a   Andreas Herrmann   hwmon: Add driver...
322
323
324
325
326
327
328
329
330
331
  {
  	u32 val;
  
  	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 3),
  				  REG_NORTHBRIDGE_CAP, &val);
  	if ((val & BIT(29)) && ((val >> 30) & 3))
  		return false;
  
  	return true;
  }
00250ec90   Andre Przywara   hwmon: fam15h_pow...
332
333
334
335
336
337
  /*
   * Newer BKDG versions have an updated recommendation on how to properly
   * initialize the running average range (was: 0xE, now: 0x9). This avoids
   * counter saturations resulting in bogus power readings.
   * We correct this value ourselves to cope with older BIOSes.
   */
5f0ecb907   Andreas Herrmann   hwmon: (fam15h_po...
338
  static const struct pci_device_id affected_device[] = {
c3e40a997   Guenter Roeck   hwmon: (fam15h_po...
339
340
341
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
  	{ 0 }
  };
5f0ecb907   Andreas Herrmann   hwmon: (fam15h_po...
342
  static void tweak_runavg_range(struct pci_dev *pdev)
00250ec90   Andre Przywara   hwmon: fam15h_pow...
343
344
  {
  	u32 val;
00250ec90   Andre Przywara   hwmon: fam15h_pow...
345
346
347
348
349
  
  	/*
  	 * let this quirk apply only to the current version of the
  	 * northbridge, since future versions may change the behavior
  	 */
c3e40a997   Guenter Roeck   hwmon: (fam15h_po...
350
  	if (!pci_match_id(affected_device, pdev))
00250ec90   Andre Przywara   hwmon: fam15h_pow...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  		return;
  
  	pci_bus_read_config_dword(pdev->bus,
  		PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
  		REG_TDP_RUNNING_AVERAGE, &val);
  	if ((val & 0xf) != 0xe)
  		return;
  
  	val &= ~0xf;
  	val |=  0x9;
  	pci_bus_write_config_dword(pdev->bus,
  		PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
  		REG_TDP_RUNNING_AVERAGE, val);
  }
5f0ecb907   Andreas Herrmann   hwmon: (fam15h_po...
365
366
367
368
369
370
371
372
373
  #ifdef CONFIG_PM
  static int fam15h_power_resume(struct pci_dev *pdev)
  {
  	tweak_runavg_range(pdev);
  	return 0;
  }
  #else
  #define fam15h_power_resume NULL
  #endif
7deb14b13   Huang Rui   hwmon: (fam15h_po...
374
375
  static int fam15h_power_init_data(struct pci_dev *f4,
  				  struct fam15h_power_data *data)
512d1027a   Andreas Herrmann   hwmon: Add driver...
376
  {
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
377
  	u32 val;
512d1027a   Andreas Herrmann   hwmon: Add driver...
378
  	u64 tmp;
7deb14b13   Huang Rui   hwmon: (fam15h_po...
379
  	int ret;
512d1027a   Andreas Herrmann   hwmon: Add driver...
380
381
382
383
384
385
386
387
388
389
390
391
392
  
  	pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val);
  	data->base_tdp = val >> 16;
  	tmp = val & 0xffff;
  
  	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
  				  REG_TDP_LIMIT3, &val);
  
  	data->tdp_to_watts = ((val & 0x3ff) << 6) | ((val >> 10) & 0x3f);
  	tmp *= data->tdp_to_watts;
  
  	/* result not allowed to be >= 256W */
  	if ((tmp >> 16) >= 256)
b55f37572   Guenter Roeck   hwmon: Fix checkp...
393
394
395
  		dev_warn(&f4->dev,
  			 "Bogus value for ProcessorPwrWatts (processor_pwr_watts>=%u)
  ",
512d1027a   Andreas Herrmann   hwmon: Add driver...
396
397
398
399
  			 (unsigned int) (tmp >> 16));
  
  	/* convert to microWatt */
  	data->processor_pwr_watts = (tmp * 15625) >> 10;
1ed32160d   Huang Rui   hwmon: (fam15h_po...
400

7deb14b13   Huang Rui   hwmon: (fam15h_po...
401
402
403
  	ret = fam15h_power_init_attrs(f4, data);
  	if (ret)
  		return ret;
1ed32160d   Huang Rui   hwmon: (fam15h_po...
404
405
  
  	/* CPUID Fn8000_0007:EDX[12] indicates to support accumulated power */
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
406
  	if (!boot_cpu_has(X86_FEATURE_ACC_POWER))
7deb14b13   Huang Rui   hwmon: (fam15h_po...
407
  		return 0;
1ed32160d   Huang Rui   hwmon: (fam15h_po...
408
409
410
411
412
413
  
  	/*
  	 * determine the ratio of the compute unit power accumulator
  	 * sample period to the PTSC counter period by executing CPUID
  	 * Fn8000_0007:ECX
  	 */
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
414
  	data->cpu_pwr_sample_ratio = cpuid_ecx(0x80000007);
7deb14b13   Huang Rui   hwmon: (fam15h_po...
415

3b5ea47db   Huang Rui   hwmon: (fam15h_po...
416
417
418
419
420
421
422
  	if (rdmsrl_safe(MSR_F15H_CU_MAX_PWR_ACCUMULATOR, &tmp)) {
  		pr_err("Failed to read max compute unit power accumulator MSR
  ");
  		return -ENODEV;
  	}
  
  	data->max_cu_acc_power = tmp;
11bf0d78c   Huang Rui   hwmon: (fam15h_po...
423
424
425
426
427
428
429
  	/*
  	 * Milliseconds are a reasonable interval for the measurement.
  	 * But it shouldn't set too long here, because several seconds
  	 * would cause the read function to hang. So set default
  	 * interval as 10 ms.
  	 */
  	data->power_period = 10;
fa7943449   Huang Rui   hwmon: (fam15h_po...
430
  	return read_registers(data);
512d1027a   Andreas Herrmann   hwmon: Add driver...
431
  }
6c931ae1c   Bill Pemberton   hwmon: remove use...
432
  static int fam15h_power_probe(struct pci_dev *pdev,
7deb14b13   Huang Rui   hwmon: (fam15h_po...
433
  			      const struct pci_device_id *id)
512d1027a   Andreas Herrmann   hwmon: Add driver...
434
435
  {
  	struct fam15h_power_data *data;
87432a2e2   Guenter Roeck   hwmon: (fam15h_po...
436
  	struct device *dev = &pdev->dev;
562dc9732   Axel Lin   hwmon: (fam15h_po...
437
  	struct device *hwmon_dev;
7deb14b13   Huang Rui   hwmon: (fam15h_po...
438
  	int ret;
512d1027a   Andreas Herrmann   hwmon: Add driver...
439

00250ec90   Andre Przywara   hwmon: fam15h_pow...
440
441
442
443
444
445
  	/*
  	 * though we ignore every other northbridge, we still have to
  	 * do the tweaking on _each_ node in MCM processors as the counters
  	 * are working hand-in-hand
  	 */
  	tweak_runavg_range(pdev);
d83e92b3a   Huang Rui   hwmon: (fam15h_po...
446
  	if (!should_load_on_this_node(pdev))
87432a2e2   Guenter Roeck   hwmon: (fam15h_po...
447
448
449
450
451
  		return -ENODEV;
  
  	data = devm_kzalloc(dev, sizeof(struct fam15h_power_data), GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
512d1027a   Andreas Herrmann   hwmon: Add driver...
452

7deb14b13   Huang Rui   hwmon: (fam15h_po...
453
454
455
  	ret = fam15h_power_init_data(pdev, data);
  	if (ret)
  		return ret;
562dc9732   Axel Lin   hwmon: (fam15h_po...
456
  	data->pdev = pdev;
512d1027a   Andreas Herrmann   hwmon: Add driver...
457

7deb14b13   Huang Rui   hwmon: (fam15h_po...
458
  	data->groups[0] = &data->group;
562dc9732   Axel Lin   hwmon: (fam15h_po...
459
460
  	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "fam15h_power",
  							   data,
7deb14b13   Huang Rui   hwmon: (fam15h_po...
461
  							   &data->groups[0]);
562dc9732   Axel Lin   hwmon: (fam15h_po...
462
  	return PTR_ERR_OR_ZERO(hwmon_dev);
512d1027a   Andreas Herrmann   hwmon: Add driver...
463
  }
cd9bb0564   Jingoo Han   hwmon: remove DEF...
464
  static const struct pci_device_id fam15h_power_id_table[] = {
512d1027a   Andreas Herrmann   hwmon: Add driver...
465
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
0a0039ad5   Aravind Gopalakrishnan   hwmon: (fam15h_po...
466
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
5dc087254   Huang Rui   hwmon: (fam15h_po...
467
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
eff2a9459   Huang Rui   hwmon: (fam15h_po...
468
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F4) },
22e32f4f5   Boris Ostrovsky   x86,AMD: Power dr...
469
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
0bd529415   Aravind Gopalakrishnan   hwmon: (fam15h_po...
470
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
512d1027a   Andreas Herrmann   hwmon: Add driver...
471
472
473
474
475
476
477
478
  	{}
  };
  MODULE_DEVICE_TABLE(pci, fam15h_power_id_table);
  
  static struct pci_driver fam15h_power_driver = {
  	.name = "fam15h_power",
  	.id_table = fam15h_power_id_table,
  	.probe = fam15h_power_probe,
5f0ecb907   Andreas Herrmann   hwmon: (fam15h_po...
479
  	.resume = fam15h_power_resume,
512d1027a   Andreas Herrmann   hwmon: Add driver...
480
  };
f71f5a550   Axel Lin   hwmon: use module...
481
  module_pci_driver(fam15h_power_driver);