Linux-HyperV List
 help / color / mirror / Atom feed
* [PATCH v3 0/5] mshv: Fixes for stats and vp state page mappings
From: Nuno Das Neves @ 2025-09-16 23:44 UTC (permalink / raw)
  To: linux-hyperv, linux-kernel, prapal, easwar.hariharan, tiala,
	anirudh, paekkaladevi
  Cc: kys, haiyangz, wei.liu, decui, Nuno Das Neves

There are some differences in how L1VH partitions must map stats and vp
state pages, some of which are due to differences across hypervisor
versions. Detect and handle these cases.

Patch 1:
Fix for the logic of when to map the vp stats page for the root scheduler.

Patch 2-3:
Add HVCALL_GET_PARTITION_PROPERTY_EX and use it to query "vmm capabilities" on
module init.

Patches 4-5:
Check a feature bit in vmm capabilities, to take a new code path for mapping
stats and vp state pages. In this case, the stats and vp state pages must be
allocated by Linux, and a new hypercall HVCALL_MAP_VP_STATS_PAGE2 must be used
to map the stats page.

---
v3:
- Fix bug in patch 4, in mshv_partition_ioctl_create_vp() cleanup path
  [kernel test robot]
- Make hv_unmap_vp_state_page() use struct page to match hv_map_vp_state_page()
- Remove SELF == PARENT check which doesn't belong in patch 5 [Easwar]

v2:
https://lore.kernel.org/linux-hyperv/1757546089-2002-1-git-send-email-nunodasneves@linux.microsoft.com/T/#t
- Remove patch falling back to SELF page if PARENT mapping fails [Easwar]
  (To be included in a future series)
- Fix formatting of function definitions [Easwar]
  - Fix some wording in commit messages [Praveen]
    - Proceed with driver init even if getting vmm capabilities fails [Anirudh]

v1:
https://lore.kernel.org/linux-hyperv/1756428230-3599-1-git-send-email-nunodasneves@linux.microsoft.com/T/#t

---
Jinank Jain (2):
  mshv: Allocate vp state page for HVCALL_MAP_VP_STATE_PAGE on L1VH
  mshv: Introduce new hypercall to map stats page for L1VH partitions

Nuno Das Neves (1):
  mshv: Only map vp->vp_stats_pages if on root scheduler

Purna Pavan Chandra Aekkaladevi (2):
  mshv: Add the HVCALL_GET_PARTITION_PROPERTY_EX hypercall
  mshv: Get the vmm capabilities offered by the hypervisor

 drivers/hv/mshv_root.h         |  24 +++--
 drivers/hv/mshv_root_hv_call.c | 181 +++++++++++++++++++++++++++++++--
 drivers/hv/mshv_root_main.c    | 132 ++++++++++++++----------
 include/hyperv/hvgdk_mini.h    |   2 +
 include/hyperv/hvhdk.h         |  40 ++++++++
 include/hyperv/hvhdk_mini.h    |  33 ++++++
 6 files changed, 338 insertions(+), 74 deletions(-)

-- 
2.34.1


^ permalink raw reply

* [PATCH v3 1/5] mshv: Only map vp->vp_stats_pages if on root scheduler
From: Nuno Das Neves @ 2025-09-16 23:44 UTC (permalink / raw)
  To: linux-hyperv, linux-kernel, prapal, easwar.hariharan, tiala,
	anirudh, paekkaladevi
  Cc: kys, haiyangz, wei.liu, decui, Nuno Das Neves
In-Reply-To: <1758066262-15477-1-git-send-email-nunodasneves@linux.microsoft.com>

This mapping is only used for checking if the dispatch thread is
blocked. This is only relevant for the root scheduler, so check the
scheduler type to determine whether to map/unmap these pages, instead of
the current check, which is incorrect.

Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Anirudh Rayabharam <anirudh@anirudhrb.com>
Reviewed-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@linux.microsoft.com>
Reviewed-by: Tianyu Lan <tiala@microsoft.com>
---
 drivers/hv/mshv_root_main.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index e3b2bd417c46..24df47726363 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -934,7 +934,11 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 			goto unmap_register_page;
 	}
 
-	if (hv_parent_partition()) {
+	/*
+	 * This mapping of the stats page is for detecting if dispatch thread
+	 * is blocked - only relevant for root scheduler
+	 */
+	if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) {
 		ret = mshv_vp_stats_map(partition->pt_id, args.vp_index,
 					stats_pages);
 		if (ret)
@@ -963,7 +967,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 	if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available())
 		vp->vp_ghcb_page = page_to_virt(ghcb_page);
 
-	if (hv_parent_partition())
+	if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
 		memcpy(vp->vp_stats_pages, stats_pages, sizeof(stats_pages));
 
 	/*
@@ -986,7 +990,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 free_vp:
 	kfree(vp);
 unmap_stats_pages:
-	if (hv_parent_partition())
+	if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
 		mshv_vp_stats_unmap(partition->pt_id, args.vp_index);
 unmap_ghcb_page:
 	if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) {
@@ -1740,7 +1744,7 @@ static void destroy_partition(struct mshv_partition *partition)
 			if (!vp)
 				continue;
 
-			if (hv_parent_partition())
+			if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
 				mshv_vp_stats_unmap(partition->pt_id, vp->vp_index);
 
 			if (vp->vp_register_page) {
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 2/5] mshv: Add the HVCALL_GET_PARTITION_PROPERTY_EX hypercall
From: Nuno Das Neves @ 2025-09-16 23:44 UTC (permalink / raw)
  To: linux-hyperv, linux-kernel, prapal, easwar.hariharan, tiala,
	anirudh, paekkaladevi
  Cc: kys, haiyangz, wei.liu, decui, Nuno Das Neves
In-Reply-To: <1758066262-15477-1-git-send-email-nunodasneves@linux.microsoft.com>

From: Purna Pavan Chandra Aekkaladevi <paekkaladevi@linux.microsoft.com>

This hypercall can be used to fetch extended properties of a
partition. Extended properties are properties with values larger than
a u64. Some of these also need additional input arguments.

Add helper function for using the hypercall in the mshv_root driver.

Signed-off-by: Purna Pavan Chandra Aekkaladevi <paekkaladevi@linux.microsoft.com>
Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Anirudh Rayabharam <anirudh@anirudhrb.com>
Reviewed-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@linux.microsoft.com>
---
 drivers/hv/mshv_root.h         |  2 ++
 drivers/hv/mshv_root_hv_call.c | 31 ++++++++++++++++++++++++++
 include/hyperv/hvgdk_mini.h    |  1 +
 include/hyperv/hvhdk.h         | 40 ++++++++++++++++++++++++++++++++++
 include/hyperv/hvhdk_mini.h    | 26 ++++++++++++++++++++++
 5 files changed, 100 insertions(+)

diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index e3931b0f1269..4aeb03bea6b6 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -303,6 +303,8 @@ int hv_call_unmap_stat_page(enum hv_stats_object_type type,
 int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
 				   u64 page_struct_count, u32 host_access,
 				   u32 flags, u8 acquire);
+int hv_call_get_partition_property_ex(u64 partition_id, u64 property_code, u64 arg,
+				      void *property_value, size_t property_value_sz);
 
 extern struct mshv_root mshv_root;
 extern enum hv_scheduler_type hv_scheduler_type;
diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
index c9c274f29c3c..3fd3cce23f69 100644
--- a/drivers/hv/mshv_root_hv_call.c
+++ b/drivers/hv/mshv_root_hv_call.c
@@ -590,6 +590,37 @@ int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
 	return hv_result_to_errno(status);
 }
 
+int hv_call_get_partition_property_ex(u64 partition_id, u64 property_code,
+				      u64 arg, void *property_value,
+				      size_t property_value_sz)
+{
+	u64 status;
+	unsigned long flags;
+	struct hv_input_get_partition_property_ex *input;
+	struct hv_output_get_partition_property_ex *output;
+
+	local_irq_save(flags);
+	input = *this_cpu_ptr(hyperv_pcpu_input_arg);
+	output = *this_cpu_ptr(hyperv_pcpu_output_arg);
+
+	memset(input, 0, sizeof(*input));
+	input->partition_id = partition_id;
+	input->property_code = property_code;
+	input->arg = arg;
+	status = hv_do_hypercall(HVCALL_GET_PARTITION_PROPERTY_EX, input, output);
+
+	if (!hv_result_success(status)) {
+		hv_status_debug(status, "\n");
+		local_irq_restore(flags);
+		return hv_result_to_errno(status);
+	}
+	memcpy(property_value, &output->property_value, property_value_sz);
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
 int
 hv_call_clear_virtual_interrupt(u64 partition_id)
 {
diff --git a/include/hyperv/hvgdk_mini.h b/include/hyperv/hvgdk_mini.h
index 1be7f6a02304..ff4325fb623a 100644
--- a/include/hyperv/hvgdk_mini.h
+++ b/include/hyperv/hvgdk_mini.h
@@ -490,6 +490,7 @@ union hv_vp_assist_msr_contents {	 /* HV_REGISTER_VP_ASSIST_PAGE */
 #define HVCALL_GET_VP_STATE				0x00e3
 #define HVCALL_SET_VP_STATE				0x00e4
 #define HVCALL_GET_VP_CPUID_VALUES			0x00f4
+#define HVCALL_GET_PARTITION_PROPERTY_EX		0x0101
 #define HVCALL_MMIO_READ				0x0106
 #define HVCALL_MMIO_WRITE				0x0107
 
diff --git a/include/hyperv/hvhdk.h b/include/hyperv/hvhdk.h
index b4067ada02cf..b91358b9c929 100644
--- a/include/hyperv/hvhdk.h
+++ b/include/hyperv/hvhdk.h
@@ -376,6 +376,46 @@ struct hv_input_set_partition_property {
 	u64 property_value;
 } __packed;
 
+union hv_partition_property_arg {
+	u64 as_uint64;
+	struct {
+		union {
+			u32 arg;
+			u32 vp_index;
+		};
+		u16 reserved0;
+		u8 reserved1;
+		u8 object_type;
+	};
+} __packed;
+
+struct hv_input_get_partition_property_ex {
+	u64 partition_id;
+	u32 property_code; /* enum hv_partition_property_code */
+	u32 padding;
+	union {
+		union hv_partition_property_arg arg_data;
+		u64 arg;
+	};
+} __packed;
+
+/*
+ * NOTE: Should use hv_input_set_partition_property_ex_header to compute this
+ * size, but hv_input_get_partition_property_ex is identical so it suffices
+ */
+#define HV_PARTITION_PROPERTY_EX_MAX_VAR_SIZE \
+	(HV_HYP_PAGE_SIZE - sizeof(struct hv_input_get_partition_property_ex))
+
+union hv_partition_property_ex {
+	u8 buffer[HV_PARTITION_PROPERTY_EX_MAX_VAR_SIZE];
+	struct hv_partition_property_vmm_capabilities vmm_capabilities;
+	/* More fields to be filled in when needed */
+} __packed;
+
+struct hv_output_get_partition_property_ex {
+	union hv_partition_property_ex property_value;
+} __packed;
+
 enum hv_vp_state_page_type {
 	HV_VP_STATE_PAGE_REGISTERS = 0,
 	HV_VP_STATE_PAGE_INTERCEPT_MESSAGE = 1,
diff --git a/include/hyperv/hvhdk_mini.h b/include/hyperv/hvhdk_mini.h
index 858f6a3925b3..bf2ce27dfcc5 100644
--- a/include/hyperv/hvhdk_mini.h
+++ b/include/hyperv/hvhdk_mini.h
@@ -96,8 +96,34 @@ enum hv_partition_property_code {
 	HV_PARTITION_PROPERTY_XSAVE_STATES                      = 0x00060007,
 	HV_PARTITION_PROPERTY_MAX_XSAVE_DATA_SIZE		= 0x00060008,
 	HV_PARTITION_PROPERTY_PROCESSOR_CLOCK_FREQUENCY		= 0x00060009,
+
+	/* Extended properties with larger property values */
+	HV_PARTITION_PROPERTY_VMM_CAPABILITIES			= 0x00090007,
 };
 
+#define HV_PARTITION_VMM_CAPABILITIES_BANK_COUNT		1
+#define HV_PARTITION_VMM_CAPABILITIES_RESERVED_BITFIELD_COUNT	59
+
+struct hv_partition_property_vmm_capabilities {
+	u16 bank_count;
+	u16 reserved[3];
+	union {
+		u64 as_uint64[HV_PARTITION_VMM_CAPABILITIES_BANK_COUNT];
+		struct {
+			u64 map_gpa_preserve_adjustable: 1;
+			u64 vmm_can_provide_overlay_gpfn: 1;
+			u64 vp_affinity_property: 1;
+#if IS_ENABLED(CONFIG_ARM64)
+			u64 vmm_can_provide_gic_overlay_locations: 1;
+#else
+			u64 reservedbit3: 1;
+#endif
+			u64 assignable_synthetic_proc_features: 1;
+			u64 reserved0: HV_PARTITION_VMM_CAPABILITIES_RESERVED_BITFIELD_COUNT;
+		} __packed;
+	};
+} __packed;
+
 enum hv_snp_status {
 	HV_SNP_STATUS_NONE = 0,
 	HV_SNP_STATUS_AVAILABLE = 1,
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 3/5] mshv: Get the vmm capabilities offered by the hypervisor
From: Nuno Das Neves @ 2025-09-16 23:44 UTC (permalink / raw)
  To: linux-hyperv, linux-kernel, prapal, easwar.hariharan, tiala,
	anirudh, paekkaladevi
  Cc: kys, haiyangz, wei.liu, decui, Nuno Das Neves
In-Reply-To: <1758066262-15477-1-git-send-email-nunodasneves@linux.microsoft.com>

From: Purna Pavan Chandra Aekkaladevi <paekkaladevi@linux.microsoft.com>

Some hypervisor APIs are gated by feature bits in the
"vmm capabilities" partition property. Store the capabilities on
mshv_root module init, using HVCALL_GET_PARTITION_PROPERTY_EX.

This is not supported on all hypervisors. In that case, just set the
capabilities to 0 and proceed as normal.

Signed-off-by: Purna Pavan Chandra Aekkaladevi <paekkaladevi@linux.microsoft.com>
Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@linux.microsoft.com>
Reviewed-by: Tianyu Lan <tiala@microsoft.com>
---
 drivers/hv/mshv_root.h      |  1 +
 drivers/hv/mshv_root_main.c | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index 4aeb03bea6b6..0cb1e2589fe1 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -178,6 +178,7 @@ struct mshv_root {
 	struct hv_synic_pages __percpu *synic_pages;
 	spinlock_t pt_ht_lock;
 	DECLARE_HASHTABLE(pt_htable, MSHV_PARTITIONS_HASH_BITS);
+	struct hv_partition_property_vmm_capabilities vmm_caps;
 };
 
 /*
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 24df47726363..f7738cefbdf3 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -2201,6 +2201,26 @@ static int __init mshv_root_partition_init(struct device *dev)
 	return err;
 }
 
+static void mshv_init_vmm_caps(struct device *dev)
+{
+	int ret;
+
+	memset(&mshv_root.vmm_caps, 0, sizeof(mshv_root.vmm_caps));
+	ret = hv_call_get_partition_property_ex(HV_PARTITION_ID_SELF,
+						HV_PARTITION_PROPERTY_VMM_CAPABILITIES,
+						0, &mshv_root.vmm_caps,
+						sizeof(mshv_root.vmm_caps));
+
+	/*
+	 * HVCALL_GET_PARTITION_PROPERTY_EX or HV_PARTITION_PROPERTY_VMM_CAPABILITIES
+	 * may not be supported. Leave them as 0 in that case.
+	 */
+	if (ret)
+		dev_warn(dev, "Unable to get VMM capabilities\n");
+
+	dev_dbg(dev, "vmm_caps=0x%llx\n", mshv_root.vmm_caps.as_uint64[0]);
+}
+
 static int __init mshv_parent_partition_init(void)
 {
 	int ret;
@@ -2253,6 +2273,8 @@ static int __init mshv_parent_partition_init(void)
 	if (ret)
 		goto remove_cpu_state;
 
+	mshv_init_vmm_caps(dev);
+
 	ret = mshv_irqfd_wq_init();
 	if (ret)
 		goto exit_partition;
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 4/5] mshv: Allocate vp state page for HVCALL_MAP_VP_STATE_PAGE on L1VH
From: Nuno Das Neves @ 2025-09-16 23:44 UTC (permalink / raw)
  To: linux-hyperv, linux-kernel, prapal, easwar.hariharan, tiala,
	anirudh, paekkaladevi
  Cc: kys, haiyangz, wei.liu, decui, Jinank Jain, Nuno Das Neves
In-Reply-To: <1758066262-15477-1-git-send-email-nunodasneves@linux.microsoft.com>

From: Jinank Jain <jinankjain@linux.microsoft.com>

Introduce mshv_use_overlay_gpfn() to check if a page needs to be
allocated and passed to the hypervisor to map VP state pages. This is
only needed on L1VH, and only on some (newer) versions of the
hypervisor, hence the need to check vmm_capabilities.

Introduce functions hv_map/unmap_vp_state_page() to handle the
allocation and freeing.

Signed-off-by: Jinank Jain <jinankjain@linux.microsoft.com>
Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@linux.microsoft.com>
---
 drivers/hv/mshv_root.h         | 11 ++---
 drivers/hv/mshv_root_hv_call.c | 61 ++++++++++++++++++++++++---
 drivers/hv/mshv_root_main.c    | 76 +++++++++++++++++-----------------
 3 files changed, 98 insertions(+), 50 deletions(-)

diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index 0cb1e2589fe1..dbe2d1d0b22f 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -279,11 +279,12 @@ int hv_call_set_vp_state(u32 vp_index, u64 partition_id,
 			 /* Choose between pages and bytes */
 			 struct hv_vp_state_data state_data, u64 page_count,
 			 struct page **pages, u32 num_bytes, u8 *bytes);
-int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
-			      union hv_input_vtl input_vtl,
-			      struct page **state_page);
-int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
-				union hv_input_vtl input_vtl);
+int hv_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
+			 union hv_input_vtl input_vtl,
+			 struct page **state_page);
+int hv_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
+			   struct page *state_page,
+			   union hv_input_vtl input_vtl);
 int hv_call_create_port(u64 port_partition_id, union hv_port_id port_id,
 			u64 connection_partition_id, struct hv_port_info *port_info,
 			u8 port_vtl, u8 min_connection_vtl, int node);
diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
index 3fd3cce23f69..98c6278ff151 100644
--- a/drivers/hv/mshv_root_hv_call.c
+++ b/drivers/hv/mshv_root_hv_call.c
@@ -526,9 +526,9 @@ int hv_call_set_vp_state(u32 vp_index, u64 partition_id,
 	return ret;
 }
 
-int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
-			      union hv_input_vtl input_vtl,
-			      struct page **state_page)
+static int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
+				     union hv_input_vtl input_vtl,
+				     struct page **state_page)
 {
 	struct hv_input_map_vp_state_page *input;
 	struct hv_output_map_vp_state_page *output;
@@ -547,7 +547,14 @@ int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
 		input->type = type;
 		input->input_vtl = input_vtl;
 
-		status = hv_do_hypercall(HVCALL_MAP_VP_STATE_PAGE, input, output);
+		if (*state_page) {
+			input->flags.map_location_provided = 1;
+			input->requested_map_location =
+				page_to_pfn(*state_page);
+		}
+
+		status = hv_do_hypercall(HVCALL_MAP_VP_STATE_PAGE, input,
+					 output);
 
 		if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) {
 			if (hv_result_success(status))
@@ -565,8 +572,39 @@ int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
 	return ret;
 }
 
-int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
-				union hv_input_vtl input_vtl)
+static bool mshv_use_overlay_gpfn(void)
+{
+	return hv_l1vh_partition() &&
+	       mshv_root.vmm_caps.vmm_can_provide_overlay_gpfn;
+}
+
+int hv_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
+			 union hv_input_vtl input_vtl,
+			 struct page **state_page)
+{
+	int ret = 0;
+	struct page *allocated_page = NULL;
+
+	if (mshv_use_overlay_gpfn()) {
+		allocated_page = alloc_page(GFP_KERNEL);
+		if (!allocated_page)
+			return -ENOMEM;
+		*state_page = allocated_page;
+	} else {
+		*state_page = NULL;
+	}
+
+	ret = hv_call_map_vp_state_page(partition_id, vp_index, type, input_vtl,
+					state_page);
+
+	if (ret && allocated_page)
+		__free_page(allocated_page);
+
+	return ret;
+}
+
+static int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
+				       union hv_input_vtl input_vtl)
 {
 	unsigned long flags;
 	u64 status;
@@ -590,6 +628,17 @@ int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
 	return hv_result_to_errno(status);
 }
 
+int hv_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type,
+			   struct page *state_page, union hv_input_vtl input_vtl)
+{
+	int ret = hv_call_unmap_vp_state_page(partition_id, vp_index, type, input_vtl);
+
+	if (mshv_use_overlay_gpfn() && state_page)
+		__free_page(state_page);
+
+	return ret;
+}
+
 int hv_call_get_partition_property_ex(u64 partition_id, u64 property_code,
 				      u64 arg, void *property_value,
 				      size_t property_value_sz)
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index f7738cefbdf3..52f69eace9b9 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -890,7 +890,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 {
 	struct mshv_create_vp args;
 	struct mshv_vp *vp;
-	struct page *intercept_message_page, *register_page, *ghcb_page;
+	struct page *intercept_msg_page, *register_page, *ghcb_page;
 	void *stats_pages[2];
 	long ret;
 
@@ -908,28 +908,25 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 	if (ret)
 		return ret;
 
-	ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index,
-					HV_VP_STATE_PAGE_INTERCEPT_MESSAGE,
-					input_vtl_zero,
-					&intercept_message_page);
+	ret = hv_map_vp_state_page(partition->pt_id, args.vp_index,
+				   HV_VP_STATE_PAGE_INTERCEPT_MESSAGE,
+				   input_vtl_zero, &intercept_msg_page);
 	if (ret)
 		goto destroy_vp;
 
 	if (!mshv_partition_encrypted(partition)) {
-		ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index,
-						HV_VP_STATE_PAGE_REGISTERS,
-						input_vtl_zero,
-						&register_page);
+		ret = hv_map_vp_state_page(partition->pt_id, args.vp_index,
+					   HV_VP_STATE_PAGE_REGISTERS,
+					   input_vtl_zero, &register_page);
 		if (ret)
 			goto unmap_intercept_message_page;
 	}
 
 	if (mshv_partition_encrypted(partition) &&
 	    is_ghcb_mapping_available()) {
-		ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index,
-						HV_VP_STATE_PAGE_GHCB,
-						input_vtl_normal,
-						&ghcb_page);
+		ret = hv_map_vp_state_page(partition->pt_id, args.vp_index,
+					   HV_VP_STATE_PAGE_GHCB,
+					   input_vtl_normal, &ghcb_page);
 		if (ret)
 			goto unmap_register_page;
 	}
@@ -960,7 +957,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 	atomic64_set(&vp->run.vp_signaled_count, 0);
 
 	vp->vp_index = args.vp_index;
-	vp->vp_intercept_msg_page = page_to_virt(intercept_message_page);
+	vp->vp_intercept_msg_page = page_to_virt(intercept_msg_page);
 	if (!mshv_partition_encrypted(partition))
 		vp->vp_register_page = page_to_virt(register_page);
 
@@ -993,21 +990,19 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 	if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
 		mshv_vp_stats_unmap(partition->pt_id, args.vp_index);
 unmap_ghcb_page:
-	if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) {
-		hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index,
-					    HV_VP_STATE_PAGE_GHCB,
-					    input_vtl_normal);
-	}
+	if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available())
+		hv_unmap_vp_state_page(partition->pt_id, args.vp_index,
+				       HV_VP_STATE_PAGE_GHCB, ghcb_page,
+				       input_vtl_normal);
 unmap_register_page:
-	if (!mshv_partition_encrypted(partition)) {
-		hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index,
-					    HV_VP_STATE_PAGE_REGISTERS,
-					    input_vtl_zero);
-	}
+	if (!mshv_partition_encrypted(partition))
+		hv_unmap_vp_state_page(partition->pt_id, args.vp_index,
+				       HV_VP_STATE_PAGE_REGISTERS,
+				       register_page, input_vtl_zero);
 unmap_intercept_message_page:
-	hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index,
-				    HV_VP_STATE_PAGE_INTERCEPT_MESSAGE,
-				    input_vtl_zero);
+	hv_unmap_vp_state_page(partition->pt_id, args.vp_index,
+			       HV_VP_STATE_PAGE_INTERCEPT_MESSAGE,
+			       intercept_msg_page, input_vtl_zero);
 destroy_vp:
 	hv_call_delete_vp(partition->pt_id, args.vp_index);
 	return ret;
@@ -1748,24 +1743,27 @@ static void destroy_partition(struct mshv_partition *partition)
 				mshv_vp_stats_unmap(partition->pt_id, vp->vp_index);
 
 			if (vp->vp_register_page) {
-				(void)hv_call_unmap_vp_state_page(partition->pt_id,
-								  vp->vp_index,
-								  HV_VP_STATE_PAGE_REGISTERS,
-								  input_vtl_zero);
+				(void)hv_unmap_vp_state_page(partition->pt_id,
+							     vp->vp_index,
+							     HV_VP_STATE_PAGE_REGISTERS,
+							     virt_to_page(vp->vp_register_page),
+							     input_vtl_zero);
 				vp->vp_register_page = NULL;
 			}
 
-			(void)hv_call_unmap_vp_state_page(partition->pt_id,
-							  vp->vp_index,
-							  HV_VP_STATE_PAGE_INTERCEPT_MESSAGE,
-							  input_vtl_zero);
+			(void)hv_unmap_vp_state_page(partition->pt_id,
+						     vp->vp_index,
+						     HV_VP_STATE_PAGE_INTERCEPT_MESSAGE,
+						     virt_to_page(vp->vp_intercept_msg_page),
+						     input_vtl_zero);
 			vp->vp_intercept_msg_page = NULL;
 
 			if (vp->vp_ghcb_page) {
-				(void)hv_call_unmap_vp_state_page(partition->pt_id,
-								  vp->vp_index,
-								  HV_VP_STATE_PAGE_GHCB,
-								  input_vtl_normal);
+				(void)hv_unmap_vp_state_page(partition->pt_id,
+							     vp->vp_index,
+							     HV_VP_STATE_PAGE_GHCB,
+							     virt_to_page(vp->vp_ghcb_page),
+							     input_vtl_normal);
 				vp->vp_ghcb_page = NULL;
 			}
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 5/5] mshv: Introduce new hypercall to map stats page for L1VH partitions
From: Nuno Das Neves @ 2025-09-16 23:44 UTC (permalink / raw)
  To: linux-hyperv, linux-kernel, prapal, easwar.hariharan, tiala,
	anirudh, paekkaladevi
  Cc: kys, haiyangz, wei.liu, decui, Jinank Jain, Nuno Das Neves
In-Reply-To: <1758066262-15477-1-git-send-email-nunodasneves@linux.microsoft.com>

From: Jinank Jain <jinankjain@linux.microsoft.com>

Introduce HVCALL_MAP_STATS_PAGE2 which provides a map location (GPFN)
to map the stats to. This hypercall is required for L1VH partitions,
depending on the hypervisor version. This uses the same check as the
state page map location; mshv_use_overlay_gpfn().

Add mshv_map_vp_state_page() helpers to use this new hypercall or the
old one depending on availability.

For unmapping, the original HVCALL_UNMAP_STATS_PAGE works for both
cases.

Signed-off-by: Jinank Jain <jinankjain@linux.microsoft.com>
Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@linux.microsoft.com>
---
 drivers/hv/mshv_root.h         | 10 ++--
 drivers/hv/mshv_root_hv_call.c | 89 ++++++++++++++++++++++++++++++++--
 drivers/hv/mshv_root_main.c    | 22 +++++----
 include/hyperv/hvgdk_mini.h    |  1 +
 include/hyperv/hvhdk_mini.h    |  7 +++
 5 files changed, 109 insertions(+), 20 deletions(-)

diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index dbe2d1d0b22f..0dfccfbe6123 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -297,11 +297,11 @@ int hv_call_connect_port(u64 port_partition_id, union hv_port_id port_id,
 int hv_call_disconnect_port(u64 connection_partition_id,
 			    union hv_connection_id connection_id);
 int hv_call_notify_port_ring_empty(u32 sint_index);
-int hv_call_map_stat_page(enum hv_stats_object_type type,
-			  const union hv_stats_object_identity *identity,
-			  void **addr);
-int hv_call_unmap_stat_page(enum hv_stats_object_type type,
-			    const union hv_stats_object_identity *identity);
+int hv_map_stats_page(enum hv_stats_object_type type,
+		      const union hv_stats_object_identity *identity,
+		      void **addr);
+int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr,
+			const union hv_stats_object_identity *identity);
 int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
 				   u64 page_struct_count, u32 host_access,
 				   u32 flags, u8 acquire);
diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
index 98c6278ff151..7fb7072c071d 100644
--- a/drivers/hv/mshv_root_hv_call.c
+++ b/drivers/hv/mshv_root_hv_call.c
@@ -804,9 +804,47 @@ hv_call_notify_port_ring_empty(u32 sint_index)
 	return hv_result_to_errno(status);
 }
 
-int hv_call_map_stat_page(enum hv_stats_object_type type,
-			  const union hv_stats_object_identity *identity,
-			  void **addr)
+static int hv_call_map_stats_page2(enum hv_stats_object_type type,
+				   const union hv_stats_object_identity *identity,
+				   u64 map_location)
+{
+	unsigned long flags;
+	struct hv_input_map_stats_page2 *input;
+	u64 status;
+	int ret;
+
+	if (!map_location || !mshv_use_overlay_gpfn())
+		return -EINVAL;
+
+	do {
+		local_irq_save(flags);
+		input = *this_cpu_ptr(hyperv_pcpu_input_arg);
+
+		memset(input, 0, sizeof(*input));
+		input->type = type;
+		input->identity = *identity;
+		input->map_location = map_location;
+
+		status = hv_do_hypercall(HVCALL_MAP_STATS_PAGE2, input, NULL);
+
+		local_irq_restore(flags);
+		if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) {
+			if (hv_result_success(status))
+				break;
+			hv_status_debug(status, "\n");
+			return hv_result_to_errno(status);
+		}
+
+		ret = hv_call_deposit_pages(NUMA_NO_NODE,
+					    hv_current_partition_id, 1);
+	} while (!ret);
+
+	return ret;
+}
+
+static int hv_call_map_stats_page(enum hv_stats_object_type type,
+				  const union hv_stats_object_identity *identity,
+				  void **addr)
 {
 	unsigned long flags;
 	struct hv_input_map_stats_page *input;
@@ -845,8 +883,36 @@ int hv_call_map_stat_page(enum hv_stats_object_type type,
 	return ret;
 }
 
-int hv_call_unmap_stat_page(enum hv_stats_object_type type,
-			    const union hv_stats_object_identity *identity)
+int hv_map_stats_page(enum hv_stats_object_type type,
+		      const union hv_stats_object_identity *identity,
+		      void **addr)
+{
+	int ret;
+	struct page *allocated_page = NULL;
+
+	if (!addr)
+		return -EINVAL;
+
+	if (mshv_use_overlay_gpfn()) {
+		allocated_page = alloc_page(GFP_KERNEL);
+		if (!allocated_page)
+			return -ENOMEM;
+
+		ret = hv_call_map_stats_page2(type, identity,
+					      page_to_pfn(allocated_page));
+		*addr = page_address(allocated_page);
+	} else {
+		ret = hv_call_map_stats_page(type, identity, addr);
+	}
+
+	if (ret && allocated_page)
+		__free_page(allocated_page);
+
+	return ret;
+}
+
+static int hv_call_unmap_stats_page(enum hv_stats_object_type type,
+				    const union hv_stats_object_identity *identity)
 {
 	unsigned long flags;
 	struct hv_input_unmap_stats_page *input;
@@ -865,6 +931,19 @@ int hv_call_unmap_stat_page(enum hv_stats_object_type type,
 	return hv_result_to_errno(status);
 }
 
+int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr,
+			const union hv_stats_object_identity *identity)
+{
+	int ret;
+
+	ret = hv_call_unmap_stats_page(type, identity);
+
+	if (mshv_use_overlay_gpfn() && page_addr)
+		__free_page(virt_to_page(page_addr));
+
+	return ret;
+}
+
 int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
 				   u64 page_struct_count, u32 host_access,
 				   u32 flags, u8 acquire)
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 52f69eace9b9..cf46f6772a89 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -841,7 +841,8 @@ mshv_vp_release(struct inode *inode, struct file *filp)
 	return 0;
 }
 
-static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index)
+static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index,
+				void *stats_pages[])
 {
 	union hv_stats_object_identity identity = {
 		.vp.partition_id = partition_id,
@@ -849,10 +850,10 @@ static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index)
 	};
 
 	identity.vp.stats_area_type = HV_STATS_AREA_SELF;
-	hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity);
+	hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity);
 
 	identity.vp.stats_area_type = HV_STATS_AREA_PARENT;
-	hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity);
+	hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity);
 }
 
 static int mshv_vp_stats_map(u64 partition_id, u32 vp_index,
@@ -865,14 +866,14 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_index,
 	int err;
 
 	identity.vp.stats_area_type = HV_STATS_AREA_SELF;
-	err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity,
-				    &stats_pages[HV_STATS_AREA_SELF]);
+	err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity,
+				&stats_pages[HV_STATS_AREA_SELF]);
 	if (err)
 		return err;
 
 	identity.vp.stats_area_type = HV_STATS_AREA_PARENT;
-	err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity,
-				    &stats_pages[HV_STATS_AREA_PARENT]);
+	err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity,
+				&stats_pages[HV_STATS_AREA_PARENT]);
 	if (err)
 		goto unmap_self;
 
@@ -880,7 +881,7 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_index,
 
 unmap_self:
 	identity.vp.stats_area_type = HV_STATS_AREA_SELF;
-	hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity);
+	hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity);
 	return err;
 }
 
@@ -988,7 +989,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 	kfree(vp);
 unmap_stats_pages:
 	if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
-		mshv_vp_stats_unmap(partition->pt_id, args.vp_index);
+		mshv_vp_stats_unmap(partition->pt_id, args.vp_index, stats_pages);
 unmap_ghcb_page:
 	if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available())
 		hv_unmap_vp_state_page(partition->pt_id, args.vp_index,
@@ -1740,7 +1741,8 @@ static void destroy_partition(struct mshv_partition *partition)
 				continue;
 
 			if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
-				mshv_vp_stats_unmap(partition->pt_id, vp->vp_index);
+				mshv_vp_stats_unmap(partition->pt_id, vp->vp_index,
+						    (void **)vp->vp_stats_pages);
 
 			if (vp->vp_register_page) {
 				(void)hv_unmap_vp_state_page(partition->pt_id,
diff --git a/include/hyperv/hvgdk_mini.h b/include/hyperv/hvgdk_mini.h
index ff4325fb623a..f66565106d21 100644
--- a/include/hyperv/hvgdk_mini.h
+++ b/include/hyperv/hvgdk_mini.h
@@ -493,6 +493,7 @@ union hv_vp_assist_msr_contents {	 /* HV_REGISTER_VP_ASSIST_PAGE */
 #define HVCALL_GET_PARTITION_PROPERTY_EX		0x0101
 #define HVCALL_MMIO_READ				0x0106
 #define HVCALL_MMIO_WRITE				0x0107
+#define HVCALL_MAP_STATS_PAGE2				0x0131
 
 /* HV_HYPERCALL_INPUT */
 #define HV_HYPERCALL_RESULT_MASK	GENMASK_ULL(15, 0)
diff --git a/include/hyperv/hvhdk_mini.h b/include/hyperv/hvhdk_mini.h
index bf2ce27dfcc5..064bf735cab6 100644
--- a/include/hyperv/hvhdk_mini.h
+++ b/include/hyperv/hvhdk_mini.h
@@ -177,6 +177,13 @@ struct hv_input_map_stats_page {
 	union hv_stats_object_identity identity;
 } __packed;
 
+struct hv_input_map_stats_page2 {
+	u32 type; /* enum hv_stats_object_type */
+	u32 padding;
+	union hv_stats_object_identity identity;
+	u64 map_location;
+} __packed;
+
 struct hv_output_map_stats_page {
 	u64 map_location;
 } __packed;
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v1 5/6] x86/hyperv: Implement hypervisor ram collection into vmcore
From: Mukesh R @ 2025-09-17  1:13 UTC (permalink / raw)
  To: Michael Kelley, linux-hyperv@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org
  Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org,
	decui@microsoft.com, tglx@linutronix.de, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, arnd@arndb.de
In-Reply-To: <SN6PR02MB4157CD8153650CC9D379A03DD415A@SN6PR02MB4157.namprd02.prod.outlook.com>

On 9/15/25 10:55, Michael Kelley wrote:
> From: Mukesh Rathor <mrathor@linux.microsoft.com> Sent: Tuesday, September 9, 2025 5:10 PM
>>
>> Introduce a new file to implement collection of hypervisor ram into the
> 
> s/ram/RAM/ (multiple places)

a quick grep indicates using saying ram is common, i like ram over RAM

>> vmcore collected by linux. By default, the hypervisor ram is locked, ie,
>> protected via hw page table. Hyper-V implements a disable hypercall which
> 
> The terminology here is a bit confusing since you have two names for
> the same thing: "disable" hypervisor, and "devirtualize". Is it possible to
> just use "devirtualize" everywhere, and drop the "disable" terminology?

The concept is devirtualize and the actual hypercall was originally named
disable. so intermixing is natural imo.

>> essentially devirtualizes the system on the fly. This mechanism makes the
>> hypervisor ram accessible to linux. Because the hypervisor ram is already
>> mapped into linux address space (as reserved ram), 
> 
> Is the hypervisor RAM mapped into the VMM process user address space,
> or somewhere in the kernel address space? If the latter, where in the kernel
> code, or what mechanism, does that? Just curious, as I wasn't aware that
> this is happening ....

mapped in kernel as normal ram and we reserve it very early in boot. i 
see that patch has not made it here yet, should be coming very soon.

>> it is automatically
>> collected into the vmcore without extra work. More details of the
>> implementation are available in the file prologue.
>>
>> Signed-off-by: Mukesh Rathor <mrathor@linux.microsoft.com>
>> ---
>>  arch/x86/hyperv/hv_crash.c | 622 +++++++++++++++++++++++++++++++++++++
>>  1 file changed, 622 insertions(+)
>>  create mode 100644 arch/x86/hyperv/hv_crash.c
>>
>> diff --git a/arch/x86/hyperv/hv_crash.c b/arch/x86/hyperv/hv_crash.c
>> new file mode 100644
>> index 000000000000..531bac79d598
>> --- /dev/null
>> +++ b/arch/x86/hyperv/hv_crash.c
>> @@ -0,0 +1,622 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * X86 specific Hyper-V kdump/crash support module
>> + *
>> + * Copyright (C) 2025, Microsoft, Inc.
>> + *
>> + * This module implements hypervisor ram collection into vmcore for both
>> + * cases of the hypervisor crash and linux dom0/root crash. 
> 
> For a hypervisor crash, does any of this apply to general guest VMs? I'm
> thinking it does not. Hypervisor RAM is collected only into the vmcore
> for the root partition, right? Maybe some additional clarification could be
> added so there's no confusion in this regard.

it would be odd for guests to collect hyp core, and target audience is
assumed to be those who are somewhat familiar with basic concepts before
getting here.

> And what *does* happen to guest VMs after a hypervisor crash?

they are gone... what else could we do?

>> + * Hyper-V implements
>> + * a devirtualization hypercall with a 32bit protected mode ABI callback. This
>> + * mechanism must be used to unlock hypervisor ram. Since the hypervisor ram
>> + * is already mapped in linux, it is automatically collected into linux vmcore,
>> + * and can be examined by the crash command (raw ram dump) or windbg.
>> + *
>> + * At a high level:
>> + *
>> + *  Hypervisor Crash:
>> + *    Upon crash, hypervisor goes into an emergency minimal dispatch loop, a
>> + *    restrictive mode with very limited hypercall and msr support.
> 
> s/msr/MSR/

msr is used all over, seems acceptable.

>> + *    Each cpu then injects NMIs into dom0/root vcpus. 
> 
> The "Each cpu" part of this sentence is confusing to me -- which CPUs does
> this refer to? Maybe it would be better to say "It then injects an NMI into
> each dom0/root partition vCPU." without being specific as to which CPUs do
> the injecting since that seems more like a hypervisor implementation detail
> that's not relevant here.

all cpus in the system. there is a dedicated/pinned dom0 vcpu for each cpu.

>> + *    A shared page is used to check
>> + *    by linux in the nmi handler if the hypervisor has crashed. This shared
> 
> s/nmi/NMI/  (multiple places)

>> + *    page is setup in hv_root_crash_init during boot.
>> + *
>> + *  Linux Crash:
>> + *    In case of linux crash, the callback hv_crash_stop_other_cpus will send
>> + *    NMIs to all cpus, then proceed to the crash_nmi_callback where it waits
>> + *    for all cpus to be in NMI.
>> + *
>> + *  NMI Handler (upon quorum):
>> + *    Eventually, in both cases, all cpus wil end up in the nmi hanlder.
> 
> s/hanlder/handler/
> 
> And maybe just drop the word "wil" (which is misspelled).
> 
>> + *    Hyper-V requires the disable hypervisor must be done from the bsp. So
> 
> s/bsp/BSP  (multiple places)
> 
>> + *    the bsp nmi handler saves current context, does some fixups and makes
>> + *    the hypercall to disable the hypervisor, ie, devirtualize. Hypervisor
>> + *    at that point will suspend all vcpus (except the bsp), unlock all its
>> + *    ram, and return to linux at the 32bit mode entry RIP.
>> + *
>> + *  Linux 32bit entry trampoline will then restore long mode and call C
>> + *  function here to restore context and continue execution to crash kexec.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/kexec.h>
>> +#include <linux/crash_dump.h>
>> +#include <linux/panic.h>
>> +#include <asm/apic.h>
>> +#include <asm/desc.h>
>> +#include <asm/page.h>
>> +#include <asm/pgalloc.h>
>> +#include <asm/mshyperv.h>
>> +#include <asm/nmi.h>
>> +#include <asm/idtentry.h>
>> +#include <asm/reboot.h>
>> +#include <asm/intel_pt.h>
>> +
>> +int hv_crash_enabled;
> 
> Seems like this is conceptually a "bool", not an "int".

yeah, can change it to bool if i do another iteration.

>> +EXPORT_SYMBOL_GPL(hv_crash_enabled);
>> +
>> +struct hv_crash_ctxt {
>> +	ulong rsp;
>> +	ulong cr0;
>> +	ulong cr2;
>> +	ulong cr4;
>> +	ulong cr8;
>> +
>> +	u16 cs;
>> +	u16 ss;
>> +	u16 ds;
>> +	u16 es;
>> +	u16 fs;
>> +	u16 gs;
>> +
>> +	u16 gdt_fill;
>> +	struct desc_ptr gdtr;
>> +	char idt_fill[6];
>> +	struct desc_ptr idtr;
>> +
>> +	u64 gsbase;
>> +	u64 efer;
>> +	u64 pat;
>> +};
>> +static struct hv_crash_ctxt hv_crash_ctxt;
>> +
>> +/* Shared hypervisor page that contains crash dump area we peek into.
>> + * NB: windbg looks for "hv_cda" symbol so don't change it.
>> + */
>> +static struct hv_crashdump_area *hv_cda;
>> +
>> +static u32 trampoline_pa, devirt_cr3arg;
>> +static atomic_t crash_cpus_wait;
>> +static void *hv_crash_ptpgs[4];
>> +static int hv_has_crashed, lx_has_crashed;
> 
> These are conceptually "bool" as well.
> 
>> +
>> +/* This cannot be inlined as it needs stack */
>> +static noinline __noclone void hv_crash_restore_tss(void)
>> +{
>> +	load_TR_desc();
>> +}
>> +
>> +/* This cannot be inlined as it needs stack */
>> +static noinline void hv_crash_clear_kernpt(void)
>> +{
>> +	pgd_t *pgd;
>> +	p4d_t *p4d;
>> +
>> +	/* Clear entry so it's not confusing to someone looking at the core */
>> +	pgd = pgd_offset_k(trampoline_pa);
>> +	p4d = p4d_offset(pgd, trampoline_pa);
>> +	native_p4d_clear(p4d);
>> +}
>> +
>> +/*
>> + * This is the C entry point from the asm glue code after the devirt hypercall.
>> + * We enter here in IA32-e long mode, ie, full 64bit mode running on kernel
>> + * page tables with our below 4G page identity mapped, but using a temporary
>> + * GDT. ds/fs/gs/es are null. ss is not usable. bp is null. stack is not
>> + * available. We restore kernel GDT, and rest of the context, and continue
>> + * to kexec.
>> + */
>> +static asmlinkage void __noreturn hv_crash_c_entry(void)
>> +{
>> +	struct hv_crash_ctxt *ctxt = &hv_crash_ctxt;
>> +
>> +	/* first thing, restore kernel gdt */
>> +	native_load_gdt(&ctxt->gdtr);
>> +
>> +	asm volatile("movw %%ax, %%ss" : : "a"(ctxt->ss));
>> +	asm volatile("movq %0, %%rsp" : : "m"(ctxt->rsp));
>> +
>> +	asm volatile("movw %%ax, %%ds" : : "a"(ctxt->ds));
>> +	asm volatile("movw %%ax, %%es" : : "a"(ctxt->es));
>> +	asm volatile("movw %%ax, %%fs" : : "a"(ctxt->fs));
>> +	asm volatile("movw %%ax, %%gs" : : "a"(ctxt->gs));
>> +
>> +	native_wrmsrq(MSR_IA32_CR_PAT, ctxt->pat);
>> +	asm volatile("movq %0, %%cr0" : : "r"(ctxt->cr0));
>> +
>> +	asm volatile("movq %0, %%cr8" : : "r"(ctxt->cr8));
>> +	asm volatile("movq %0, %%cr4" : : "r"(ctxt->cr4));
>> +	asm volatile("movq %0, %%cr2" : : "r"(ctxt->cr4));
>> +
>> +	native_load_idt(&ctxt->idtr);
>> +	native_wrmsrq(MSR_GS_BASE, ctxt->gsbase);
>> +	native_wrmsrq(MSR_EFER, ctxt->efer);
>> +
>> +	/* restore the original kernel CS now via far return */
>> +	asm volatile("movzwq %0, %%rax\n\t"
>> +		     "pushq %%rax\n\t"
>> +		     "pushq $1f\n\t"
>> +		     "lretq\n\t"
>> +		     "1:nop\n\t" : : "m"(ctxt->cs) : "rax");
>> +
>> +	/* We are in asmlinkage without stack frame, hence make a C function
>> +	 * call which will buy stack frame to restore the tss or clear PT entry.
>> +	 */
>> +	hv_crash_restore_tss();
>> +	hv_crash_clear_kernpt();
>> +
>> +	/* we are now fully in devirtualized normal kernel mode */
>> +	__crash_kexec(NULL);
> 
> The comments for __crash_kexec() say that "panic_cpu" should be set to
> the current CPU. I don't see that such is the case here.

if linux panic, it would be set by vpanic, if hyp crash, that is
irrelevant.

>> +
>> +	for (;;)
>> +		cpu_relax();
> 
> Is the intent that __crash_kexec() should never return, on any of the vCPUs,
> because devirtualization isn't done unless there's a valid kdump image loaded?
> I wonder if
> 
> 	native_wrmsrq(HV_X64_MSR_RESET, 1);
> 
> would be better than looping forever in case __crash_kexec() fails
> somewhere along the way even if there's a kdump image loaded.

yeah, i've gone thru all 3 possibilities here:
  o loop forever
  o reset
  o BUG() : this was in V0

reset is just bad because system would just reboot without any indication
if hyp crashes. with loop at least there is a hang, and one could make
note of it, and if internal, attach debugger.

BUG is best imo because with hyp gone linux will try to redo panic
and we would print something extra to help. I think i'll just go
back to my V0: BUG()

>> +}
>> +/* Tell gcc we are using lretq long jump in the above function intentionally */
>> +STACK_FRAME_NON_STANDARD(hv_crash_c_entry);
>> +
>> +static void hv_mark_tss_not_busy(void)
>> +{
>> +	struct desc_struct *desc = get_current_gdt_rw();
>> +	tss_desc tss;
>> +
>> +	memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc));
>> +	tss.type = 0x9;        /* available 64-bit TSS. 0xB is busy TSS */
>> +	write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
>> +}
>> +
>> +/* Save essential context */
>> +static void hv_hvcrash_ctxt_save(void)
>> +{
>> +	struct hv_crash_ctxt *ctxt = &hv_crash_ctxt;
>> +
>> +	asm volatile("movq %%rsp,%0" : "=m"(ctxt->rsp));
>> +
>> +	ctxt->cr0 = native_read_cr0();
>> +	ctxt->cr4 = native_read_cr4();
>> +
>> +	asm volatile("movq %%cr2, %0" : "=a"(ctxt->cr2));
>> +	asm volatile("movq %%cr8, %0" : "=a"(ctxt->cr8));
>> +
>> +	asm volatile("movl %%cs, %%eax" : "=a"(ctxt->cs));
>> +	asm volatile("movl %%ss, %%eax" : "=a"(ctxt->ss));
>> +	asm volatile("movl %%ds, %%eax" : "=a"(ctxt->ds));
>> +	asm volatile("movl %%es, %%eax" : "=a"(ctxt->es));
>> +	asm volatile("movl %%fs, %%eax" : "=a"(ctxt->fs));
>> +	asm volatile("movl %%gs, %%eax" : "=a"(ctxt->gs));
>> +
>> +	native_store_gdt(&ctxt->gdtr);
>> +	store_idt(&ctxt->idtr);
>> +
>> +	ctxt->gsbase = __rdmsr(MSR_GS_BASE);
>> +	ctxt->efer = __rdmsr(MSR_EFER);
>> +	ctxt->pat = __rdmsr(MSR_IA32_CR_PAT);
>> +}
>> +
>> +/* Add trampoline page to the kernel pagetable for transition to kernel PT */
>> +static void hv_crash_fixup_kernpt(void)
>> +{
>> +	pgd_t *pgd;
>> +	p4d_t *p4d;
>> +
>> +	pgd = pgd_offset_k(trampoline_pa);
>> +	p4d = p4d_offset(pgd, trampoline_pa);
>> +
>> +	/* trampoline_pa is below 4G, so no pre-existing entry to clobber */
>> +	p4d_populate(&init_mm, p4d, (pud_t *)hv_crash_ptpgs[1]);
>> +	p4d->p4d = p4d->p4d & ~(_PAGE_NX);    /* enable execute */
>> +}
>> +
>> +/*
>> + * Now that all cpus are in nmi and spinning, we notify the hyp that linux has
>> + * crashed and will collect core. This will cause the hyp to quiesce and
>> + * suspend all VPs except the bsp. Called if linux crashed and not the hyp.
>> + */
>> +static void hv_notify_prepare_hyp(void)
>> +{
>> +	u64 status;
>> +	struct hv_input_notify_partition_event *input;
>> +	struct hv_partition_event_root_crashdump_input *cda;
>> +
>> +	input = *this_cpu_ptr(hyperv_pcpu_input_arg);
>> +	cda = &input->input.crashdump_input;
> 
> The code ordering here is a bit weird. I'd expect this line to be grouped
> with cda->crashdump_action being set.

we are setting two pointers, and using them later. setting pointers 
up front is pretty normal.

>> +	memset(input, 0, sizeof(*input));
>> +	input->event = HV_PARTITION_EVENT_ROOT_CRASHDUMP;
>> +
>> +	cda->crashdump_action = HV_CRASHDUMP_ENTRY;
>> +	status = hv_do_hypercall(HVCALL_NOTIFY_PARTITION_EVENT, input, NULL);
>> +	if (!hv_result_success(status))
>> +		return;
>> +
>> +	cda->crashdump_action = HV_CRASHDUMP_SUSPEND_ALL_VPS;
>> +	hv_do_hypercall(HVCALL_NOTIFY_PARTITION_EVENT, input, NULL);
>> +}
>> +
>> +/*
>> + * Common function for all cpus before devirtualization.
>> + *
>> + * Hypervisor crash: all cpus get here in nmi context.
>> + * Linux crash: the panicing cpu gets here at base level, all others in nmi
>> + *		context. Note, panicing cpu may not be the bsp.
>> + *
>> + * The function is not inlined so it will show on the stack. It is named so
>> + * because the crash cmd looks for certain well known function names on the
>> + * stack before looking into the cpu saved note in the elf section, and
>> + * that work is currently incomplete.
>> + *
>> + * Notes:
>> + *  Hypervisor crash:
>> + *    - the hypervisor is in a very restrictive mode at this point and any
>> + *	vmexit it cannot handle would result in reboot. For example, console
>> + *	output from here would result in synic ipi hcall, which would result
>> + *	in reboot. So, no mumbo jumbo, just get to kexec as quickly as possible.
>> + *
>> + *  Devirtualization is supported from the bsp only.
>> + */
>> +static noinline __noclone void crash_nmi_callback(struct pt_regs *regs)
>> +{
>> +	struct hv_input_disable_hyp_ex *input;
>> +	u64 status;
>> +	int msecs = 1000, ccpu = smp_processor_id();
>> +
>> +	if (ccpu == 0) {
>> +		/* crash_save_cpu() will be done in the kexec path */
>> +		cpu_emergency_stop_pt();	/* disable performance trace */
>> +		atomic_inc(&crash_cpus_wait);
>> +	} else {
>> +		crash_save_cpu(regs, ccpu);
>> +		cpu_emergency_stop_pt();	/* disable performance trace */
>> +		atomic_inc(&crash_cpus_wait);
>> +		for (;;);			/* cause no vmexits */
>> +	}
>> +
>> +	while (atomic_read(&crash_cpus_wait) < num_online_cpus() && msecs--)
>> +		mdelay(1);
>> +
>> +	stop_nmi();
>> +	if (!hv_has_crashed)
>> +		hv_notify_prepare_hyp();
>> +
>> +	if (crashing_cpu == -1)
>> +		crashing_cpu = ccpu;		/* crash cmd uses this */
> 
> Could just be "crashing_cpu = 0" since only the BSP gets here.

a code change request has been open for while to remove the requirement 
of bsp..

>> +
>> +	hv_hvcrash_ctxt_save();
>> +	hv_mark_tss_not_busy();
>> +	hv_crash_fixup_kernpt();
>> +
>> +	input = *this_cpu_ptr(hyperv_pcpu_input_arg);
>> +	memset(input, 0, sizeof(*input));
>> +	input->rip = trampoline_pa;	/* PA of hv_crash_asm32 */
>> +	input->arg = devirt_cr3arg;	/* PA of trampoline page table L4 */
> 
> Is this comment correct? Isn't it the PA of struct hv_crash_tramp_data?
> And just for clarification, Hyper-V treats this "arg" value as opaque and does
> not access it. It only provides it in EDI when it invokes the trampoline
> function, right?

comment is correct. cr3 always points to l4 (or l5 if 5 level page tables).

right, comes in edi, i don't know what EDI is (just kidding!)... 

>> +
>> +	status = hv_do_hypercall(HVCALL_DISABLE_HYP_EX, input, NULL);
>> +
>> +	/* Devirt failed, just reboot as things are in very bad state now */
>> +	native_wrmsrq(HV_X64_MSR_RESET, 1);    /* get hv to reboot */
>> +}
>> +
>> +/*
>> + * Generic nmi callback handler: could be called without any crash also.
>> + *   hv crash: hypervisor injects nmi's into all cpus
>> + *   lx crash: panicing cpu sends nmi to all but self via crash_stop_other_cpus
>> + */
>> +static int hv_crash_nmi_local(unsigned int cmd, struct pt_regs *regs)
>> +{
>> +	int ccpu = smp_processor_id();
>> +
>> +	if (!hv_has_crashed && hv_cda && hv_cda->cda_valid)
>> +		hv_has_crashed = 1;
>> +
>> +	if (!hv_has_crashed && !lx_has_crashed)
>> +		return NMI_DONE;	/* ignore the nmi */
>> +
>> +	if (hv_has_crashed) {
>> +		if (!kexec_crash_loaded() || !hv_crash_enabled) {
>> +			if (ccpu == 0) {
>> +				native_wrmsrq(HV_X64_MSR_RESET, 1); /* reboot */
>> +			} else
>> +				for (;;);	/* cause no vmexits */
>> +		}
>> +	}
>> +
>> +	crash_nmi_callback(regs);
>> +
>> +	return NMI_DONE;
> 
> crash_nmi_callback() should never return, right? Normally one would
> expect to return NMI_HANDLED here, but I guess it doesn't matter
> if the return is never executed.

correct. 

>> +}
>> +
>> +/*
>> + * hv_crash_stop_other_cpus() == smp_ops.crash_stop_other_cpus
>> + *
>> + * On normal linux panic, this is called twice: first from panic and then again
>> + * from native_machine_crash_shutdown.
>> + *
>> + * In case of mshv, 3 ways to get here:
>> + *  1. hv crash (only bsp will get here):
>> + *	BSP : nmi callback -> DisableHv -> hv_crash_asm32 -> hv_crash_c_entry
>> + *		  -> __crash_kexec -> native_machine_crash_shutdown
>> + *		  -> crash_smp_send_stop -> smp_ops.crash_stop_other_cpus
>> + *  linux panic:
>> + *	2. panic cpu x: panic() -> crash_smp_send_stop
>> + *				     -> smp_ops.crash_stop_other_cpus
>> + *	3. bsp: native_machine_crash_shutdown -> crash_smp_send_stop
>> + *
>> + * NB: noclone and non standard stack because of call to crash_setup_regs().
>> + */
>> +static void __noclone hv_crash_stop_other_cpus(void)
>> +{
>> +	static int crash_stop_done;
>> +	struct pt_regs lregs;
>> +	int ccpu = smp_processor_id();
>> +
>> +	if (hv_has_crashed)
>> +		return;		/* all cpus already in nmi handler path */
>> +
>> +	if (!kexec_crash_loaded())
>> +		return;
> 
> If we're in a normal panic path (your Case #2 above) with no kdump kernel
> loaded, why leave the other vCPUs running? Seems like that could violate
> expectations in vpanic(), where it calls panic_other_cpus_shutdown() and
> thereafter assumes other vCPUs are not running.

no, there is lots of complexity here!

if we hang vcpus here, hyp will note and may trigger its own watchdog.
also, machine_crash_shutdown() does another ipi.

I think the best thing to do here is go back to my V0 which did not
have check for kexec_crash_loaded(), but had this in hv_crash_c_entry:

+       /* we are now fully in devirtualized normal kernel mode */
+       __crash_kexec(NULL);
+
+       BUG();


this way hyp would be disabled, ie, system devirtualized, and 
__crash_kernel() will return, resulting in BUG() that will cause
it to go thru panic and honor panic= parameter with either hang
or reset. instead of bug, i could just call panic() also.

>> +
>> +	if (crash_stop_done)
>> +		return;
>> +	crash_stop_done = 1;
> 
> Is crash_stop_done necessary?  hv_crash_stop_other_cpus() is called
> from crash_smp_send_stop(), which has its own static variable 
> "cpus_stopped" that does the same thing.

yes. for error paths.

>> +
>> +	/* linux has crashed: hv is healthy, we can ipi safely */
>> +	lx_has_crashed = 1;
>> +	wmb();			/* nmi handlers look at lx_has_crashed */
>> +
>> +	apic->send_IPI_allbutself(NMI_VECTOR);
> 
> The default .crash_stop_other_cpus function is kdump_nmi_shootdown_cpus().
> In addition to sending the NMI IPI, it does disable_local_APIC(). I don't know, but
> should disable_local_APIC() be done somewhere here as well?

no, hyp does that.

>> +
>> +	if (crashing_cpu == -1)
>> +		crashing_cpu = ccpu;		/* crash cmd uses this */
>> +
>> +	/* crash_setup_regs() happens in kexec also, but for the kexec cpu which
>> +	 * is the bsp. We could be here on non-bsp cpu, collect regs if so.
>> +	 */
>> +	if (ccpu)
>> +		crash_setup_regs(&lregs, NULL);
>> +
>> +	crash_nmi_callback(&lregs);
>> +}
>> +STACK_FRAME_NON_STANDARD(hv_crash_stop_other_cpus);
>> +
>> +/* This GDT is accessed in IA32-e compat mode which uses 32bits addresses */
>> +struct hv_gdtreg_32 {
>> +	u16 fill;
>> +	u16 limit;
>> +	u32 address;
>> +} __packed;
>> +
>> +/* We need a CS with L bit to goto IA32-e long mode from 32bit compat mode */
>> +struct hv_crash_tramp_gdt {
>> +	u64 null;	/* index 0, selector 0, null selector */
>> +	u64 cs64;	/* index 1, selector 8, cs64 selector */
>> +} __packed;
>> +
>> +/* No stack, so jump via far ptr in memory to load the 64bit CS */
>> +struct hv_cs_jmptgt {
>> +	u32 address;
>> +	u16 csval;
>> +	u16 fill;
>> +} __packed;
>> +
>> +/* This trampoline data is copied onto the trampoline page after the asm code */
>> +struct hv_crash_tramp_data {
>> +	u64 tramp32_cr3;
>> +	u64 kernel_cr3;
>> +	struct hv_gdtreg_32 gdtr32;
>> +	struct hv_crash_tramp_gdt tramp_gdt;
>> +	struct hv_cs_jmptgt cs_jmptgt;
>> +	u64 c_entry_addr;
>> +} __packed;
>> +
>> +/*
>> + * Setup a temporary gdt to allow the asm code to switch to the long mode.
>> + * Since the asm code is relocated/copied to a below 4G page, it cannot use rip
>> + * relative addressing, hence we must use trampoline_pa here. Also, save other
>> + * info like jmp and C entry targets for same reasons.
>> + *
>> + * Returns: 0 on success, -1 on error
>> + */
>> +static int hv_crash_setup_trampdata(u64 trampoline_va)
>> +{
>> +	int size, offs;
>> +	void *dest;
>> +	struct hv_crash_tramp_data *tramp;
>> +
>> +	/* These must match exactly the ones in the corresponding asm file */
>> +	BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, tramp32_cr3) != 0);
>> +	BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, kernel_cr3) != 8);
>> +	BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, gdtr32.limit) != 18);
>> +	BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data,
>> +						     cs_jmptgt.address) != 40);
> 
> It would be nice to pick up the constants from a #include file that is
> shared with the asm code in Patch 4 of the series.

yeah, could go either way, some don't like tiny headers...  if there are
no objections to new header for this, i could go that way too.

>> +
>> +	/* hv_crash_asm_end is beyond last byte by 1 */
>> +	size = &hv_crash_asm_end - &hv_crash_asm32;
>> +	if (size + sizeof(struct hv_crash_tramp_data) > PAGE_SIZE) {
>> +		pr_err("%s: trampoline page overflow\n", __func__);
>> +		return -1;
>> +	}
>> +
>> +	dest = (void *)trampoline_va;
>> +	memcpy(dest, &hv_crash_asm32, size);
>> +
>> +	dest += size;
>> +	dest = (void *)round_up((ulong)dest, 16);
>> +	tramp = (struct hv_crash_tramp_data *)dest;
>> +
>> +	/* see MAX_ASID_AVAILABLE in tlb.c: "PCID 0 is reserved for use by
>> +	 * non-PCID-aware users". Build cr3 with pcid 0
>> +	 */
>> +	tramp->tramp32_cr3 = __sme_pa(hv_crash_ptpgs[0]);
>> +
>> +	/* Note, when restoring X86_CR4_PCIDE, cr3[11:0] must be zero */
>> +	tramp->kernel_cr3 = __sme_pa(init_mm.pgd);
>> +
>> +	tramp->gdtr32.limit = sizeof(struct hv_crash_tramp_gdt);
>> +	tramp->gdtr32.address = trampoline_pa +
>> +				   (ulong)&tramp->tramp_gdt - trampoline_va;
>> +
>> +	 /* base:0 limit:0xfffff type:b dpl:0 P:1 L:1 D:0 avl:0 G:1 */
>> +	tramp->tramp_gdt.cs64 = 0x00af9a000000ffff;
>> +
>> +	tramp->cs_jmptgt.csval = 0x8;
>> +	offs = (ulong)&hv_crash_asm64_lbl - (ulong)&hv_crash_asm32;
>> +	tramp->cs_jmptgt.address = trampoline_pa + offs;
>> +
>> +	tramp->c_entry_addr = (u64)&hv_crash_c_entry;
>> +
>> +	devirt_cr3arg = trampoline_pa + (ulong)dest - trampoline_va;
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>> + * Build 32bit trampoline page table for transition from protected mode
>> + * non-paging to long-mode paging. This transition needs pagetables below 4G.
>> + */
>> +static void hv_crash_build_tramp_pt(void)
>> +{
>> +	p4d_t *p4d;
>> +	pud_t *pud;
>> +	pmd_t *pmd;
>> +	pte_t *pte;
>> +	u64 pa, addr = trampoline_pa;
>> +
>> +	p4d = hv_crash_ptpgs[0] + pgd_index(addr) * sizeof(p4d);
>> +	pa = virt_to_phys(hv_crash_ptpgs[1]);
>> +	set_p4d(p4d, __p4d(_PAGE_TABLE | pa));
>> +	p4d->p4d &= ~(_PAGE_NX);	/* disable no execute */
>> +
>> +	pud = hv_crash_ptpgs[1] + pud_index(addr) * sizeof(pud);
>> +	pa = virt_to_phys(hv_crash_ptpgs[2]);
>> +	set_pud(pud, __pud(_PAGE_TABLE | pa));
>> +
>> +	pmd = hv_crash_ptpgs[2] + pmd_index(addr) * sizeof(pmd);
>> +	pa = virt_to_phys(hv_crash_ptpgs[3]);
>> +	set_pmd(pmd, __pmd(_PAGE_TABLE | pa));
>> +
>> +	pte = hv_crash_ptpgs[3] + pte_index(addr) * sizeof(pte);
>> +	set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_EXEC));
>> +}
>> +
>> +/*
>> + * Setup trampoline for devirtualization:
>> + *  - a page below 4G, ie 32bit addr containing asm glue code that mshv jmps to
>> + *    in protected mode.
>> + *  - 4 pages for a temporary page table that asm code uses to turn paging on
>> + *  - a temporary gdt to use in the compat mode.
>> + *
>> + *  Returns: 0 on success
>> + */
>> +static int hv_crash_trampoline_setup(void)
>> +{
>> +	int i, rc, order;
>> +	struct page *page;
>> +	u64 trampoline_va;
>> +	gfp_t flags32 = GFP_KERNEL | GFP_DMA32 | __GFP_ZERO;
>> +
>> +	/* page for 32bit trampoline assembly code + hv_crash_tramp_data */
>> +	page = alloc_page(flags32);
>> +	if (page == NULL) {
>> +		pr_err("%s: failed to alloc asm stub page\n", __func__);
>> +		return -1;
>> +	}
>> +
>> +	trampoline_va = (u64)page_to_virt(page);
>> +	trampoline_pa = (u32)page_to_phys(page);
>> +
>> +	order = 2;	   /* alloc 2^2 pages */
>> +	page = alloc_pages(flags32, order);
>> +	if (page == NULL) {
>> +		pr_err("%s: failed to alloc pt pages\n", __func__);
>> +		free_page(trampoline_va);
>> +		return -1;
>> +	}
>> +
>> +	for (i = 0; i < 4; i++, page++)
>> +		hv_crash_ptpgs[i] = page_to_virt(page);
>> +
>> +	hv_crash_build_tramp_pt();
>> +
>> +	rc = hv_crash_setup_trampdata(trampoline_va);
>> +	if (rc)
>> +		goto errout;
>> +
>> +	return 0;
>> +
>> +errout:
>> +	free_page(trampoline_va);
>> +	free_pages((ulong)hv_crash_ptpgs[0], order);
>> +
>> +	return rc;
>> +}
>> +
>> +/* Setup for kdump kexec to collect hypervisor ram when running as mshv root */
>> +void hv_root_crash_init(void)
>> +{
>> +	int rc;
>> +	struct hv_input_get_system_property *input;
>> +	struct hv_output_get_system_property *output;
>> +	unsigned long flags;
>> +	u64 status;
>> +	union hv_pfn_range cda_info;
>> +
>> +	if (pgtable_l5_enabled()) {
>> +		pr_err("Hyper-V: crash dump not yet supported on 5level PTs\n");
>> +		return;
>> +	}
>> +
>> +	rc = register_nmi_handler(NMI_LOCAL, hv_crash_nmi_local, NMI_FLAG_FIRST,
>> +				  "hv_crash_nmi");
>> +	if (rc) {
>> +		pr_err("Hyper-V: failed to register crash nmi handler\n");
>> +		return;
>> +	}
>> +
>> +	local_irq_save(flags);
>> +	input = *this_cpu_ptr(hyperv_pcpu_input_arg);
>> +	output = *this_cpu_ptr(hyperv_pcpu_output_arg);
>> +
>> +	memset(input, 0, sizeof(*input));
>> +	memset(output, 0, sizeof(*output));
> 
> Why zero the output area? This is one of those hypercall things that we're
> inconsistent about. A few hypercall call sites zero the output area, and it's
> not clear why they do. Hyper-V should be responsible for properly filling in
> the output area. Linux should not need to do this zero'ing, unless there's some
> known bug in Hyper-V for certain hypercalls, in which case there should be
> a code comment stating "why".

for the same reason sometimes you see char *p = NULL, either leftover
code or someone was debugging or just copy and paste. this is just copy
paste. i agree in general that we don't need to clear it at all, in fact,
i'd like to remove them all! but i also understand people with different
skills and junior members find it easier to debug, and also we were in
early product development. for that reason, it doesn't have to be 
consistent either, if some complex hypercalls are failing repeatedly, 
just for ease of debug, one might leave it there temporarily.  but
now that things are stable, i think we should just remove them all and 
get used to a bit more inconvenient debugging...

>> +	input->property_id = HV_SYSTEM_PROPERTY_CRASHDUMPAREA;
>> +
>> +	status = hv_do_hypercall(HVCALL_GET_SYSTEM_PROPERTY, input, output);
>> +	cda_info.as_uint64 = output->hv_cda_info.as_uint64;
>> +	local_irq_restore(flags);
>> +
>> +	if (!hv_result_success(status)) {
>> +		pr_err("Hyper-V: %s: property:%d %s\n", __func__,
>> +		       input->property_id, hv_result_to_string(status));
>> +		goto err_out;
>> +	}
>> +
>> +	if (cda_info.base_pfn == 0) {
>> +		pr_err("Hyper-V: hypervisor crash dump area pfn is 0\n");
>> +		goto err_out;
>> +	}
>> +
>> +	hv_cda = phys_to_virt(cda_info.base_pfn << PAGE_SHIFT);
> 
> Use HV_HYP_PAGE_SHIFT, since PFNs provided by Hyper-V are always in
> terms of the Hyper-V page size, which isn't necessarily the guest page size. 
> Yes, on x86 there's no difference, but for future robustness ....

i don't know about guests, but we won't even boot if dom0 pg size
didn't match.. but easier to change than to make the case..

>> +
>> +	rc = hv_crash_trampoline_setup();
>> +	if (rc)
>> +		goto err_out;
>> +
>> +	smp_ops.crash_stop_other_cpus = hv_crash_stop_other_cpus;
>> +
>> +	crash_kexec_post_notifiers = true;
>> +	hv_crash_enabled = 1;
>> +	pr_info("Hyper-V: linux and hv kdump support enabled\n");
> 
> This message and the message below aren't consistent. One refers
> to "hv kdump" and the other to "hyp kdump".

>> +
>> +	return;
>> +
>> +err_out:
>> +	unregister_nmi_handler(NMI_LOCAL, "hv_crash_nmi");
>> +	pr_err("Hyper-V: only linux (but not hyp) kdump support enabled\n");
>> +}
>> --
>> 2.36.1.vfs.0.0
>>
> 


^ permalink raw reply

* Re: [PATCH v1 6/6] x86/hyperv: Enable build of hypervisor crashdump collection files
From: Mukesh R @ 2025-09-17  1:15 UTC (permalink / raw)
  To: Michael Kelley, linux-hyperv@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org
  Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org,
	decui@microsoft.com, tglx@linutronix.de, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, arnd@arndb.de
In-Reply-To: <SN6PR02MB415730C50D722D289E33296ED415A@SN6PR02MB4157.namprd02.prod.outlook.com>

On 9/15/25 10:56, Michael Kelley wrote:
> From: Mukesh Rathor <mrathor@linux.microsoft.com> Sent: Tuesday, September 9, 2025 5:10 PM
>>
>> Enable build of the new files introduced in the earlier commits and add
>> call to do the setup during boot.
>>
>> Signed-off-by: Mukesh Rathor <mrathor@linux.microsoft.com>
>> ---
>>  arch/x86/hyperv/Makefile       | 6 ++++++
>>  arch/x86/hyperv/hv_init.c      | 1 +
>>  include/asm-generic/mshyperv.h | 9 +++++++++
>>  3 files changed, 16 insertions(+)
>>
>> diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile
>> index d55f494f471d..6f5d97cddd80 100644
>> --- a/arch/x86/hyperv/Makefile
>> +++ b/arch/x86/hyperv/Makefile
>> @@ -5,4 +5,10 @@ obj-$(CONFIG_HYPERV_VTL_MODE)	+= hv_vtl.o
>>
>>  ifdef CONFIG_X86_64
>>  obj-$(CONFIG_PARAVIRT_SPINLOCKS)	+= hv_spinlock.o
>> +
>> + ifdef CONFIG_MSHV_ROOT
>> +  CFLAGS_REMOVE_hv_trampoline.o += -pg
>> +  CFLAGS_hv_trampoline.o        += -fno-stack-protector
>> +  obj-$(CONFIG_CRASH_DUMP)      += hv_crash.o hv_trampoline.o
>> + endif
>>  endif
>> diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
>> index afdbda2dd7b7..577bbd143527 100644
>> --- a/arch/x86/hyperv/hv_init.c
>> +++ b/arch/x86/hyperv/hv_init.c
>> @@ -510,6 +510,7 @@ void __init hyperv_init(void)
>>  		memunmap(src);
>>
>>  		hv_remap_tsc_clocksource();
>> +		hv_root_crash_init();
>>  	} else {
>>  		hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
>>  		wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
>> diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
>> index dbd4c2f3aee3..952c221765f5 100644
>> --- a/include/asm-generic/mshyperv.h
>> +++ b/include/asm-generic/mshyperv.h
>> @@ -367,6 +367,15 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32
>> num_pages);
>>  int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id);
>>  int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags);
>>
>> +#if CONFIG_CRASH_DUMP
>> +void hv_root_crash_init(void);
>> +void hv_crash_asm32(void);
>> +void hv_crash_asm64_lbl(void);
>> +void hv_crash_asm_end(void);
>> +#else   /* CONFIG_CRASH_DUMP */
>> +static inline void hv_root_crash_init(void) {}
>> +#endif  /* CONFIG_CRASH_DUMP */
>> +
> 
> The hv_crash_asm* functions are x86 specific. Seems like their
> declarations should go in arch/x86/include/asm/mshyperv.h, not in
> the architecture-neutral include/asm-generic/mshyperv.h.

well, arm port is going on. i suppose i could move it to x86 and
they can move it back  here in their patch submissions. hopefully
they will remember or someone will catch it.

>>  #else /* CONFIG_MSHV_ROOT */
>>  static inline bool hv_root_partition(void) { return false; }
>>  static inline bool hv_l1vh_partition(void) { return false; }
>> --
>> 2.36.1.vfs.0.0
>>


^ permalink raw reply

* Re: [PATCH v4 4/4] drm/hypervdrm: Use vblank timer
From: Prasanna Kumar T S M @ 2025-09-17  5:12 UTC (permalink / raw)
  To: Thomas Zimmermann, louis.chauvet, drawat.floss, hamohammed.sa,
	melissa.srw, mhklinux, ptsm, simona, airlied, maarten.lankhorst,
	ville.syrjala, lyude, javierm
  Cc: dri-devel, linux-hyperv
In-Reply-To: <20250916083816.30275-5-tzimmermann@suse.de>

On Tue, Sep 16, 2025 at 10:36:22AM +0200, Thomas Zimmermann wrote:
> HyperV's virtual hardware does not provide vblank interrupts. Use a
> vblank timer to simulate the interrupt. Rate-limits the display's
> update frequency to the display-mode settings. Avoids excessive CPU
> overhead with compositors that do not rate-limit their output.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Tested-by: Michael Kelley <mhklinux@outlook.com>
> ---
>  drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
> index 945b9482bcb3..6e6eb1c12a68 100644
> --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
> +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
> @@ -19,6 +19,8 @@
>  #include <drm/drm_probe_helper.h>
>  #include <drm/drm_panic.h>
>  #include <drm/drm_plane.h>
> +#include <drm/drm_vblank.h>
> +#include <drm/drm_vblank_helper.h>
>  
>  #include "hyperv_drm.h"
>  
> @@ -111,11 +113,15 @@ static void hyperv_crtc_helper_atomic_enable(struct drm_crtc *crtc,
>  				crtc_state->mode.hdisplay,
>  				crtc_state->mode.vdisplay,
>  				plane_state->fb->pitches[0]);
> +
> +	drm_crtc_vblank_on(crtc);
>  }
>  
>  static const struct drm_crtc_helper_funcs hyperv_crtc_helper_funcs = {
>  	.atomic_check = drm_crtc_helper_atomic_check,
> +	.atomic_flush = drm_crtc_vblank_atomic_flush,
>  	.atomic_enable = hyperv_crtc_helper_atomic_enable,
> +	.atomic_disable = drm_crtc_vblank_atomic_disable,
>  };
>  
>  static const struct drm_crtc_funcs hyperv_crtc_funcs = {
> @@ -125,6 +131,7 @@ static const struct drm_crtc_funcs hyperv_crtc_funcs = {
>  	.page_flip = drm_atomic_helper_page_flip,
>  	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
>  	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +	DRM_CRTC_VBLANK_TIMER_FUNCS,
>  };
>  
>  static int hyperv_plane_atomic_check(struct drm_plane *plane,
> @@ -321,6 +328,10 @@ int hyperv_mode_config_init(struct hyperv_drm_device *hv)
>  		return ret;
>  	}
>  
> +	ret = drm_vblank_init(dev, 1);
> +	if (ret)
> +		return ret;
> +
>  	drm_mode_config_reset(dev);
>  
>  	return 0;
> 
> -- 
> 2.51.0
> 

Tested this series.

On a Hyper-V VM running Ubuntu,

with this patch

$ time find /
real	0m13.911s
user	0m0.965s
sys	0m3.815s


without this patch

$ time find /
real	0m14.254s
user	0m0.954s
sys	0m3.863s

Tested-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>

^ permalink raw reply

* Re: [PATCH 2/2] net: mana: Add standard counter rx_missed_errors
From: Erni Sri Satya Vennela @ 2025-09-17  5:53 UTC (permalink / raw)
  To: Paolo Abeni
  Cc: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
	kuba, longli, kotaranov, horms, shradhagupta, dipayanroy,
	shirazsaleem, rosenp, linux-hyperv, netdev, linux-kernel,
	linux-rdma
In-Reply-To: <0b5b0d1d-438a-4e41-99c8-a6f61d7581b4@redhat.com>

On Tue, Sep 16, 2025 at 03:22:54PM +0200, Paolo Abeni wrote:
> On 9/15/25 5:58 AM, Erni Sri Satya Vennela wrote:
> > Report standard counter stats->rx_missed_errors
> > using hc_rx_discards_no_wqe from the hardware.
> > 
> > Add a dedicated workqueue to periodically run
> > mana_query_gf_stats every 2 seconds to get the latest
> > info in eth_stats and define a driver capability flag
> > to notify hardware of the periodic queries.
> > 
> > To avoid repeated failures and log flooding, the workqueue
> > is not rescheduled if mana_query_gf_stats fails.
> 
> Can the failure root cause be a "transient" one? If so, this looks like
> a dangerous strategy; is such scenario, AFAICS, stats will be broken
> until the device is removed and re-probed.
> 
We are working on using the stats query as a health check for the
hardware and its channel. Even if it fails once, the VF needs to
be reset, similar to a probe. The hardware team also confirmed that even
a one-time or temporary failure needs a VF reset.

- Vennela

> /P

^ permalink raw reply

* [PATCH v2] drivers: hv: vmbus: Clean up sscanf format specifier in target_cpu_store()
From: Alok Tiwari @ 2025-09-17  8:59 UTC (permalink / raw)
  To: mhklinux, kys, haiyangz, wei.liu, decui, linux-hyperv
  Cc: alok.a.tiwari, linux-kernel

The target_cpu_store() function parses the target CPU from the sysfs
buffer using sscanf(). The format string currently uses "%uu", which
is redundant. The compiler ignores the extra "u", so there is no
incorrect parsing at runtime.

Update the format string to use "%u" for clarity and consistency.

Signed-off-by: Alok Tiwari <alok.a.tiwari@oracle.com>
---
v1 -> v2
Rephrase commit message and subject to clarify
that there is no incorrect parsing at runtime.
---
 drivers/hv/vmbus_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 5b4f8d009ca5..69591dc7bad2 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1742,7 +1742,7 @@ static ssize_t target_cpu_store(struct vmbus_channel *channel,
 	u32 target_cpu;
 	ssize_t ret;
 
-	if (sscanf(buf, "%uu", &target_cpu) != 1)
+	if (sscanf(buf, "%u", &target_cpu) != 1)
 		return -EIO;
 
 	cpus_read_lock();
-- 
2.50.1


^ permalink raw reply related

* [PATCH 0/2] deprecate Hyper-V fb driver in favor of Hyper-V DRM driver
From: Prasanna Kumar T S M @ 2025-09-17 14:02 UTC (permalink / raw)
  To: dri-devel, linux-hyperv, linux-fbdev, linux-kernel, ssengar,
	mhklinux, ptsm, rdunlap, bartosz.golaszewski, gonzalo.silvalde,
	arnd, tzimmermann, decui, wei.liu, deller, kys, haiyangz

The Hyper-V DRM driver is available since kernel version 5.14 and it
provides full KMS support and fbdev emulation via the DRM fbdev helpers.
Deprecate this driver in favor of Hyper-V DRM driver.

Prasanna Kumar T S M (2):
  fbdev/hyperv_fb: deprecate this in favor of Hyper-V DRM driver
  MAINTAINERS: Mark hyperv_fb driver Obsolete

 MAINTAINERS                     | 11 ++++++++++-
 drivers/video/fbdev/Kconfig     |  5 ++++-
 drivers/video/fbdev/hyperv_fb.c |  2 ++
 3 files changed, 16 insertions(+), 2 deletions(-)

-- 
2.49.0


^ permalink raw reply

* [PATCH 1/2] fbdev/hyperv_fb: deprecate this in favor of Hyper-V DRM driver
From: Prasanna Kumar T S M @ 2025-09-17 14:03 UTC (permalink / raw)
  To: dri-devel, linux-hyperv, linux-fbdev, linux-kernel, ssengar,
	mhklinux, ptsm, rdunlap, bartosz.golaszewski, gonzalo.silvalde,
	arnd, tzimmermann, decui, wei.liu, deller, kys, haiyangz
In-Reply-To: <E5C2A201B1BD>

The Hyper-V DRM driver is available since kernel version 5.14 and it
provides full KMS support and fbdev emulation via the DRM fbdev helpers.
Deprecate this driver in favor of Hyper-V DRM driver.

Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
---
 drivers/video/fbdev/Kconfig     | 5 ++++-
 drivers/video/fbdev/hyperv_fb.c | 2 ++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index c21484d15f0c..48c1c7417f6d 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1773,13 +1773,16 @@ config FB_BROADSHEET
 	  a bridge adapter.
 
 config FB_HYPERV
-	tristate "Microsoft Hyper-V Synthetic Video support"
+	tristate "Microsoft Hyper-V Synthetic Video support (DEPRECATED)"
 	depends on FB && HYPERV
 	select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA
 	select FB_IOMEM_HELPERS_DEFERRED
 	help
 	  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
+	  This driver is deprecated, please use the Hyper-V DRM driver at
+	  drivers/gpu/drm/hyperv (CONFIG_DRM_HYPERV) instead.
+
 config FB_SIMPLE
 	tristate "Simple framebuffer support"
 	depends on FB
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 75338ffc703f..c99e2ea4b3de 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -1357,6 +1357,8 @@ static int __init hvfb_drv_init(void)
 {
 	int ret;
 
+	pr_warn("Deprecated: use Hyper-V DRM driver instead\n");
+
 	if (fb_modesetting_disabled("hyper_fb"))
 		return -ENODEV;
 
-- 
2.49.0


^ permalink raw reply related

* [PATCH 2/2] MAINTAINERS: Mark hyperv_fb driver Obsolete
From: Prasanna Kumar T S M @ 2025-09-17 14:03 UTC (permalink / raw)
  To: dri-devel, linux-hyperv, linux-fbdev, linux-kernel, ssengar,
	mhklinux, ptsm, rdunlap, bartosz.golaszewski, gonzalo.silvalde,
	arnd, tzimmermann, decui, wei.liu, deller, kys, haiyangz
In-Reply-To: <E5C2A201B1BD>

The hyperv_fb driver is deprecated in favor of Hyper-V DRM driver. Split
the hyperv_fb entry from the hyperv drivers list, mark it obsolete.

Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
---
 MAINTAINERS | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index f6206963efbf..aa9d0fa6020b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11424,7 +11424,6 @@ F:	drivers/pci/controller/pci-hyperv-intf.c
 F:	drivers/pci/controller/pci-hyperv.c
 F:	drivers/scsi/storvsc_drv.c
 F:	drivers/uio/uio_hv_generic.c
-F:	drivers/video/fbdev/hyperv_fb.c
 F:	include/asm-generic/mshyperv.h
 F:	include/clocksource/hyperv_timer.h
 F:	include/hyperv/hvgdk.h
@@ -11438,6 +11437,16 @@ F:	include/uapi/linux/hyperv.h
 F:	net/vmw_vsock/hyperv_transport.c
 F:	tools/hv/
 
+HYPER-V FRAMEBUFFER DRIVER
+M:	"K. Y. Srinivasan" <kys@microsoft.com>
+M:	Haiyang Zhang <haiyangz@microsoft.com>
+M:	Wei Liu <wei.liu@kernel.org>
+M:	Dexuan Cui <decui@microsoft.com>
+L:	linux-hyperv@vger.kernel.org
+S:	Obsolete
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
+F:	drivers/video/fbdev/hyperv_fb.c
+
 HYPERBUS SUPPORT
 M:	Vignesh Raghavendra <vigneshr@ti.com>
 R:	Tudor Ambarus <tudor.ambarus@linaro.org>
-- 
2.49.0


^ permalink raw reply related

* Re: [PATCH 1/2] fbdev/hyperv_fb: deprecate this in favor of Hyper-V DRM driver
From: Thomas Zimmermann @ 2025-09-17 14:41 UTC (permalink / raw)
  To: Prasanna Kumar T S M, dri-devel, linux-hyperv, linux-fbdev,
	linux-kernel, ssengar, mhklinux, rdunlap, bartosz.golaszewski,
	gonzalo.silvalde, arnd, decui, wei.liu, deller, kys, haiyangz
In-Reply-To: <1758117785-20653-1-git-send-email-ptsm@linux.microsoft.com>



Am 17.09.25 um 16:03 schrieb Prasanna Kumar T S M:
> The Hyper-V DRM driver is available since kernel version 5.14 and it
> provides full KMS support and fbdev emulation via the DRM fbdev helpers.
> Deprecate this driver in favor of Hyper-V DRM driver.
>
> Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>

Acked-by: Thomas Zimmermann <tzimmermann@suse.de>

> ---
>   drivers/video/fbdev/Kconfig     | 5 ++++-
>   drivers/video/fbdev/hyperv_fb.c | 2 ++
>   2 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
> index c21484d15f0c..48c1c7417f6d 100644
> --- a/drivers/video/fbdev/Kconfig
> +++ b/drivers/video/fbdev/Kconfig
> @@ -1773,13 +1773,16 @@ config FB_BROADSHEET
>   	  a bridge adapter.
>   
>   config FB_HYPERV
> -	tristate "Microsoft Hyper-V Synthetic Video support"
> +	tristate "Microsoft Hyper-V Synthetic Video support (DEPRECATED)"
>   	depends on FB && HYPERV
>   	select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA
>   	select FB_IOMEM_HELPERS_DEFERRED
>   	help
>   	  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
>   
> +	  This driver is deprecated, please use the Hyper-V DRM driver at
> +	  drivers/gpu/drm/hyperv (CONFIG_DRM_HYPERV) instead.
> +
>   config FB_SIMPLE
>   	tristate "Simple framebuffer support"
>   	depends on FB
> diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
> index 75338ffc703f..c99e2ea4b3de 100644
> --- a/drivers/video/fbdev/hyperv_fb.c
> +++ b/drivers/video/fbdev/hyperv_fb.c
> @@ -1357,6 +1357,8 @@ static int __init hvfb_drv_init(void)
>   {
>   	int ret;
>   
> +	pr_warn("Deprecated: use Hyper-V DRM driver instead\n");
> +
>   	if (fb_modesetting_disabled("hyper_fb"))
>   		return -ENODEV;
>   

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)



^ permalink raw reply

* Re: [PATCH 2/2] MAINTAINERS: Mark hyperv_fb driver Obsolete
From: Thomas Zimmermann @ 2025-09-17 14:42 UTC (permalink / raw)
  To: Prasanna Kumar T S M, dri-devel, linux-hyperv, linux-fbdev,
	linux-kernel, ssengar, mhklinux, rdunlap, bartosz.golaszewski,
	gonzalo.silvalde, arnd, decui, wei.liu, deller, kys, haiyangz
In-Reply-To: <1758117804-20798-1-git-send-email-ptsm@linux.microsoft.com>



Am 17.09.25 um 16:03 schrieb Prasanna Kumar T S M:
> The hyperv_fb driver is deprecated in favor of Hyper-V DRM driver. Split
> the hyperv_fb entry from the hyperv drivers list, mark it obsolete.
>
> Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>

Acked-by: Thomas Zimmermann <tzimmermann@suse.de>

> ---
>   MAINTAINERS | 11 ++++++++++-
>   1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f6206963efbf..aa9d0fa6020b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11424,7 +11424,6 @@ F:	drivers/pci/controller/pci-hyperv-intf.c
>   F:	drivers/pci/controller/pci-hyperv.c
>   F:	drivers/scsi/storvsc_drv.c
>   F:	drivers/uio/uio_hv_generic.c
> -F:	drivers/video/fbdev/hyperv_fb.c
>   F:	include/asm-generic/mshyperv.h
>   F:	include/clocksource/hyperv_timer.h
>   F:	include/hyperv/hvgdk.h
> @@ -11438,6 +11437,16 @@ F:	include/uapi/linux/hyperv.h
>   F:	net/vmw_vsock/hyperv_transport.c
>   F:	tools/hv/
>   
> +HYPER-V FRAMEBUFFER DRIVER
> +M:	"K. Y. Srinivasan" <kys@microsoft.com>
> +M:	Haiyang Zhang <haiyangz@microsoft.com>
> +M:	Wei Liu <wei.liu@kernel.org>
> +M:	Dexuan Cui <decui@microsoft.com>
> +L:	linux-hyperv@vger.kernel.org
> +S:	Obsolete
> +T:	git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
> +F:	drivers/video/fbdev/hyperv_fb.c
> +
>   HYPERBUS SUPPORT
>   M:	Vignesh Raghavendra <vigneshr@ti.com>
>   R:	Tudor Ambarus <tudor.ambarus@linaro.org>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)



^ permalink raw reply

* [PATCH v2 00/21] paravirt: cleanup and reorg
From: Juergen Gross @ 2025-09-17 14:51 UTC (permalink / raw)
  To: linux-kernel, x86, linux-hyperv, virtualization, loongarch,
	linuxppc-dev, linux-riscv, kvm
  Cc: Juergen Gross, Andy Lutomirski, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, H. Peter Anvin, K. Y. Srinivasan,
	Haiyang Zhang, Wei Liu, Dexuan Cui, Peter Zijlstra, Will Deacon,
	Boqun Feng, Waiman Long, Jiri Kosina, Josh Poimboeuf, Pawan Gupta,
	Boris Ostrovsky, xen-devel, Ajay Kaher, Alexey Makhalov,
	Broadcom internal kernel review list, Russell King,
	Catalin Marinas, Huacai Chen, WANG Xuerui, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
	Ben Segall, Mel Gorman, Valentin Schneider, linux-arm-kernel,
	Paolo Bonzini, Vitaly Kuznetsov, Stefano Stabellini,
	Oleksandr Tyshchenko, Daniel Lezcano, Oleg Nesterov

Some cleanups and reorg of paravirt code and headers:

- The first 2 patches should be not controversial at all, as they
  remove just some no longer needed #include and struct forward
  declarations.

- The 3rd patch is removing CONFIG_PARAVIRT_DEBUG, which IMO has
  no real value, as it just changes a crash to a BUG() (the stack
  trace will basically be the same). As the maintainer of the main
  paravirt user (Xen) I have never seen this crash/BUG() to happen.

- The 4th patch is just a movement of code.

- I don't know for what reason asm/paravirt_api_clock.h was added,
  as all archs supporting it do it exactly in the same way. Patch
  5 is removing it.

- Patches 6-14 are streamlining the paravirt clock interfaces by
  using a common implementation across architectures where possible
  and by moving the related code into common sched code, as this is
  where it should live.

- Patches 15-20 are more like RFC material preparing the paravirt
  infrastructure to support multiple pv_ops function arrays.
  As a prerequisite for that it makes life in objtool much easier
  with dropping the Xen static initializers of the pv_ops sub-
  structures, which is done in patches 15-17.
  Patches 18-20 are doing the real preparations for multiple pv_ops
  arrays and using those arrays in multiple headers.

- Patch 21 is an example how the new scheme can look like using the
  PV-spinlocks.

Changes in V2:
- new patches 13-18 and 20
- complete rework of patch 21

Juergen Gross (21):
  x86/paravirt: Remove not needed includes of paravirt.h
  x86/paravirt: Remove some unneeded struct declarations
  x86/paravirt: Remove PARAVIRT_DEBUG config option
  x86/paravirt: Move thunk macros to paravirt_types.h
  paravirt: Remove asm/paravirt_api_clock.h
  sched: Move clock related paravirt code to kernel/sched
  arm/paravirt: Use common code for paravirt_steal_clock()
  arm64/paravirt: Use common code for paravirt_steal_clock()
  loongarch/paravirt: Use common code for paravirt_steal_clock()
  riscv/paravirt: Use common code for paravirt_steal_clock()
  x86/paravirt: Use common code for paravirt_steal_clock()
  x86/paravirt: Move paravirt_sched_clock() related code into tsc.c
  x86/paravirt: Introduce new paravirt-base.h header
  x86/paravirt: Move pv_native_*() prototypes to paravirt.c
  x86/xen: Drop xen_irq_ops
  x86/xen: Drop xen_cpu_ops
  x86/xen: Drop xen_mmu_ops
  objtool: Allow multiple pv_ops arrays
  x86/paravirt: Allow pv-calls outside paravirt.h
  x86/paravirt: Specify pv_ops array in paravirt macros
  x86/pvlocks: Move paravirt spinlock functions into own header

 arch/Kconfig                                  |   3 +
 arch/arm/Kconfig                              |   1 +
 arch/arm/include/asm/paravirt.h               |  22 --
 arch/arm/include/asm/paravirt_api_clock.h     |   1 -
 arch/arm/kernel/Makefile                      |   1 -
 arch/arm/kernel/paravirt.c                    |  23 --
 arch/arm64/Kconfig                            |   1 +
 arch/arm64/include/asm/paravirt.h             |  14 -
 arch/arm64/include/asm/paravirt_api_clock.h   |   1 -
 arch/arm64/kernel/paravirt.c                  |  11 +-
 arch/loongarch/Kconfig                        |   1 +
 arch/loongarch/include/asm/paravirt.h         |  13 -
 .../include/asm/paravirt_api_clock.h          |   1 -
 arch/loongarch/kernel/paravirt.c              |  10 +-
 arch/powerpc/include/asm/paravirt.h           |   3 -
 arch/powerpc/include/asm/paravirt_api_clock.h |   2 -
 arch/powerpc/platforms/pseries/setup.c        |   4 +-
 arch/riscv/Kconfig                            |   1 +
 arch/riscv/include/asm/paravirt.h             |  14 -
 arch/riscv/include/asm/paravirt_api_clock.h   |   1 -
 arch/riscv/kernel/paravirt.c                  |  11 +-
 arch/x86/Kconfig                              |   8 +-
 arch/x86/entry/entry_64.S                     |   1 -
 arch/x86/entry/vsyscall/vsyscall_64.c         |   1 -
 arch/x86/hyperv/hv_spinlock.c                 |  11 +-
 arch/x86/include/asm/apic.h                   |   4 -
 arch/x86/include/asm/highmem.h                |   1 -
 arch/x86/include/asm/mmu_context.h            |   1 -
 arch/x86/include/asm/mshyperv.h               |   1 -
 arch/x86/include/asm/paravirt-base.h          |  29 ++
 arch/x86/include/asm/paravirt-spinlock.h      | 146 ++++++++
 arch/x86/include/asm/paravirt.h               | 331 +++++-------------
 arch/x86/include/asm/paravirt_api_clock.h     |   1 -
 arch/x86/include/asm/paravirt_types.h         | 269 +++++++-------
 arch/x86/include/asm/pgtable_32.h             |   1 -
 arch/x86/include/asm/ptrace.h                 |   2 +-
 arch/x86/include/asm/qspinlock.h              |  89 +----
 arch/x86/include/asm/spinlock.h               |   1 -
 arch/x86/include/asm/timer.h                  |   1 +
 arch/x86/include/asm/tlbflush.h               |   4 -
 arch/x86/kernel/Makefile                      |   2 +-
 arch/x86/kernel/apm_32.c                      |   1 -
 arch/x86/kernel/callthunks.c                  |   1 -
 arch/x86/kernel/cpu/bugs.c                    |   1 -
 arch/x86/kernel/cpu/vmware.c                  |   1 +
 arch/x86/kernel/kvm.c                         |  11 +-
 arch/x86/kernel/kvmclock.c                    |   1 +
 arch/x86/kernel/paravirt-spinlocks.c          |  24 +-
 arch/x86/kernel/paravirt.c                    |  42 +--
 arch/x86/kernel/tsc.c                         |  10 +-
 arch/x86/kernel/vsmp_64.c                     |   1 -
 arch/x86/kernel/x86_init.c                    |   1 -
 arch/x86/lib/cache-smp.c                      |   1 -
 arch/x86/mm/init.c                            |   1 -
 arch/x86/xen/enlighten_pv.c                   |  82 ++---
 arch/x86/xen/irq.c                            |  20 +-
 arch/x86/xen/mmu_pv.c                         | 100 ++----
 arch/x86/xen/spinlock.c                       |  11 +-
 arch/x86/xen/time.c                           |   2 +
 drivers/clocksource/hyperv_timer.c            |   2 +
 drivers/xen/time.c                            |   2 +-
 include/linux/sched/cputime.h                 |  18 +
 kernel/sched/core.c                           |   5 +
 kernel/sched/cputime.c                        |  13 +
 kernel/sched/sched.h                          |   3 +-
 tools/objtool/arch/x86/decode.c               |   8 +-
 tools/objtool/check.c                         |  78 ++++-
 tools/objtool/include/objtool/check.h         |   2 +
 68 files changed, 657 insertions(+), 828 deletions(-)
 delete mode 100644 arch/arm/include/asm/paravirt.h
 delete mode 100644 arch/arm/include/asm/paravirt_api_clock.h
 delete mode 100644 arch/arm/kernel/paravirt.c
 delete mode 100644 arch/arm64/include/asm/paravirt_api_clock.h
 delete mode 100644 arch/loongarch/include/asm/paravirt_api_clock.h
 delete mode 100644 arch/powerpc/include/asm/paravirt_api_clock.h
 delete mode 100644 arch/riscv/include/asm/paravirt_api_clock.h
 create mode 100644 arch/x86/include/asm/paravirt-base.h
 create mode 100644 arch/x86/include/asm/paravirt-spinlock.h
 delete mode 100644 arch/x86/include/asm/paravirt_api_clock.h

-- 
2.51.0


^ permalink raw reply

* [PATCH v2 01/21] x86/paravirt: Remove not needed includes of paravirt.h
From: Juergen Gross @ 2025-09-17 14:52 UTC (permalink / raw)
  To: linux-kernel, x86, linux-hyperv
  Cc: Juergen Gross, Andy Lutomirski, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, H. Peter Anvin, K. Y. Srinivasan,
	Haiyang Zhang, Wei Liu, Dexuan Cui, Peter Zijlstra, Will Deacon,
	Boqun Feng, Waiman Long, Jiri Kosina, Josh Poimboeuf, Pawan Gupta,
	Boris Ostrovsky, xen-devel
In-Reply-To: <20250917145220.31064-1-jgross@suse.com>

In some places asm/paravirt.h is included without really being needed.

Remove the related #include statements.

Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
 arch/x86/entry/entry_64.S             | 1 -
 arch/x86/entry/vsyscall/vsyscall_64.c | 1 -
 arch/x86/hyperv/hv_spinlock.c         | 1 -
 arch/x86/include/asm/apic.h           | 4 ----
 arch/x86/include/asm/highmem.h        | 1 -
 arch/x86/include/asm/mmu_context.h    | 1 -
 arch/x86/include/asm/mshyperv.h       | 1 -
 arch/x86/include/asm/pgtable_32.h     | 1 -
 arch/x86/include/asm/spinlock.h       | 1 -
 arch/x86/include/asm/tlbflush.h       | 4 ----
 arch/x86/kernel/apm_32.c              | 1 -
 arch/x86/kernel/callthunks.c          | 1 -
 arch/x86/kernel/cpu/bugs.c            | 1 -
 arch/x86/kernel/vsmp_64.c             | 1 -
 arch/x86/kernel/x86_init.c            | 1 -
 arch/x86/lib/cache-smp.c              | 1 -
 arch/x86/mm/init.c                    | 1 -
 arch/x86/xen/spinlock.c               | 1 -
 18 files changed, 24 deletions(-)

diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index ed04a968cc7d..7a82305405af 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -30,7 +30,6 @@
 #include <asm/hw_irq.h>
 #include <asm/page_types.h>
 #include <asm/irqflags.h>
-#include <asm/paravirt.h>
 #include <asm/percpu.h>
 #include <asm/asm.h>
 #include <asm/smap.h>
diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c
index c9103a6fa06e..53e50b506471 100644
--- a/arch/x86/entry/vsyscall/vsyscall_64.c
+++ b/arch/x86/entry/vsyscall/vsyscall_64.c
@@ -37,7 +37,6 @@
 #include <asm/unistd.h>
 #include <asm/fixmap.h>
 #include <asm/traps.h>
-#include <asm/paravirt.h>
 
 #define CREATE_TRACE_POINTS
 #include "vsyscall_trace.h"
diff --git a/arch/x86/hyperv/hv_spinlock.c b/arch/x86/hyperv/hv_spinlock.c
index 81b006601370..2a3c2afb0154 100644
--- a/arch/x86/hyperv/hv_spinlock.c
+++ b/arch/x86/hyperv/hv_spinlock.c
@@ -13,7 +13,6 @@
 #include <linux/spinlock.h>
 
 #include <asm/mshyperv.h>
-#include <asm/paravirt.h>
 #include <asm/apic.h>
 #include <asm/msr.h>
 
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 07ba4935e873..e1de090e51dd 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -90,10 +90,6 @@ static inline bool apic_from_smp_config(void)
 /*
  * Basic functions accessing APICs.
  */
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#endif
-
 static inline void native_apic_mem_write(u32 reg, u32 v)
 {
 	volatile u32 *addr = (volatile u32 *)(APIC_BASE + reg);
diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h
index 585bdadba47d..decfaaf52326 100644
--- a/arch/x86/include/asm/highmem.h
+++ b/arch/x86/include/asm/highmem.h
@@ -24,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <linux/threads.h>
 #include <asm/tlbflush.h>
-#include <asm/paravirt.h>
 #include <asm/fixmap.h>
 #include <asm/pgtable_areas.h>
 
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 73bf3b1b44e8..ee15657d25b3 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -9,7 +9,6 @@
 #include <trace/events/tlb.h>
 
 #include <asm/tlbflush.h>
-#include <asm/paravirt.h>
 #include <asm/debugreg.h>
 #include <asm/gsseg.h>
 #include <asm/desc.h>
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index abc4659f5809..a9ab46fcb6a1 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -7,7 +7,6 @@
 #include <linux/msi.h>
 #include <linux/io.h>
 #include <asm/nospec-branch.h>
-#include <asm/paravirt.h>
 #include <asm/msr.h>
 #include <hyperv/hvhdk.h>
 
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index b612cc57a4d3..acea0cfa2460 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -16,7 +16,6 @@
 #ifndef __ASSEMBLER__
 #include <asm/processor.h>
 #include <linux/threads.h>
-#include <asm/paravirt.h>
 
 #include <linux/bitops.h>
 #include <linux/list.h>
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 5b6bc7016c22..934632b78d09 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -7,7 +7,6 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <linux/compiler.h>
-#include <asm/paravirt.h>
 #include <asm/bitops.h>
 
 /*
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index 00daedfefc1b..238a6b807da5 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -300,10 +300,6 @@ static inline void mm_clear_asid_transition(struct mm_struct *mm) { }
 static inline bool mm_in_asid_transition(struct mm_struct *mm) { return false; }
 #endif /* CONFIG_BROADCAST_TLB_FLUSH */
 
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#endif
-
 #define flush_tlb_mm(mm)						\
 		flush_tlb_mm_range(mm, 0UL, TLB_FLUSH_ALL, 0UL, true)
 
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index b37ab1095707..3175d7c134e9 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -229,7 +229,6 @@
 #include <linux/uaccess.h>
 #include <asm/desc.h>
 #include <asm/olpc.h>
-#include <asm/paravirt.h>
 #include <asm/reboot.h>
 #include <asm/nospec-branch.h>
 #include <asm/ibt.h>
diff --git a/arch/x86/kernel/callthunks.c b/arch/x86/kernel/callthunks.c
index a951333c5995..e37728f70322 100644
--- a/arch/x86/kernel/callthunks.c
+++ b/arch/x86/kernel/callthunks.c
@@ -15,7 +15,6 @@
 #include <asm/insn.h>
 #include <asm/kexec.h>
 #include <asm/nospec-branch.h>
-#include <asm/paravirt.h>
 #include <asm/sections.h>
 #include <asm/switch_to.h>
 #include <asm/sync_core.h>
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 36dcfc5105be..d278d37c9690 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -25,7 +25,6 @@
 #include <asm/fpu/api.h>
 #include <asm/msr.h>
 #include <asm/vmx.h>
-#include <asm/paravirt.h>
 #include <asm/cpu_device_id.h>
 #include <asm/e820/api.h>
 #include <asm/hypervisor.h>
diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c
index 73511332bb67..25625e3fc183 100644
--- a/arch/x86/kernel/vsmp_64.c
+++ b/arch/x86/kernel/vsmp_64.c
@@ -18,7 +18,6 @@
 #include <asm/apic.h>
 #include <asm/pci-direct.h>
 #include <asm/io.h>
-#include <asm/paravirt.h>
 #include <asm/setup.h>
 
 #define TOPOLOGY_REGISTER_OFFSET 0x10
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 0a2bbd674a6d..02ca90378bf9 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -12,7 +12,6 @@
 
 #include <asm/acpi.h>
 #include <asm/bios_ebda.h>
-#include <asm/paravirt.h>
 #include <asm/pci_x86.h>
 #include <asm/mpspec.h>
 #include <asm/setup.h>
diff --git a/arch/x86/lib/cache-smp.c b/arch/x86/lib/cache-smp.c
index c5c60d07308c..ae5a5dfd33c7 100644
--- a/arch/x86/lib/cache-smp.c
+++ b/arch/x86/lib/cache-smp.c
@@ -1,5 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
-#include <asm/paravirt.h>
 #include <linux/smp.h>
 #include <linux/export.h>
 
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index bb57e93b4caf..f52ebcac50d9 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -27,7 +27,6 @@
 #include <asm/pti.h>
 #include <asm/text-patching.h>
 #include <asm/memtype.h>
-#include <asm/paravirt.h>
 #include <asm/mmu_context.h>
 
 /*
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index 8e4efe0fb6f9..fe56646d6919 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -8,7 +8,6 @@
 #include <linux/slab.h>
 #include <linux/atomic.h>
 
-#include <asm/paravirt.h>
 #include <asm/qspinlock.h>
 
 #include <xen/events.h>
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 12/21] x86/paravirt: Move paravirt_sched_clock() related code into tsc.c
From: Juergen Gross @ 2025-09-17 14:52 UTC (permalink / raw)
  To: linux-kernel, x86, virtualization, kvm, linux-hyperv
  Cc: Juergen Gross, Ajay Kaher, Alexey Makhalov,
	Broadcom internal kernel review list, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Paolo Bonzini, Vitaly Kuznetsov, Boris Ostrovsky,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Daniel Lezcano, xen-devel, Peter Zijlstra (Intel)
In-Reply-To: <20250917145220.31064-1-jgross@suse.com>

The only user of paravirt_sched_clock() is in tsc.c, so move the code
from paravirt.c and paravirt.h to tsc.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
 arch/x86/include/asm/paravirt.h    | 12 ------------
 arch/x86/include/asm/timer.h       |  1 +
 arch/x86/kernel/kvmclock.c         |  1 +
 arch/x86/kernel/paravirt.c         |  7 -------
 arch/x86/kernel/tsc.c              | 10 +++++++++-
 arch/x86/xen/time.c                |  1 +
 drivers/clocksource/hyperv_timer.c |  2 ++
 7 files changed, 14 insertions(+), 20 deletions(-)

diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 766a7cee3d64..b69e75a5c872 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -14,20 +14,8 @@
 #ifndef __ASSEMBLER__
 #include <linux/types.h>
 #include <linux/cpumask.h>
-#include <linux/static_call_types.h>
 #include <asm/frame.h>
 
-u64 dummy_sched_clock(void);
-
-DECLARE_STATIC_CALL(pv_sched_clock, dummy_sched_clock);
-
-void paravirt_set_sched_clock(u64 (*func)(void));
-
-static __always_inline u64 paravirt_sched_clock(void)
-{
-	return static_call(pv_sched_clock)();
-}
-
 __visible void __native_queued_spin_unlock(struct qspinlock *lock);
 bool pv_is_native_spin_unlock(void);
 __visible bool __native_vcpu_is_preempted(long cpu);
diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h
index 23baf8c9b34c..fda18bcb19b4 100644
--- a/arch/x86/include/asm/timer.h
+++ b/arch/x86/include/asm/timer.h
@@ -12,6 +12,7 @@ extern void recalibrate_cpu_khz(void);
 extern int no_timer_check;
 
 extern bool using_native_sched_clock(void);
+void paravirt_set_sched_clock(u64 (*func)(void));
 
 /*
  * We use the full linear equation: f(x) = a + b*x, in order to allow
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index ca0a49eeac4a..b5991d53fc0e 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -19,6 +19,7 @@
 #include <linux/cc_platform.h>
 
 #include <asm/hypervisor.h>
+#include <asm/timer.h>
 #include <asm/x86_init.h>
 #include <asm/kvmclock.h>
 
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 42991d471bf3..4e37db8073f9 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -60,13 +60,6 @@ void __init native_pv_lock_init(void)
 		static_branch_enable(&virt_spin_lock_key);
 }
 
-DEFINE_STATIC_CALL(pv_sched_clock, native_sched_clock);
-
-void paravirt_set_sched_clock(u64 (*func)(void))
-{
-	static_call_update(pv_sched_clock, func);
-}
-
 static noinstr void pv_native_safe_halt(void)
 {
 	native_safe_halt();
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 87e749106dda..554b54783a04 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -266,19 +266,27 @@ u64 native_sched_clock_from_tsc(u64 tsc)
 /* We need to define a real function for sched_clock, to override the
    weak default version */
 #ifdef CONFIG_PARAVIRT
+DEFINE_STATIC_CALL(pv_sched_clock, native_sched_clock);
+
 noinstr u64 sched_clock_noinstr(void)
 {
-	return paravirt_sched_clock();
+	return static_call(pv_sched_clock)();
 }
 
 bool using_native_sched_clock(void)
 {
 	return static_call_query(pv_sched_clock) == native_sched_clock;
 }
+
+void paravirt_set_sched_clock(u64 (*func)(void))
+{
+	static_call_update(pv_sched_clock, func);
+}
 #else
 u64 sched_clock_noinstr(void) __attribute__((alias("native_sched_clock")));
 
 bool using_native_sched_clock(void) { return true; }
+void paravirt_set_sched_clock(u64 (*func)(void)) { }
 #endif
 
 notrace u64 sched_clock(void)
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index e4754b2fa900..6f9f665bb7ae 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -19,6 +19,7 @@
 #include <linux/sched/cputime.h>
 
 #include <asm/pvclock.h>
+#include <asm/timer.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/cpuid.h>
diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
index 2edc13ca184e..6397a7ba4a98 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -535,6 +535,8 @@ static __always_inline void hv_setup_sched_clock(void *sched_clock)
 	sched_clock_register(sched_clock, 64, NSEC_PER_SEC);
 }
 #elif defined CONFIG_PARAVIRT
+#include <asm/timer.h>
+
 static __always_inline void hv_setup_sched_clock(void *sched_clock)
 {
 	/* We're on x86/x64 *and* using PV ops */
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 21/21] x86/pvlocks: Move paravirt spinlock functions into own header
From: Juergen Gross @ 2025-09-17 14:52 UTC (permalink / raw)
  To: linux-kernel, x86, linux-hyperv, virtualization, kvm
  Cc: Juergen Gross, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
	Dexuan Cui, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Ajay Kaher, Alexey Makhalov,
	Broadcom internal kernel review list, Paolo Bonzini,
	Vitaly Kuznetsov, Boris Ostrovsky, Josh Poimboeuf, Peter Zijlstra,
	xen-devel
In-Reply-To: <20250917145220.31064-1-jgross@suse.com>

Instead of having the pv spinlock function definitions in paravirt.h,
move them into the new header paravirt-spinlock.h.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- use new header instead of qspinlock.h
- use dedicated pv_ops_lock array
- move more paravirt related lock code
---
 arch/x86/hyperv/hv_spinlock.c            |  10 +-
 arch/x86/include/asm/paravirt-spinlock.h | 146 +++++++++++++++++++++++
 arch/x86/include/asm/paravirt.h          |  61 ----------
 arch/x86/include/asm/paravirt_types.h    |  17 ---
 arch/x86/include/asm/qspinlock.h         |  89 ++------------
 arch/x86/kernel/Makefile                 |   2 +-
 arch/x86/kernel/kvm.c                    |  10 +-
 arch/x86/kernel/paravirt-spinlocks.c     |  24 +++-
 arch/x86/kernel/paravirt.c               |  21 ----
 arch/x86/xen/spinlock.c                  |  10 +-
 tools/objtool/check.c                    |   1 +
 11 files changed, 192 insertions(+), 199 deletions(-)
 create mode 100644 arch/x86/include/asm/paravirt-spinlock.h

diff --git a/arch/x86/hyperv/hv_spinlock.c b/arch/x86/hyperv/hv_spinlock.c
index 2a3c2afb0154..210b494e4de0 100644
--- a/arch/x86/hyperv/hv_spinlock.c
+++ b/arch/x86/hyperv/hv_spinlock.c
@@ -78,11 +78,11 @@ void __init hv_init_spinlocks(void)
 	pr_info("PV spinlocks enabled\n");
 
 	__pv_init_lock_hash();
-	pv_ops.lock.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
-	pv_ops.lock.queued_spin_unlock = PV_CALLEE_SAVE(__pv_queued_spin_unlock);
-	pv_ops.lock.wait = hv_qlock_wait;
-	pv_ops.lock.kick = hv_qlock_kick;
-	pv_ops.lock.vcpu_is_preempted = PV_CALLEE_SAVE(hv_vcpu_is_preempted);
+	pv_ops_lock.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
+	pv_ops_lock.queued_spin_unlock = PV_CALLEE_SAVE(__pv_queued_spin_unlock);
+	pv_ops_lock.wait = hv_qlock_wait;
+	pv_ops_lock.kick = hv_qlock_kick;
+	pv_ops_lock.vcpu_is_preempted = PV_CALLEE_SAVE(hv_vcpu_is_preempted);
 }
 
 static __init int hv_parse_nopvspin(char *arg)
diff --git a/arch/x86/include/asm/paravirt-spinlock.h b/arch/x86/include/asm/paravirt-spinlock.h
new file mode 100644
index 000000000000..ed3ed343903d
--- /dev/null
+++ b/arch/x86/include/asm/paravirt-spinlock.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_X86_PARAVIRT_SPINLOCK_H
+#define _ASM_X86_PARAVIRT_SPINLOCK_H
+
+#include <asm/paravirt_types.h>
+
+#ifdef CONFIG_SMP
+#include <asm/spinlock_types.h>
+#endif
+
+struct qspinlock;
+
+struct pv_lock_ops {
+	void (*queued_spin_lock_slowpath)(struct qspinlock *lock, u32 val);
+	struct paravirt_callee_save queued_spin_unlock;
+
+	void (*wait)(u8 *ptr, u8 val);
+	void (*kick)(int cpu);
+
+	struct paravirt_callee_save vcpu_is_preempted;
+} __no_randomize_layout;
+
+extern struct pv_lock_ops pv_ops_lock;
+
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
+void __init paravirt_set_cap(void);
+extern void native_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
+extern void __pv_init_lock_hash(void);
+extern void __pv_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
+extern void __raw_callee_save___pv_queued_spin_unlock(struct qspinlock *lock);
+extern bool nopvspin;
+
+static __always_inline void pv_queued_spin_lock_slowpath(struct qspinlock *lock,
+							 u32 val)
+{
+	PVOP_VCALL2(pv_ops_lock, queued_spin_lock_slowpath, lock, val);
+}
+
+static __always_inline void pv_queued_spin_unlock(struct qspinlock *lock)
+{
+	PVOP_ALT_VCALLEE1(pv_ops_lock, queued_spin_unlock, lock,
+			  "movb $0, (%%" _ASM_ARG1 ");",
+			  ALT_NOT(X86_FEATURE_PVUNLOCK));
+}
+
+static __always_inline bool pv_vcpu_is_preempted(long cpu)
+{
+	return PVOP_ALT_CALLEE1(bool, pv_ops_lock, vcpu_is_preempted, cpu,
+				"xor %%" _ASM_AX ", %%" _ASM_AX ";",
+				ALT_NOT(X86_FEATURE_VCPUPREEMPT));
+}
+
+#define queued_spin_unlock queued_spin_unlock
+/**
+ * queued_spin_unlock - release a queued spinlock
+ * @lock : Pointer to queued spinlock structure
+ *
+ * A smp_store_release() on the least-significant byte.
+ */
+static inline void native_queued_spin_unlock(struct qspinlock *lock)
+{
+	smp_store_release(&lock->locked, 0);
+}
+
+static inline void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
+{
+	pv_queued_spin_lock_slowpath(lock, val);
+}
+
+static inline void queued_spin_unlock(struct qspinlock *lock)
+{
+	kcsan_release();
+	pv_queued_spin_unlock(lock);
+}
+
+#define vcpu_is_preempted vcpu_is_preempted
+static inline bool vcpu_is_preempted(long cpu)
+{
+	return pv_vcpu_is_preempted(cpu);
+}
+
+static __always_inline void pv_wait(u8 *ptr, u8 val)
+{
+	PVOP_VCALL2(pv_ops_lock, wait, ptr, val);
+}
+
+static __always_inline void pv_kick(int cpu)
+{
+	PVOP_VCALL1(pv_ops_lock, kick, cpu);
+}
+
+void __raw_callee_save___native_queued_spin_unlock(struct qspinlock *lock);
+bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
+#endif /* CONFIG_PARAVIRT_SPINLOCKS */
+
+void __init native_pv_lock_init(void);
+__visible void __native_queued_spin_unlock(struct qspinlock *lock);
+bool pv_is_native_spin_unlock(void);
+__visible bool __native_vcpu_is_preempted(long cpu);
+bool pv_is_native_vcpu_is_preempted(void);
+
+/*
+ * virt_spin_lock_key - disables by default the virt_spin_lock() hijack.
+ *
+ * Native (and PV wanting native due to vCPU pinning) should keep this key
+ * disabled. Native does not touch the key.
+ *
+ * When in a guest then native_pv_lock_init() enables the key first and
+ * KVM/XEN might conditionally disable it later in the boot process again.
+ */
+DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);
+
+/*
+ * Shortcut for the queued_spin_lock_slowpath() function that allows
+ * virt to hijack it.
+ *
+ * Returns:
+ *   true - lock has been negotiated, all done;
+ *   false - queued_spin_lock_slowpath() will do its thing.
+ */
+#define virt_spin_lock virt_spin_lock
+static inline bool virt_spin_lock(struct qspinlock *lock)
+{
+	int val;
+
+	if (!static_branch_likely(&virt_spin_lock_key))
+		return false;
+
+	/*
+	 * On hypervisors without PARAVIRT_SPINLOCKS support we fall
+	 * back to a Test-and-Set spinlock, because fair locks have
+	 * horrible lock 'holder' preemption issues.
+	 */
+
+ __retry:
+	val = atomic_read(&lock->val);
+
+	if (val || !atomic_try_cmpxchg(&lock->val, &val, _Q_LOCKED_VAL)) {
+		cpu_relax();
+		goto __retry;
+	}
+
+	return true;
+}
+
+#endif /* _ASM_X86_PARAVIRT_SPINLOCK_H */
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index ec274d13bae0..b21072af731d 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -19,15 +19,6 @@
 #include <linux/cpumask.h>
 #include <asm/frame.h>
 
-__visible void __native_queued_spin_unlock(struct qspinlock *lock);
-bool pv_is_native_spin_unlock(void);
-__visible bool __native_vcpu_is_preempted(long cpu);
-bool pv_is_native_vcpu_is_preempted(void);
-
-#ifdef CONFIG_PARAVIRT_SPINLOCKS
-void __init paravirt_set_cap(void);
-#endif
-
 /* The paravirtualized I/O functions */
 static inline void slow_down_io(void)
 {
@@ -522,46 +513,7 @@ static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
 {
 	pv_ops.mmu.set_fixmap(idx, phys, flags);
 }
-#endif
-
-#if defined(CONFIG_SMP) && defined(CONFIG_PARAVIRT_SPINLOCKS)
-
-static __always_inline void pv_queued_spin_lock_slowpath(struct qspinlock *lock,
-							u32 val)
-{
-	PVOP_VCALL2(pv_ops, lock.queued_spin_lock_slowpath, lock, val);
-}
-
-static __always_inline void pv_queued_spin_unlock(struct qspinlock *lock)
-{
-	PVOP_ALT_VCALLEE1(pv_ops, lock.queued_spin_unlock, lock,
-			  "movb $0, (%%" _ASM_ARG1 ");",
-			  ALT_NOT(X86_FEATURE_PVUNLOCK));
-}
-
-static __always_inline void pv_wait(u8 *ptr, u8 val)
-{
-	PVOP_VCALL2(pv_ops, lock.wait, ptr, val);
-}
-
-static __always_inline void pv_kick(int cpu)
-{
-	PVOP_VCALL1(pv_ops, lock.kick, cpu);
-}
-
-static __always_inline bool pv_vcpu_is_preempted(long cpu)
-{
-	return PVOP_ALT_CALLEE1(bool, pv_ops, lock.vcpu_is_preempted, cpu,
-				"xor %%" _ASM_AX ", %%" _ASM_AX ";",
-				ALT_NOT(X86_FEATURE_VCPUPREEMPT));
-}
 
-void __raw_callee_save___native_queued_spin_unlock(struct qspinlock *lock);
-bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
-
-#endif /* SMP && PARAVIRT_SPINLOCKS */
-
-#ifdef CONFIG_PARAVIRT_XXL
 static __always_inline unsigned long arch_local_save_flags(void)
 {
 	return PVOP_ALT_CALLEE0(unsigned long, pv_ops, irq.save_fl, "pushf; pop %%rax;",
@@ -588,8 +540,6 @@ static __always_inline unsigned long arch_local_irq_save(void)
 }
 #endif
 
-void native_pv_lock_init(void) __init;
-
 #else  /* __ASSEMBLER__ */
 
 #ifdef CONFIG_X86_64
@@ -613,12 +563,6 @@ void native_pv_lock_init(void) __init;
 #endif /* __ASSEMBLER__ */
 #else  /* CONFIG_PARAVIRT */
 # define default_banner x86_init_noop
-
-#ifndef __ASSEMBLER__
-static inline void native_pv_lock_init(void)
-{
-}
-#endif
 #endif /* !CONFIG_PARAVIRT */
 
 #ifndef __ASSEMBLER__
@@ -634,10 +578,5 @@ static inline void paravirt_arch_exit_mmap(struct mm_struct *mm)
 }
 #endif
 
-#ifndef CONFIG_PARAVIRT_SPINLOCKS
-static inline void paravirt_set_cap(void)
-{
-}
-#endif
 #endif /* __ASSEMBLER__ */
 #endif /* _ASM_X86_PARAVIRT_H */
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 01a485f1a7f1..e2b487d35d14 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -184,22 +184,6 @@ struct pv_mmu_ops {
 #endif
 } __no_randomize_layout;
 
-#ifdef CONFIG_SMP
-#include <asm/spinlock_types.h>
-#endif
-
-struct qspinlock;
-
-struct pv_lock_ops {
-	void (*queued_spin_lock_slowpath)(struct qspinlock *lock, u32 val);
-	struct paravirt_callee_save queued_spin_unlock;
-
-	void (*wait)(u8 *ptr, u8 val);
-	void (*kick)(int cpu);
-
-	struct paravirt_callee_save vcpu_is_preempted;
-} __no_randomize_layout;
-
 /* This contains all the paravirt structures: we get a convenient
  * number for each function using the offset which we use to indicate
  * what to patch. */
@@ -207,7 +191,6 @@ struct paravirt_patch_template {
 	struct pv_cpu_ops	cpu;
 	struct pv_irq_ops	irq;
 	struct pv_mmu_ops	mmu;
-	struct pv_lock_ops	lock;
 } __no_randomize_layout;
 
 extern struct paravirt_patch_template pv_ops;
diff --git a/arch/x86/include/asm/qspinlock.h b/arch/x86/include/asm/qspinlock.h
index 68da67df304d..a2668bdf4c84 100644
--- a/arch/x86/include/asm/qspinlock.h
+++ b/arch/x86/include/asm/qspinlock.h
@@ -7,6 +7,9 @@
 #include <asm-generic/qspinlock_types.h>
 #include <asm/paravirt.h>
 #include <asm/rmwcc.h>
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt-spinlock.h>
+#endif
 
 #define _Q_PENDING_LOOPS	(1 << 9)
 
@@ -27,89 +30,13 @@ static __always_inline u32 queued_fetch_set_pending_acquire(struct qspinlock *lo
 	return val;
 }
 
-#ifdef CONFIG_PARAVIRT_SPINLOCKS
-extern void native_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
-extern void __pv_init_lock_hash(void);
-extern void __pv_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
-extern void __raw_callee_save___pv_queued_spin_unlock(struct qspinlock *lock);
-extern bool nopvspin;
-
-#define	queued_spin_unlock queued_spin_unlock
-/**
- * queued_spin_unlock - release a queued spinlock
- * @lock : Pointer to queued spinlock structure
- *
- * A smp_store_release() on the least-significant byte.
- */
-static inline void native_queued_spin_unlock(struct qspinlock *lock)
-{
-	smp_store_release(&lock->locked, 0);
-}
-
-static inline void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
-{
-	pv_queued_spin_lock_slowpath(lock, val);
-}
-
-static inline void queued_spin_unlock(struct qspinlock *lock)
-{
-	kcsan_release();
-	pv_queued_spin_unlock(lock);
-}
-
-#define vcpu_is_preempted vcpu_is_preempted
-static inline bool vcpu_is_preempted(long cpu)
-{
-	return pv_vcpu_is_preempted(cpu);
-}
+#ifndef CONFIG_PARAVIRT_SPINLOCKS
+static inline void paravirt_set_cap(void) { }
 #endif
 
-#ifdef CONFIG_PARAVIRT
-/*
- * virt_spin_lock_key - disables by default the virt_spin_lock() hijack.
- *
- * Native (and PV wanting native due to vCPU pinning) should keep this key
- * disabled. Native does not touch the key.
- *
- * When in a guest then native_pv_lock_init() enables the key first and
- * KVM/XEN might conditionally disable it later in the boot process again.
- */
-DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);
-
-/*
- * Shortcut for the queued_spin_lock_slowpath() function that allows
- * virt to hijack it.
- *
- * Returns:
- *   true - lock has been negotiated, all done;
- *   false - queued_spin_lock_slowpath() will do its thing.
- */
-#define virt_spin_lock virt_spin_lock
-static inline bool virt_spin_lock(struct qspinlock *lock)
-{
-	int val;
-
-	if (!static_branch_likely(&virt_spin_lock_key))
-		return false;
-
-	/*
-	 * On hypervisors without PARAVIRT_SPINLOCKS support we fall
-	 * back to a Test-and-Set spinlock, because fair locks have
-	 * horrible lock 'holder' preemption issues.
-	 */
-
- __retry:
-	val = atomic_read(&lock->val);
-
-	if (val || !atomic_try_cmpxchg(&lock->val, &val, _Q_LOCKED_VAL)) {
-		cpu_relax();
-		goto __retry;
-	}
-
-	return true;
-}
-
-#endif /* CONFIG_PARAVIRT */
+#ifndef CONFIG_PARAVIRT
+static inline void native_pv_lock_init(void) { }
+#endif
 
 #include <asm-generic/qspinlock.h>
 
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 0d2a6d953be9..56d57944fa4b 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -126,7 +126,7 @@ obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o
 
 obj-$(CONFIG_KVM_GUEST)		+= kvm.o kvmclock.o
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o
-obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= paravirt-spinlocks.o
+obj-$(CONFIG_PARAVIRT)		+= paravirt-spinlocks.o
 obj-$(CONFIG_PARAVIRT_CLOCK)	+= pvclock.o
 obj-$(CONFIG_X86_PMEM_LEGACY_DEVICE) += pmem.o
 
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index a23211eaaeed..a94376d04dca 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -825,7 +825,7 @@ static void __init kvm_guest_init(void)
 		has_steal_clock = 1;
 		static_call_update(pv_steal_clock, kvm_steal_clock);
 
-		pv_ops.lock.vcpu_is_preempted =
+		pv_ops_lock.vcpu_is_preempted =
 			PV_CALLEE_SAVE(__kvm_vcpu_is_preempted);
 	}
 
@@ -1105,11 +1105,11 @@ void __init kvm_spinlock_init(void)
 	pr_info("PV spinlocks enabled\n");
 
 	__pv_init_lock_hash();
-	pv_ops.lock.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
-	pv_ops.lock.queued_spin_unlock =
+	pv_ops_lock.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
+	pv_ops_lock.queued_spin_unlock =
 		PV_CALLEE_SAVE(__pv_queued_spin_unlock);
-	pv_ops.lock.wait = kvm_wait;
-	pv_ops.lock.kick = kvm_kick_cpu;
+	pv_ops_lock.wait = kvm_wait;
+	pv_ops_lock.kick = kvm_kick_cpu;
 
 	/*
 	 * When PV spinlock is enabled which is preferred over
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
index 9e1ea99ad9df..f9cf6f71395a 100644
--- a/arch/x86/kernel/paravirt-spinlocks.c
+++ b/arch/x86/kernel/paravirt-spinlocks.c
@@ -3,12 +3,20 @@
  * Split spinlock implementation out into its own file, so it can be
  * compiled in a FTRACE-compatible way.
  */
+#include <linux/static_call.h>
 #include <linux/spinlock.h>
 #include <linux/export.h>
 #include <linux/jump_label.h>
 
-#include <asm/paravirt.h>
+DEFINE_STATIC_KEY_FALSE(virt_spin_lock_key);
 
+void __init native_pv_lock_init(void)
+{
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
+		static_branch_enable(&virt_spin_lock_key);
+}
+
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
 __visible void __native_queued_spin_unlock(struct qspinlock *lock)
 {
 	native_queued_spin_unlock(lock);
@@ -17,7 +25,7 @@ PV_CALLEE_SAVE_REGS_THUNK(__native_queued_spin_unlock);
 
 bool pv_is_native_spin_unlock(void)
 {
-	return pv_ops.lock.queued_spin_unlock.func ==
+	return pv_ops_lock.queued_spin_unlock.func ==
 		__raw_callee_save___native_queued_spin_unlock;
 }
 
@@ -29,7 +37,7 @@ PV_CALLEE_SAVE_REGS_THUNK(__native_vcpu_is_preempted);
 
 bool pv_is_native_vcpu_is_preempted(void)
 {
-	return pv_ops.lock.vcpu_is_preempted.func ==
+	return pv_ops_lock.vcpu_is_preempted.func ==
 		__raw_callee_save___native_vcpu_is_preempted;
 }
 
@@ -41,3 +49,13 @@ void __init paravirt_set_cap(void)
 	if (!pv_is_native_vcpu_is_preempted())
 		setup_force_cpu_cap(X86_FEATURE_VCPUPREEMPT);
 }
+
+struct pv_lock_ops pv_ops_lock = {
+	.queued_spin_lock_slowpath	= native_queued_spin_lock_slowpath,
+	.queued_spin_unlock		= PV_CALLEE_SAVE(__native_queued_spin_unlock),
+	.wait				= paravirt_nop,
+	.kick				= paravirt_nop,
+	.vcpu_is_preempted		= PV_CALLEE_SAVE(__native_vcpu_is_preempted),
+};
+EXPORT_SYMBOL(pv_ops_lock);
+#endif
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 5dfbd3f55792..a6ed52cae003 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -57,14 +57,6 @@ DEFINE_ASM_FUNC(pv_native_irq_enable, "sti", .noinstr.text);
 DEFINE_ASM_FUNC(pv_native_read_cr2, "mov %cr2, %rax", .noinstr.text);
 #endif
 
-DEFINE_STATIC_KEY_FALSE(virt_spin_lock_key);
-
-void __init native_pv_lock_init(void)
-{
-	if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
-		static_branch_enable(&virt_spin_lock_key);
-}
-
 static noinstr void pv_native_safe_halt(void)
 {
 	native_safe_halt();
@@ -221,19 +213,6 @@ struct paravirt_patch_template pv_ops = {
 
 	.mmu.set_fixmap		= native_set_fixmap,
 #endif /* CONFIG_PARAVIRT_XXL */
-
-#if defined(CONFIG_PARAVIRT_SPINLOCKS)
-	/* Lock ops. */
-#ifdef CONFIG_SMP
-	.lock.queued_spin_lock_slowpath	= native_queued_spin_lock_slowpath,
-	.lock.queued_spin_unlock	=
-				PV_CALLEE_SAVE(__native_queued_spin_unlock),
-	.lock.wait			= paravirt_nop,
-	.lock.kick			= paravirt_nop,
-	.lock.vcpu_is_preempted		=
-				PV_CALLEE_SAVE(__native_vcpu_is_preempted),
-#endif /* SMP */
-#endif
 };
 
 #ifdef CONFIG_PARAVIRT_XXL
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index fe56646d6919..83ac24ead289 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -134,10 +134,10 @@ void __init xen_init_spinlocks(void)
 	printk(KERN_DEBUG "xen: PV spinlocks enabled\n");
 
 	__pv_init_lock_hash();
-	pv_ops.lock.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
-	pv_ops.lock.queued_spin_unlock =
+	pv_ops_lock.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
+	pv_ops_lock.queued_spin_unlock =
 		PV_CALLEE_SAVE(__pv_queued_spin_unlock);
-	pv_ops.lock.wait = xen_qlock_wait;
-	pv_ops.lock.kick = xen_qlock_kick;
-	pv_ops.lock.vcpu_is_preempted = PV_CALLEE_SAVE(xen_vcpu_stolen);
+	pv_ops_lock.wait = xen_qlock_wait;
+	pv_ops_lock.kick = xen_qlock_kick;
+	pv_ops_lock.vcpu_is_preempted = PV_CALLEE_SAVE(xen_vcpu_stolen);
 }
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index ca6ad92618d8..e9e1b5d321e5 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -549,6 +549,7 @@ static struct {
 	int idx_off;
 } pv_ops_tables[] = {
 	{ .name = "pv_ops", },
+	{ .name = "pv_ops_lock", },
 	{ .name = NULL, .idx_off = -1 }
 };
 
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH net-next v6 0/9] vsock: add namespace support to vhost-vsock
From: Simon Horman @ 2025-09-17 16:19 UTC (permalink / raw)
  To: Bobby Eshleman
  Cc: Stefano Garzarella, Shuah Khan, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Stefan Hajnoczi, Michael S. Tsirkin,
	Jason Wang, Xuan Zhuo, Eugenio Pérez, K. Y. Srinivasan,
	Haiyang Zhang, Wei Liu, Dexuan Cui, Bryan Tan, Vishnu Dasa,
	Broadcom internal kernel review list, virtualization, netdev,
	linux-kselftest, linux-kernel, kvm, linux-hyperv, berrange,
	Bobby Eshleman
In-Reply-To: <20250916-vsock-vmtest-v6-0-064d2eb0c89d@meta.com>

On Tue, Sep 16, 2025 at 04:43:44PM -0700, Bobby Eshleman wrote:

...

> base-commit: 949ddfb774fe527cebfa3f769804344940f7ed2e

Hi Bobby,

This series does not seem to compile when applied to the commit above.
Likewise when applied to current net-next (which is now slightly newer).

hyperv_transport.c: In function ‘hvs_open_connection’:
hyperv_transport.c:316:14: error: too few arguments to function ‘vsock_find_bound_socket’
  316 |         sk = vsock_find_bound_socket(&addr, vsock_global_dummy_net());
      |              ^~~~~~~~~~~~~~~~~~~~~~~
In file included from hyperv_transport.c:15:
/home/horms/projects/linux/linux/include/net/af_vsock.h:218:14: note: declared here
  218 | struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr, struct net *net,
      |              ^~~~~~~~~~~~~~~~~~~~~~~

-- 
pw-bot: changes-requested

^ permalink raw reply

* Re: [PATCH net-next v6 0/9] vsock: add namespace support to vhost-vsock
From: Bobby Eshleman @ 2025-09-17 16:33 UTC (permalink / raw)
  To: Simon Horman
  Cc: Stefano Garzarella, Shuah Khan, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Stefan Hajnoczi, Michael S. Tsirkin,
	Jason Wang, Xuan Zhuo, Eugenio Pérez, K. Y. Srinivasan,
	Haiyang Zhang, Wei Liu, Dexuan Cui, Bryan Tan, Vishnu Dasa,
	Broadcom internal kernel review list, virtualization, netdev,
	linux-kselftest, linux-kernel, kvm, linux-hyperv, berrange,
	Bobby Eshleman
In-Reply-To: <20250917161928.GR394836@horms.kernel.org>

On Wed, Sep 17, 2025 at 05:19:28PM +0100, Simon Horman wrote:
> On Tue, Sep 16, 2025 at 04:43:44PM -0700, Bobby Eshleman wrote:
> 
> ...
> 
> > base-commit: 949ddfb774fe527cebfa3f769804344940f7ed2e
> 
> Hi Bobby,
> 
> This series does not seem to compile when applied to the commit above.
> Likewise when applied to current net-next (which is now slightly newer).
> 
> hyperv_transport.c: In function ‘hvs_open_connection’:
> hyperv_transport.c:316:14: error: too few arguments to function ‘vsock_find_bound_socket’
>   316 |         sk = vsock_find_bound_socket(&addr, vsock_global_dummy_net());
>       |              ^~~~~~~~~~~~~~~~~~~~~~~
> In file included from hyperv_transport.c:15:
> /home/horms/projects/linux/linux/include/net/af_vsock.h:218:14: note: declared here
>   218 | struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr, struct net *net,
>       |              ^~~~~~~~~~~~~~~~~~~~~~~
> 
> -- 
> pw-bot: changes-requested

Ah dang it, looks like I had hvc disabled when I build tested it.

Thanks for the catch, I'll fix this in the next rev.

Best,
Bobby

^ permalink raw reply

* Re: [PATCH net-next v6 0/9] vsock: add namespace support to vhost-vsock
From: Simon Horman @ 2025-09-17 18:40 UTC (permalink / raw)
  To: Bobby Eshleman
  Cc: Stefano Garzarella, Shuah Khan, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Stefan Hajnoczi, Michael S. Tsirkin,
	Jason Wang, Xuan Zhuo, Eugenio Pérez, K. Y. Srinivasan,
	Haiyang Zhang, Wei Liu, Dexuan Cui, Bryan Tan, Vishnu Dasa,
	Broadcom internal kernel review list, virtualization, netdev,
	linux-kselftest, linux-kernel, kvm, linux-hyperv, berrange,
	Bobby Eshleman
In-Reply-To: <aMri5apAxBpHtZbJ@devvm11784.nha0.facebook.com>

On Wed, Sep 17, 2025 at 09:33:41AM -0700, Bobby Eshleman wrote:
> On Wed, Sep 17, 2025 at 05:19:28PM +0100, Simon Horman wrote:
> > On Tue, Sep 16, 2025 at 04:43:44PM -0700, Bobby Eshleman wrote:
> > 
> > ...
> > 
> > > base-commit: 949ddfb774fe527cebfa3f769804344940f7ed2e
> > 
> > Hi Bobby,
> > 
> > This series does not seem to compile when applied to the commit above.
> > Likewise when applied to current net-next (which is now slightly newer).
> > 
> > hyperv_transport.c: In function ‘hvs_open_connection’:
> > hyperv_transport.c:316:14: error: too few arguments to function ‘vsock_find_bound_socket’
> >   316 |         sk = vsock_find_bound_socket(&addr, vsock_global_dummy_net());
> >       |              ^~~~~~~~~~~~~~~~~~~~~~~
> > In file included from hyperv_transport.c:15:
> > /home/horms/projects/linux/linux/include/net/af_vsock.h:218:14: note: declared here
> >   218 | struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr, struct net *net,
> >       |              ^~~~~~~~~~~~~~~~~~~~~~~
> > 
> > -- 
> > pw-bot: changes-requested
> 
> Ah dang it, looks like I had hvc disabled when I build tested it.
> 
> Thanks for the catch, I'll fix this in the next rev.

Thanks, that would explain things.
Stuff happens :)

^ permalink raw reply

* Re: [PATCH v1 5/6] x86/hyperv: Implement hypervisor ram collection into vmcore
From: Mukesh R @ 2025-09-17 20:37 UTC (permalink / raw)
  To: Michael Kelley, linux-hyperv@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org
  Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org,
	decui@microsoft.com, tglx@linutronix.de, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, arnd@arndb.de
In-Reply-To: <87cab5ec-ab76-b1cf-4891-30314e5dace6@linux.microsoft.com>

On 9/16/25 18:13, Mukesh R wrote:
> On 9/15/25 10:55, Michael Kelley wrote:
>> From: Mukesh Rathor <mrathor@linux.microsoft.com> Sent: Tuesday, September 9, 2025 5:10 PM
>>>
>>> Introduce a new file to implement collection of hypervisor ram into the
>>
>> s/ram/RAM/ (multiple places)
> 
> a quick grep indicates using saying ram is common, i like ram over RAM
> 
>>> vmcore collected by linux. By default, the hypervisor ram is locked, ie,
>>> protected via hw page table. Hyper-V implements a disable hypercall which
>>
>> The terminology here is a bit confusing since you have two names for
>> the same thing: "disable" hypervisor, and "devirtualize". Is it possible to
>> just use "devirtualize" everywhere, and drop the "disable" terminology?
> 
> The concept is devirtualize and the actual hypercall was originally named
> disable. so intermixing is natural imo.

[snip]

>>> +
>>> +/*
>>> + * Setup a temporary gdt to allow the asm code to switch to the long mode.
>>> + * Since the asm code is relocated/copied to a below 4G page, it cannot use rip
>>> + * relative addressing, hence we must use trampoline_pa here. Also, save other
>>> + * info like jmp and C entry targets for same reasons.
>>> + *
>>> + * Returns: 0 on success, -1 on error
>>> + */
>>> +static int hv_crash_setup_trampdata(u64 trampoline_va)
>>> +{
>>> +	int size, offs;
>>> +	void *dest;
>>> +	struct hv_crash_tramp_data *tramp;
>>> +
>>> +	/* These must match exactly the ones in the corresponding asm file */
>>> +	BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, tramp32_cr3) != 0);
>>> +	BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, kernel_cr3) != 8);
>>> +	BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, gdtr32.limit) != 18);
>>> +	BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data,
>>> +						     cs_jmptgt.address) != 40);
>>
>> It would be nice to pick up the constants from a #include file that is
>> shared with the asm code in Patch 4 of the series.
> 
> yeah, could go either way, some don't like tiny headers...  if there are
> no objections to new header for this, i could go that way too.


yeah, i experimented with creating a new header or try to add to existing.
new header doesn't make sense for just 5 #defines, adding C struct there
is not a great idea given it's scope is limited to the specific function
in the c file. adding to another header results in ifdefs for ASM/KERNEL,
so not really worth it. I think for now it is ok, we can live with it.
If arm ends up adding more declarations, we can look into it.


Thanks,
-Mukesh

[ .. deleted.. ]

^ permalink raw reply

* Re: [PATCH net-next v6 3/9] vsock: add netns to vsock core
From: kernel test robot @ 2025-09-17 22:12 UTC (permalink / raw)
  To: Bobby Eshleman, Stefano Garzarella, Shuah Khan, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang, Xuan Zhuo,
	Eugenio Pérez, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
	Dexuan Cui, Bryan Tan, Vishnu Dasa,
	Broadcom internal kernel review list
  Cc: oe-kbuild-all, netdev, virtualization, linux-kselftest,
	linux-kernel, kvm, linux-hyperv, Bobby Eshleman, berrange
In-Reply-To: <20250916-vsock-vmtest-v6-3-064d2eb0c89d@meta.com>

Hi Bobby,

kernel test robot noticed the following build errors:

[auto build test ERROR on 949ddfb774fe527cebfa3f769804344940f7ed2e]

url:    https://github.com/intel-lab-lkp/linux/commits/Bobby-Eshleman/vsock-a-per-net-vsock-NS-mode-state/20250917-074823
base:   949ddfb774fe527cebfa3f769804344940f7ed2e
patch link:    https://lore.kernel.org/r/20250916-vsock-vmtest-v6-3-064d2eb0c89d%40meta.com
patch subject: [PATCH net-next v6 3/9] vsock: add netns to vsock core
config: i386-allmodconfig (https://download.01.org/0day-ci/archive/20250918/202509180511.5pJaP7gr-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250918/202509180511.5pJaP7gr-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509180511.5pJaP7gr-lkp@intel.com/

All errors (new ones prefixed by >>):

   net/vmw_vsock/hyperv_transport.c: In function 'hvs_open_connection':
>> net/vmw_vsock/hyperv_transport.c:316:14: error: too few arguments to function 'vsock_find_bound_socket'
     316 |         sk = vsock_find_bound_socket(&addr, vsock_global_dummy_net());
         |              ^~~~~~~~~~~~~~~~~~~~~~~
   In file included from net/vmw_vsock/hyperv_transport.c:15:
   include/net/af_vsock.h:218:14: note: declared here
     218 | struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr, struct net *net,
         |              ^~~~~~~~~~~~~~~~~~~~~~~


vim +/vsock_find_bound_socket +316 net/vmw_vsock/hyperv_transport.c

   294	
   295	static void hvs_open_connection(struct vmbus_channel *chan)
   296	{
   297		guid_t *if_instance, *if_type;
   298		unsigned char conn_from_host;
   299	
   300		struct sockaddr_vm addr;
   301		struct sock *sk, *new = NULL;
   302		struct vsock_sock *vnew = NULL;
   303		struct hvsock *hvs = NULL;
   304		struct hvsock *hvs_new = NULL;
   305		int rcvbuf;
   306		int ret;
   307		int sndbuf;
   308	
   309		if_type = &chan->offermsg.offer.if_type;
   310		if_instance = &chan->offermsg.offer.if_instance;
   311		conn_from_host = chan->offermsg.offer.u.pipe.user_def[0];
   312		if (!is_valid_srv_id(if_type))
   313			return;
   314	
   315		hvs_addr_init(&addr, conn_from_host ? if_type : if_instance);
 > 316		sk = vsock_find_bound_socket(&addr, vsock_global_dummy_net());
   317		if (!sk)
   318			return;
   319	
   320		lock_sock(sk);
   321		if ((conn_from_host && sk->sk_state != TCP_LISTEN) ||
   322		    (!conn_from_host && sk->sk_state != TCP_SYN_SENT))
   323			goto out;
   324	
   325		if (conn_from_host) {
   326			if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog)
   327				goto out;
   328	
   329			new = vsock_create_connected(sk);
   330			if (!new)
   331				goto out;
   332	
   333			new->sk_state = TCP_SYN_SENT;
   334			vnew = vsock_sk(new);
   335	
   336			hvs_addr_init(&vnew->local_addr, if_type);
   337	
   338			/* Remote peer is always the host */
   339			vsock_addr_init(&vnew->remote_addr,
   340					VMADDR_CID_HOST, VMADDR_PORT_ANY);
   341			vnew->remote_addr.svm_port = get_port_by_srv_id(if_instance);
   342			ret = vsock_assign_transport(vnew, vsock_sk(sk));
   343			/* Transport assigned (looking at remote_addr) must be the
   344			 * same where we received the request.
   345			 */
   346			if (ret || !hvs_check_transport(vnew)) {
   347				sock_put(new);
   348				goto out;
   349			}
   350			hvs_new = vnew->trans;
   351			hvs_new->chan = chan;
   352		} else {
   353			hvs = vsock_sk(sk)->trans;
   354			hvs->chan = chan;
   355		}
   356	
   357		set_channel_read_mode(chan, HV_CALL_DIRECT);
   358	
   359		/* Use the socket buffer sizes as hints for the VMBUS ring size. For
   360		 * server side sockets, 'sk' is the parent socket and thus, this will
   361		 * allow the child sockets to inherit the size from the parent. Keep
   362		 * the mins to the default value and align to page size as per VMBUS
   363		 * requirements.
   364		 * For the max, the socket core library will limit the socket buffer
   365		 * size that can be set by the user, but, since currently, the hv_sock
   366		 * VMBUS ring buffer is physically contiguous allocation, restrict it
   367		 * further.
   368		 * Older versions of hv_sock host side code cannot handle bigger VMBUS
   369		 * ring buffer size. Use the version number to limit the change to newer
   370		 * versions.
   371		 */
   372		if (vmbus_proto_version < VERSION_WIN10_V5) {
   373			sndbuf = RINGBUFFER_HVS_SND_SIZE;
   374			rcvbuf = RINGBUFFER_HVS_RCV_SIZE;
   375		} else {
   376			sndbuf = max_t(int, sk->sk_sndbuf, RINGBUFFER_HVS_SND_SIZE);
   377			sndbuf = min_t(int, sndbuf, RINGBUFFER_HVS_MAX_SIZE);
   378			sndbuf = ALIGN(sndbuf, HV_HYP_PAGE_SIZE);
   379			rcvbuf = max_t(int, sk->sk_rcvbuf, RINGBUFFER_HVS_RCV_SIZE);
   380			rcvbuf = min_t(int, rcvbuf, RINGBUFFER_HVS_MAX_SIZE);
   381			rcvbuf = ALIGN(rcvbuf, HV_HYP_PAGE_SIZE);
   382		}
   383	
   384		chan->max_pkt_size = HVS_MAX_PKT_SIZE;
   385	
   386		ret = vmbus_open(chan, sndbuf, rcvbuf, NULL, 0, hvs_channel_cb,
   387				 conn_from_host ? new : sk);
   388		if (ret != 0) {
   389			if (conn_from_host) {
   390				hvs_new->chan = NULL;
   391				sock_put(new);
   392			} else {
   393				hvs->chan = NULL;
   394			}
   395			goto out;
   396		}
   397	
   398		set_per_channel_state(chan, conn_from_host ? new : sk);
   399	
   400		/* This reference will be dropped by hvs_close_connection(). */
   401		sock_hold(conn_from_host ? new : sk);
   402		vmbus_set_chn_rescind_callback(chan, hvs_close_connection);
   403	
   404		/* Set the pending send size to max packet size to always get
   405		 * notifications from the host when there is enough writable space.
   406		 * The host is optimized to send notifications only when the pending
   407		 * size boundary is crossed, and not always.
   408		 */
   409		hvs_set_channel_pending_send_size(chan);
   410	
   411		if (conn_from_host) {
   412			new->sk_state = TCP_ESTABLISHED;
   413			sk_acceptq_added(sk);
   414	
   415			hvs_new->vm_srv_id = *if_type;
   416			hvs_new->host_srv_id = *if_instance;
   417	
   418			vsock_insert_connected(vnew);
   419	
   420			vsock_enqueue_accept(sk, new);
   421		} else {
   422			sk->sk_state = TCP_ESTABLISHED;
   423			sk->sk_socket->state = SS_CONNECTED;
   424	
   425			vsock_insert_connected(vsock_sk(sk));
   426		}
   427	
   428		sk->sk_state_change(sk);
   429	
   430	out:
   431		/* Release refcnt obtained when we called vsock_find_bound_socket() */
   432		sock_put(sk);
   433	
   434		release_sock(sk);
   435	}
   436	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox