From nobody Tue Dec 16 07:34:53 2025 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 646A4348890; Fri, 5 Dec 2025 19:04:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764961475; cv=none; b=CwyE+KHvkGJs8wFAM1QQ0K6eP07LQ8VmDcru1ECKca/0zKiUMfPNvfgXZQvGYpHl07Jp+z9XdWqsJEGhCGgPR2YqWeT5m9j1suDGT4q7osmZ3cYjGL2LPUbbrC6BytxY4muo9w7YjRGnLNMguF1GcV9eH/op1tNyX5uKE7slJWM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764961475; c=relaxed/simple; bh=v34lNSYUMfAClbsC8dxdNs47oE5/pIRrGyM+BO0aMZE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=Spj/NgUSII+fvyUyX81iDdI8hagCtK06ymhX+FH7drN0Qp3X3qjvdFp1rGGf6eZG4outvfgvpd7ZF/95MLdsT6YA7dbyxBiI3oH73Jmtk5c00CBN/b+qUYJXqX3er8gc805yKl4ivYKCwHFFtugpLtuLePzPa8WrNYDkvljRaFg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=AbTsZugB; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="AbTsZugB" Received: by linux.microsoft.com (Postfix, from userid 1032) id 327212120EB9; Fri, 5 Dec 2025 10:58:44 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 327212120EB9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1764961124; bh=RZBYaJ6/0ul+gTNYIsLZ8iJuQGpVcMEkKZo5zmlTEY8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AbTsZugBaRuJC6p+1+KzsPkH5OIcKXXuw3w/MlvmHT8X64yfHxH+znTC6MK83Tzbn hCZ4VVWBnVaRtZr716Cx+x22Fqh2eyQej6AS8sU03l9Spz+SVSdTQegA09ucayU1bM zcVAmi2CgJjfPt6tnqWMeaVWuqKiLzTHGMAHiGPg= From: Nuno Das Neves To: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, skinsburskii@linux.microsoft.com Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com, longli@microsoft.com, mhklinux@outlook.com, prapal@linux.microsoft.com, mrathor@linux.microsoft.com, paekkaladevi@linux.microsoft.com, Nuno Das Neves Subject: [PATCH v2 1/3] mshv: Ignore second stats page map result failure Date: Fri, 5 Dec 2025 10:58:40 -0800 Message-Id: <1764961122-31679-2-git-send-email-nunodasneves@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1764961122-31679-1-git-send-email-nunodasneves@linux.microsoft.com> References: <1764961122-31679-1-git-send-email-nunodasneves@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Purna Pavan Chandra Aekkaladevi Older versions of the hypervisor do not support HV_STATS_AREA_PARENT and return HV_STATUS_INVALID_PARAMETER for the second stats page mapping request. This results a failure in module init. Instead of failing, gracefully fall back to populating stats_pages[HV_STATS_AREA_PARENT] with the already-mapped stats_pages[HV_STATS_AREA_SELF]. Signed-off-by: Purna Pavan Chandra Aekkaladevi Signed-off-by: Nuno Das Neves Reviewed-by: Stanislav Kinsburskii --- drivers/hv/mshv_root_hv_call.c | 41 ++++++++++++++++++++++++++++++---- drivers/hv/mshv_root_main.c | 3 +++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c index 598eaff4ff29..b1770c7b500c 100644 --- a/drivers/hv/mshv_root_hv_call.c +++ b/drivers/hv/mshv_root_hv_call.c @@ -855,6 +855,24 @@ static int hv_call_map_stats_page2(enum hv_stats_objec= t_type type, return ret; } =20 +static int +hv_stats_get_area_type(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity) +{ + switch (type) { + case HV_STATS_OBJECT_HYPERVISOR: + return identity->hv.stats_area_type; + case HV_STATS_OBJECT_LOGICAL_PROCESSOR: + return identity->lp.stats_area_type; + case HV_STATS_OBJECT_PARTITION: + return identity->partition.stats_area_type; + case HV_STATS_OBJECT_VP: + return identity->vp.stats_area_type; + } + + return -EINVAL; +} + static int hv_call_map_stats_page(enum hv_stats_object_type type, const union hv_stats_object_identity *identity, void **addr) @@ -863,7 +881,7 @@ static int hv_call_map_stats_page(enum hv_stats_object_= type type, struct hv_input_map_stats_page *input; struct hv_output_map_stats_page *output; u64 status, pfn; - int ret =3D 0; + int hv_status, ret =3D 0; =20 do { local_irq_save(flags); @@ -878,11 +896,26 @@ static int hv_call_map_stats_page(enum hv_stats_objec= t_type type, pfn =3D output->map_location; =20 local_irq_restore(flags); - if (hv_result(status) !=3D HV_STATUS_INSUFFICIENT_MEMORY) { - ret =3D hv_result_to_errno(status); + + hv_status =3D hv_result(status); + if (hv_status !=3D HV_STATUS_INSUFFICIENT_MEMORY) { if (hv_result_success(status)) break; - return ret; + + /* + * Older versions of the hypervisor do not support the + * PARENT stats area. In this case return "success" but + * set the page to NULL. The caller should check for + * this case and instead just use the SELF area. + */ + if (hv_stats_get_area_type(type, identity) =3D=3D HV_STATS_AREA_PARENT = && + hv_status =3D=3D HV_STATUS_INVALID_PARAMETER) { + *addr =3D NULL; + return 0; + } + + hv_status_debug(status, "\n"); + return hv_result_to_errno(status); } =20 ret =3D hv_call_deposit_pages(NUMA_NO_NODE, diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index bc15d6f6922f..f59a4ab47685 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -905,6 +905,9 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_i= ndex, if (err) goto unmap_self; =20 + if (!stats_pages[HV_STATS_AREA_PARENT]) + stats_pages[HV_STATS_AREA_PARENT] =3D stats_pages[HV_STATS_AREA_SELF]; + return 0; =20 unmap_self: --=20 2.34.1 From nobody Tue Dec 16 07:34:53 2025 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6472C3491F2; Fri, 5 Dec 2025 19:04:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764961475; cv=none; b=he8HyX0/bbCillWQ8vqASD5yEM18WvOVMtqf+1gDDF52zRodQGOlWJvClUyhCUeE3ZSwKCo7Mzq4fekwWDp5cvhuAy6Eto269fVSoF6JQbltR40yb1BXJIkPePcfd8QYHd1Y5eX7P+nTlAgEZxCOWSWoWLdZCvuvPa9FGz2Idoo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764961475; c=relaxed/simple; bh=bM9PElcuEXWdGYkayhR6EZIGiGNZy0scIboXcaRA2Os=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=XQu3TVzmjXEmSk4ZQGovl56F8R88YeakcZlzJGQFoHKefrBq8Yv3gg/6Yc/pS0qPcWErTod07Hzl1VGSCOrwks6VvRZRorQdfT0k+mev5XABIrmHTwVD+gD9F+k8j14JHL7BMh+wE9O4ZybozWnKTZ8T2rFFLyqoaQyl53Gh8M8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=lRcFWhPm; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="lRcFWhPm" Received: by linux.microsoft.com (Postfix, from userid 1032) id CB76F2123275; Fri, 5 Dec 2025 10:58:44 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com CB76F2123275 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1764961124; bh=WYIwhizzfmF9qkkAuYpnBp5edUqACZ3Pw9ibhDwG1TE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lRcFWhPmo8YAVQpv3qpbU9ze8FHJWzVojQI/XzrxgSFtXFuc7JGrL7ExilaFGOb55 YRISsvdOc4yMzyo9FzOO6qOftUbKAvYa7sz7J5j2dvC0K0gCcsLIWhTIFjDDDQd302 ps8Km9sn56zfavGmKl/+fAmeRHDONL2TzgpGEznY= From: Nuno Das Neves To: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, skinsburskii@linux.microsoft.com Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com, longli@microsoft.com, mhklinux@outlook.com, prapal@linux.microsoft.com, mrathor@linux.microsoft.com, paekkaladevi@linux.microsoft.com, Nuno Das Neves Subject: [PATCH v2 2/3] mshv: Add definitions for stats pages Date: Fri, 5 Dec 2025 10:58:41 -0800 Message-Id: <1764961122-31679-3-git-send-email-nunodasneves@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1764961122-31679-1-git-send-email-nunodasneves@linux.microsoft.com> References: <1764961122-31679-1-git-send-email-nunodasneves@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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 Acked-by: Stanislav Kinsburskii --- 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/ms= hv"); =20 -/* TODO move this to another file when debugfs code is added */ -enum hv_stats_vp_counters { /* HV_THREAD_COUNTER */ -#if defined(CONFIG_X86) - VpRootDispatchThreadBlocked =3D 202, -#elif defined(CONFIG_ARM64) - VpRootDispatchThreadBlocked =3D 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; =20 enum hv_scheduler_type hv_scheduler_type; diff --git a/include/hyperv/hvhdk.h b/include/hyperv/hvhdk.h index 469186df7826..51abbcd0ec37 100644 --- a/include/hyperv/hvhdk.h +++ b/include/hyperv/hvhdk.h @@ -10,6 +10,443 @@ #include "hvhdk_mini.h" #include "hvgdk.h" =20 +enum hv_stats_hypervisor_counters { /* HV_HYPERVISOR_COUNTER */ + HvLogicalProcessors =3D 1, + HvPartitions =3D 2, + HvTotalPages =3D 3, + HvVirtualProcessors =3D 4, + HvMonitoredNotifications =3D 5, + HvModernStandbyEntries =3D 6, + HvPlatformIdleTransitions =3D 7, + HvHypervisorStartupCost =3D 8, + HvIOSpacePages =3D 10, + HvNonEssentialPagesForDump =3D 11, + HvSubsumedPages =3D 12, + HvStatsMaxCounter +}; + +enum hv_stats_partition_counters { /* HV_PROCESS_COUNTER */ + PartitionVirtualProcessors =3D 1, + PartitionTlbSize =3D 3, + PartitionAddressSpaces =3D 4, + PartitionDepositedPages =3D 5, + PartitionGpaPages =3D 6, + PartitionGpaSpaceModifications =3D 7, + PartitionVirtualTlbFlushEntires =3D 8, + PartitionRecommendedTlbSize =3D 9, + PartitionGpaPages4K =3D 10, + PartitionGpaPages2M =3D 11, + PartitionGpaPages1G =3D 12, + PartitionGpaPages512G =3D 13, + PartitionDevicePages4K =3D 14, + PartitionDevicePages2M =3D 15, + PartitionDevicePages1G =3D 16, + PartitionDevicePages512G =3D 17, + PartitionAttachedDevices =3D 18, + PartitionDeviceInterruptMappings =3D 19, + PartitionIoTlbFlushes =3D 20, + PartitionIoTlbFlushCost =3D 21, + PartitionDeviceInterruptErrors =3D 22, + PartitionDeviceDmaErrors =3D 23, + PartitionDeviceInterruptThrottleEvents =3D 24, + PartitionSkippedTimerTicks =3D 25, + PartitionPartitionId =3D 26, +#if IS_ENABLED(CONFIG_X86_64) + PartitionNestedTlbSize =3D 27, + PartitionRecommendedNestedTlbSize =3D 28, + PartitionNestedTlbFreeListSize =3D 29, + PartitionNestedTlbTrimmedPages =3D 30, + PartitionPagesShattered =3D 31, + PartitionPagesRecombined =3D 32, + PartitionHwpRequestValue =3D 33, +#elif IS_ENABLED(CONFIG_ARM64) + PartitionHwpRequestValue =3D 27, +#endif + PartitionStatsMaxCounter +}; + +enum hv_stats_vp_counters { /* HV_THREAD_COUNTER */ + VpTotalRunTime =3D 1, + VpHypervisorRunTime =3D 2, + VpRemoteNodeRunTime =3D 3, + VpNormalizedRunTime =3D 4, + VpIdealCpu =3D 5, + VpHypercallsCount =3D 7, + VpHypercallsTime =3D 8, +#if IS_ENABLED(CONFIG_X86_64) + VpPageInvalidationsCount =3D 9, + VpPageInvalidationsTime =3D 10, + VpControlRegisterAccessesCount =3D 11, + VpControlRegisterAccessesTime =3D 12, + VpIoInstructionsCount =3D 13, + VpIoInstructionsTime =3D 14, + VpHltInstructionsCount =3D 15, + VpHltInstructionsTime =3D 16, + VpMwaitInstructionsCount =3D 17, + VpMwaitInstructionsTime =3D 18, + VpCpuidInstructionsCount =3D 19, + VpCpuidInstructionsTime =3D 20, + VpMsrAccessesCount =3D 21, + VpMsrAccessesTime =3D 22, + VpOtherInterceptsCount =3D 23, + VpOtherInterceptsTime =3D 24, + VpExternalInterruptsCount =3D 25, + VpExternalInterruptsTime =3D 26, + VpPendingInterruptsCount =3D 27, + VpPendingInterruptsTime =3D 28, + VpEmulatedInstructionsCount =3D 29, + VpEmulatedInstructionsTime =3D 30, + VpDebugRegisterAccessesCount =3D 31, + VpDebugRegisterAccessesTime =3D 32, + VpPageFaultInterceptsCount =3D 33, + VpPageFaultInterceptsTime =3D 34, + VpGuestPageTableMaps =3D 35, + VpLargePageTlbFills =3D 36, + VpSmallPageTlbFills =3D 37, + VpReflectedGuestPageFaults =3D 38, + VpApicMmioAccesses =3D 39, + VpIoInterceptMessages =3D 40, + VpMemoryInterceptMessages =3D 41, + VpApicEoiAccesses =3D 42, + VpOtherMessages =3D 43, + VpPageTableAllocations =3D 44, + VpLogicalProcessorMigrations =3D 45, + VpAddressSpaceEvictions =3D 46, + VpAddressSpaceSwitches =3D 47, + VpAddressDomainFlushes =3D 48, + VpAddressSpaceFlushes =3D 49, + VpGlobalGvaRangeFlushes =3D 50, + VpLocalGvaRangeFlushes =3D 51, + VpPageTableEvictions =3D 52, + VpPageTableReclamations =3D 53, + VpPageTableResets =3D 54, + VpPageTableValidations =3D 55, + VpApicTprAccesses =3D 56, + VpPageTableWriteIntercepts =3D 57, + VpSyntheticInterrupts =3D 58, + VpVirtualInterrupts =3D 59, + VpApicIpisSent =3D 60, + VpApicSelfIpisSent =3D 61, + VpGpaSpaceHypercalls =3D 62, + VpLogicalProcessorHypercalls =3D 63, + VpLongSpinWaitHypercalls =3D 64, + VpOtherHypercalls =3D 65, + VpSyntheticInterruptHypercalls =3D 66, + VpVirtualInterruptHypercalls =3D 67, + VpVirtualMmuHypercalls =3D 68, + VpVirtualProcessorHypercalls =3D 69, + VpHardwareInterrupts =3D 70, + VpNestedPageFaultInterceptsCount =3D 71, + VpNestedPageFaultInterceptsTime =3D 72, + VpPageScans =3D 73, + VpLogicalProcessorDispatches =3D 74, + VpWaitingForCpuTime =3D 75, + VpExtendedHypercalls =3D 76, + VpExtendedHypercallInterceptMessages =3D 77, + VpMbecNestedPageTableSwitches =3D 78, + VpOtherReflectedGuestExceptions =3D 79, + VpGlobalIoTlbFlushes =3D 80, + VpGlobalIoTlbFlushCost =3D 81, + VpLocalIoTlbFlushes =3D 82, + VpLocalIoTlbFlushCost =3D 83, + VpHypercallsForwardedCount =3D 84, + VpHypercallsForwardingTime =3D 85, + VpPageInvalidationsForwardedCount =3D 86, + VpPageInvalidationsForwardingTime =3D 87, + VpControlRegisterAccessesForwardedCount =3D 88, + VpControlRegisterAccessesForwardingTime =3D 89, + VpIoInstructionsForwardedCount =3D 90, + VpIoInstructionsForwardingTime =3D 91, + VpHltInstructionsForwardedCount =3D 92, + VpHltInstructionsForwardingTime =3D 93, + VpMwaitInstructionsForwardedCount =3D 94, + VpMwaitInstructionsForwardingTime =3D 95, + VpCpuidInstructionsForwardedCount =3D 96, + VpCpuidInstructionsForwardingTime =3D 97, + VpMsrAccessesForwardedCount =3D 98, + VpMsrAccessesForwardingTime =3D 99, + VpOtherInterceptsForwardedCount =3D 100, + VpOtherInterceptsForwardingTime =3D 101, + VpExternalInterruptsForwardedCount =3D 102, + VpExternalInterruptsForwardingTime =3D 103, + VpPendingInterruptsForwardedCount =3D 104, + VpPendingInterruptsForwardingTime =3D 105, + VpEmulatedInstructionsForwardedCount =3D 106, + VpEmulatedInstructionsForwardingTime =3D 107, + VpDebugRegisterAccessesForwardedCount =3D 108, + VpDebugRegisterAccessesForwardingTime =3D 109, + VpPageFaultInterceptsForwardedCount =3D 110, + VpPageFaultInterceptsForwardingTime =3D 111, + VpVmclearEmulationCount =3D 112, + VpVmclearEmulationTime =3D 113, + VpVmptrldEmulationCount =3D 114, + VpVmptrldEmulationTime =3D 115, + VpVmptrstEmulationCount =3D 116, + VpVmptrstEmulationTime =3D 117, + VpVmreadEmulationCount =3D 118, + VpVmreadEmulationTime =3D 119, + VpVmwriteEmulationCount =3D 120, + VpVmwriteEmulationTime =3D 121, + VpVmxoffEmulationCount =3D 122, + VpVmxoffEmulationTime =3D 123, + VpVmxonEmulationCount =3D 124, + VpVmxonEmulationTime =3D 125, + VpNestedVMEntriesCount =3D 126, + VpNestedVMEntriesTime =3D 127, + VpNestedSLATSoftPageFaultsCount =3D 128, + VpNestedSLATSoftPageFaultsTime =3D 129, + VpNestedSLATHardPageFaultsCount =3D 130, + VpNestedSLATHardPageFaultsTime =3D 131, + VpInvEptAllContextEmulationCount =3D 132, + VpInvEptAllContextEmulationTime =3D 133, + VpInvEptSingleContextEmulationCount =3D 134, + VpInvEptSingleContextEmulationTime =3D 135, + VpInvVpidAllContextEmulationCount =3D 136, + VpInvVpidAllContextEmulationTime =3D 137, + VpInvVpidSingleContextEmulationCount =3D 138, + VpInvVpidSingleContextEmulationTime =3D 139, + VpInvVpidSingleAddressEmulationCount =3D 140, + VpInvVpidSingleAddressEmulationTime =3D 141, + VpNestedTlbPageTableReclamations =3D 142, + VpNestedTlbPageTableEvictions =3D 143, + VpFlushGuestPhysicalAddressSpaceHypercalls =3D 144, + VpFlushGuestPhysicalAddressListHypercalls =3D 145, + VpPostedInterruptNotifications =3D 146, + VpPostedInterruptScans =3D 147, + VpTotalCoreRunTime =3D 148, + VpMaximumRunTime =3D 149, + VpHwpRequestContextSwitches =3D 150, + VpWaitingForCpuTimeBucket0 =3D 151, + VpWaitingForCpuTimeBucket1 =3D 152, + VpWaitingForCpuTimeBucket2 =3D 153, + VpWaitingForCpuTimeBucket3 =3D 154, + VpWaitingForCpuTimeBucket4 =3D 155, + VpWaitingForCpuTimeBucket5 =3D 156, + VpWaitingForCpuTimeBucket6 =3D 157, + VpVmloadEmulationCount =3D 158, + VpVmloadEmulationTime =3D 159, + VpVmsaveEmulationCount =3D 160, + VpVmsaveEmulationTime =3D 161, + VpGifInstructionEmulationCount =3D 162, + VpGifInstructionEmulationTime =3D 163, + VpEmulatedErrataSvmInstructions =3D 164, + VpPlaceholder1 =3D 165, + VpPlaceholder2 =3D 166, + VpPlaceholder3 =3D 167, + VpPlaceholder4 =3D 168, + VpPlaceholder5 =3D 169, + VpPlaceholder6 =3D 170, + VpPlaceholder7 =3D 171, + VpPlaceholder8 =3D 172, + VpPlaceholder9 =3D 173, + VpPlaceholder10 =3D 174, + VpSchedulingPriority =3D 175, + VpRdpmcInstructionsCount =3D 176, + VpRdpmcInstructionsTime =3D 177, + VpPerfmonPmuMsrAccessesCount =3D 178, + VpPerfmonLbrMsrAccessesCount =3D 179, + VpPerfmonIptMsrAccessesCount =3D 180, + VpPerfmonInterruptCount =3D 181, + VpVtl1DispatchCount =3D 182, + VpVtl2DispatchCount =3D 183, + VpVtl2DispatchBucket0 =3D 184, + VpVtl2DispatchBucket1 =3D 185, + VpVtl2DispatchBucket2 =3D 186, + VpVtl2DispatchBucket3 =3D 187, + VpVtl2DispatchBucket4 =3D 188, + VpVtl2DispatchBucket5 =3D 189, + VpVtl2DispatchBucket6 =3D 190, + VpVtl1RunTime =3D 191, + VpVtl2RunTime =3D 192, + VpIommuHypercalls =3D 193, + VpCpuGroupHypercalls =3D 194, + VpVsmHypercalls =3D 195, + VpEventLogHypercalls =3D 196, + VpDeviceDomainHypercalls =3D 197, + VpDepositHypercalls =3D 198, + VpSvmHypercalls =3D 199, + VpBusLockAcquisitionCount =3D 200, + VpUnused =3D 201, + VpRootDispatchThreadBlocked =3D 202, +#elif IS_ENABLED(CONFIG_ARM64) + VpSysRegAccessesCount =3D 9, + VpSysRegAccessesTime =3D 10, + VpSmcInstructionsCount =3D 11, + VpSmcInstructionsTime =3D 12, + VpOtherInterceptsCount =3D 13, + VpOtherInterceptsTime =3D 14, + VpExternalInterruptsCount =3D 15, + VpExternalInterruptsTime =3D 16, + VpPendingInterruptsCount =3D 17, + VpPendingInterruptsTime =3D 18, + VpGuestPageTableMaps =3D 19, + VpLargePageTlbFills =3D 20, + VpSmallPageTlbFills =3D 21, + VpReflectedGuestPageFaults =3D 22, + VpMemoryInterceptMessages =3D 23, + VpOtherMessages =3D 24, + VpLogicalProcessorMigrations =3D 25, + VpAddressDomainFlushes =3D 26, + VpAddressSpaceFlushes =3D 27, + VpSyntheticInterrupts =3D 28, + VpVirtualInterrupts =3D 29, + VpApicSelfIpisSent =3D 30, + VpGpaSpaceHypercalls =3D 31, + VpLogicalProcessorHypercalls =3D 32, + VpLongSpinWaitHypercalls =3D 33, + VpOtherHypercalls =3D 34, + VpSyntheticInterruptHypercalls =3D 35, + VpVirtualInterruptHypercalls =3D 36, + VpVirtualMmuHypercalls =3D 37, + VpVirtualProcessorHypercalls =3D 38, + VpHardwareInterrupts =3D 39, + VpNestedPageFaultInterceptsCount =3D 40, + VpNestedPageFaultInterceptsTime =3D 41, + VpLogicalProcessorDispatches =3D 42, + VpWaitingForCpuTime =3D 43, + VpExtendedHypercalls =3D 44, + VpExtendedHypercallInterceptMessages =3D 45, + VpMbecNestedPageTableSwitches =3D 46, + VpOtherReflectedGuestExceptions =3D 47, + VpGlobalIoTlbFlushes =3D 48, + VpGlobalIoTlbFlushCost =3D 49, + VpLocalIoTlbFlushes =3D 50, + VpLocalIoTlbFlushCost =3D 51, + VpFlushGuestPhysicalAddressSpaceHypercalls =3D 52, + VpFlushGuestPhysicalAddressListHypercalls =3D 53, + VpPostedInterruptNotifications =3D 54, + VpPostedInterruptScans =3D 55, + VpTotalCoreRunTime =3D 56, + VpMaximumRunTime =3D 57, + VpWaitingForCpuTimeBucket0 =3D 58, + VpWaitingForCpuTimeBucket1 =3D 59, + VpWaitingForCpuTimeBucket2 =3D 60, + VpWaitingForCpuTimeBucket3 =3D 61, + VpWaitingForCpuTimeBucket4 =3D 62, + VpWaitingForCpuTimeBucket5 =3D 63, + VpWaitingForCpuTimeBucket6 =3D 64, + VpHwpRequestContextSwitches =3D 65, + VpPlaceholder2 =3D 66, + VpPlaceholder3 =3D 67, + VpPlaceholder4 =3D 68, + VpPlaceholder5 =3D 69, + VpPlaceholder6 =3D 70, + VpPlaceholder7 =3D 71, + VpPlaceholder8 =3D 72, + VpContentionTime =3D 73, + VpWakeUpTime =3D 74, + VpSchedulingPriority =3D 75, + VpVtl1DispatchCount =3D 76, + VpVtl2DispatchCount =3D 77, + VpVtl2DispatchBucket0 =3D 78, + VpVtl2DispatchBucket1 =3D 79, + VpVtl2DispatchBucket2 =3D 80, + VpVtl2DispatchBucket3 =3D 81, + VpVtl2DispatchBucket4 =3D 82, + VpVtl2DispatchBucket5 =3D 83, + VpVtl2DispatchBucket6 =3D 84, + VpVtl1RunTime =3D 85, + VpVtl2RunTime =3D 86, + VpIommuHypercalls =3D 87, + VpCpuGroupHypercalls =3D 88, + VpVsmHypercalls =3D 89, + VpEventLogHypercalls =3D 90, + VpDeviceDomainHypercalls =3D 91, + VpDepositHypercalls =3D 92, + VpSvmHypercalls =3D 93, + VpLoadAvg =3D 94, + VpRootDispatchThreadBlocked =3D 95, +#endif + VpStatsMaxCounter +}; + +enum hv_stats_lp_counters { /* HV_CPU_COUNTER */ + LpGlobalTime =3D 1, + LpTotalRunTime =3D 2, + LpHypervisorRunTime =3D 3, + LpHardwareInterrupts =3D 4, + LpContextSwitches =3D 5, + LpInterProcessorInterrupts =3D 6, + LpSchedulerInterrupts =3D 7, + LpTimerInterrupts =3D 8, + LpInterProcessorInterruptsSent =3D 9, + LpProcessorHalts =3D 10, + LpMonitorTransitionCost =3D 11, + LpContextSwitchTime =3D 12, + LpC1TransitionsCount =3D 13, + LpC1RunTime =3D 14, + LpC2TransitionsCount =3D 15, + LpC2RunTime =3D 16, + LpC3TransitionsCount =3D 17, + LpC3RunTime =3D 18, + LpRootVpIndex =3D 19, + LpIdleSequenceNumber =3D 20, + LpGlobalTscCount =3D 21, + LpActiveTscCount =3D 22, + LpIdleAccumulation =3D 23, + LpReferenceCycleCount0 =3D 24, + LpActualCycleCount0 =3D 25, + LpReferenceCycleCount1 =3D 26, + LpActualCycleCount1 =3D 27, + LpProximityDomainId =3D 28, + LpPostedInterruptNotifications =3D 29, + LpBranchPredictorFlushes =3D 30, +#if IS_ENABLED(CONFIG_X86_64) + LpL1DataCacheFlushes =3D 31, + LpImmediateL1DataCacheFlushes =3D 32, + LpMbFlushes =3D 33, + LpCounterRefreshSequenceNumber =3D 34, + LpCounterRefreshReferenceTime =3D 35, + LpIdleAccumulationSnapshot =3D 36, + LpActiveTscCountSnapshot =3D 37, + LpHwpRequestContextSwitches =3D 38, + LpPlaceholder1 =3D 39, + LpPlaceholder2 =3D 40, + LpPlaceholder3 =3D 41, + LpPlaceholder4 =3D 42, + LpPlaceholder5 =3D 43, + LpPlaceholder6 =3D 44, + LpPlaceholder7 =3D 45, + LpPlaceholder8 =3D 46, + LpPlaceholder9 =3D 47, + LpPlaceholder10 =3D 48, + LpReserveGroupId =3D 49, + LpRunningPriority =3D 50, + LpPerfmonInterruptCount =3D 51, +#elif IS_ENABLED(CONFIG_ARM64) + LpCounterRefreshSequenceNumber =3D 31, + LpCounterRefreshReferenceTime =3D 32, + LpIdleAccumulationSnapshot =3D 33, + LpActiveTscCountSnapshot =3D 34, + LpHwpRequestContextSwitches =3D 35, + LpPlaceholder2 =3D 36, + LpPlaceholder3 =3D 37, + LpPlaceholder4 =3D 38, + LpPlaceholder5 =3D 39, + LpPlaceholder6 =3D 40, + LpPlaceholder7 =3D 41, + LpPlaceholder8 =3D 42, + LpPlaceholder9 =3D 43, + LpSchLocalRunListSize =3D 44, + LpReserveGroupId =3D 45, + LpRunningPriority =3D 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 --=20 2.34.1 From nobody Tue Dec 16 07:34:53 2025 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6480F3491FB; Fri, 5 Dec 2025 19:04:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764961476; cv=none; b=MFx7hnKjrNmfJQTZhw4GBudQlJejmZw2w/B9vHZd+PgbZ3FzPF6AigbP/Bzz7VK5ZcI7kMs0G1lqou707BB8MsWoe3t7bw4C9n6/i0mNp+HKN04qZxQyuUI4BpOA2rmuknYzW7XPrDNTD6J74GWPMsPFqT8fEIwoUzBQvXApnWc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764961476; c=relaxed/simple; bh=SBa7ByFejkDK+WtcSyQ0TRpixYAp2NxwTNryE0yuTgA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=J5/6UZFhFSOFCm/ll/viwKl6CjkyoTV3sSCWTeNISvWPJZayxGUVXWK5E6Ll9ASi0e37h3QAjX308DAag+uXJbCq15qjprknq/cX4Ah6tMgPIn8iSWpUnafHeuboCNm6GJSU8s3gK56rcgxFiX/rhDPxM7n5EwehOtBOl/l1Gvs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=KQg/OeVy; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="KQg/OeVy" Received: by linux.microsoft.com (Postfix, from userid 1032) id 1B1B22123282; Fri, 5 Dec 2025 10:58:46 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 1B1B22123282 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1764961126; bh=H1a87/xyv5lgWRwcCdF1rt7+FmmR9XysOBhe1i1jZtc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KQg/OeVyrnLgjW/GVyTT8CsWdTH0TsleDNPdR0qD6mq2ko8l7xvJrL8z2uQqQmtPZ /IEjqrA9R0isCVkzAhLyMH8dtlcvWVNvjIznqj5Ps1KeqP8ddkV3oE0ulFE9o9VLNB lN/uhkzCmT27iNBLLROAGm6n7XQNYAb63u1oGd4E= From: Nuno Das Neves To: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, skinsburskii@linux.microsoft.com Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com, longli@microsoft.com, mhklinux@outlook.com, prapal@linux.microsoft.com, mrathor@linux.microsoft.com, paekkaladevi@linux.microsoft.com, Nuno Das Neves , Jinank Jain Subject: [PATCH v2 3/3] mshv: Add debugfs to view hypervisor statistics Date: Fri, 5 Dec 2025 10:58:42 -0800 Message-Id: <1764961122-31679-4-git-send-email-nunodasneves@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1764961122-31679-1-git-send-email-nunodasneves@linux.microsoft.com> References: <1764961122-31679-1-git-send-email-nunodasneves@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Stanislav Kinsburskii Co-developed-by: Praveen K Paladugu Signed-off-by: Praveen K Paladugu Co-developed-by: Mukesh Rathor Signed-off-by: Mukesh Rathor Co-developed-by: Purna Pavan Chandra Aekkaladevi Signed-off-by: Purna Pavan Chandra Aekkaladevi Co-developed-by: Jinank Jain Signed-off-by: Jinank Jain Signed-off-by: Nuno Das Neves Reviewed-by: Stanislav Kinsburskii --- 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) +=3D hv_debugfs.o hv_utils-y :=3D hv_util.o hv_kvp.o hv_snapshot.o hv_utils_transport.o mshv_root-y :=3D 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) +=3D mshv_debugfs.o mshv_vtl-y :=3D mshv_vtl_main.o =20 # 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 +#include +#include +#include + +#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 =3D=3D HV_PARTITION_ID_SELF); +} + +static int lp_stats_show(struct seq_file *m, void *v) +{ + const struct hv_stats_page *stats =3D 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 =3D { + .lp.lp_index =3D lp_index, + .lp.stats_area_type =3D HV_STATS_AREA_SELF, + }; + int err; + + err =3D 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 =3D { + .lp.lp_index =3D lp_index, + .lp.stats_area_type =3D HV_STATS_AREA_SELF, + }; + void *stats; + int err; + + err =3D 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 *p= arent) +{ + struct dentry *dentry; + void *stats; + + stats =3D mshv_lp_stats_map(lp_index); + if (IS_ERR(stats)) + return stats; + + dentry =3D 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 =3D debugfs_create_dir(lp_idx_str, parent); + if (IS_ERR(idx)) + return PTR_ERR(idx); + + stats =3D lp_debugfs_stats_create(lp_index, idx); + if (IS_ERR(stats)) { + err =3D 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 =3D 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 =3D debugfs_create_dir("lp", parent); + if (IS_ERR(lp_dir)) + return PTR_ERR(lp_dir); + + for (lp_index =3D 0; lp_index < mshv_lps_count; lp_index++) { + err =3D lp_debugfs_create(lp_index, lp_dir); + if (err) + goto remove_debugfs_lps; + } + + mshv_debugfs_lp =3D lp_dir; + + return 0; + +remove_debugfs_lps: + for (lp_index -=3D 1; lp_index >=3D 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 =3D 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 *stat= s_page_addr, + enum hv_stats_area_type stats_area_type) +{ + union hv_stats_object_identity identity =3D { + .vp.partition_id =3D partition_id, + .vp.vp_index =3D vp_index, + .vp.stats_area_type =3D stats_area_type, + }; + int err; + + err =3D hv_unmap_stats_page(HV_STATS_OBJECT_VP, stats_page_addr, &identit= y); + 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 =3D=3D 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 =3D { + .vp.partition_id =3D partition_id, + .vp.vp_index =3D vp_index, + .vp.stats_area_type =3D stats_area_type, + }; + void *stats; + int err; + + err =3D 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 =3D=3D 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 =3D kcalloc(2, sizeof(struct hv_stats_page *), GFP_KERNEL_ACCOUNT); + if (!pstats) + return -ENOMEM; + + pstats[HV_STATS_AREA_SELF] =3D mshv_vp_stats_map(partition_id, vp_index, + HV_STATS_AREA_SELF); + if (IS_ERR(pstats[HV_STATS_AREA_SELF])) { + err =3D 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] =3D pstats[HV_STATS_AREA_SELF]; + } else { + pstats[HV_STATS_AREA_PARENT] =3D mshv_vp_stats_map( + partition_id, vp_index, HV_STATS_AREA_PARENT); + if (IS_ERR(pstats[HV_STATS_AREA_PARENT])) { + err =3D PTR_ERR(pstats[HV_STATS_AREA_PARENT]); + goto unmap_self; + } + if (!pstats[HV_STATS_AREA_PARENT]) + pstats[HV_STATS_AREA_PARENT] =3D pstats[HV_STATS_AREA_SELF]; + } + + dentry =3D debugfs_create_file("stats", 0400, parent, + pstats, &vp_stats_fops); + if (IS_ERR(dentry)) { + err =3D PTR_ERR(dentry); + goto unmap_vp_stats; + } + + *vp_stats_ptr =3D dentry; + return 0; + +unmap_vp_stats: + if (pstats[HV_STATS_AREA_PARENT] !=3D 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 =3D NULL; + void *stats; + + pstats =3D vp_stats->d_inode->i_private; + debugfs_remove_recursive(vp_stats->d_parent); + if (pstats[HV_STATS_AREA_PARENT] !=3D pstats[HV_STATS_AREA_SELF]) { + stats =3D pstats[HV_STATS_AREA_PARENT]; + mshv_vp_stats_unmap(partition_id, vp_index, stats, + HV_STATS_AREA_PARENT); + } + + stats =3D 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 =3D debugfs_create_dir(vp_idx_str, parent); + if (IS_ERR(vp_idx_dir)) + return PTR_ERR(vp_idx_dir); + + err =3D 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 =3D 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 =3D { + .partition.partition_id =3D partition_id, + .partition.stats_area_type =3D stats_area_type, + }; + int err; + + err =3D 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 =3D=3D 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 =3D { + .partition.partition_id =3D partition_id, + .partition.stats_area_type =3D stats_area_type, + }; + void *stats; + int err; + + err =3D 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 =3D=3D 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 =3D kcalloc(2, sizeof(struct hv_stats_page *), GFP_KERNEL_ACCOUNT); + if (!pstats) + return -ENOMEM; + + pstats[HV_STATS_AREA_SELF] =3D mshv_partition_stats_map(partition_id, + HV_STATS_AREA_SELF); + if (IS_ERR(pstats[HV_STATS_AREA_SELF])) { + err =3D 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] =3D pstats[HV_STATS_AREA_SELF]; + } else { + pstats[HV_STATS_AREA_PARENT] =3D mshv_partition_stats_map(partition_id, + HV_STATS_AREA_PARENT); + if (IS_ERR(pstats[HV_STATS_AREA_PARENT])) { + err =3D PTR_ERR(pstats[HV_STATS_AREA_PARENT]); + goto unmap_self; + } + if (!pstats[HV_STATS_AREA_PARENT]) + pstats[HV_STATS_AREA_PARENT] =3D pstats[HV_STATS_AREA_SELF]; + } + + dentry =3D debugfs_create_file("stats", 0400, parent, + pstats, &partition_stats_fops); + if (IS_ERR(dentry)) { + err =3D PTR_ERR(dentry); + goto unmap_partition_stats; + } + + *partition_stats_ptr =3D dentry; + return 0; + +unmap_partition_stats: + if (pstats[HV_STATS_AREA_PARENT] !=3D 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 *dent= ry) +{ + struct hv_stats_page **pstats =3D NULL; + void *stats; + + pstats =3D dentry->d_inode->i_private; + + debugfs_remove_recursive(dentry->d_parent); + + if (pstats[HV_STATS_AREA_PARENT] !=3D pstats[HV_STATS_AREA_SELF]) { + stats =3D pstats[HV_STATS_AREA_PARENT]; + mshv_partition_stats_unmap(partition_id, stats, HV_STATS_AREA_PARENT); + } + + stats =3D 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 =3D debugfs_create_dir(part_id_str, parent); + if (IS_ERR(part_id_dir)) + return PTR_ERR(part_id_dir); + + vp_dir =3D debugfs_create_dir("vp", part_id_dir); + if (IS_ERR(vp_dir)) { + err =3D PTR_ERR(vp_dir); + goto remove_debugfs_partition_id; + } + + err =3D mshv_debugfs_partition_stats_create(partition_id, + partition_stats_ptr, + part_id_dir); + if (err) + goto remove_debugfs_partition_id; + + *vp_dir_ptr =3D 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 =3D debugfs_create_dir("partition", + mshv_debugfs); + if (IS_ERR(mshv_debugfs_partition)) + return PTR_ERR(mshv_debugfs_partition); + + err =3D 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 =3D 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 >=3D 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 =3D 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 =3D { + .hv.stats_area_type =3D HV_STATS_AREA_SELF, + }; + int err; + + err =3D 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 =3D { + .hv.stats_area_type =3D HV_STATS_AREA_SELF, + }; + void *stats; + int err; + + err =3D 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 =3D mshv_hv_stats_map(); + if (IS_ERR(stats)) + return PTR_ERR(stats); + + dentry =3D debugfs_create_file("stats", 0400, parent, + stats, &hv_stats_fops); + if (IS_ERR(dentry)) { + err =3D PTR_ERR(dentry); + pr_err("%s: failed to create hypervisor stats dentry: %d\n", + __func__, err); + goto unmap_hv_stats; + } + + mshv_lps_count =3D 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 =3D vp->vp_partition; + int err; + + if (!mshv_debugfs) + return 0; + + err =3D 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 =3D 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 =3D 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 =3D mshv_debugfs_hv_stats_create(mshv_debugfs); + if (err) + goto remove_mshv_dir; + + err =3D mshv_debugfs_lp_create(mshv_debugfs); + if (err) + goto unmap_hv_stats; + } + + err =3D 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 }; =20 #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 }; =20 #define pt_fmt(fmt) "p%llu: " fmt @@ -308,6 +315,33 @@ int hv_call_modify_spa_host_access(u64 partition_id, s= truct 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); =20 +#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 *par= tition) +{ + return 0; +} +static inline void mshv_debugfs_partition_remove(struct mshv_partition *pa= rtition) { } +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 =3D=3D HV_SCHEDULER_TYPE_ROOT) memcpy(vp->vp_stats_pages, stats_pages, sizeof(stats_pages)); =20 + ret =3D 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 *p= artition, ret =3D anon_inode_getfd("mshv_vp", &mshv_vp_fops, vp, O_RDWR | O_CLOEXEC); if (ret < 0) - goto put_partition; + goto remove_debugfs_vp; =20 /* 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, =20 return ret; =20 +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_partiti= on *partition) =20 ret =3D hv_call_initialize_partition(partition->pt_id); if (ret) - goto withdraw_mem; + return ret; + + ret =3D mshv_debugfs_partition_create(partition); + if (ret) + goto finalize_partition; =20 partition->pt_initialized =3D true; =20 return 0; =20 -withdraw_mem: +finalize_partition: + hv_call_finalize_partition(partition->pt_id); hv_call_withdraw_memory(U64_MAX, NUMA_NO_NODE, partition->pt_id); =20 return ret; @@ -1741,6 +1752,8 @@ static void destroy_partition(struct mshv_partition *= partition) if (!vp) continue; =20 + mshv_debugfs_vp_remove(vp); + if (hv_scheduler_type =3D=3D 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] =3D NULL; } =20 + mshv_debugfs_partition_remove(partition); + /* Deallocates and unmaps everything including vcpus, GPA mappings etc */ hv_call_finalize_partition(partition->pt_id); =20 @@ -2351,10 +2366,14 @@ static int __init mshv_parent_partition_init(void) =20 mshv_init_vmm_caps(dev); =20 - ret =3D mshv_irqfd_wq_init(); + ret =3D mshv_debugfs_init(); if (ret) goto exit_partition; =20 + ret =3D mshv_irqfd_wq_init(); + if (ret) + goto exit_debugfs; + spin_lock_init(&mshv_root.pt_ht_lock); hash_init(mshv_root.pt_htable); =20 @@ -2362,6 +2381,10 @@ static int __init mshv_parent_partition_init(void) =20 return 0; =20 +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()) --=20 2.34.1