Unverified Commit 85ab6fdf authored by Palmer Dabbelt's avatar Palmer Dabbelt
Browse files

Merge patch series "RISC-V: ACPI: Add LPI support"

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

This series adds support for Low Power Idle (LPI) on ACPI based
platforms.

LPI 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#lpi-low-power-idle-states
[2] - https://github.com/riscv-non-isa/riscv-acpi-ffh/releases/download/v/riscv-ffh.pdf

* b4-shazam-merge:
  ACPI: Enable ACPI_PROCESSOR for RISC-V
  ACPI: RISC-V: Add LPI driver
  cpuidle: RISC-V: Move few functions to arch/riscv

Link: https://lore.kernel.org/r/20240118062930.245937-1-sunilvl@ventanamicro.com


Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parents 728e7ea2 359df7c5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -55,4 +55,7 @@ int hibernate_resume_nonboot_cpu_disable(void);
asmlinkage void hibernate_restore_image(unsigned long resume_satp, unsigned long satp_temp,
					unsigned long cpu_resume);
asmlinkage int hibernate_core_restore_code(void);
bool riscv_sbi_hsm_is_supported(void);
bool riscv_sbi_suspend_state_is_valid(u32 state);
int riscv_sbi_hart_suspend(u32 state);
#endif
+49 −0
Original line number Diff line number Diff line
@@ -128,4 +128,53 @@ static int __init sbi_system_suspend_init(void)
}

arch_initcall(sbi_system_suspend_init);

static int sbi_suspend_finisher(unsigned long suspend_type,
				unsigned long resume_addr,
				unsigned long opaque)
{
	struct sbiret ret;

	ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_SUSPEND,
			suspend_type, resume_addr, opaque, 0, 0, 0);

	return (ret.error) ? sbi_err_map_linux_errno(ret.error) : 0;
}

int riscv_sbi_hart_suspend(u32 state)
{
	if (state & SBI_HSM_SUSP_NON_RET_BIT)
		return cpu_suspend(state, sbi_suspend_finisher);
	else
		return sbi_suspend_finisher(state, 0, 0);
}

bool riscv_sbi_suspend_state_is_valid(u32 state)
{
	if (state > SBI_HSM_SUSPEND_RET_DEFAULT &&
	    state < SBI_HSM_SUSPEND_RET_PLATFORM)
		return false;

	if (state > SBI_HSM_SUSPEND_NON_RET_DEFAULT &&
	    state < SBI_HSM_SUSPEND_NON_RET_PLATFORM)
		return false;

	return true;
}

bool riscv_sbi_hsm_is_supported(void)
{
	/*
	 * The SBI HSM suspend function is only available when:
	 * 1) SBI version is 0.3 or higher
	 * 2) SBI HSM extension is available
	 */
	if (sbi_spec_version < sbi_mk_version(0, 3) ||
	    !sbi_probe_extension(SBI_EXT_HSM)) {
		pr_info("HSM suspend not available\n");
		return false;
	}

	return true;
}
#endif /* CONFIG_RISCV_SBI */
+1 −1
Original line number Diff line number Diff line
@@ -286,7 +286,7 @@ config ACPI_CPPC_LIB

config ACPI_PROCESSOR
	tristate "Processor"
	depends on X86 || ARM64 || LOONGARCH
	depends on X86 || ARM64 || LOONGARCH || RISCV
	select ACPI_PROCESSOR_IDLE
	select ACPI_CPU_FREQ_PSS if X86 || LOONGARCH
	select THERMAL
+2 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
obj-y					+= rhct.o
obj-$(CONFIG_ACPI_PROCESSOR_IDLE)	+= cpuidle.o
+81 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2024, Ventana Micro Systems Inc
 *	Author: Sunil V L <sunilvl@ventanamicro.com>
 *
 */

#include <linux/acpi.h>
#include <acpi/processor.h>
#include <linux/cpu_pm.h>
#include <linux/cpuidle.h>
#include <linux/suspend.h>
#include <asm/cpuidle.h>
#include <asm/sbi.h>
#include <asm/suspend.h>

#define RISCV_FFH_LPI_TYPE_MASK	GENMASK_ULL(63, 60)
#define RISCV_FFH_LPI_RSVD_MASK	GENMASK_ULL(59, 32)

#define RISCV_FFH_LPI_TYPE_SBI	BIT_ULL(60)

static int acpi_cpu_init_idle(unsigned int cpu)
{
	int i;
	struct acpi_lpi_state *lpi;
	struct acpi_processor *pr = per_cpu(processors, cpu);

	if (unlikely(!pr || !pr->flags.has_lpi))
		return -EINVAL;

	if (!riscv_sbi_hsm_is_supported())
		return -ENODEV;

	if (pr->power.count <= 1)
		return -ENODEV;

	for (i = 1; i < pr->power.count; i++) {
		u32 state;

		lpi = &pr->power.lpi_states[i];

		/*
		 * Validate Entry Method as per FFH spec.
		 * bits[63:60] should be 0x1
		 * bits[59:32] should be 0x0
		 * bits[31:0] represent a SBI power_state
		 */
		if (((lpi->address & RISCV_FFH_LPI_TYPE_MASK) != RISCV_FFH_LPI_TYPE_SBI) ||
		    (lpi->address & RISCV_FFH_LPI_RSVD_MASK)) {
			pr_warn("Invalid LPI entry method %#llx\n", lpi->address);
			return -EINVAL;
		}

		state = lpi->address;
		if (!riscv_sbi_suspend_state_is_valid(state)) {
			pr_warn("Invalid SBI power state %#x\n", state);
			return -EINVAL;
		}
	}

	return 0;
}

int acpi_processor_ffh_lpi_probe(unsigned int cpu)
{
	return acpi_cpu_init_idle(cpu);
}

int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
{
	u32 state = lpi->address;

	if (state & SBI_HSM_SUSP_NON_RET_BIT)
		return CPU_PM_CPU_IDLE_ENTER_PARAM(riscv_sbi_hart_suspend,
						   lpi->index,
						   state);
	else
		return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(riscv_sbi_hart_suspend,
							     lpi->index,
							     state);
}
Loading