Skip to content

Commit 50b813b

Browse files
vingu-linaroingomolnar
authored andcommitted
cpufreq/cppc: Move and rename cppc_cpufreq_{perf_to_khz|khz_to_perf}()
Move and rename cppc_cpufreq_perf_to_khz() and cppc_cpufreq_khz_to_perf() to use them outside cppc_cpufreq in topology_init_cpu_capacity_cppc(). Modify the interface to use struct cppc_perf_caps *caps instead of struct cppc_cpudata *cpu_data as we only use the fields of cppc_perf_caps. cppc_cpufreq was converting the lowest and nominal freq from MHz to kHz before using them. We move this conversion inside cppc_perf_to_khz and cppc_khz_to_perf to make them generic and usable outside cppc_cpufreq. No functional change Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Tested-by: Pierre Gondois <pierre.gondois@arm.com> Acked-by: Rafael J. Wysocki <rafael@kernel.org> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Link: https://lore.kernel.org/r/20231211104855.558096-6-vincent.guittot@linaro.org
1 parent 15cbbd1 commit 50b813b

3 files changed

Lines changed: 123 additions & 122 deletions

File tree

drivers/acpi/cppc_acpi.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
#include <linux/rwsem.h>
4040
#include <linux/wait.h>
4141
#include <linux/topology.h>
42+
#include <linux/dmi.h>
43+
#include <linux/units.h>
44+
#include <asm/unaligned.h>
4245

4346
#include <acpi/cppc_acpi.h>
4447

@@ -1760,3 +1763,104 @@ unsigned int cppc_get_transition_latency(int cpu_num)
17601763
return latency_ns;
17611764
}
17621765
EXPORT_SYMBOL_GPL(cppc_get_transition_latency);
1766+
1767+
/* Minimum struct length needed for the DMI processor entry we want */
1768+
#define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48
1769+
1770+
/* Offset in the DMI processor structure for the max frequency */
1771+
#define DMI_PROCESSOR_MAX_SPEED 0x14
1772+
1773+
/* Callback function used to retrieve the max frequency from DMI */
1774+
static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
1775+
{
1776+
const u8 *dmi_data = (const u8 *)dm;
1777+
u16 *mhz = (u16 *)private;
1778+
1779+
if (dm->type == DMI_ENTRY_PROCESSOR &&
1780+
dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) {
1781+
u16 val = (u16)get_unaligned((const u16 *)
1782+
(dmi_data + DMI_PROCESSOR_MAX_SPEED));
1783+
*mhz = val > *mhz ? val : *mhz;
1784+
}
1785+
}
1786+
1787+
/* Look up the max frequency in DMI */
1788+
static u64 cppc_get_dmi_max_khz(void)
1789+
{
1790+
u16 mhz = 0;
1791+
1792+
dmi_walk(cppc_find_dmi_mhz, &mhz);
1793+
1794+
/*
1795+
* Real stupid fallback value, just in case there is no
1796+
* actual value set.
1797+
*/
1798+
mhz = mhz ? mhz : 1;
1799+
1800+
return KHZ_PER_MHZ * mhz;
1801+
}
1802+
1803+
/*
1804+
* If CPPC lowest_freq and nominal_freq registers are exposed then we can
1805+
* use them to convert perf to freq and vice versa. The conversion is
1806+
* extrapolated as an affine function passing by the 2 points:
1807+
* - (Low perf, Low freq)
1808+
* - (Nominal perf, Nominal freq)
1809+
*/
1810+
unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf)
1811+
{
1812+
s64 retval, offset = 0;
1813+
static u64 max_khz;
1814+
u64 mul, div;
1815+
1816+
if (caps->lowest_freq && caps->nominal_freq) {
1817+
mul = caps->nominal_freq - caps->lowest_freq;
1818+
mul *= KHZ_PER_MHZ;
1819+
div = caps->nominal_perf - caps->lowest_perf;
1820+
offset = caps->nominal_freq * KHZ_PER_MHZ -
1821+
div64_u64(caps->nominal_perf * mul, div);
1822+
} else {
1823+
if (!max_khz)
1824+
max_khz = cppc_get_dmi_max_khz();
1825+
mul = max_khz;
1826+
div = caps->highest_perf;
1827+
}
1828+
1829+
retval = offset + div64_u64(perf * mul, div);
1830+
if (retval >= 0)
1831+
return retval;
1832+
return 0;
1833+
}
1834+
EXPORT_SYMBOL_GPL(cppc_perf_to_khz);
1835+
1836+
unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq)
1837+
{
1838+
s64 retval, offset = 0;
1839+
static u64 max_khz;
1840+
u64 mul, div;
1841+
1842+
if (caps->lowest_freq && caps->nominal_freq) {
1843+
mul = caps->nominal_perf - caps->lowest_perf;
1844+
div = caps->nominal_freq - caps->lowest_freq;
1845+
/*
1846+
* We don't need to convert to kHz for computing offset and can
1847+
* directly use nominal_freq and lowest_freq as the div64_u64
1848+
* will remove the frequency unit.
1849+
*/
1850+
offset = caps->nominal_perf -
1851+
div64_u64(caps->nominal_freq * mul, div);
1852+
/* But we need it for computing the perf level. */
1853+
div *= KHZ_PER_MHZ;
1854+
} else {
1855+
if (!max_khz)
1856+
max_khz = cppc_get_dmi_max_khz();
1857+
mul = caps->highest_perf;
1858+
div = max_khz;
1859+
}
1860+
1861+
retval = offset + div64_u64(freq * mul, div);
1862+
if (retval >= 0)
1863+
return retval;
1864+
return 0;
1865+
}
1866+
EXPORT_SYMBOL_GPL(cppc_khz_to_perf);

drivers/cpufreq/cppc_cpufreq.c

Lines changed: 17 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include <linux/delay.h>
1717
#include <linux/cpu.h>
1818
#include <linux/cpufreq.h>
19-
#include <linux/dmi.h>
2019
#include <linux/irq_work.h>
2120
#include <linux/kthread.h>
2221
#include <linux/time.h>
@@ -27,12 +26,6 @@
2726

2827
#include <acpi/cppc_acpi.h>
2928

30-
/* Minimum struct length needed for the DMI processor entry we want */
31-
#define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48
32-
33-
/* Offset in the DMI processor structure for the max frequency */
34-
#define DMI_PROCESSOR_MAX_SPEED 0x14
35-
3629
/*
3730
* This list contains information parsed from per CPU ACPI _CPC and _PSD
3831
* structures: e.g. the highest and lowest supported performance, capabilities,
@@ -291,105 +284,17 @@ static inline void cppc_freq_invariance_exit(void)
291284
}
292285
#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
293286

294-
/* Callback function used to retrieve the max frequency from DMI */
295-
static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
296-
{
297-
const u8 *dmi_data = (const u8 *)dm;
298-
u16 *mhz = (u16 *)private;
299-
300-
if (dm->type == DMI_ENTRY_PROCESSOR &&
301-
dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) {
302-
u16 val = (u16)get_unaligned((const u16 *)
303-
(dmi_data + DMI_PROCESSOR_MAX_SPEED));
304-
*mhz = val > *mhz ? val : *mhz;
305-
}
306-
}
307-
308-
/* Look up the max frequency in DMI */
309-
static u64 cppc_get_dmi_max_khz(void)
310-
{
311-
u16 mhz = 0;
312-
313-
dmi_walk(cppc_find_dmi_mhz, &mhz);
314-
315-
/*
316-
* Real stupid fallback value, just in case there is no
317-
* actual value set.
318-
*/
319-
mhz = mhz ? mhz : 1;
320-
321-
return (1000 * mhz);
322-
}
323-
324-
/*
325-
* If CPPC lowest_freq and nominal_freq registers are exposed then we can
326-
* use them to convert perf to freq and vice versa. The conversion is
327-
* extrapolated as an affine function passing by the 2 points:
328-
* - (Low perf, Low freq)
329-
* - (Nominal perf, Nominal perf)
330-
*/
331-
static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu_data,
332-
unsigned int perf)
333-
{
334-
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
335-
s64 retval, offset = 0;
336-
static u64 max_khz;
337-
u64 mul, div;
338-
339-
if (caps->lowest_freq && caps->nominal_freq) {
340-
mul = caps->nominal_freq - caps->lowest_freq;
341-
div = caps->nominal_perf - caps->lowest_perf;
342-
offset = caps->nominal_freq - div64_u64(caps->nominal_perf * mul, div);
343-
} else {
344-
if (!max_khz)
345-
max_khz = cppc_get_dmi_max_khz();
346-
mul = max_khz;
347-
div = caps->highest_perf;
348-
}
349-
350-
retval = offset + div64_u64(perf * mul, div);
351-
if (retval >= 0)
352-
return retval;
353-
return 0;
354-
}
355-
356-
static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu_data,
357-
unsigned int freq)
358-
{
359-
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
360-
s64 retval, offset = 0;
361-
static u64 max_khz;
362-
u64 mul, div;
363-
364-
if (caps->lowest_freq && caps->nominal_freq) {
365-
mul = caps->nominal_perf - caps->lowest_perf;
366-
div = caps->nominal_freq - caps->lowest_freq;
367-
offset = caps->nominal_perf - div64_u64(caps->nominal_freq * mul, div);
368-
} else {
369-
if (!max_khz)
370-
max_khz = cppc_get_dmi_max_khz();
371-
mul = caps->highest_perf;
372-
div = max_khz;
373-
}
374-
375-
retval = offset + div64_u64(freq * mul, div);
376-
if (retval >= 0)
377-
return retval;
378-
return 0;
379-
}
380-
381287
static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
382288
unsigned int target_freq,
383289
unsigned int relation)
384-
385290
{
386291
struct cppc_cpudata *cpu_data = policy->driver_data;
387292
unsigned int cpu = policy->cpu;
388293
struct cpufreq_freqs freqs;
389294
u32 desired_perf;
390295
int ret = 0;
391296

392-
desired_perf = cppc_cpufreq_khz_to_perf(cpu_data, target_freq);
297+
desired_perf = cppc_khz_to_perf(&cpu_data->perf_caps, target_freq);
393298
/* Return if it is exactly the same perf */
394299
if (desired_perf == cpu_data->perf_ctrls.desired_perf)
395300
return ret;
@@ -417,7 +322,7 @@ static unsigned int cppc_cpufreq_fast_switch(struct cpufreq_policy *policy,
417322
u32 desired_perf;
418323
int ret;
419324

420-
desired_perf = cppc_cpufreq_khz_to_perf(cpu_data, target_freq);
325+
desired_perf = cppc_khz_to_perf(&cpu_data->perf_caps, target_freq);
421326
cpu_data->perf_ctrls.desired_perf = desired_perf;
422327
ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
423328

@@ -530,7 +435,7 @@ static int cppc_get_cpu_power(struct device *cpu_dev,
530435
min_step = min_cap / CPPC_EM_CAP_STEP;
531436
max_step = max_cap / CPPC_EM_CAP_STEP;
532437

533-
perf_prev = cppc_cpufreq_khz_to_perf(cpu_data, *KHz);
438+
perf_prev = cppc_khz_to_perf(perf_caps, *KHz);
534439
step = perf_prev / perf_step;
535440

536441
if (step > max_step)
@@ -550,8 +455,8 @@ static int cppc_get_cpu_power(struct device *cpu_dev,
550455
perf = step * perf_step;
551456
}
552457

553-
*KHz = cppc_cpufreq_perf_to_khz(cpu_data, perf);
554-
perf_check = cppc_cpufreq_khz_to_perf(cpu_data, *KHz);
458+
*KHz = cppc_perf_to_khz(perf_caps, perf);
459+
perf_check = cppc_khz_to_perf(perf_caps, *KHz);
555460
step_check = perf_check / perf_step;
556461

557462
/*
@@ -561,8 +466,8 @@ static int cppc_get_cpu_power(struct device *cpu_dev,
561466
*/
562467
while ((*KHz == prev_freq) || (step_check != step)) {
563468
perf++;
564-
*KHz = cppc_cpufreq_perf_to_khz(cpu_data, perf);
565-
perf_check = cppc_cpufreq_khz_to_perf(cpu_data, *KHz);
469+
*KHz = cppc_perf_to_khz(perf_caps, perf);
470+
perf_check = cppc_khz_to_perf(perf_caps, *KHz);
566471
step_check = perf_check / perf_step;
567472
}
568473

@@ -591,7 +496,7 @@ static int cppc_get_cpu_cost(struct device *cpu_dev, unsigned long KHz,
591496
perf_caps = &cpu_data->perf_caps;
592497
max_cap = arch_scale_cpu_capacity(cpu_dev->id);
593498

594-
perf_prev = cppc_cpufreq_khz_to_perf(cpu_data, KHz);
499+
perf_prev = cppc_khz_to_perf(perf_caps, KHz);
595500
perf_step = CPPC_EM_CAP_STEP * perf_caps->highest_perf / max_cap;
596501
step = perf_prev / perf_step;
597502

@@ -679,10 +584,6 @@ static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu)
679584
goto free_mask;
680585
}
681586

682-
/* Convert the lowest and nominal freq from MHz to KHz */
683-
cpu_data->perf_caps.lowest_freq *= 1000;
684-
cpu_data->perf_caps.nominal_freq *= 1000;
685-
686587
list_add(&cpu_data->node, &cpu_data_list);
687588

688589
return cpu_data;
@@ -724,20 +625,16 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
724625
* Set min to lowest nonlinear perf to avoid any efficiency penalty (see
725626
* Section 8.4.7.1.1.5 of ACPI 6.1 spec)
726627
*/
727-
policy->min = cppc_cpufreq_perf_to_khz(cpu_data,
728-
caps->lowest_nonlinear_perf);
729-
policy->max = cppc_cpufreq_perf_to_khz(cpu_data,
730-
caps->nominal_perf);
628+
policy->min = cppc_perf_to_khz(caps, caps->lowest_nonlinear_perf);
629+
policy->max = cppc_perf_to_khz(caps, caps->nominal_perf);
731630

732631
/*
733632
* Set cpuinfo.min_freq to Lowest to make the full range of performance
734633
* available if userspace wants to use any perf between lowest & lowest
735634
* nonlinear perf
736635
*/
737-
policy->cpuinfo.min_freq = cppc_cpufreq_perf_to_khz(cpu_data,
738-
caps->lowest_perf);
739-
policy->cpuinfo.max_freq = cppc_cpufreq_perf_to_khz(cpu_data,
740-
caps->nominal_perf);
636+
policy->cpuinfo.min_freq = cppc_perf_to_khz(caps, caps->lowest_perf);
637+
policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->nominal_perf);
741638

742639
policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu);
743640
policy->shared_type = cpu_data->shared_type;
@@ -773,7 +670,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
773670
boost_supported = true;
774671

775672
/* Set policy->cur to max now. The governors will adjust later. */
776-
policy->cur = cppc_cpufreq_perf_to_khz(cpu_data, caps->highest_perf);
673+
policy->cur = cppc_perf_to_khz(caps, caps->highest_perf);
777674
cpu_data->perf_ctrls.desired_perf = caps->highest_perf;
778675

779676
ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
@@ -863,7 +760,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
863760
delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0,
864761
&fb_ctrs_t1);
865762

866-
return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf);
763+
return cppc_perf_to_khz(&cpu_data->perf_caps, delivered_perf);
867764
}
868765

869766
static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state)
@@ -878,11 +775,9 @@ static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state)
878775
}
879776

880777
if (state)
881-
policy->max = cppc_cpufreq_perf_to_khz(cpu_data,
882-
caps->highest_perf);
778+
policy->max = cppc_perf_to_khz(caps, caps->highest_perf);
883779
else
884-
policy->max = cppc_cpufreq_perf_to_khz(cpu_data,
885-
caps->nominal_perf);
780+
policy->max = cppc_perf_to_khz(caps, caps->nominal_perf);
886781
policy->cpuinfo.max_freq = policy->max;
887782

888783
ret = freq_qos_update_request(policy->max_freq_req, policy->max);
@@ -937,7 +832,7 @@ static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu)
937832
if (ret < 0)
938833
return -EIO;
939834

940-
return cppc_cpufreq_perf_to_khz(cpu_data, desired_perf);
835+
return cppc_perf_to_khz(&cpu_data->perf_caps, desired_perf);
941836
}
942837

943838
static void cppc_check_hisi_workaround(void)

include/acpi/cppc_acpi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
144144
extern int cppc_set_enable(int cpu, bool enable);
145145
extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
146146
extern bool cppc_perf_ctrs_in_pcc(void);
147+
extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf);
148+
extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq);
147149
extern bool acpi_cpc_valid(void);
148150
extern bool cppc_allow_fast_switch(void);
149151
extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);

0 commit comments

Comments
 (0)