Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/cpufreq/amd_freq_sensitivity.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* amd_freq_sensitivity.c: AMD frequency sensitivity feedback powersave bias
4
* for the ondemand governor.
5
*
6
* Copyright (C) 2013 Advanced Micro Devices, Inc.
7
*
8
* Author: Jacob Shin <[email protected]>
9
*/
10
11
#include <linux/kernel.h>
12
#include <linux/module.h>
13
#include <linux/types.h>
14
#include <linux/pci.h>
15
#include <linux/percpu-defs.h>
16
#include <linux/init.h>
17
#include <linux/mod_devicetable.h>
18
19
#include <asm/msr.h>
20
#include <asm/cpufeature.h>
21
#include <asm/cpu_device_id.h>
22
23
#include "cpufreq_ondemand.h"
24
25
#define MSR_AMD64_FREQ_SENSITIVITY_ACTUAL 0xc0010080
26
#define MSR_AMD64_FREQ_SENSITIVITY_REFERENCE 0xc0010081
27
#define CLASS_CODE_SHIFT 56
28
#define POWERSAVE_BIAS_MAX 1000
29
#define POWERSAVE_BIAS_DEF 400
30
31
struct cpu_data_t {
32
u64 actual;
33
u64 reference;
34
unsigned int freq_prev;
35
};
36
37
static DEFINE_PER_CPU(struct cpu_data_t, cpu_data);
38
39
static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy,
40
unsigned int freq_next,
41
unsigned int relation)
42
{
43
int sensitivity;
44
long d_actual, d_reference;
45
struct msr actual, reference;
46
struct cpu_data_t *data = &per_cpu(cpu_data, policy->cpu);
47
struct policy_dbs_info *policy_dbs = policy->governor_data;
48
struct dbs_data *od_data = policy_dbs->dbs_data;
49
struct od_dbs_tuners *od_tuners = od_data->tuners;
50
51
if (!policy->freq_table)
52
return freq_next;
53
54
rdmsr_on_cpu(policy->cpu, MSR_AMD64_FREQ_SENSITIVITY_ACTUAL,
55
&actual.l, &actual.h);
56
rdmsr_on_cpu(policy->cpu, MSR_AMD64_FREQ_SENSITIVITY_REFERENCE,
57
&reference.l, &reference.h);
58
actual.h &= 0x00ffffff;
59
reference.h &= 0x00ffffff;
60
61
/* counter wrapped around, so stay on current frequency */
62
if (actual.q < data->actual || reference.q < data->reference) {
63
freq_next = policy->cur;
64
goto out;
65
}
66
67
d_actual = actual.q - data->actual;
68
d_reference = reference.q - data->reference;
69
70
/* divide by 0, so stay on current frequency as well */
71
if (d_reference == 0) {
72
freq_next = policy->cur;
73
goto out;
74
}
75
76
sensitivity = POWERSAVE_BIAS_MAX -
77
(POWERSAVE_BIAS_MAX * (d_reference - d_actual) / d_reference);
78
79
clamp(sensitivity, 0, POWERSAVE_BIAS_MAX);
80
81
/* this workload is not CPU bound, so choose a lower freq */
82
if (sensitivity < od_tuners->powersave_bias) {
83
if (data->freq_prev == policy->cur)
84
freq_next = policy->cur;
85
86
if (freq_next > policy->cur)
87
freq_next = policy->cur;
88
else if (freq_next < policy->cur)
89
freq_next = policy->min;
90
else {
91
unsigned int index;
92
93
index = cpufreq_table_find_index_h(policy,
94
policy->cur - 1,
95
relation & CPUFREQ_RELATION_E);
96
freq_next = policy->freq_table[index].frequency;
97
}
98
99
data->freq_prev = freq_next;
100
} else
101
data->freq_prev = 0;
102
103
out:
104
data->actual = actual.q;
105
data->reference = reference.q;
106
return freq_next;
107
}
108
109
static int __init amd_freq_sensitivity_init(void)
110
{
111
u64 val;
112
struct pci_dev *pcidev;
113
unsigned int pci_vendor;
114
115
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
116
pci_vendor = PCI_VENDOR_ID_AMD;
117
else if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
118
pci_vendor = PCI_VENDOR_ID_HYGON;
119
else
120
return -ENODEV;
121
122
pcidev = pci_get_device(pci_vendor,
123
PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, NULL);
124
125
if (!pcidev) {
126
if (!boot_cpu_has(X86_FEATURE_PROC_FEEDBACK))
127
return -ENODEV;
128
} else {
129
pci_dev_put(pcidev);
130
}
131
132
if (rdmsrq_safe(MSR_AMD64_FREQ_SENSITIVITY_ACTUAL, &val))
133
return -ENODEV;
134
135
if (!(val >> CLASS_CODE_SHIFT))
136
return -ENODEV;
137
138
od_register_powersave_bias_handler(amd_powersave_bias_target,
139
POWERSAVE_BIAS_DEF);
140
return 0;
141
}
142
late_initcall(amd_freq_sensitivity_init);
143
144
static void __exit amd_freq_sensitivity_exit(void)
145
{
146
od_unregister_powersave_bias_handler();
147
}
148
module_exit(amd_freq_sensitivity_exit);
149
150
static const struct x86_cpu_id __maybe_unused amd_freq_sensitivity_ids[] = {
151
X86_MATCH_FEATURE(X86_FEATURE_PROC_FEEDBACK, NULL),
152
{}
153
};
154
MODULE_DEVICE_TABLE(x86cpu, amd_freq_sensitivity_ids);
155
156
MODULE_AUTHOR("Jacob Shin <[email protected]>");
157
MODULE_DESCRIPTION("AMD frequency sensitivity feedback powersave bias for "
158
"the ondemand governor.");
159
MODULE_LICENSE("GPL");
160
161