Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kvm powerpc/book3s-apiv2: Introduce kvm-hv specific PMU

Introduce a new PMU named 'kvm-hv' inside a new module named 'kvm-hv-pmu'
to report Book3s kvm-hv specific performance counters. This will expose
KVM-HV specific performance attributes to user-space via kernel's PMU
infrastructure and would enableusers to monitor active kvm-hv based guests.

The patch creates necessary scaffolding to for the new PMU callbacks and
introduces the new kernel module name 'kvm-hv-pmu' which is built with
CONFIG_KVM_BOOK3S_HV_PMU. The patch doesn't introduce any perf-events yet,
which will be introduced in later patches

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/20250416162740.93143-5-vaibhav@linux.ibm.com

authored by

Vaibhav Jain and committed by
Madhavan Srinivasan
ff45bf50 1f35ad2b

+153
+13
arch/powerpc/kvm/Kconfig
··· 83 83 depends on KVM_BOOK3S_64 && PPC_POWERNV 84 84 select KVM_BOOK3S_HV_POSSIBLE 85 85 select KVM_GENERIC_MMU_NOTIFIER 86 + select KVM_BOOK3S_HV_PMU 86 87 select CMA 87 88 help 88 89 Support running unmodified book3s_64 guest kernels in ··· 171 170 Selecting this option for the L0 host implements a workaround for 172 171 those buggy L1s which saves the L2 state, at the cost of performance 173 172 in all nested-capable guest entry/exit. 173 + 174 + config KVM_BOOK3S_HV_PMU 175 + tristate "Hypervisor Perf events for KVM Book3s-HV" 176 + depends on KVM_BOOK3S_64_HV 177 + help 178 + Enable Book3s-HV Hypervisor Perf events PMU named 'kvm-hv'. These 179 + Perf events give an overview of hypervisor performance overall 180 + instead of a specific guests. Currently the PMU reports 181 + L0-Hypervisor stats on a kvm-hv enabled PSeries LPAR like: 182 + * Total/Used Guest-Heap 183 + * Total/Used Guest Page-table Memory 184 + * Total amount of Guest Page-table Memory reclaimed 174 185 175 186 config KVM_BOOKE_HV 176 187 bool
+2
arch/powerpc/perf/Makefile
··· 18 18 19 19 obj-$(CONFIG_VPA_PMU) += vpa-pmu.o 20 20 21 + obj-$(CONFIG_KVM_BOOK3S_HV_PMU) += kvm-hv-pmu.o 22 + 21 23 obj-$(CONFIG_PPC_8xx) += 8xx-pmu.o 22 24 23 25 obj-$(CONFIG_PPC64) += $(obj64-y)
+138
arch/powerpc/perf/kvm-hv-pmu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Description: PMUs specific to running nested KVM-HV guests 4 + * on Book3S processors (specifically POWER9 and later). 5 + */ 6 + 7 + #define pr_fmt(fmt) "kvmppc-pmu: " fmt 8 + 9 + #include "asm-generic/local64.h" 10 + #include <linux/kernel.h> 11 + #include <linux/errno.h> 12 + #include <linux/ratelimit.h> 13 + #include <linux/kvm_host.h> 14 + #include <linux/gfp_types.h> 15 + #include <linux/pgtable.h> 16 + #include <linux/perf_event.h> 17 + #include <linux/spinlock_types.h> 18 + #include <linux/spinlock.h> 19 + 20 + #include <asm/types.h> 21 + #include <asm/kvm_ppc.h> 22 + #include <asm/kvm_book3s.h> 23 + #include <asm/mmu.h> 24 + #include <asm/pgalloc.h> 25 + #include <asm/pte-walk.h> 26 + #include <asm/reg.h> 27 + #include <asm/plpar_wrappers.h> 28 + #include <asm/firmware.h> 29 + 30 + enum kvmppc_pmu_eventid { 31 + KVMPPC_EVENT_MAX, 32 + }; 33 + 34 + static struct attribute *kvmppc_pmu_events_attr[] = { 35 + NULL, 36 + }; 37 + 38 + static const struct attribute_group kvmppc_pmu_events_group = { 39 + .name = "events", 40 + .attrs = kvmppc_pmu_events_attr, 41 + }; 42 + 43 + PMU_FORMAT_ATTR(event, "config:0"); 44 + static struct attribute *kvmppc_pmu_format_attr[] = { 45 + &format_attr_event.attr, 46 + NULL, 47 + }; 48 + 49 + static struct attribute_group kvmppc_pmu_format_group = { 50 + .name = "format", 51 + .attrs = kvmppc_pmu_format_attr, 52 + }; 53 + 54 + static const struct attribute_group *kvmppc_pmu_attr_groups[] = { 55 + &kvmppc_pmu_events_group, 56 + &kvmppc_pmu_format_group, 57 + NULL, 58 + }; 59 + 60 + static int kvmppc_pmu_event_init(struct perf_event *event) 61 + { 62 + unsigned int config = event->attr.config; 63 + 64 + pr_debug("%s: Event(%p) id=%llu cpu=%x on_cpu=%x config=%u", 65 + __func__, event, event->id, event->cpu, 66 + event->oncpu, config); 67 + 68 + if (event->attr.type != event->pmu->type) 69 + return -ENOENT; 70 + 71 + if (config >= KVMPPC_EVENT_MAX) 72 + return -EINVAL; 73 + 74 + local64_set(&event->hw.prev_count, 0); 75 + local64_set(&event->count, 0); 76 + 77 + return 0; 78 + } 79 + 80 + static void kvmppc_pmu_del(struct perf_event *event, int flags) 81 + { 82 + } 83 + 84 + static int kvmppc_pmu_add(struct perf_event *event, int flags) 85 + { 86 + return 0; 87 + } 88 + 89 + static void kvmppc_pmu_read(struct perf_event *event) 90 + { 91 + } 92 + 93 + /* L1 wide counters PMU */ 94 + static struct pmu kvmppc_pmu = { 95 + .module = THIS_MODULE, 96 + .task_ctx_nr = perf_sw_context, 97 + .name = "kvm-hv", 98 + .event_init = kvmppc_pmu_event_init, 99 + .add = kvmppc_pmu_add, 100 + .del = kvmppc_pmu_del, 101 + .read = kvmppc_pmu_read, 102 + .attr_groups = kvmppc_pmu_attr_groups, 103 + .type = -1, 104 + }; 105 + 106 + static int __init kvmppc_register_pmu(void) 107 + { 108 + int rc = -EOPNOTSUPP; 109 + 110 + /* only support events for nestedv2 right now */ 111 + if (kvmhv_is_nestedv2()) { 112 + /* Register the pmu */ 113 + rc = perf_pmu_register(&kvmppc_pmu, kvmppc_pmu.name, -1); 114 + if (rc) 115 + goto out; 116 + 117 + pr_info("Registered kvm-hv pmu"); 118 + } 119 + 120 + out: 121 + return rc; 122 + } 123 + 124 + static void __exit kvmppc_unregister_pmu(void) 125 + { 126 + if (kvmhv_is_nestedv2()) { 127 + if (kvmppc_pmu.type != -1) 128 + perf_pmu_unregister(&kvmppc_pmu); 129 + 130 + pr_info("kvmhv_pmu unregistered.\n"); 131 + } 132 + } 133 + 134 + module_init(kvmppc_register_pmu); 135 + module_exit(kvmppc_unregister_pmu); 136 + MODULE_DESCRIPTION("KVM PPC Book3s-hv PMU"); 137 + MODULE_AUTHOR("Vaibhav Jain <vaibhav@linux.ibm.com>"); 138 + MODULE_LICENSE("GPL");