99#include <asm/processor.h>
1010#include <asm/topology.h>
1111
12+ #define CPPC_HIGHEST_PERF_PERFORMANCE 196
13+ #define CPPC_HIGHEST_PERF_PREFCORE 166
14+
15+ enum amd_pref_core {
16+ AMD_PREF_CORE_UNKNOWN = 0 ,
17+ AMD_PREF_CORE_SUPPORTED ,
18+ AMD_PREF_CORE_UNSUPPORTED ,
19+ };
20+ static enum amd_pref_core amd_pref_core_detected ;
21+ static u64 boost_numerator ;
22+
1223/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
1324
1425bool cpc_supported_by_cpu (void )
@@ -69,7 +80,7 @@ int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
6980static void amd_set_max_freq_ratio (void )
7081{
7182 struct cppc_perf_caps perf_caps ;
72- u64 highest_perf , nominal_perf ;
83+ u64 numerator , nominal_perf ;
7384 u64 perf_ratio ;
7485 int rc ;
7586
@@ -79,15 +90,19 @@ static void amd_set_max_freq_ratio(void)
7990 return ;
8091 }
8192
82- highest_perf = amd_get_highest_perf ();
93+ rc = amd_get_boost_ratio_numerator (0 , & numerator );
94+ if (rc ) {
95+ pr_debug ("Could not retrieve highest performance (%d)\n" , rc );
96+ return ;
97+ }
8398 nominal_perf = perf_caps .nominal_perf ;
8499
85- if (!highest_perf || ! nominal_perf ) {
86- pr_debug ("Could not retrieve highest or nominal performance\n" );
100+ if (!nominal_perf ) {
101+ pr_debug ("Could not retrieve nominal performance\n" );
87102 return ;
88103 }
89104
90- perf_ratio = div_u64 (highest_perf * SCHED_CAPACITY_SCALE , nominal_perf );
105+ perf_ratio = div_u64 (numerator * SCHED_CAPACITY_SCALE , nominal_perf );
91106 /* midpoint between max_boost and max_P */
92107 perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE ) >> 1 ;
93108 if (!perf_ratio ) {
@@ -100,7 +115,7 @@ static void amd_set_max_freq_ratio(void)
100115
101116static DEFINE_MUTEX (freq_invariance_lock );
102117
103- void init_freq_invariance_cppc (void )
118+ static inline void init_freq_invariance_cppc (void )
104119{
105120 static bool init_done ;
106121
@@ -116,3 +131,148 @@ void init_freq_invariance_cppc(void)
116131 init_done = true;
117132 mutex_unlock (& freq_invariance_lock );
118133}
134+
135+ void acpi_processor_init_invariance_cppc (void )
136+ {
137+ init_freq_invariance_cppc ();
138+ }
139+
140+ /*
141+ * Get the highest performance register value.
142+ * @cpu: CPU from which to get highest performance.
143+ * @highest_perf: Return address for highest performance value.
144+ *
145+ * Return: 0 for success, negative error code otherwise.
146+ */
147+ int amd_get_highest_perf (unsigned int cpu , u32 * highest_perf )
148+ {
149+ u64 val ;
150+ int ret ;
151+
152+ if (cpu_feature_enabled (X86_FEATURE_CPPC )) {
153+ ret = rdmsrl_safe_on_cpu (cpu , MSR_AMD_CPPC_CAP1 , & val );
154+ if (ret )
155+ goto out ;
156+
157+ val = AMD_CPPC_HIGHEST_PERF (val );
158+ } else {
159+ ret = cppc_get_highest_perf (cpu , & val );
160+ if (ret )
161+ goto out ;
162+ }
163+
164+ WRITE_ONCE (* highest_perf , (u32 )val );
165+ out :
166+ return ret ;
167+ }
168+ EXPORT_SYMBOL_GPL (amd_get_highest_perf );
169+
170+ /**
171+ * amd_detect_prefcore: Detect if CPUs in the system support preferred cores
172+ * @detected: Output variable for the result of the detection.
173+ *
174+ * Determine whether CPUs in the system support preferred cores. On systems
175+ * that support preferred cores, different highest perf values will be found
176+ * on different cores. On other systems, the highest perf value will be the
177+ * same on all cores.
178+ *
179+ * The result of the detection will be stored in the 'detected' parameter.
180+ *
181+ * Return: 0 for success, negative error code otherwise
182+ */
183+ int amd_detect_prefcore (bool * detected )
184+ {
185+ int cpu , count = 0 ;
186+ u64 highest_perf [2 ] = {0 };
187+
188+ if (WARN_ON (!detected ))
189+ return - EINVAL ;
190+
191+ switch (amd_pref_core_detected ) {
192+ case AMD_PREF_CORE_SUPPORTED :
193+ * detected = true;
194+ return 0 ;
195+ case AMD_PREF_CORE_UNSUPPORTED :
196+ * detected = false;
197+ return 0 ;
198+ default :
199+ break ;
200+ }
201+
202+ for_each_present_cpu (cpu ) {
203+ u32 tmp ;
204+ int ret ;
205+
206+ ret = amd_get_highest_perf (cpu , & tmp );
207+ if (ret )
208+ return ret ;
209+
210+ if (!count || (count == 1 && tmp != highest_perf [0 ]))
211+ highest_perf [count ++ ] = tmp ;
212+
213+ if (count == 2 )
214+ break ;
215+ }
216+
217+ * detected = (count == 2 );
218+ boost_numerator = highest_perf [0 ];
219+
220+ amd_pref_core_detected = * detected ? AMD_PREF_CORE_SUPPORTED :
221+ AMD_PREF_CORE_UNSUPPORTED ;
222+
223+ pr_debug ("AMD CPPC preferred core is %ssupported (highest perf: 0x%llx)\n" ,
224+ * detected ? "" : "un" , highest_perf [0 ]);
225+
226+ return 0 ;
227+ }
228+ EXPORT_SYMBOL_GPL (amd_detect_prefcore );
229+
230+ /**
231+ * amd_get_boost_ratio_numerator: Get the numerator to use for boost ratio calculation
232+ * @cpu: CPU to get numerator for.
233+ * @numerator: Output variable for numerator.
234+ *
235+ * Determine the numerator to use for calculating the boost ratio on
236+ * a CPU. On systems that support preferred cores, this will be a hardcoded
237+ * value. On other systems this will the highest performance register value.
238+ *
239+ * If booting the system with amd-pstate enabled but preferred cores disabled then
240+ * the correct boost numerator will be returned to match hardware capabilities
241+ * even if the preferred cores scheduling hints are not enabled.
242+ *
243+ * Return: 0 for success, negative error code otherwise.
244+ */
245+ int amd_get_boost_ratio_numerator (unsigned int cpu , u64 * numerator )
246+ {
247+ bool prefcore ;
248+ int ret ;
249+
250+ ret = amd_detect_prefcore (& prefcore );
251+ if (ret )
252+ return ret ;
253+
254+ /* without preferred cores, return the highest perf register value */
255+ if (!prefcore ) {
256+ * numerator = boost_numerator ;
257+ return 0 ;
258+ }
259+
260+ /*
261+ * For AMD CPUs with Family ID 19H and Model ID range 0x70 to 0x7f,
262+ * the highest performance level is set to 196.
263+ * https://bugzilla.kernel.org/show_bug.cgi?id=218759
264+ */
265+ if (cpu_feature_enabled (X86_FEATURE_ZEN4 )) {
266+ switch (boot_cpu_data .x86_model ) {
267+ case 0x70 ... 0x7f :
268+ * numerator = CPPC_HIGHEST_PERF_PERFORMANCE ;
269+ return 0 ;
270+ default :
271+ break ;
272+ }
273+ }
274+ * numerator = CPPC_HIGHEST_PERF_PREFCORE ;
275+
276+ return 0 ;
277+ }
278+ EXPORT_SYMBOL_GPL (amd_get_boost_ratio_numerator );
0 commit comments