Merge patch series "RISC-V: ACPI: Enable CPPC based cpufreq support"

Sunil V L <sunilvl@ventanamicro.com> says:

This series enables the support for "Collaborative Processor Performance
Control (CPPC) on ACPI based RISC-V platforms. It depends on the
encoding of CPPC registers as defined in RISC-V FFH spec [2].

CPPC is described in the ACPI spec [1]. RISC-V FFH spec required to
enable this, is available at [2].

[1] - https://uefi.org/specs/ACPI/6.5/08_Processor_Configuration_and_Control.html#collaborative-processor-performance-control
[2] - https://github.com/riscv-non-isa/riscv-acpi-ffh/releases/download/v1.0.0/riscv-ffh.pdf

* b4-shazam-merge:
  RISC-V: defconfig: Enable CONFIG_ACPI_CPPC_CPUFREQ
  cpufreq: Move CPPC configs to common Kconfig and add RISC-V
  ACPI: RISC-V: Add CPPC driver

Link: https://lore.kernel.org/r/20240208034414.22579-1-sunilvl@ventanamicro.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
This commit is contained in:
Palmer Dabbelt 2024-03-19 18:30:58 -07:00
commit 028d1aee1f
No known key found for this signature in database
GPG Key ID: 2E1319F35FBB1889
5 changed files with 188 additions and 26 deletions

View File

@ -44,6 +44,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
CONFIG_CPUFREQ_DT=y CONFIG_CPUFREQ_DT=y
CONFIG_ACPI_CPPC_CPUFREQ=m
CONFIG_VIRTUALIZATION=y CONFIG_VIRTUALIZATION=y
CONFIG_KVM=m CONFIG_KVM=m
CONFIG_ACPI=y CONFIG_ACPI=y

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
obj-y += rhct.o obj-y += rhct.o
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o

157
drivers/acpi/riscv/cppc.c Normal file
View File

@ -0,0 +1,157 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Implement CPPC FFH helper routines for RISC-V.
*
* Copyright (C) 2024 Ventana Micro Systems Inc.
*/
#include <acpi/cppc_acpi.h>
#include <asm/csr.h>
#include <asm/sbi.h>
#define SBI_EXT_CPPC 0x43505043
/* CPPC interfaces defined in SBI spec */
#define SBI_CPPC_PROBE 0x0
#define SBI_CPPC_READ 0x1
#define SBI_CPPC_READ_HI 0x2
#define SBI_CPPC_WRITE 0x3
/* RISC-V FFH definitions from RISC-V FFH spec */
#define FFH_CPPC_TYPE(r) (((r) & GENMASK_ULL(63, 60)) >> 60)
#define FFH_CPPC_SBI_REG(r) ((r) & GENMASK(31, 0))
#define FFH_CPPC_CSR_NUM(r) ((r) & GENMASK(11, 0))
#define FFH_CPPC_SBI 0x1
#define FFH_CPPC_CSR 0x2
struct sbi_cppc_data {
u64 val;
u32 reg;
struct sbiret ret;
};
static bool cppc_ext_present;
static int __init sbi_cppc_init(void)
{
if (sbi_spec_version >= sbi_mk_version(2, 0) &&
sbi_probe_extension(SBI_EXT_CPPC) > 0) {
pr_info("SBI CPPC extension detected\n");
cppc_ext_present = true;
} else {
pr_info("SBI CPPC extension NOT detected!!\n");
cppc_ext_present = false;
}
return 0;
}
device_initcall(sbi_cppc_init);
static void sbi_cppc_read(void *read_data)
{
struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_READ,
data->reg, 0, 0, 0, 0, 0);
}
static void sbi_cppc_write(void *write_data)
{
struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_WRITE,
data->reg, data->val, 0, 0, 0, 0);
}
static void cppc_ffh_csr_read(void *read_data)
{
struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
switch (data->reg) {
/* Support only TIME CSR for now */
case CSR_TIME:
data->ret.value = csr_read(CSR_TIME);
data->ret.error = 0;
break;
default:
data->ret.error = -EINVAL;
break;
}
}
static void cppc_ffh_csr_write(void *write_data)
{
struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
data->ret.error = -EINVAL;
}
/*
* Refer to drivers/acpi/cppc_acpi.c for the description of the functions
* below.
*/
bool cpc_ffh_supported(void)
{
return true;
}
int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
{
struct sbi_cppc_data data;
if (WARN_ON_ONCE(irqs_disabled()))
return -EPERM;
if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
if (!cppc_ext_present)
return -EINVAL;
data.reg = FFH_CPPC_SBI_REG(reg->address);
smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
*val = data.ret.value;
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
data.reg = FFH_CPPC_CSR_NUM(reg->address);
smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
*val = data.ret.value;
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
}
return -EINVAL;
}
int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
{
struct sbi_cppc_data data;
if (WARN_ON_ONCE(irqs_disabled()))
return -EPERM;
if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
if (!cppc_ext_present)
return -EINVAL;
data.reg = FFH_CPPC_SBI_REG(reg->address);
data.val = val;
smp_call_function_single(cpu, sbi_cppc_write, &data, 1);
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
data.reg = FFH_CPPC_CSR_NUM(reg->address);
data.val = val;
smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1);
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
}
return -EINVAL;
}

View File

@ -302,4 +302,33 @@ config QORIQ_CPUFREQ
which are capable of changing the CPU's frequency dynamically. which are capable of changing the CPU's frequency dynamically.
endif endif
config ACPI_CPPC_CPUFREQ
tristate "CPUFreq driver based on the ACPI CPPC spec"
depends on ACPI_PROCESSOR
depends on ARM || ARM64 || RISCV
select ACPI_CPPC_LIB
help
This adds a CPUFreq driver which uses CPPC methods
as described in the ACPIv5.1 spec. CPPC stands for
Collaborative Processor Performance Controls. It
is based on an abstract continuous scale of CPU
performance values which allows the remote power
processor to flexibly optimize for power and
performance. CPPC relies on power management firmware
support for its operation.
If in doubt, say N.
config ACPI_CPPC_CPUFREQ_FIE
bool "Frequency Invariance support for CPPC cpufreq driver"
depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY
depends on ARM || ARM64 || RISCV
default y
help
This extends frequency invariance support in the CPPC cpufreq driver,
by using CPPC delivered and reference performance counters.
If in doubt, say N.
endmenu endmenu

View File

@ -3,32 +3,6 @@
# ARM CPU Frequency scaling drivers # ARM CPU Frequency scaling drivers
# #
config ACPI_CPPC_CPUFREQ
tristate "CPUFreq driver based on the ACPI CPPC spec"
depends on ACPI_PROCESSOR
select ACPI_CPPC_LIB
help
This adds a CPUFreq driver which uses CPPC methods
as described in the ACPIv5.1 spec. CPPC stands for
Collaborative Processor Performance Controls. It
is based on an abstract continuous scale of CPU
performance values which allows the remote power
processor to flexibly optimize for power and
performance. CPPC relies on power management firmware
support for its operation.
If in doubt, say N.
config ACPI_CPPC_CPUFREQ_FIE
bool "Frequency Invariance support for CPPC cpufreq driver"
depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY
default y
help
This extends frequency invariance support in the CPPC cpufreq driver,
by using CPPC delivered and reference performance counters.
If in doubt, say N.
config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
tristate "Allwinner nvmem based SUN50I CPUFreq driver" tristate "Allwinner nvmem based SUN50I CPUFreq driver"
depends on ARCH_SUNXI depends on ARCH_SUNXI