* [PATCH 2/3] mshv: Add definitions for stats pages
2025-12-03 17:53 [PATCH 0/3] mshv: Debugfs interface for mshv_root Nuno Das Neves
2025-12-03 17:53 ` [PATCH 1/3] mshv: Ignore second stats page map result failure Nuno Das Neves
@ 2025-12-03 17:53 ` Nuno Das Neves
2025-12-03 19:06 ` Stanislav Kinsburskii
2025-12-03 17:53 ` [PATCH 3/3] mshv: Add debugfs to view hypervisor statistics Nuno Das Neves
2 siblings, 1 reply; 10+ messages in thread
From: Nuno Das Neves @ 2025-12-03 17:53 UTC (permalink / raw)
To: linux-hyperv, linux-kernel
Cc: kys, haiyangz, wei.liu, decui, longli, mhklinux, skinsburskii,
prapal, mrathor, paekkaladevi, Nuno Das Neves
Add the definitions for hypervisor, logical processor, and partition
stats pages.
Move the definition for the VP stats page to its rightful place in
hvhdk.h, and add the missing members.
These enum members retain their CamelCase style, since they are imported
directly from the hypervisor code They will be stringified when printing
the stats out, and retain more readability in this form.
Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
---
drivers/hv/mshv_root_main.c | 17 --
include/hyperv/hvhdk.h | 437 ++++++++++++++++++++++++++++++++++++
2 files changed, 437 insertions(+), 17 deletions(-)
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index f59a4ab47685..19006b788e85 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -38,23 +38,6 @@ MODULE_AUTHOR("Microsoft");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Microsoft Hyper-V root partition VMM interface /dev/mshv");
-/* TODO move this to another file when debugfs code is added */
-enum hv_stats_vp_counters { /* HV_THREAD_COUNTER */
-#if defined(CONFIG_X86)
- VpRootDispatchThreadBlocked = 202,
-#elif defined(CONFIG_ARM64)
- VpRootDispatchThreadBlocked = 94,
-#endif
- VpStatsMaxCounter
-};
-
-struct hv_stats_page {
- union {
- u64 vp_cntrs[VpStatsMaxCounter]; /* VP counters */
- u8 data[HV_HYP_PAGE_SIZE];
- };
-} __packed;
-
struct mshv_root mshv_root;
enum hv_scheduler_type hv_scheduler_type;
diff --git a/include/hyperv/hvhdk.h b/include/hyperv/hvhdk.h
index 469186df7826..2e3a7f80a560 100644
--- a/include/hyperv/hvhdk.h
+++ b/include/hyperv/hvhdk.h
@@ -10,6 +10,443 @@
#include "hvhdk_mini.h"
#include "hvgdk.h"
+enum hv_stats_hypervisor_counters { /* HV_HYPERVISOR_COUNTER */
+ HvLogicalProcessors = 1,
+ HvPartitions = 2,
+ HvTotalPages = 3,
+ HvVirtualProcessors = 4,
+ HvMonitoredNotifications = 5,
+ HvModernStandbyEntries = 6,
+ HvPlatformIdleTransitions = 7,
+ HvHypervisorStartupCost = 8,
+ HvIOSpacePages = 10,
+ HvNonEssentialPagesForDump = 11,
+ HvSubsumedPages = 12,
+ HvStatsMaxCounter
+};
+
+enum hv_stats_partition_counters { /* HV_PROCESS_COUNTER */
+ PartitionVirtualProcessors = 1,
+ PartitionTlbSize = 3,
+ PartitionAddressSpaces = 4,
+ PartitionDepositedPages = 5,
+ PartitionGpaPages = 6,
+ PartitionGpaSpaceModifications = 7,
+ PartitionVirtualTlbFlushEntires = 8,
+ PartitionRecommendedTlbSize = 9,
+ PartitionGpaPages4K = 10,
+ PartitionGpaPages2M = 11,
+ PartitionGpaPages1G = 12,
+ PartitionGpaPages512G = 13,
+ PartitionDevicePages4K = 14,
+ PartitionDevicePages2M = 15,
+ PartitionDevicePages1G = 16,
+ PartitionDevicePages512G = 17,
+ PartitionAttachedDevices = 18,
+ PartitionDeviceInterruptMappings = 19,
+ PartitionIoTlbFlushes = 20,
+ PartitionIoTlbFlushCost = 21,
+ PartitionDeviceInterruptErrors = 22,
+ PartitionDeviceDmaErrors = 23,
+ PartitionDeviceInterruptThrottleEvents = 24,
+ PartitionSkippedTimerTicks = 25,
+ PartitionPartitionId = 26,
+#if IS_ENABLED(CONFIG_X86)
+ PartitionNestedTlbSize = 27,
+ PartitionRecommendedNestedTlbSize = 28,
+ PartitionNestedTlbFreeListSize = 29,
+ PartitionNestedTlbTrimmedPages = 30,
+ PartitionPagesShattered = 31,
+ PartitionPagesRecombined = 32,
+ PartitionHwpRequestValue = 33,
+#elif IS_ENABLED(CONFIG_ARM64)
+ PartitionHwpRequestValue = 27,
+#endif
+ PartitionStatsMaxCounter
+};
+
+enum hv_stats_vp_counters { /* HV_THREAD_COUNTER */
+ VpTotalRunTime = 1,
+ VpHypervisorRunTime = 2,
+ VpRemoteNodeRunTime = 3,
+ VpNormalizedRunTime = 4,
+ VpIdealCpu = 5,
+ VpHypercallsCount = 7,
+ VpHypercallsTime = 8,
+#if IS_ENABLED(CONFIG_X86)
+ VpPageInvalidationsCount = 9,
+ VpPageInvalidationsTime = 10,
+ VpControlRegisterAccessesCount = 11,
+ VpControlRegisterAccessesTime = 12,
+ VpIoInstructionsCount = 13,
+ VpIoInstructionsTime = 14,
+ VpHltInstructionsCount = 15,
+ VpHltInstructionsTime = 16,
+ VpMwaitInstructionsCount = 17,
+ VpMwaitInstructionsTime = 18,
+ VpCpuidInstructionsCount = 19,
+ VpCpuidInstructionsTime = 20,
+ VpMsrAccessesCount = 21,
+ VpMsrAccessesTime = 22,
+ VpOtherInterceptsCount = 23,
+ VpOtherInterceptsTime = 24,
+ VpExternalInterruptsCount = 25,
+ VpExternalInterruptsTime = 26,
+ VpPendingInterruptsCount = 27,
+ VpPendingInterruptsTime = 28,
+ VpEmulatedInstructionsCount = 29,
+ VpEmulatedInstructionsTime = 30,
+ VpDebugRegisterAccessesCount = 31,
+ VpDebugRegisterAccessesTime = 32,
+ VpPageFaultInterceptsCount = 33,
+ VpPageFaultInterceptsTime = 34,
+ VpGuestPageTableMaps = 35,
+ VpLargePageTlbFills = 36,
+ VpSmallPageTlbFills = 37,
+ VpReflectedGuestPageFaults = 38,
+ VpApicMmioAccesses = 39,
+ VpIoInterceptMessages = 40,
+ VpMemoryInterceptMessages = 41,
+ VpApicEoiAccesses = 42,
+ VpOtherMessages = 43,
+ VpPageTableAllocations = 44,
+ VpLogicalProcessorMigrations = 45,
+ VpAddressSpaceEvictions = 46,
+ VpAddressSpaceSwitches = 47,
+ VpAddressDomainFlushes = 48,
+ VpAddressSpaceFlushes = 49,
+ VpGlobalGvaRangeFlushes = 50,
+ VpLocalGvaRangeFlushes = 51,
+ VpPageTableEvictions = 52,
+ VpPageTableReclamations = 53,
+ VpPageTableResets = 54,
+ VpPageTableValidations = 55,
+ VpApicTprAccesses = 56,
+ VpPageTableWriteIntercepts = 57,
+ VpSyntheticInterrupts = 58,
+ VpVirtualInterrupts = 59,
+ VpApicIpisSent = 60,
+ VpApicSelfIpisSent = 61,
+ VpGpaSpaceHypercalls = 62,
+ VpLogicalProcessorHypercalls = 63,
+ VpLongSpinWaitHypercalls = 64,
+ VpOtherHypercalls = 65,
+ VpSyntheticInterruptHypercalls = 66,
+ VpVirtualInterruptHypercalls = 67,
+ VpVirtualMmuHypercalls = 68,
+ VpVirtualProcessorHypercalls = 69,
+ VpHardwareInterrupts = 70,
+ VpNestedPageFaultInterceptsCount = 71,
+ VpNestedPageFaultInterceptsTime = 72,
+ VpPageScans = 73,
+ VpLogicalProcessorDispatches = 74,
+ VpWaitingForCpuTime = 75,
+ VpExtendedHypercalls = 76,
+ VpExtendedHypercallInterceptMessages = 77,
+ VpMbecNestedPageTableSwitches = 78,
+ VpOtherReflectedGuestExceptions = 79,
+ VpGlobalIoTlbFlushes = 80,
+ VpGlobalIoTlbFlushCost = 81,
+ VpLocalIoTlbFlushes = 82,
+ VpLocalIoTlbFlushCost = 83,
+ VpHypercallsForwardedCount = 84,
+ VpHypercallsForwardingTime = 85,
+ VpPageInvalidationsForwardedCount = 86,
+ VpPageInvalidationsForwardingTime = 87,
+ VpControlRegisterAccessesForwardedCount = 88,
+ VpControlRegisterAccessesForwardingTime = 89,
+ VpIoInstructionsForwardedCount = 90,
+ VpIoInstructionsForwardingTime = 91,
+ VpHltInstructionsForwardedCount = 92,
+ VpHltInstructionsForwardingTime = 93,
+ VpMwaitInstructionsForwardedCount = 94,
+ VpMwaitInstructionsForwardingTime = 95,
+ VpCpuidInstructionsForwardedCount = 96,
+ VpCpuidInstructionsForwardingTime = 97,
+ VpMsrAccessesForwardedCount = 98,
+ VpMsrAccessesForwardingTime = 99,
+ VpOtherInterceptsForwardedCount = 100,
+ VpOtherInterceptsForwardingTime = 101,
+ VpExternalInterruptsForwardedCount = 102,
+ VpExternalInterruptsForwardingTime = 103,
+ VpPendingInterruptsForwardedCount = 104,
+ VpPendingInterruptsForwardingTime = 105,
+ VpEmulatedInstructionsForwardedCount = 106,
+ VpEmulatedInstructionsForwardingTime = 107,
+ VpDebugRegisterAccessesForwardedCount = 108,
+ VpDebugRegisterAccessesForwardingTime = 109,
+ VpPageFaultInterceptsForwardedCount = 110,
+ VpPageFaultInterceptsForwardingTime = 111,
+ VpVmclearEmulationCount = 112,
+ VpVmclearEmulationTime = 113,
+ VpVmptrldEmulationCount = 114,
+ VpVmptrldEmulationTime = 115,
+ VpVmptrstEmulationCount = 116,
+ VpVmptrstEmulationTime = 117,
+ VpVmreadEmulationCount = 118,
+ VpVmreadEmulationTime = 119,
+ VpVmwriteEmulationCount = 120,
+ VpVmwriteEmulationTime = 121,
+ VpVmxoffEmulationCount = 122,
+ VpVmxoffEmulationTime = 123,
+ VpVmxonEmulationCount = 124,
+ VpVmxonEmulationTime = 125,
+ VpNestedVMEntriesCount = 126,
+ VpNestedVMEntriesTime = 127,
+ VpNestedSLATSoftPageFaultsCount = 128,
+ VpNestedSLATSoftPageFaultsTime = 129,
+ VpNestedSLATHardPageFaultsCount = 130,
+ VpNestedSLATHardPageFaultsTime = 131,
+ VpInvEptAllContextEmulationCount = 132,
+ VpInvEptAllContextEmulationTime = 133,
+ VpInvEptSingleContextEmulationCount = 134,
+ VpInvEptSingleContextEmulationTime = 135,
+ VpInvVpidAllContextEmulationCount = 136,
+ VpInvVpidAllContextEmulationTime = 137,
+ VpInvVpidSingleContextEmulationCount = 138,
+ VpInvVpidSingleContextEmulationTime = 139,
+ VpInvVpidSingleAddressEmulationCount = 140,
+ VpInvVpidSingleAddressEmulationTime = 141,
+ VpNestedTlbPageTableReclamations = 142,
+ VpNestedTlbPageTableEvictions = 143,
+ VpFlushGuestPhysicalAddressSpaceHypercalls = 144,
+ VpFlushGuestPhysicalAddressListHypercalls = 145,
+ VpPostedInterruptNotifications = 146,
+ VpPostedInterruptScans = 147,
+ VpTotalCoreRunTime = 148,
+ VpMaximumRunTime = 149,
+ VpHwpRequestContextSwitches = 150,
+ VpWaitingForCpuTimeBucket0 = 151,
+ VpWaitingForCpuTimeBucket1 = 152,
+ VpWaitingForCpuTimeBucket2 = 153,
+ VpWaitingForCpuTimeBucket3 = 154,
+ VpWaitingForCpuTimeBucket4 = 155,
+ VpWaitingForCpuTimeBucket5 = 156,
+ VpWaitingForCpuTimeBucket6 = 157,
+ VpVmloadEmulationCount = 158,
+ VpVmloadEmulationTime = 159,
+ VpVmsaveEmulationCount = 160,
+ VpVmsaveEmulationTime = 161,
+ VpGifInstructionEmulationCount = 162,
+ VpGifInstructionEmulationTime = 163,
+ VpEmulatedErrataSvmInstructions = 164,
+ VpPlaceholder1 = 165,
+ VpPlaceholder2 = 166,
+ VpPlaceholder3 = 167,
+ VpPlaceholder4 = 168,
+ VpPlaceholder5 = 169,
+ VpPlaceholder6 = 170,
+ VpPlaceholder7 = 171,
+ VpPlaceholder8 = 172,
+ VpPlaceholder9 = 173,
+ VpPlaceholder10 = 174,
+ VpSchedulingPriority = 175,
+ VpRdpmcInstructionsCount = 176,
+ VpRdpmcInstructionsTime = 177,
+ VpPerfmonPmuMsrAccessesCount = 178,
+ VpPerfmonLbrMsrAccessesCount = 179,
+ VpPerfmonIptMsrAccessesCount = 180,
+ VpPerfmonInterruptCount = 181,
+ VpVtl1DispatchCount = 182,
+ VpVtl2DispatchCount = 183,
+ VpVtl2DispatchBucket0 = 184,
+ VpVtl2DispatchBucket1 = 185,
+ VpVtl2DispatchBucket2 = 186,
+ VpVtl2DispatchBucket3 = 187,
+ VpVtl2DispatchBucket4 = 188,
+ VpVtl2DispatchBucket5 = 189,
+ VpVtl2DispatchBucket6 = 190,
+ VpVtl1RunTime = 191,
+ VpVtl2RunTime = 192,
+ VpIommuHypercalls = 193,
+ VpCpuGroupHypercalls = 194,
+ VpVsmHypercalls = 195,
+ VpEventLogHypercalls = 196,
+ VpDeviceDomainHypercalls = 197,
+ VpDepositHypercalls = 198,
+ VpSvmHypercalls = 199,
+ VpBusLockAcquisitionCount = 200,
+ VpUnused = 201,
+ VpRootDispatchThreadBlocked = 202,
+#elif IS_ENABLED(CONFIG_ARM64)
+ VpSysRegAccessesCount = 9,
+ VpSysRegAccessesTime = 10,
+ VpSmcInstructionsCount = 11,
+ VpSmcInstructionsTime = 12,
+ VpOtherInterceptsCount = 13,
+ VpOtherInterceptsTime = 14,
+ VpExternalInterruptsCount = 15,
+ VpExternalInterruptsTime = 16,
+ VpPendingInterruptsCount = 17,
+ VpPendingInterruptsTime = 18,
+ VpGuestPageTableMaps = 19,
+ VpLargePageTlbFills = 20,
+ VpSmallPageTlbFills = 21,
+ VpReflectedGuestPageFaults = 22,
+ VpMemoryInterceptMessages = 23,
+ VpOtherMessages = 24,
+ VpLogicalProcessorMigrations = 25,
+ VpAddressDomainFlushes = 26,
+ VpAddressSpaceFlushes = 27,
+ VpSyntheticInterrupts = 28,
+ VpVirtualInterrupts = 29,
+ VpApicSelfIpisSent = 30,
+ VpGpaSpaceHypercalls = 31,
+ VpLogicalProcessorHypercalls = 32,
+ VpLongSpinWaitHypercalls = 33,
+ VpOtherHypercalls = 34,
+ VpSyntheticInterruptHypercalls = 35,
+ VpVirtualInterruptHypercalls = 36,
+ VpVirtualMmuHypercalls = 37,
+ VpVirtualProcessorHypercalls = 38,
+ VpHardwareInterrupts = 39,
+ VpNestedPageFaultInterceptsCount = 40,
+ VpNestedPageFaultInterceptsTime = 41,
+ VpLogicalProcessorDispatches = 42,
+ VpWaitingForCpuTime = 43,
+ VpExtendedHypercalls = 44,
+ VpExtendedHypercallInterceptMessages = 45,
+ VpMbecNestedPageTableSwitches = 46,
+ VpOtherReflectedGuestExceptions = 47,
+ VpGlobalIoTlbFlushes = 48,
+ VpGlobalIoTlbFlushCost = 49,
+ VpLocalIoTlbFlushes = 50,
+ VpLocalIoTlbFlushCost = 51,
+ VpFlushGuestPhysicalAddressSpaceHypercalls = 52,
+ VpFlushGuestPhysicalAddressListHypercalls = 53,
+ VpPostedInterruptNotifications = 54,
+ VpPostedInterruptScans = 55,
+ VpTotalCoreRunTime = 56,
+ VpMaximumRunTime = 57,
+ VpWaitingForCpuTimeBucket0 = 58,
+ VpWaitingForCpuTimeBucket1 = 59,
+ VpWaitingForCpuTimeBucket2 = 60,
+ VpWaitingForCpuTimeBucket3 = 61,
+ VpWaitingForCpuTimeBucket4 = 62,
+ VpWaitingForCpuTimeBucket5 = 63,
+ VpWaitingForCpuTimeBucket6 = 64,
+ VpHwpRequestContextSwitches = 65,
+ VpPlaceholder2 = 66,
+ VpPlaceholder3 = 67,
+ VpPlaceholder4 = 68,
+ VpPlaceholder5 = 69,
+ VpPlaceholder6 = 70,
+ VpPlaceholder7 = 71,
+ VpPlaceholder8 = 72,
+ VpContentionTime = 73,
+ VpWakeUpTime = 74,
+ VpSchedulingPriority = 75,
+ VpVtl1DispatchCount = 76,
+ VpVtl2DispatchCount = 77,
+ VpVtl2DispatchBucket0 = 78,
+ VpVtl2DispatchBucket1 = 79,
+ VpVtl2DispatchBucket2 = 80,
+ VpVtl2DispatchBucket3 = 81,
+ VpVtl2DispatchBucket4 = 82,
+ VpVtl2DispatchBucket5 = 83,
+ VpVtl2DispatchBucket6 = 84,
+ VpVtl1RunTime = 85,
+ VpVtl2RunTime = 86,
+ VpIommuHypercalls = 87,
+ VpCpuGroupHypercalls = 88,
+ VpVsmHypercalls = 89,
+ VpEventLogHypercalls = 90,
+ VpDeviceDomainHypercalls = 91,
+ VpDepositHypercalls = 92,
+ VpSvmHypercalls = 93,
+ VpLoadAvg = 94,
+ VpRootDispatchThreadBlocked = 95,
+#endif
+ VpStatsMaxCounter
+};
+
+enum hv_stats_lp_counters { /* HV_CPU_COUNTER */
+ LpGlobalTime = 1,
+ LpTotalRunTime = 2,
+ LpHypervisorRunTime = 3,
+ LpHardwareInterrupts = 4,
+ LpContextSwitches = 5,
+ LpInterProcessorInterrupts = 6,
+ LpSchedulerInterrupts = 7,
+ LpTimerInterrupts = 8,
+ LpInterProcessorInterruptsSent = 9,
+ LpProcessorHalts = 10,
+ LpMonitorTransitionCost = 11,
+ LpContextSwitchTime = 12,
+ LpC1TransitionsCount = 13,
+ LpC1RunTime = 14,
+ LpC2TransitionsCount = 15,
+ LpC2RunTime = 16,
+ LpC3TransitionsCount = 17,
+ LpC3RunTime = 18,
+ LpRootVpIndex = 19,
+ LpIdleSequenceNumber = 20,
+ LpGlobalTscCount = 21,
+ LpActiveTscCount = 22,
+ LpIdleAccumulation = 23,
+ LpReferenceCycleCount0 = 24,
+ LpActualCycleCount0 = 25,
+ LpReferenceCycleCount1 = 26,
+ LpActualCycleCount1 = 27,
+ LpProximityDomainId = 28,
+ LpPostedInterruptNotifications = 29,
+ LpBranchPredictorFlushes = 30,
+#if IS_ENABLED(CONFIG_X86)
+ LpL1DataCacheFlushes = 31,
+ LpImmediateL1DataCacheFlushes = 32,
+ LpMbFlushes = 33,
+ LpCounterRefreshSequenceNumber = 34,
+ LpCounterRefreshReferenceTime = 35,
+ LpIdleAccumulationSnapshot = 36,
+ LpActiveTscCountSnapshot = 37,
+ LpHwpRequestContextSwitches = 38,
+ LpPlaceholder1 = 39,
+ LpPlaceholder2 = 40,
+ LpPlaceholder3 = 41,
+ LpPlaceholder4 = 42,
+ LpPlaceholder5 = 43,
+ LpPlaceholder6 = 44,
+ LpPlaceholder7 = 45,
+ LpPlaceholder8 = 46,
+ LpPlaceholder9 = 47,
+ LpPlaceholder10 = 48,
+ LpReserveGroupId = 49,
+ LpRunningPriority = 50,
+ LpPerfmonInterruptCount = 51,
+#elif IS_ENABLED(CONFIG_ARM64)
+ LpCounterRefreshSequenceNumber = 31,
+ LpCounterRefreshReferenceTime = 32,
+ LpIdleAccumulationSnapshot = 33,
+ LpActiveTscCountSnapshot = 34,
+ LpHwpRequestContextSwitches = 35,
+ LpPlaceholder2 = 36,
+ LpPlaceholder3 = 37,
+ LpPlaceholder4 = 38,
+ LpPlaceholder5 = 39,
+ LpPlaceholder6 = 40,
+ LpPlaceholder7 = 41,
+ LpPlaceholder8 = 42,
+ LpPlaceholder9 = 43,
+ LpSchLocalRunListSize = 44,
+ LpReserveGroupId = 45,
+ LpRunningPriority = 46,
+#endif
+ LpStatsMaxCounter
+};
+
+/*
+ * Hypervisor statsitics page format
+ */
+struct hv_stats_page {
+ union {
+ u64 hv_cntrs[HvStatsMaxCounter]; /* Hypervisor counters */
+ u64 pt_cntrs[PartitionStatsMaxCounter]; /* Partition counters */
+ u64 vp_cntrs[VpStatsMaxCounter]; /* VP counters */
+ u64 lp_cntrs[LpStatsMaxCounter]; /* LP counters */
+ u8 data[HV_HYP_PAGE_SIZE];
+ };
+} __packed;
+
/* Bits for dirty mask of hv_vp_register_page */
#define HV_X64_REGISTER_CLASS_GENERAL 0
#define HV_X64_REGISTER_CLASS_IP 1
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 3/3] mshv: Add debugfs to view hypervisor statistics
2025-12-03 17:53 [PATCH 0/3] mshv: Debugfs interface for mshv_root Nuno Das Neves
2025-12-03 17:53 ` [PATCH 1/3] mshv: Ignore second stats page map result failure Nuno Das Neves
2025-12-03 17:53 ` [PATCH 2/3] mshv: Add definitions for stats pages Nuno Das Neves
@ 2025-12-03 17:53 ` Nuno Das Neves
2025-12-03 19:21 ` Stanislav Kinsburskii
2 siblings, 1 reply; 10+ messages in thread
From: Nuno Das Neves @ 2025-12-03 17:53 UTC (permalink / raw)
To: linux-hyperv, linux-kernel
Cc: kys, haiyangz, wei.liu, decui, longli, mhklinux, skinsburskii,
prapal, mrathor, paekkaladevi, Nuno Das Neves, Jinank Jain
Introduce a debugfs interface to expose root and child partition stats
when running with mshv_root.
Create a debugfs directory "mshv" containing 'stats' files organized by
type and id. A stats file contains a number of counters depending on
its type. e.g. an excerpt from a VP stats file:
TotalRunTime : 1997602722
HypervisorRunTime : 649671371
RemoteNodeRunTime : 0
NormalizedRunTime : 1997602721
IdealCpu : 0
HypercallsCount : 1708169
HypercallsTime : 111914774
PageInvalidationsCount : 0
PageInvalidationsTime : 0
On a root partition with some active child partitions, the entire
directory structure may look like:
mshv/
stats # hypervisor stats
lp/ # logical processors
0/ # LP id
stats # LP 0 stats
1/
2/
3/
partition/ # partition stats
1/ # root partition id
stats # root partition stats
vp/ # root virtual processors
0/ # root VP id
stats # root VP 0 stats
1/
2/
3/
42/ # child partition id
stats # child partition stats
vp/ # child VPs
0/ # child VP id
stats # child VP 0 stats
1/
43/
55/
On L1VH, some stats are not present as it does not own the hardware
like the root partition does:
- The hypervisor and lp stats are not present
- L1VH's partition directory is named "self" because it can't get its
own id
- Some of L1VH's partition and VP stats fields are not populated, because
it can't map its own HV_STATS_AREA_PARENT page.
Co-developed-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Co-developed-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Co-developed-by: Mukesh Rathor <mrathor@linux.microsoft.com>
Signed-off-by: Mukesh Rathor <mrathor@linux.microsoft.com>
Co-developed-by: Purna Pavan Chandra Aekkaladevi <paekkaladevi@linux.microsoft.com>
Signed-off-by: Purna Pavan Chandra Aekkaladevi <paekkaladevi@linux.microsoft.com>
Co-developed-by: Jinank Jain <jinankjain@microsoft.com>
Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
---
drivers/hv/Makefile | 1 +
drivers/hv/mshv_debugfs.c | 1122 +++++++++++++++++++++++++++++++++++
drivers/hv/mshv_root.h | 34 ++
drivers/hv/mshv_root_main.c | 32 +-
4 files changed, 1185 insertions(+), 4 deletions(-)
create mode 100644 drivers/hv/mshv_debugfs.c
diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
index 58b8d07639f3..36278c936914 100644
--- a/drivers/hv/Makefile
+++ b/drivers/hv/Makefile
@@ -15,6 +15,7 @@ hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o
hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_utils_transport.o
mshv_root-y := mshv_root_main.o mshv_synic.o mshv_eventfd.o mshv_irq.o \
mshv_root_hv_call.o mshv_portid_table.o
+mshv_root-$(CONFIG_DEBUG_FS) += mshv_debugfs.o
mshv_vtl-y := mshv_vtl_main.o
# Code that must be built-in
diff --git a/drivers/hv/mshv_debugfs.c b/drivers/hv/mshv_debugfs.c
new file mode 100644
index 000000000000..581018690a27
--- /dev/null
+++ b/drivers/hv/mshv_debugfs.c
@@ -0,0 +1,1122 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025, Microsoft Corporation.
+ *
+ * The /sys/kernel/debug/mshv directory contents.
+ * Contains various statistics data, provided by the hypervisor.
+ *
+ * Authors: Microsoft Linux virtualization team
+ */
+
+#include <linux/debugfs.h>
+#include <linux/stringify.h>
+#include <asm/mshyperv.h>
+#include <linux/slab.h>
+
+#include "mshv.h"
+#include "mshv_root.h"
+
+#define U32_BUF_SZ 11
+#define U64_BUF_SZ 21
+
+static struct dentry *mshv_debugfs;
+static struct dentry *mshv_debugfs_partition;
+static struct dentry *mshv_debugfs_lp;
+
+static u64 mshv_lps_count;
+
+static bool is_l1vh_parent(u64 partition_id)
+{
+ return hv_l1vh_partition() && (partition_id == HV_PARTITION_ID_SELF);
+}
+
+static int lp_stats_show(struct seq_file *m, void *v)
+{
+ const struct hv_stats_page *stats = m->private;
+
+#define LP_SEQ_PRINTF(cnt) \
+ seq_printf(m, "%-29s: %llu\n", __stringify(cnt), stats->lp_cntrs[Lp##cnt])
+
+ LP_SEQ_PRINTF(GlobalTime);
+ LP_SEQ_PRINTF(TotalRunTime);
+ LP_SEQ_PRINTF(HypervisorRunTime);
+ LP_SEQ_PRINTF(HardwareInterrupts);
+ LP_SEQ_PRINTF(ContextSwitches);
+ LP_SEQ_PRINTF(InterProcessorInterrupts);
+ LP_SEQ_PRINTF(SchedulerInterrupts);
+ LP_SEQ_PRINTF(TimerInterrupts);
+ LP_SEQ_PRINTF(InterProcessorInterruptsSent);
+ LP_SEQ_PRINTF(ProcessorHalts);
+ LP_SEQ_PRINTF(MonitorTransitionCost);
+ LP_SEQ_PRINTF(ContextSwitchTime);
+ LP_SEQ_PRINTF(C1TransitionsCount);
+ LP_SEQ_PRINTF(C1RunTime);
+ LP_SEQ_PRINTF(C2TransitionsCount);
+ LP_SEQ_PRINTF(C2RunTime);
+ LP_SEQ_PRINTF(C3TransitionsCount);
+ LP_SEQ_PRINTF(C3RunTime);
+ LP_SEQ_PRINTF(RootVpIndex);
+ LP_SEQ_PRINTF(IdleSequenceNumber);
+ LP_SEQ_PRINTF(GlobalTscCount);
+ LP_SEQ_PRINTF(ActiveTscCount);
+ LP_SEQ_PRINTF(IdleAccumulation);
+ LP_SEQ_PRINTF(ReferenceCycleCount0);
+ LP_SEQ_PRINTF(ActualCycleCount0);
+ LP_SEQ_PRINTF(ReferenceCycleCount1);
+ LP_SEQ_PRINTF(ActualCycleCount1);
+ LP_SEQ_PRINTF(ProximityDomainId);
+ LP_SEQ_PRINTF(PostedInterruptNotifications);
+ LP_SEQ_PRINTF(BranchPredictorFlushes);
+#if IS_ENABLED(CONFIG_X86_64)
+ LP_SEQ_PRINTF(L1DataCacheFlushes);
+ LP_SEQ_PRINTF(ImmediateL1DataCacheFlushes);
+ LP_SEQ_PRINTF(MbFlushes);
+ LP_SEQ_PRINTF(CounterRefreshSequenceNumber);
+ LP_SEQ_PRINTF(CounterRefreshReferenceTime);
+ LP_SEQ_PRINTF(IdleAccumulationSnapshot);
+ LP_SEQ_PRINTF(ActiveTscCountSnapshot);
+ LP_SEQ_PRINTF(HwpRequestContextSwitches);
+ LP_SEQ_PRINTF(Placeholder1);
+ LP_SEQ_PRINTF(Placeholder2);
+ LP_SEQ_PRINTF(Placeholder3);
+ LP_SEQ_PRINTF(Placeholder4);
+ LP_SEQ_PRINTF(Placeholder5);
+ LP_SEQ_PRINTF(Placeholder6);
+ LP_SEQ_PRINTF(Placeholder7);
+ LP_SEQ_PRINTF(Placeholder8);
+ LP_SEQ_PRINTF(Placeholder9);
+ LP_SEQ_PRINTF(Placeholder10);
+ LP_SEQ_PRINTF(ReserveGroupId);
+ LP_SEQ_PRINTF(RunningPriority);
+ LP_SEQ_PRINTF(PerfmonInterruptCount);
+#elif IS_ENABLED(CONFIG_ARM64)
+ LP_SEQ_PRINTF(CounterRefreshSequenceNumber);
+ LP_SEQ_PRINTF(CounterRefreshReferenceTime);
+ LP_SEQ_PRINTF(IdleAccumulationSnapshot);
+ LP_SEQ_PRINTF(ActiveTscCountSnapshot);
+ LP_SEQ_PRINTF(HwpRequestContextSwitches);
+ LP_SEQ_PRINTF(Placeholder2);
+ LP_SEQ_PRINTF(Placeholder3);
+ LP_SEQ_PRINTF(Placeholder4);
+ LP_SEQ_PRINTF(Placeholder5);
+ LP_SEQ_PRINTF(Placeholder6);
+ LP_SEQ_PRINTF(Placeholder7);
+ LP_SEQ_PRINTF(Placeholder8);
+ LP_SEQ_PRINTF(Placeholder9);
+ LP_SEQ_PRINTF(SchLocalRunListSize);
+ LP_SEQ_PRINTF(ReserveGroupId);
+ LP_SEQ_PRINTF(RunningPriority);
+#endif
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(lp_stats);
+
+static void mshv_lp_stats_unmap(u32 lp_index, void *stats_page_addr)
+{
+ union hv_stats_object_identity identity = {
+ .lp.lp_index = lp_index,
+ .lp.stats_area_type = HV_STATS_AREA_SELF,
+ };
+ int err;
+
+ err = hv_unmap_stats_page(HV_STATS_OBJECT_LOGICAL_PROCESSOR,
+ stats_page_addr, &identity);
+ if (err)
+ pr_err("%s: failed to unmap logical processor %u stats, err: %d\n",
+ __func__, lp_index, err);
+}
+
+static void __init *mshv_lp_stats_map(u32 lp_index)
+{
+ union hv_stats_object_identity identity = {
+ .lp.lp_index = lp_index,
+ .lp.stats_area_type = HV_STATS_AREA_SELF,
+ };
+ void *stats;
+ int err;
+
+ err = hv_map_stats_page(HV_STATS_OBJECT_LOGICAL_PROCESSOR, &identity,
+ &stats);
+ if (err) {
+ pr_err("%s: failed to map logical processor %u stats, err: %d\n",
+ __func__, lp_index, err);
+ return ERR_PTR(err);
+ }
+
+ return stats;
+}
+
+static void __init *lp_debugfs_stats_create(u32 lp_index, struct dentry *parent)
+{
+ struct dentry *dentry;
+ void *stats;
+
+ stats = mshv_lp_stats_map(lp_index);
+ if (IS_ERR(stats))
+ return stats;
+
+ dentry = debugfs_create_file("stats", 0400, parent,
+ stats, &lp_stats_fops);
+ if (IS_ERR(dentry)) {
+ mshv_lp_stats_unmap(lp_index, stats);
+ return dentry;
+ }
+ return stats;
+}
+
+static int __init lp_debugfs_create(u32 lp_index, struct dentry *parent)
+{
+ struct dentry *idx;
+ char lp_idx_str[U32_BUF_SZ];
+ void *stats;
+ int err;
+
+ sprintf(lp_idx_str, "%u", lp_index);
+
+ idx = debugfs_create_dir(lp_idx_str, parent);
+ if (IS_ERR(idx))
+ return PTR_ERR(idx);
+
+ stats = lp_debugfs_stats_create(lp_index, idx);
+ if (IS_ERR(stats)) {
+ err = PTR_ERR(stats);
+ goto remove_debugfs_lp_idx;
+ }
+
+ return 0;
+
+remove_debugfs_lp_idx:
+ debugfs_remove_recursive(idx);
+ return err;
+}
+
+static void mshv_debugfs_lp_remove(void)
+{
+ int lp_index;
+
+ debugfs_remove_recursive(mshv_debugfs_lp);
+
+ for (lp_index = 0; lp_index < mshv_lps_count; lp_index++)
+ mshv_lp_stats_unmap(lp_index, NULL);
+}
+
+static int __init mshv_debugfs_lp_create(struct dentry *parent)
+{
+ struct dentry *lp_dir;
+ int err, lp_index;
+
+ lp_dir = debugfs_create_dir("lp", parent);
+ if (IS_ERR(lp_dir))
+ return PTR_ERR(lp_dir);
+
+ for (lp_index = 0; lp_index < mshv_lps_count; lp_index++) {
+ err = lp_debugfs_create(lp_index, lp_dir);
+ if (err)
+ goto remove_debugfs_lps;
+ }
+
+ mshv_debugfs_lp = lp_dir;
+
+ return 0;
+
+remove_debugfs_lps:
+ for (lp_index -= 1; lp_index >= 0; lp_index--)
+ mshv_lp_stats_unmap(lp_index, NULL);
+ debugfs_remove_recursive(lp_dir);
+ return err;
+}
+
+static int vp_stats_show(struct seq_file *m, void *v)
+{
+ const struct hv_stats_page **pstats = m->private;
+
+#define VP_SEQ_PRINTF(cnt) \
+do { \
+ if (pstats[HV_STATS_AREA_SELF]->vp_cntrs[Vp##cnt]) \
+ seq_printf(m, "%-30s: %llu\n", __stringify(cnt), \
+ pstats[HV_STATS_AREA_SELF]->vp_cntrs[Vp##cnt]); \
+ else \
+ seq_printf(m, "%-30s: %llu\n", __stringify(cnt), \
+ pstats[HV_STATS_AREA_PARENT]->vp_cntrs[Vp##cnt]); \
+} while (0)
+
+ VP_SEQ_PRINTF(TotalRunTime);
+ VP_SEQ_PRINTF(HypervisorRunTime);
+ VP_SEQ_PRINTF(RemoteNodeRunTime);
+ VP_SEQ_PRINTF(NormalizedRunTime);
+ VP_SEQ_PRINTF(IdealCpu);
+ VP_SEQ_PRINTF(HypercallsCount);
+ VP_SEQ_PRINTF(HypercallsTime);
+#if IS_ENABLED(CONFIG_X86_64)
+ VP_SEQ_PRINTF(PageInvalidationsCount);
+ VP_SEQ_PRINTF(PageInvalidationsTime);
+ VP_SEQ_PRINTF(ControlRegisterAccessesCount);
+ VP_SEQ_PRINTF(ControlRegisterAccessesTime);
+ VP_SEQ_PRINTF(IoInstructionsCount);
+ VP_SEQ_PRINTF(IoInstructionsTime);
+ VP_SEQ_PRINTF(HltInstructionsCount);
+ VP_SEQ_PRINTF(HltInstructionsTime);
+ VP_SEQ_PRINTF(MwaitInstructionsCount);
+ VP_SEQ_PRINTF(MwaitInstructionsTime);
+ VP_SEQ_PRINTF(CpuidInstructionsCount);
+ VP_SEQ_PRINTF(CpuidInstructionsTime);
+ VP_SEQ_PRINTF(MsrAccessesCount);
+ VP_SEQ_PRINTF(MsrAccessesTime);
+ VP_SEQ_PRINTF(OtherInterceptsCount);
+ VP_SEQ_PRINTF(OtherInterceptsTime);
+ VP_SEQ_PRINTF(ExternalInterruptsCount);
+ VP_SEQ_PRINTF(ExternalInterruptsTime);
+ VP_SEQ_PRINTF(PendingInterruptsCount);
+ VP_SEQ_PRINTF(PendingInterruptsTime);
+ VP_SEQ_PRINTF(EmulatedInstructionsCount);
+ VP_SEQ_PRINTF(EmulatedInstructionsTime);
+ VP_SEQ_PRINTF(DebugRegisterAccessesCount);
+ VP_SEQ_PRINTF(DebugRegisterAccessesTime);
+ VP_SEQ_PRINTF(PageFaultInterceptsCount);
+ VP_SEQ_PRINTF(PageFaultInterceptsTime);
+ VP_SEQ_PRINTF(GuestPageTableMaps);
+ VP_SEQ_PRINTF(LargePageTlbFills);
+ VP_SEQ_PRINTF(SmallPageTlbFills);
+ VP_SEQ_PRINTF(ReflectedGuestPageFaults);
+ VP_SEQ_PRINTF(ApicMmioAccesses);
+ VP_SEQ_PRINTF(IoInterceptMessages);
+ VP_SEQ_PRINTF(MemoryInterceptMessages);
+ VP_SEQ_PRINTF(ApicEoiAccesses);
+ VP_SEQ_PRINTF(OtherMessages);
+ VP_SEQ_PRINTF(PageTableAllocations);
+ VP_SEQ_PRINTF(LogicalProcessorMigrations);
+ VP_SEQ_PRINTF(AddressSpaceEvictions);
+ VP_SEQ_PRINTF(AddressSpaceSwitches);
+ VP_SEQ_PRINTF(AddressDomainFlushes);
+ VP_SEQ_PRINTF(AddressSpaceFlushes);
+ VP_SEQ_PRINTF(GlobalGvaRangeFlushes);
+ VP_SEQ_PRINTF(LocalGvaRangeFlushes);
+ VP_SEQ_PRINTF(PageTableEvictions);
+ VP_SEQ_PRINTF(PageTableReclamations);
+ VP_SEQ_PRINTF(PageTableResets);
+ VP_SEQ_PRINTF(PageTableValidations);
+ VP_SEQ_PRINTF(ApicTprAccesses);
+ VP_SEQ_PRINTF(PageTableWriteIntercepts);
+ VP_SEQ_PRINTF(SyntheticInterrupts);
+ VP_SEQ_PRINTF(VirtualInterrupts);
+ VP_SEQ_PRINTF(ApicIpisSent);
+ VP_SEQ_PRINTF(ApicSelfIpisSent);
+ VP_SEQ_PRINTF(GpaSpaceHypercalls);
+ VP_SEQ_PRINTF(LogicalProcessorHypercalls);
+ VP_SEQ_PRINTF(LongSpinWaitHypercalls);
+ VP_SEQ_PRINTF(OtherHypercalls);
+ VP_SEQ_PRINTF(SyntheticInterruptHypercalls);
+ VP_SEQ_PRINTF(VirtualInterruptHypercalls);
+ VP_SEQ_PRINTF(VirtualMmuHypercalls);
+ VP_SEQ_PRINTF(VirtualProcessorHypercalls);
+ VP_SEQ_PRINTF(HardwareInterrupts);
+ VP_SEQ_PRINTF(NestedPageFaultInterceptsCount);
+ VP_SEQ_PRINTF(NestedPageFaultInterceptsTime);
+ VP_SEQ_PRINTF(PageScans);
+ VP_SEQ_PRINTF(LogicalProcessorDispatches);
+ VP_SEQ_PRINTF(WaitingForCpuTime);
+ VP_SEQ_PRINTF(ExtendedHypercalls);
+ VP_SEQ_PRINTF(ExtendedHypercallInterceptMessages);
+ VP_SEQ_PRINTF(MbecNestedPageTableSwitches);
+ VP_SEQ_PRINTF(OtherReflectedGuestExceptions);
+ VP_SEQ_PRINTF(GlobalIoTlbFlushes);
+ VP_SEQ_PRINTF(GlobalIoTlbFlushCost);
+ VP_SEQ_PRINTF(LocalIoTlbFlushes);
+ VP_SEQ_PRINTF(LocalIoTlbFlushCost);
+ VP_SEQ_PRINTF(HypercallsForwardedCount);
+ VP_SEQ_PRINTF(HypercallsForwardingTime);
+ VP_SEQ_PRINTF(PageInvalidationsForwardedCount);
+ VP_SEQ_PRINTF(PageInvalidationsForwardingTime);
+ VP_SEQ_PRINTF(ControlRegisterAccessesForwardedCount);
+ VP_SEQ_PRINTF(ControlRegisterAccessesForwardingTime);
+ VP_SEQ_PRINTF(IoInstructionsForwardedCount);
+ VP_SEQ_PRINTF(IoInstructionsForwardingTime);
+ VP_SEQ_PRINTF(HltInstructionsForwardedCount);
+ VP_SEQ_PRINTF(HltInstructionsForwardingTime);
+ VP_SEQ_PRINTF(MwaitInstructionsForwardedCount);
+ VP_SEQ_PRINTF(MwaitInstructionsForwardingTime);
+ VP_SEQ_PRINTF(CpuidInstructionsForwardedCount);
+ VP_SEQ_PRINTF(CpuidInstructionsForwardingTime);
+ VP_SEQ_PRINTF(MsrAccessesForwardedCount);
+ VP_SEQ_PRINTF(MsrAccessesForwardingTime);
+ VP_SEQ_PRINTF(OtherInterceptsForwardedCount);
+ VP_SEQ_PRINTF(OtherInterceptsForwardingTime);
+ VP_SEQ_PRINTF(ExternalInterruptsForwardedCount);
+ VP_SEQ_PRINTF(ExternalInterruptsForwardingTime);
+ VP_SEQ_PRINTF(PendingInterruptsForwardedCount);
+ VP_SEQ_PRINTF(PendingInterruptsForwardingTime);
+ VP_SEQ_PRINTF(EmulatedInstructionsForwardedCount);
+ VP_SEQ_PRINTF(EmulatedInstructionsForwardingTime);
+ VP_SEQ_PRINTF(DebugRegisterAccessesForwardedCount);
+ VP_SEQ_PRINTF(DebugRegisterAccessesForwardingTime);
+ VP_SEQ_PRINTF(PageFaultInterceptsForwardedCount);
+ VP_SEQ_PRINTF(PageFaultInterceptsForwardingTime);
+ VP_SEQ_PRINTF(VmclearEmulationCount);
+ VP_SEQ_PRINTF(VmclearEmulationTime);
+ VP_SEQ_PRINTF(VmptrldEmulationCount);
+ VP_SEQ_PRINTF(VmptrldEmulationTime);
+ VP_SEQ_PRINTF(VmptrstEmulationCount);
+ VP_SEQ_PRINTF(VmptrstEmulationTime);
+ VP_SEQ_PRINTF(VmreadEmulationCount);
+ VP_SEQ_PRINTF(VmreadEmulationTime);
+ VP_SEQ_PRINTF(VmwriteEmulationCount);
+ VP_SEQ_PRINTF(VmwriteEmulationTime);
+ VP_SEQ_PRINTF(VmxoffEmulationCount);
+ VP_SEQ_PRINTF(VmxoffEmulationTime);
+ VP_SEQ_PRINTF(VmxonEmulationCount);
+ VP_SEQ_PRINTF(VmxonEmulationTime);
+ VP_SEQ_PRINTF(NestedVMEntriesCount);
+ VP_SEQ_PRINTF(NestedVMEntriesTime);
+ VP_SEQ_PRINTF(NestedSLATSoftPageFaultsCount);
+ VP_SEQ_PRINTF(NestedSLATSoftPageFaultsTime);
+ VP_SEQ_PRINTF(NestedSLATHardPageFaultsCount);
+ VP_SEQ_PRINTF(NestedSLATHardPageFaultsTime);
+ VP_SEQ_PRINTF(InvEptAllContextEmulationCount);
+ VP_SEQ_PRINTF(InvEptAllContextEmulationTime);
+ VP_SEQ_PRINTF(InvEptSingleContextEmulationCount);
+ VP_SEQ_PRINTF(InvEptSingleContextEmulationTime);
+ VP_SEQ_PRINTF(InvVpidAllContextEmulationCount);
+ VP_SEQ_PRINTF(InvVpidAllContextEmulationTime);
+ VP_SEQ_PRINTF(InvVpidSingleContextEmulationCount);
+ VP_SEQ_PRINTF(InvVpidSingleContextEmulationTime);
+ VP_SEQ_PRINTF(InvVpidSingleAddressEmulationCount);
+ VP_SEQ_PRINTF(InvVpidSingleAddressEmulationTime);
+ VP_SEQ_PRINTF(NestedTlbPageTableReclamations);
+ VP_SEQ_PRINTF(NestedTlbPageTableEvictions);
+ VP_SEQ_PRINTF(FlushGuestPhysicalAddressSpaceHypercalls);
+ VP_SEQ_PRINTF(FlushGuestPhysicalAddressListHypercalls);
+ VP_SEQ_PRINTF(PostedInterruptNotifications);
+ VP_SEQ_PRINTF(PostedInterruptScans);
+ VP_SEQ_PRINTF(TotalCoreRunTime);
+ VP_SEQ_PRINTF(MaximumRunTime);
+ VP_SEQ_PRINTF(HwpRequestContextSwitches);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket0);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket1);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket2);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket3);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket4);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket5);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket6);
+ VP_SEQ_PRINTF(VmloadEmulationCount);
+ VP_SEQ_PRINTF(VmloadEmulationTime);
+ VP_SEQ_PRINTF(VmsaveEmulationCount);
+ VP_SEQ_PRINTF(VmsaveEmulationTime);
+ VP_SEQ_PRINTF(GifInstructionEmulationCount);
+ VP_SEQ_PRINTF(GifInstructionEmulationTime);
+ VP_SEQ_PRINTF(EmulatedErrataSvmInstructions);
+ VP_SEQ_PRINTF(Placeholder1);
+ VP_SEQ_PRINTF(Placeholder2);
+ VP_SEQ_PRINTF(Placeholder3);
+ VP_SEQ_PRINTF(Placeholder4);
+ VP_SEQ_PRINTF(Placeholder5);
+ VP_SEQ_PRINTF(Placeholder6);
+ VP_SEQ_PRINTF(Placeholder7);
+ VP_SEQ_PRINTF(Placeholder8);
+ VP_SEQ_PRINTF(Placeholder9);
+ VP_SEQ_PRINTF(Placeholder10);
+ VP_SEQ_PRINTF(SchedulingPriority);
+ VP_SEQ_PRINTF(RdpmcInstructionsCount);
+ VP_SEQ_PRINTF(RdpmcInstructionsTime);
+ VP_SEQ_PRINTF(PerfmonPmuMsrAccessesCount);
+ VP_SEQ_PRINTF(PerfmonLbrMsrAccessesCount);
+ VP_SEQ_PRINTF(PerfmonIptMsrAccessesCount);
+ VP_SEQ_PRINTF(PerfmonInterruptCount);
+ VP_SEQ_PRINTF(Vtl1DispatchCount);
+ VP_SEQ_PRINTF(Vtl2DispatchCount);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket0);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket1);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket2);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket3);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket4);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket5);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket6);
+ VP_SEQ_PRINTF(Vtl1RunTime);
+ VP_SEQ_PRINTF(Vtl2RunTime);
+ VP_SEQ_PRINTF(IommuHypercalls);
+ VP_SEQ_PRINTF(CpuGroupHypercalls);
+ VP_SEQ_PRINTF(VsmHypercalls);
+ VP_SEQ_PRINTF(EventLogHypercalls);
+ VP_SEQ_PRINTF(DeviceDomainHypercalls);
+ VP_SEQ_PRINTF(DepositHypercalls);
+ VP_SEQ_PRINTF(SvmHypercalls);
+ VP_SEQ_PRINTF(BusLockAcquisitionCount);
+#elif IS_ENABLED(CONFIG_ARM64)
+ VP_SEQ_PRINTF(SysRegAccessesCount);
+ VP_SEQ_PRINTF(SysRegAccessesTime);
+ VP_SEQ_PRINTF(SmcInstructionsCount);
+ VP_SEQ_PRINTF(SmcInstructionsTime);
+ VP_SEQ_PRINTF(OtherInterceptsCount);
+ VP_SEQ_PRINTF(OtherInterceptsTime);
+ VP_SEQ_PRINTF(ExternalInterruptsCount);
+ VP_SEQ_PRINTF(ExternalInterruptsTime);
+ VP_SEQ_PRINTF(PendingInterruptsCount);
+ VP_SEQ_PRINTF(PendingInterruptsTime);
+ VP_SEQ_PRINTF(GuestPageTableMaps);
+ VP_SEQ_PRINTF(LargePageTlbFills);
+ VP_SEQ_PRINTF(SmallPageTlbFills);
+ VP_SEQ_PRINTF(ReflectedGuestPageFaults);
+ VP_SEQ_PRINTF(MemoryInterceptMessages);
+ VP_SEQ_PRINTF(OtherMessages);
+ VP_SEQ_PRINTF(LogicalProcessorMigrations);
+ VP_SEQ_PRINTF(AddressDomainFlushes);
+ VP_SEQ_PRINTF(AddressSpaceFlushes);
+ VP_SEQ_PRINTF(SyntheticInterrupts);
+ VP_SEQ_PRINTF(VirtualInterrupts);
+ VP_SEQ_PRINTF(ApicSelfIpisSent);
+ VP_SEQ_PRINTF(GpaSpaceHypercalls);
+ VP_SEQ_PRINTF(LogicalProcessorHypercalls);
+ VP_SEQ_PRINTF(LongSpinWaitHypercalls);
+ VP_SEQ_PRINTF(OtherHypercalls);
+ VP_SEQ_PRINTF(SyntheticInterruptHypercalls);
+ VP_SEQ_PRINTF(VirtualInterruptHypercalls);
+ VP_SEQ_PRINTF(VirtualMmuHypercalls);
+ VP_SEQ_PRINTF(VirtualProcessorHypercalls);
+ VP_SEQ_PRINTF(HardwareInterrupts);
+ VP_SEQ_PRINTF(NestedPageFaultInterceptsCount);
+ VP_SEQ_PRINTF(NestedPageFaultInterceptsTime);
+ VP_SEQ_PRINTF(LogicalProcessorDispatches);
+ VP_SEQ_PRINTF(WaitingForCpuTime);
+ VP_SEQ_PRINTF(ExtendedHypercalls);
+ VP_SEQ_PRINTF(ExtendedHypercallInterceptMessages);
+ VP_SEQ_PRINTF(MbecNestedPageTableSwitches);
+ VP_SEQ_PRINTF(OtherReflectedGuestExceptions);
+ VP_SEQ_PRINTF(GlobalIoTlbFlushes);
+ VP_SEQ_PRINTF(GlobalIoTlbFlushCost);
+ VP_SEQ_PRINTF(LocalIoTlbFlushes);
+ VP_SEQ_PRINTF(LocalIoTlbFlushCost);
+ VP_SEQ_PRINTF(FlushGuestPhysicalAddressSpaceHypercalls);
+ VP_SEQ_PRINTF(FlushGuestPhysicalAddressListHypercalls);
+ VP_SEQ_PRINTF(PostedInterruptNotifications);
+ VP_SEQ_PRINTF(PostedInterruptScans);
+ VP_SEQ_PRINTF(TotalCoreRunTime);
+ VP_SEQ_PRINTF(MaximumRunTime);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket0);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket1);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket2);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket3);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket4);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket5);
+ VP_SEQ_PRINTF(WaitingForCpuTimeBucket6);
+ VP_SEQ_PRINTF(HwpRequestContextSwitches);
+ VP_SEQ_PRINTF(Placeholder2);
+ VP_SEQ_PRINTF(Placeholder3);
+ VP_SEQ_PRINTF(Placeholder4);
+ VP_SEQ_PRINTF(Placeholder5);
+ VP_SEQ_PRINTF(Placeholder6);
+ VP_SEQ_PRINTF(Placeholder7);
+ VP_SEQ_PRINTF(Placeholder8);
+ VP_SEQ_PRINTF(ContentionTime);
+ VP_SEQ_PRINTF(WakeUpTime);
+ VP_SEQ_PRINTF(SchedulingPriority);
+ VP_SEQ_PRINTF(Vtl1DispatchCount);
+ VP_SEQ_PRINTF(Vtl2DispatchCount);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket0);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket1);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket2);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket3);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket4);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket5);
+ VP_SEQ_PRINTF(Vtl2DispatchBucket6);
+ VP_SEQ_PRINTF(Vtl1RunTime);
+ VP_SEQ_PRINTF(Vtl2RunTime);
+ VP_SEQ_PRINTF(IommuHypercalls);
+ VP_SEQ_PRINTF(CpuGroupHypercalls);
+ VP_SEQ_PRINTF(VsmHypercalls);
+ VP_SEQ_PRINTF(EventLogHypercalls);
+ VP_SEQ_PRINTF(DeviceDomainHypercalls);
+ VP_SEQ_PRINTF(DepositHypercalls);
+ VP_SEQ_PRINTF(SvmHypercalls);
+#endif
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(vp_stats);
+
+static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index, void *stats_page_addr,
+ enum hv_stats_area_type stats_area_type)
+{
+ union hv_stats_object_identity identity = {
+ .vp.partition_id = partition_id,
+ .vp.vp_index = vp_index,
+ .vp.stats_area_type = stats_area_type,
+ };
+ int err;
+
+ err = hv_unmap_stats_page(HV_STATS_OBJECT_VP, stats_page_addr, &identity);
+ if (err)
+ pr_err("%s: failed to unmap partition %llu vp %u %s stats, err: %d\n",
+ __func__, partition_id, vp_index,
+ (stats_area_type == HV_STATS_AREA_SELF) ? "self" : "parent",
+ err);
+}
+
+static void *mshv_vp_stats_map(u64 partition_id, u32 vp_index,
+ enum hv_stats_area_type stats_area_type)
+{
+ union hv_stats_object_identity identity = {
+ .vp.partition_id = partition_id,
+ .vp.vp_index = vp_index,
+ .vp.stats_area_type = stats_area_type,
+ };
+ void *stats;
+ int err;
+
+ err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, &stats);
+ if (err) {
+ pr_err("%s: failed to map partition %llu vp %u %s stats, err: %d\n",
+ __func__, partition_id, vp_index,
+ (stats_area_type == HV_STATS_AREA_SELF) ? "self" : "parent",
+ err);
+ return ERR_PTR(err);
+ }
+ return stats;
+}
+
+static int vp_debugfs_stats_create(u64 partition_id, u32 vp_index,
+ struct dentry **vp_stats_ptr,
+ struct dentry *parent)
+{
+ struct dentry *dentry;
+ struct hv_stats_page **pstats;
+ int err;
+
+ pstats = kcalloc(2, sizeof(struct hv_stats_page *), GFP_KERNEL_ACCOUNT);
+ if (!pstats)
+ return -ENOMEM;
+
+ pstats[HV_STATS_AREA_SELF] = mshv_vp_stats_map(partition_id, vp_index,
+ HV_STATS_AREA_SELF);
+ if (IS_ERR(pstats[HV_STATS_AREA_SELF])) {
+ err = PTR_ERR(pstats[HV_STATS_AREA_SELF]);
+ goto cleanup;
+ }
+
+ /*
+ * L1VH partition cannot access its vp stats in parent area.
+ */
+ if (is_l1vh_parent(partition_id)) {
+ pstats[HV_STATS_AREA_PARENT] = pstats[HV_STATS_AREA_SELF];
+ } else {
+ pstats[HV_STATS_AREA_PARENT] = mshv_vp_stats_map(
+ partition_id, vp_index, HV_STATS_AREA_PARENT);
+ if (IS_ERR(pstats[HV_STATS_AREA_PARENT])) {
+ err = PTR_ERR(pstats[HV_STATS_AREA_PARENT]);
+ goto unmap_self;
+ }
+ if (!pstats[HV_STATS_AREA_PARENT])
+ pstats[HV_STATS_AREA_PARENT] = pstats[HV_STATS_AREA_SELF];
+ }
+
+ dentry = debugfs_create_file("stats", 0400, parent,
+ pstats, &vp_stats_fops);
+ if (IS_ERR(dentry)) {
+ err = PTR_ERR(dentry);
+ goto unmap_vp_stats;
+ }
+
+ *vp_stats_ptr = dentry;
+ return 0;
+
+unmap_vp_stats:
+ if (pstats[HV_STATS_AREA_PARENT] != pstats[HV_STATS_AREA_SELF])
+ mshv_vp_stats_unmap(partition_id, vp_index, pstats[HV_STATS_AREA_PARENT],
+ HV_STATS_AREA_PARENT);
+unmap_self:
+ mshv_vp_stats_unmap(partition_id, vp_index, pstats[HV_STATS_AREA_SELF],
+ HV_STATS_AREA_SELF);
+cleanup:
+ kfree(pstats);
+ return err;
+}
+
+static void vp_debugfs_remove(u64 partition_id, u32 vp_index,
+ struct dentry *vp_stats)
+{
+ struct hv_stats_page **pstats = NULL;
+ void *stats;
+
+ pstats = vp_stats->d_inode->i_private;
+ debugfs_remove_recursive(vp_stats->d_parent);
+ if (pstats[HV_STATS_AREA_PARENT] != pstats[HV_STATS_AREA_SELF]) {
+ stats = pstats[HV_STATS_AREA_PARENT];
+ mshv_vp_stats_unmap(partition_id, vp_index, stats,
+ HV_STATS_AREA_PARENT);
+ }
+
+ stats = pstats[HV_STATS_AREA_SELF];
+ mshv_vp_stats_unmap(partition_id, vp_index, stats, HV_STATS_AREA_SELF);
+
+ kfree(pstats);
+}
+
+static int vp_debugfs_create(u64 partition_id, u32 vp_index,
+ struct dentry **vp_stats_ptr,
+ struct dentry *parent)
+{
+ struct dentry *vp_idx_dir;
+ char vp_idx_str[U32_BUF_SZ];
+ int err;
+
+ sprintf(vp_idx_str, "%u", vp_index);
+
+ vp_idx_dir = debugfs_create_dir(vp_idx_str, parent);
+ if (IS_ERR(vp_idx_dir))
+ return PTR_ERR(vp_idx_dir);
+
+ err = vp_debugfs_stats_create(partition_id, vp_index, vp_stats_ptr,
+ vp_idx_dir);
+ if (err)
+ goto remove_debugfs_vp_idx;
+
+ return 0;
+
+remove_debugfs_vp_idx:
+ debugfs_remove_recursive(vp_idx_dir);
+ return err;
+}
+
+static int partition_stats_show(struct seq_file *m, void *v)
+{
+ const struct hv_stats_page **pstats = m->private;
+
+#define PARTITION_SEQ_PRINTF(cnt) \
+do { \
+ if (pstats[HV_STATS_AREA_SELF]->pt_cntrs[Partition##cnt]) \
+ seq_printf(m, "%-30s: %llu\n", __stringify(cnt), \
+ pstats[HV_STATS_AREA_SELF]->pt_cntrs[Partition##cnt]); \
+ else \
+ seq_printf(m, "%-30s: %llu\n", __stringify(cnt), \
+ pstats[HV_STATS_AREA_PARENT]->pt_cntrs[Partition##cnt]); \
+} while (0)
+
+ PARTITION_SEQ_PRINTF(VirtualProcessors);
+ PARTITION_SEQ_PRINTF(TlbSize);
+ PARTITION_SEQ_PRINTF(AddressSpaces);
+ PARTITION_SEQ_PRINTF(DepositedPages);
+ PARTITION_SEQ_PRINTF(GpaPages);
+ PARTITION_SEQ_PRINTF(GpaSpaceModifications);
+ PARTITION_SEQ_PRINTF(VirtualTlbFlushEntires);
+ PARTITION_SEQ_PRINTF(RecommendedTlbSize);
+ PARTITION_SEQ_PRINTF(GpaPages4K);
+ PARTITION_SEQ_PRINTF(GpaPages2M);
+ PARTITION_SEQ_PRINTF(GpaPages1G);
+ PARTITION_SEQ_PRINTF(GpaPages512G);
+ PARTITION_SEQ_PRINTF(DevicePages4K);
+ PARTITION_SEQ_PRINTF(DevicePages2M);
+ PARTITION_SEQ_PRINTF(DevicePages1G);
+ PARTITION_SEQ_PRINTF(DevicePages512G);
+ PARTITION_SEQ_PRINTF(AttachedDevices);
+ PARTITION_SEQ_PRINTF(DeviceInterruptMappings);
+ PARTITION_SEQ_PRINTF(IoTlbFlushes);
+ PARTITION_SEQ_PRINTF(IoTlbFlushCost);
+ PARTITION_SEQ_PRINTF(DeviceInterruptErrors);
+ PARTITION_SEQ_PRINTF(DeviceDmaErrors);
+ PARTITION_SEQ_PRINTF(DeviceInterruptThrottleEvents);
+ PARTITION_SEQ_PRINTF(SkippedTimerTicks);
+ PARTITION_SEQ_PRINTF(PartitionId);
+#if IS_ENABLED(CONFIG_X86_64)
+ PARTITION_SEQ_PRINTF(NestedTlbSize);
+ PARTITION_SEQ_PRINTF(RecommendedNestedTlbSize);
+ PARTITION_SEQ_PRINTF(NestedTlbFreeListSize);
+ PARTITION_SEQ_PRINTF(NestedTlbTrimmedPages);
+ PARTITION_SEQ_PRINTF(PagesShattered);
+ PARTITION_SEQ_PRINTF(PagesRecombined);
+ PARTITION_SEQ_PRINTF(HwpRequestValue);
+#elif IS_ENABLED(CONFIG_ARM64)
+ PARTITION_SEQ_PRINTF(HwpRequestValue);
+#endif
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(partition_stats);
+
+static void mshv_partition_stats_unmap(u64 partition_id, void *stats_page_addr,
+ enum hv_stats_area_type stats_area_type)
+{
+ union hv_stats_object_identity identity = {
+ .partition.partition_id = partition_id,
+ .partition.stats_area_type = stats_area_type,
+ };
+ int err;
+
+ err = hv_unmap_stats_page(HV_STATS_OBJECT_PARTITION, stats_page_addr,
+ &identity);
+ if (err) {
+ pr_err("%s: failed to unmap partition %lld %s stats, err: %d\n",
+ __func__, partition_id,
+ (stats_area_type == HV_STATS_AREA_SELF) ? "self" : "parent",
+ err);
+ }
+}
+
+static void *mshv_partition_stats_map(u64 partition_id,
+ enum hv_stats_area_type stats_area_type)
+{
+ union hv_stats_object_identity identity = {
+ .partition.partition_id = partition_id,
+ .partition.stats_area_type = stats_area_type,
+ };
+ void *stats;
+ int err;
+
+ err = hv_map_stats_page(HV_STATS_OBJECT_PARTITION, &identity, &stats);
+ if (err) {
+ pr_err("%s: failed to map partition %lld %s stats, err: %d\n",
+ __func__, partition_id,
+ (stats_area_type == HV_STATS_AREA_SELF) ? "self" : "parent",
+ err);
+ return ERR_PTR(err);
+ }
+ return stats;
+}
+
+static int mshv_debugfs_partition_stats_create(u64 partition_id,
+ struct dentry **partition_stats_ptr,
+ struct dentry *parent)
+{
+ struct dentry *dentry;
+ struct hv_stats_page **pstats;
+ int err;
+
+ pstats = kcalloc(2, sizeof(struct hv_stats_page *), GFP_KERNEL_ACCOUNT);
+ if (!pstats)
+ return -ENOMEM;
+
+ pstats[HV_STATS_AREA_SELF] = mshv_partition_stats_map(partition_id,
+ HV_STATS_AREA_SELF);
+ if (IS_ERR(pstats[HV_STATS_AREA_SELF])) {
+ err = PTR_ERR(pstats[HV_STATS_AREA_SELF]);
+ goto cleanup;
+ }
+
+ /*
+ * L1VH partition cannot access its partition stats in parent area.
+ */
+ if (is_l1vh_parent(partition_id)) {
+ pstats[HV_STATS_AREA_PARENT] = pstats[HV_STATS_AREA_SELF];
+ } else {
+ pstats[HV_STATS_AREA_PARENT] = mshv_partition_stats_map(partition_id,
+ HV_STATS_AREA_PARENT);
+ if (IS_ERR(pstats[HV_STATS_AREA_PARENT])) {
+ err = PTR_ERR(pstats[HV_STATS_AREA_PARENT]);
+ goto unmap_self;
+ }
+ if (!pstats[HV_STATS_AREA_PARENT])
+ pstats[HV_STATS_AREA_PARENT] = pstats[HV_STATS_AREA_SELF];
+ }
+
+ dentry = debugfs_create_file("stats", 0400, parent,
+ pstats, &partition_stats_fops);
+ if (IS_ERR(dentry)) {
+ err = PTR_ERR(dentry);
+ goto unmap_partition_stats;
+ }
+
+ *partition_stats_ptr = dentry;
+ return 0;
+
+unmap_partition_stats:
+ if (pstats[HV_STATS_AREA_PARENT] != pstats[HV_STATS_AREA_SELF])
+ mshv_partition_stats_unmap(partition_id, pstats[HV_STATS_AREA_PARENT],
+ HV_STATS_AREA_PARENT);
+unmap_self:
+ mshv_partition_stats_unmap(partition_id, pstats[HV_STATS_AREA_SELF],
+ HV_STATS_AREA_SELF);
+cleanup:
+ kfree(pstats);
+ return err;
+}
+
+static void partition_debugfs_remove(u64 partition_id, struct dentry *dentry)
+{
+ struct hv_stats_page **pstats = NULL;
+ void *stats;
+
+ pstats = dentry->d_inode->i_private;
+
+ debugfs_remove_recursive(dentry->d_parent);
+
+ if (pstats[HV_STATS_AREA_PARENT] != pstats[HV_STATS_AREA_SELF]) {
+ stats = pstats[HV_STATS_AREA_PARENT];
+ mshv_partition_stats_unmap(partition_id, stats, HV_STATS_AREA_PARENT);
+ }
+
+ stats = pstats[HV_STATS_AREA_SELF];
+ mshv_partition_stats_unmap(partition_id, stats, HV_STATS_AREA_SELF);
+
+ kfree(pstats);
+}
+
+static int partition_debugfs_create(u64 partition_id,
+ struct dentry **vp_dir_ptr,
+ struct dentry **partition_stats_ptr,
+ struct dentry *parent)
+{
+ char part_id_str[U64_BUF_SZ];
+ struct dentry *part_id_dir, *vp_dir;
+ int err;
+
+ if (is_l1vh_parent(partition_id))
+ sprintf(part_id_str, "self");
+ else
+ sprintf(part_id_str, "%llu", partition_id);
+
+ part_id_dir = debugfs_create_dir(part_id_str, parent);
+ if (IS_ERR(part_id_dir))
+ return PTR_ERR(part_id_dir);
+
+ vp_dir = debugfs_create_dir("vp", part_id_dir);
+ if (IS_ERR(vp_dir)) {
+ err = PTR_ERR(vp_dir);
+ goto remove_debugfs_partition_id;
+ }
+
+ err = mshv_debugfs_partition_stats_create(partition_id,
+ partition_stats_ptr,
+ part_id_dir);
+ if (err)
+ goto remove_debugfs_partition_id;
+
+ *vp_dir_ptr = vp_dir;
+
+ return 0;
+
+remove_debugfs_partition_id:
+ debugfs_remove_recursive(part_id_dir);
+ return err;
+}
+
+static void mshv_debugfs_parent_partition_remove(void)
+{
+ int idx;
+
+ for_each_online_cpu(idx)
+ vp_debugfs_remove(hv_current_partition_id, idx, NULL);
+
+ partition_debugfs_remove(hv_current_partition_id, NULL);
+}
+
+static int __init mshv_debugfs_parent_partition_create(void)
+{
+ struct dentry *partition_stats, *vp_dir;
+ int err, idx, i;
+
+ mshv_debugfs_partition = debugfs_create_dir("partition",
+ mshv_debugfs);
+ if (IS_ERR(mshv_debugfs_partition))
+ return PTR_ERR(mshv_debugfs_partition);
+
+ err = partition_debugfs_create(hv_current_partition_id,
+ &vp_dir,
+ &partition_stats,
+ mshv_debugfs_partition);
+ if (err)
+ goto remove_debugfs_partition;
+
+ for_each_online_cpu(idx) {
+ struct dentry *vp_stats;
+
+ err = vp_debugfs_create(hv_current_partition_id,
+ hv_vp_index[idx],
+ &vp_stats,
+ vp_dir);
+ if (err)
+ goto remove_debugfs_partition_vp;
+ }
+
+ return 0;
+
+remove_debugfs_partition_vp:
+ for_each_online_cpu(i) {
+ if (i >= idx)
+ break;
+ vp_debugfs_remove(hv_current_partition_id, i, NULL);
+ }
+ partition_debugfs_remove(hv_current_partition_id, NULL);
+remove_debugfs_partition:
+ debugfs_remove_recursive(mshv_debugfs_partition);
+ return err;
+}
+
+static int hv_stats_show(struct seq_file *m, void *v)
+{
+ const struct hv_stats_page *stats = m->private;
+
+#define HV_SEQ_PRINTF(cnt) \
+ seq_printf(m, "%-25s: %llu\n", __stringify(cnt), stats->hv_cntrs[Hv##cnt])
+
+ HV_SEQ_PRINTF(LogicalProcessors);
+ HV_SEQ_PRINTF(Partitions);
+ HV_SEQ_PRINTF(TotalPages);
+ HV_SEQ_PRINTF(VirtualProcessors);
+ HV_SEQ_PRINTF(MonitoredNotifications);
+ HV_SEQ_PRINTF(ModernStandbyEntries);
+ HV_SEQ_PRINTF(PlatformIdleTransitions);
+ HV_SEQ_PRINTF(HypervisorStartupCost);
+ HV_SEQ_PRINTF(IOSpacePages);
+ HV_SEQ_PRINTF(NonEssentialPagesForDump);
+ HV_SEQ_PRINTF(SubsumedPages);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(hv_stats);
+
+static void mshv_hv_stats_unmap(void)
+{
+ union hv_stats_object_identity identity = {
+ .hv.stats_area_type = HV_STATS_AREA_SELF,
+ };
+ int err;
+
+ err = hv_unmap_stats_page(HV_STATS_OBJECT_HYPERVISOR, NULL, &identity);
+ if (err)
+ pr_err("%s: failed to unmap hypervisor stats: %d\n",
+ __func__, err);
+}
+
+static void * __init mshv_hv_stats_map(void)
+{
+ union hv_stats_object_identity identity = {
+ .hv.stats_area_type = HV_STATS_AREA_SELF,
+ };
+ void *stats;
+ int err;
+
+ err = hv_map_stats_page(HV_STATS_OBJECT_HYPERVISOR, &identity, &stats);
+ if (err) {
+ pr_err("%s: failed to map hypervisor stats: %d\n",
+ __func__, err);
+ return ERR_PTR(err);
+ }
+ return stats;
+}
+
+static int __init mshv_debugfs_hv_stats_create(struct dentry *parent)
+{
+ struct dentry *dentry;
+ u64 *stats;
+ int err;
+
+ stats = mshv_hv_stats_map();
+ if (IS_ERR(stats))
+ return PTR_ERR(stats);
+
+ dentry = debugfs_create_file("stats", 0400, parent,
+ stats, &hv_stats_fops);
+ if (IS_ERR(dentry)) {
+ err = PTR_ERR(dentry);
+ pr_err("%s: failed to create hypervisor stats dentry: %d\n",
+ __func__, err);
+ goto unmap_hv_stats;
+ }
+
+ mshv_lps_count = stats[HvLogicalProcessors];
+
+ return 0;
+
+unmap_hv_stats:
+ mshv_hv_stats_unmap();
+ return err;
+}
+
+int mshv_debugfs_vp_create(struct mshv_vp *vp)
+{
+ struct mshv_partition *p = vp->vp_partition;
+ int err;
+
+ if (!mshv_debugfs)
+ return 0;
+
+ err = vp_debugfs_create(p->pt_id, vp->vp_index,
+ &vp->vp_debugfs_stats_dentry,
+ p->pt_debugfs_vp_dentry);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+void mshv_debugfs_vp_remove(struct mshv_vp *vp)
+{
+ if (!mshv_debugfs)
+ return;
+
+ vp_debugfs_remove(vp->vp_partition->pt_id, vp->vp_index,
+ vp->vp_debugfs_stats_dentry);
+}
+
+int mshv_debugfs_partition_create(struct mshv_partition *partition)
+{
+ int err;
+
+ if (!mshv_debugfs)
+ return 0;
+
+ err = partition_debugfs_create(partition->pt_id,
+ &partition->pt_debugfs_vp_dentry,
+ &partition->pt_debugfs_stats_dentry,
+ mshv_debugfs_partition);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+void mshv_debugfs_partition_remove(struct mshv_partition *partition)
+{
+ if (!mshv_debugfs)
+ return;
+
+ partition_debugfs_remove(partition->pt_id,
+ partition->pt_debugfs_stats_dentry);
+}
+
+int __init mshv_debugfs_init(void)
+{
+ int err;
+
+ mshv_debugfs = debugfs_create_dir("mshv", NULL);
+ if (IS_ERR(mshv_debugfs)) {
+ pr_err("%s: failed to create debugfs directory\n", __func__);
+ return PTR_ERR(mshv_debugfs);
+ }
+
+ if (hv_root_partition()) {
+ err = mshv_debugfs_hv_stats_create(mshv_debugfs);
+ if (err)
+ goto remove_mshv_dir;
+
+ err = mshv_debugfs_lp_create(mshv_debugfs);
+ if (err)
+ goto unmap_hv_stats;
+ }
+
+ err = mshv_debugfs_parent_partition_create();
+ if (err)
+ goto unmap_lp_stats;
+
+ return 0;
+
+unmap_lp_stats:
+ if (hv_root_partition())
+ mshv_debugfs_lp_remove();
+unmap_hv_stats:
+ if (hv_root_partition())
+ mshv_hv_stats_unmap();
+remove_mshv_dir:
+ debugfs_remove_recursive(mshv_debugfs);
+ return err;
+}
+
+void mshv_debugfs_exit(void)
+{
+ mshv_debugfs_parent_partition_remove();
+
+ if (hv_root_partition()) {
+ mshv_debugfs_lp_remove();
+ mshv_hv_stats_unmap();
+ }
+
+ debugfs_remove_recursive(mshv_debugfs);
+}
diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index 3eb815011b46..1f1b1984449b 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -51,6 +51,9 @@ struct mshv_vp {
unsigned int kicked_by_hv;
wait_queue_head_t vp_suspend_queue;
} run;
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+ struct dentry *vp_debugfs_stats_dentry;
+#endif
};
#define vp_fmt(fmt) "p%lluvp%u: " fmt
@@ -128,6 +131,10 @@ struct mshv_partition {
u64 isolation_type;
bool import_completed;
bool pt_initialized;
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+ struct dentry *pt_debugfs_stats_dentry;
+ struct dentry *pt_debugfs_vp_dentry;
+#endif
};
#define pt_fmt(fmt) "p%llu: " fmt
@@ -308,6 +315,33 @@ int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
int hv_call_get_partition_property_ex(u64 partition_id, u64 property_code, u64 arg,
void *property_value, size_t property_value_sz);
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+int __init mshv_debugfs_init(void);
+void mshv_debugfs_exit(void);
+
+int mshv_debugfs_partition_create(struct mshv_partition *partition);
+void mshv_debugfs_partition_remove(struct mshv_partition *partition);
+int mshv_debugfs_vp_create(struct mshv_vp *vp);
+void mshv_debugfs_vp_remove(struct mshv_vp *vp);
+#else
+static inline int __init mshv_debugfs_init(void)
+{
+ return 0;
+}
+static inline void mshv_debugfs_exit(void) { }
+
+static inline int mshv_debugfs_partition_create(struct mshv_partition *partition)
+{
+ return 0;
+}
+static inline void mshv_debugfs_partition_remove(struct mshv_partition *partition) { }
+static inline int mshv_debugfs_vp_create(struct mshv_vp *vp)
+{
+ return 0;
+}
+static inline void mshv_debugfs_vp_remove(struct mshv_vp *vp) { }
+#endif
+
extern struct mshv_root mshv_root;
extern enum hv_scheduler_type hv_scheduler_type;
extern u8 * __percpu *hv_synic_eventring_tail;
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 19006b788e85..152fcd9b45e6 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -982,6 +982,10 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
memcpy(vp->vp_stats_pages, stats_pages, sizeof(stats_pages));
+ ret = mshv_debugfs_vp_create(vp);
+ if (ret)
+ goto put_partition;
+
/*
* Keep anon_inode_getfd last: it installs fd in the file struct and
* thus makes the state accessible in user space.
@@ -989,7 +993,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
ret = anon_inode_getfd("mshv_vp", &mshv_vp_fops, vp,
O_RDWR | O_CLOEXEC);
if (ret < 0)
- goto put_partition;
+ goto remove_debugfs_vp;
/* already exclusive with the partition mutex for all ioctls */
partition->pt_vp_count++;
@@ -997,6 +1001,8 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
return ret;
+remove_debugfs_vp:
+ mshv_debugfs_vp_remove(vp);
put_partition:
mshv_partition_put(partition);
free_vp:
@@ -1556,13 +1562,18 @@ mshv_partition_ioctl_initialize(struct mshv_partition *partition)
ret = hv_call_initialize_partition(partition->pt_id);
if (ret)
- goto withdraw_mem;
+ return ret;
+
+ ret = mshv_debugfs_partition_create(partition);
+ if (ret)
+ goto finalize_partition;
partition->pt_initialized = true;
return 0;
-withdraw_mem:
+finalize_partition:
+ hv_call_finalize_partition(partition->pt_id);
hv_call_withdraw_memory(U64_MAX, NUMA_NO_NODE, partition->pt_id);
return ret;
@@ -1741,6 +1752,8 @@ static void destroy_partition(struct mshv_partition *partition)
if (!vp)
continue;
+ mshv_debugfs_vp_remove(vp);
+
if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
mshv_vp_stats_unmap(partition->pt_id, vp->vp_index,
(void **)vp->vp_stats_pages);
@@ -1775,6 +1788,8 @@ static void destroy_partition(struct mshv_partition *partition)
partition->pt_vp_array[i] = NULL;
}
+ mshv_debugfs_partition_remove(partition);
+
/* Deallocates and unmaps everything including vcpus, GPA mappings etc */
hv_call_finalize_partition(partition->pt_id);
@@ -2351,10 +2366,14 @@ static int __init mshv_parent_partition_init(void)
mshv_init_vmm_caps(dev);
- ret = mshv_irqfd_wq_init();
+ ret = mshv_debugfs_init();
if (ret)
goto exit_partition;
+ ret = mshv_irqfd_wq_init();
+ if (ret)
+ goto exit_debugfs;
+
spin_lock_init(&mshv_root.pt_ht_lock);
hash_init(mshv_root.pt_htable);
@@ -2362,6 +2381,10 @@ static int __init mshv_parent_partition_init(void)
return 0;
+destroy_irqds_wq:
+ mshv_irqfd_wq_cleanup();
+exit_debugfs:
+ mshv_debugfs_exit();
exit_partition:
if (hv_root_partition())
mshv_root_partition_exit();
@@ -2378,6 +2401,7 @@ static void __exit mshv_parent_partition_exit(void)
{
hv_setup_mshv_handler(NULL);
mshv_port_table_fini();
+ mshv_debugfs_exit();
misc_deregister(&mshv_dev);
mshv_irqfd_wq_cleanup();
if (hv_root_partition())
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread