[RFC PATCH v2 20/58] KVM: arm64: Support power domains
Mostafa Saleh
smostafa at google.com
Thu Dec 12 10:03:44 PST 2024
Unfortunately, as power management is not widely standardized we have
to work around that.
One implementation we can support is HOST_HVC, where the host
is in control of the power management and it notifies the
hypervisor about the updates.
This adds extra constraints to the IOMMUs, as they must reset to
blocking DMA traffic to be able to use this PD interface.
Unfortunately again, for SMMUv3 which is the only IOMMU currently
supported, there is no architectural way to discover this, so we
rely on enabling this driver when it fits the constraints, also
the driver sets GBPA and assumes that the SMMU retains across
power cycling.
In the next patch SCMI support is added.
Signed-off-by: Mostafa Saleh <smostafa at google.com>
Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
---
arch/arm64/include/asm/kvm_asm.h | 1 +
arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 30 ++++++++++++++++
arch/arm64/kvm/hyp/nvhe/Makefile | 2 +-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 9 +++++
arch/arm64/kvm/hyp/nvhe/power/hvc.c | 47 ++++++++++++++++++++++++++
include/kvm/power_domain.h | 17 ++++++++++
6 files changed, 105 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/kvm/hyp/nvhe/power/hvc.c
create mode 100644 include/kvm/power_domain.h
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 9ea155a04332..3dbf30cd10f3 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -114,6 +114,7 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___pkvm_host_iommu_map_pages,
__KVM_HOST_SMCCC_FUNC___pkvm_host_iommu_unmap_pages,
__KVM_HOST_SMCCC_FUNC___pkvm_host_iommu_iova_to_phys,
+ __KVM_HOST_SMCCC_FUNC___pkvm_host_hvc_pd,
/*
* Start of the dynamically registered hypercalls. Start a bit
diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
index 8a5554615e40..e4a94696b10e 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
@@ -8,6 +8,7 @@
#define __ARM64_KVM_NVHE_PKVM_H__
#include <asm/kvm_pkvm.h>
+#include <kvm/power_domain.h>
#include <nvhe/gfp.h>
#include <nvhe/spinlock.h>
@@ -146,4 +147,33 @@ void pkvm_poison_pvmfw_pages(void);
int pkvm_timer_init(void);
void pkvm_udelay(unsigned long usecs);
+#define MAX_POWER_DOMAINS 32
+
+struct kvm_power_domain_ops {
+ int (*power_on)(struct kvm_power_domain *pd);
+ int (*power_off)(struct kvm_power_domain *pd);
+};
+
+int pkvm_init_hvc_pd(struct kvm_power_domain *pd,
+ const struct kvm_power_domain_ops *ops);
+
+int pkvm_host_hvc_pd(u64 device_id, u64 on);
+
+/*
+ * Register a power domain. When the hypervisor catches power requests from the
+ * host for this power domain, it calls the power ops with @pd as argument.
+ */
+static inline int pkvm_init_power_domain(struct kvm_power_domain *pd,
+ const struct kvm_power_domain_ops *ops)
+{
+ switch (pd->type) {
+ case KVM_POWER_DOMAIN_NONE:
+ return 0;
+ case KVM_POWER_DOMAIN_HOST_HVC:
+ return pkvm_init_hvc_pd(pd, ops);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
#endif /* __ARM64_KVM_NVHE_PKVM_H__ */
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index 9e1b74c661d2..950d34ba6e50 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -8,7 +8,7 @@ CFLAGS_switch.nvhe.o += -Wno-override-init
hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o \
hyp-main.o hyp-smp.o psci-relay.o alloc.o early_alloc.o page_alloc.o \
cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o \
- serial.o alloc_mgt.o iommu/iommu.o
+ serial.o alloc_mgt.o iommu/iommu.o power/hvc.o
hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 9b224842c487..5df98bf04ef4 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -1674,6 +1674,14 @@ static void handle___pkvm_host_iommu_iova_to_phys(struct kvm_cpu_context *host_c
cpu_reg(host_ctxt, 1) = kvm_iommu_iova_to_phys(domain, iova);
}
+static void handle___pkvm_host_hvc_pd(struct kvm_cpu_context *host_ctxt)
+{
+ DECLARE_REG(u64, device_id, host_ctxt, 1);
+ DECLARE_REG(u64, on, host_ctxt, 2);
+
+ cpu_reg(host_ctxt, 1) = pkvm_host_hvc_pd(device_id, on);
+}
+
typedef void (*hcall_t)(struct kvm_cpu_context *);
#define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -1738,6 +1746,7 @@ static const hcall_t host_hcall[] = {
HANDLE_FUNC(__pkvm_host_iommu_map_pages),
HANDLE_FUNC(__pkvm_host_iommu_unmap_pages),
HANDLE_FUNC(__pkvm_host_iommu_iova_to_phys),
+ HANDLE_FUNC(__pkvm_host_hvc_pd),
};
static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/nvhe/power/hvc.c b/arch/arm64/kvm/hyp/nvhe/power/hvc.c
new file mode 100644
index 000000000000..f4d811847e73
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/power/hvc.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Google LLC
+ * Author: Mostafa Saleh <smostafa at google.com>
+ */
+
+#include <nvhe/pkvm.h>
+
+struct hvc_power_domain {
+ struct kvm_power_domain *pd;
+ const struct kvm_power_domain_ops *ops;
+};
+
+struct hvc_power_domain handlers[MAX_POWER_DOMAINS];
+
+int pkvm_init_hvc_pd(struct kvm_power_domain *pd,
+ const struct kvm_power_domain_ops *ops)
+{
+ if (pd->device_id >= MAX_POWER_DOMAINS)
+ return -E2BIG;
+
+ handlers[pd->device_id].ops = ops;
+ handlers[pd->device_id].pd = pd;
+
+ return 0;
+}
+
+int pkvm_host_hvc_pd(u64 device_id, u64 on)
+{
+ struct hvc_power_domain *pd;
+
+ if (device_id >= MAX_POWER_DOMAINS)
+ return -E2BIG;
+
+ device_id = array_index_nospec(device_id, MAX_POWER_DOMAINS);
+ pd = &handlers[device_id];
+
+ if (!pd->ops)
+ return -ENOENT;
+
+ if (on)
+ pd->ops->power_on(pd->pd);
+ else
+ pd->ops->power_off(pd->pd);
+
+ return 0;
+}
diff --git a/include/kvm/power_domain.h b/include/kvm/power_domain.h
new file mode 100644
index 000000000000..f6a9c5cdfebb
--- /dev/null
+++ b/include/kvm/power_domain.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_POWER_DOMAIN_H
+#define __KVM_POWER_DOMAIN_H
+
+enum kvm_power_domain_type {
+ KVM_POWER_DOMAIN_NONE,
+ KVM_POWER_DOMAIN_HOST_HVC,
+};
+
+struct kvm_power_domain {
+ enum kvm_power_domain_type type;
+ union {
+ u64 device_id; /* HOST_HVC device ID*/
+ };
+};
+
+#endif /* __KVM_POWER_DOMAIN_H */
--
2.47.0.338.g60cca15819-goog
More information about the linux-arm-kernel
mailing list