Linux-HyperV List
 help / color / mirror / Atom feed
* [PATCH v5 07/10] x86/hyperv/vtl: Setup the 64-bit trampoline for TDX guests
From: Ricardo Neri @ 2025-06-28  3:35 UTC (permalink / raw)
  To: x86, Krzysztof Kozlowski, Conor Dooley, Rob Herring,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Michael Kelley, Rafael J. Wysocki
  Cc: Saurabh Sengar, Chris Oo, Kirill A. Shutemov, linux-hyperv,
	devicetree, linux-acpi, linux-kernel, Ricardo Neri, Yunhong Jiang,
	Ricardo Neri
In-Reply-To: <20250627-rneri-wakeup-mailbox-v5-0-df547b1d196e@linux.intel.com>

From: Yunhong Jiang <yunhong.jiang@linux.intel.com>

The hypervisor is an untrusted entity for TDX guests. It cannot be used
to boot secondary CPUs - neither via hypercalls not the INIT assert,
de-assert plus Start-Up IPI messages.

Instead, the platform virtual firmware boots the secondary CPUs and
puts them in a state to transfer control to the kernel. This mechanism uses
the wakeup mailbox described in the Multiprocessor Wakeup Structure of the
ACPI specification. The entry point to the kernel is trampoline_start64.

Allocate and setup the trampoline using the default x86_platform callbacks.

The platform firmware configures the secondary CPUs in long mode. It is no
longer necessary to locate the trampoline under 1MB memory. After handoff
from firmware, the trampoline code switches briefly to 32-bit addressing
mode, which has an addressing limit of 4GB. Set the upper bound of the
trampoline memory accordingly.

Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes since v4:
 - None

Changes since v3:
 - Added Reviewed-by tag from Michael. Thanks!

Changes since v2:
 - Added a note regarding there is no need to check for a present
   paravisor.
 - Edited commit message for clarity.

Changes since v1:
 - Dropped the function hv_reserve_real_mode(). Instead, used the new
   members realmode_limit and reserve_bios members of x86_init to
   set the upper bound of the trampoline memory. (Thomas)
---
 arch/x86/hyperv/hv_vtl.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c
index e10b63b7a49f..ca0d23206e67 100644
--- a/arch/x86/hyperv/hv_vtl.c
+++ b/arch/x86/hyperv/hv_vtl.c
@@ -63,9 +63,14 @@ void __init hv_vtl_init_platform(void)
 	 */
 	pr_info("Linux runs in Hyper-V Virtual Trust Level %d\n", ms_hyperv.vtl);
 
-	x86_platform.realmode_reserve = x86_init_noop;
-	x86_platform.realmode_init = x86_init_noop;
-	real_mode_header = &hv_vtl_real_mode_header;
+	/* There is no paravisor present if we are here. */
+	if (hv_isolation_type_tdx()) {
+		x86_init.resources.realmode_limit = SZ_4G;
+	} else {
+		x86_platform.realmode_reserve = x86_init_noop;
+		x86_platform.realmode_init = x86_init_noop;
+		real_mode_header = &hv_vtl_real_mode_header;
+	}
 	x86_init.irqs.pre_vector_init = x86_init_noop;
 	x86_init.timers.timer_init = x86_init_noop;
 	x86_init.resources.probe_roms = x86_init_noop;

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 06/10] x86/realmode: Make the location of the trampoline configurable
From: Ricardo Neri @ 2025-06-28  3:35 UTC (permalink / raw)
  To: x86, Krzysztof Kozlowski, Conor Dooley, Rob Herring,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Michael Kelley, Rafael J. Wysocki
  Cc: Saurabh Sengar, Chris Oo, Kirill A. Shutemov, linux-hyperv,
	devicetree, linux-acpi, linux-kernel, Ricardo Neri, Yunhong Jiang,
	Thomas Gleixner, Ricardo Neri
In-Reply-To: <20250627-rneri-wakeup-mailbox-v5-0-df547b1d196e@linux.intel.com>

From: Yunhong Jiang <yunhong.jiang@linux.intel.com>

x86 CPUs boot in real mode. This mode uses 20-bit memory addresses (16-bit
registers plus 4-bit segment selectors). This implies that the trampoline
must reside under the 1MB memory boundary.

There are platforms in which the firmware boots the secondary CPUs,
switches them to long mode and transfers control to the kernel. An example
of such mechanism is the ACPI Multiprocessor Wakeup Structure.

In this scenario there is no restriction to locate the trampoline under 1MB
memory. Moreover, certain platforms (for example, Hyper-V VTL guests) may
not have memory available for allocation under 1MB.

Add a new member to struct x86_init_resources to specify the upper bound
for the location of the trampoline memory. Keep the default upper bound of
1MB to conserve the current behavior.

Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Originally-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes since v4:
 - None

Changes since v3:
 - Added Reviewed-by tag from Michael. Thanks!

Changes since v2:
 - Edited the commit message for clarity.
 - Minor tweaks to comments.
 - Removed the option to not reserve the first 1MB of memory as it is
   not needed.

Changes since v1:
 - Added this patch using code that Thomas suggested:
   https://lore.kernel.org/lkml/87a5ho2q6x.ffs@tglx/
---
 arch/x86/include/asm/x86_init.h | 3 +++
 arch/x86/kernel/x86_init.c      | 3 +++
 arch/x86/realmode/init.c        | 7 +++----
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 36698cc9fb44..e770ce507a87 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -31,12 +31,15 @@ struct x86_init_mpparse {
  *				platform
  * @memory_setup:		platform specific memory setup
  * @dmi_setup:			platform specific DMI setup
+ * @realmode_limit:		platform specific address limit for the real mode trampoline
+ *				(default 1M)
  */
 struct x86_init_resources {
 	void (*probe_roms)(void);
 	void (*reserve_resources)(void);
 	char *(*memory_setup)(void);
 	void (*dmi_setup)(void);
+	unsigned long realmode_limit;
 };
 
 /**
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 0a2bbd674a6d..a25fd7282811 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -9,6 +9,7 @@
 #include <linux/export.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <linux/sizes.h>
 
 #include <asm/acpi.h>
 #include <asm/bios_ebda.h>
@@ -69,6 +70,8 @@ struct x86_init_ops x86_init __initdata = {
 		.reserve_resources	= reserve_standard_io_resources,
 		.memory_setup		= e820__memory_setup_default,
 		.dmi_setup		= dmi_setup,
+		/* Has to be under 1M so we can execute real-mode AP code. */
+		.realmode_limit		= SZ_1M,
 	},
 
 	.mpparse = {
diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c
index 88be32026768..694d80a5c68e 100644
--- a/arch/x86/realmode/init.c
+++ b/arch/x86/realmode/init.c
@@ -46,7 +46,7 @@ void load_trampoline_pgtable(void)
 
 void __init reserve_real_mode(void)
 {
-	phys_addr_t mem;
+	phys_addr_t mem, limit = x86_init.resources.realmode_limit;
 	size_t size = real_mode_size_needed();
 
 	if (!size)
@@ -54,10 +54,9 @@ void __init reserve_real_mode(void)
 
 	WARN_ON(slab_is_available());
 
-	/* Has to be under 1M so we can execute real-mode AP code. */
-	mem = memblock_phys_alloc_range(size, PAGE_SIZE, 0, 1<<20);
+	mem = memblock_phys_alloc_range(size, PAGE_SIZE, 0, limit);
 	if (!mem)
-		pr_info("No sub-1M memory is available for the trampoline\n");
+		pr_info("No memory below %pa for the real-mode trampoline\n", &limit);
 	else
 		set_real_mode_mem(mem);
 

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 05/10] x86/hyperv/vtl: Set real_mode_header in hv_vtl_init_platform()
From: Ricardo Neri @ 2025-06-28  3:35 UTC (permalink / raw)
  To: x86, Krzysztof Kozlowski, Conor Dooley, Rob Herring,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Michael Kelley, Rafael J. Wysocki
  Cc: Saurabh Sengar, Chris Oo, Kirill A. Shutemov, linux-hyperv,
	devicetree, linux-acpi, linux-kernel, Ricardo Neri, Yunhong Jiang,
	Thomas Gleixner, Ricardo Neri
In-Reply-To: <20250627-rneri-wakeup-mailbox-v5-0-df547b1d196e@linux.intel.com>

From: Yunhong Jiang <yunhong.jiang@linux.intel.com>

Hyper-V VTL clears x86_platform.realmode_{init(), reserve()} in
hv_vtl_platform_init() whereas it sets real_mode_header later in
hv_vtl_early_init(). There is no need to deal with the real mode memory
in two places: x86_platform.realmode_init() is invoked much later via an
early_initcall.

Set real_mode_header in hv_vtl_init_platform() to keep all code dealing
with memory for the real mode trampoline in one place. Besides making the
code more readable, it prepares it for a subsequent changeset in which the
behavior needs to change to support Hyper-V VTL guests in TDX environment.

Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes since v4:
 - None

Changes since v3:
 - Added Reviewed-by tag from Michael. Thanks!

Changes since v2:
 - Edited the commit message for clarity.

Changes since v1:
 - Introduced this patch.
---
 arch/x86/hyperv/hv_vtl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c
index 042e8712d8de..e10b63b7a49f 100644
--- a/arch/x86/hyperv/hv_vtl.c
+++ b/arch/x86/hyperv/hv_vtl.c
@@ -65,6 +65,7 @@ void __init hv_vtl_init_platform(void)
 
 	x86_platform.realmode_reserve = x86_init_noop;
 	x86_platform.realmode_init = x86_init_noop;
+	real_mode_header = &hv_vtl_real_mode_header;
 	x86_init.irqs.pre_vector_init = x86_init_noop;
 	x86_init.timers.timer_init = x86_init_noop;
 	x86_init.resources.probe_roms = x86_init_noop;
@@ -244,7 +245,6 @@ int __init hv_vtl_early_init(void)
 		panic("XSAVE has to be disabled as it is not supported by this module.\n"
 			  "Please add 'noxsave' to the kernel command line.\n");
 
-	real_mode_header = &hv_vtl_real_mode_header;
 	apic_update_callback(wakeup_secondary_cpu_64, hv_vtl_wakeup_secondary_cpu);
 
 	return 0;

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 04/10] x86/dt: Parse the Wakeup Mailbox for Intel processors
From: Ricardo Neri @ 2025-06-28  3:35 UTC (permalink / raw)
  To: x86, Krzysztof Kozlowski, Conor Dooley, Rob Herring,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Michael Kelley, Rafael J. Wysocki
  Cc: Saurabh Sengar, Chris Oo, Kirill A. Shutemov, linux-hyperv,
	devicetree, linux-acpi, linux-kernel, Ricardo Neri, Yunhong Jiang,
	Ricardo Neri
In-Reply-To: <20250627-rneri-wakeup-mailbox-v5-0-df547b1d196e@linux.intel.com>

The Wakeup Mailbox is a mechanism to boot secondary CPUs used on systems
that do not want or cannot use the INIT + StartUp IPI messages.

The platform firmware is expected to implement the mailbox as described in
the Multiprocessor Wakeup Structure of the ACPI specification. It is also
expected to publish the mailbox to the operating system as described in the
corresponding DeviceTree schema that accompanies the documentation of the
Linux kernel.

Reuse the existing functionality to set the memory location of the mailbox
and update the wakeup_secondary_cpu_64() APIC callback. Make this
functionality available to DeviceTree-based systems by making CONFIG_X86_
MAILBOX_WAKEUP depend on either CONFIG_OF or CONFIG_ACPI_MADT_WAKEUP.

do_boot_cpu() uses wakeup_secondary_cpu_64() when set. If a wakeup mailbox
is found (enumerated via an ACPI table or a DeviceTree node) it will be
used unconditionally. For cases in which this behavior is not desired, this
APIC callback can be updated later during boot using platform-specific
hooks.

Co-developed-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes since v4:
 - Made CONFIG_X86_MAILBOX_WAKEUP depend on CONFIG_OF or CONFIG_ACPI_
   MADT_WAKEUP.

Changes since v3:
 - Look for the wakeup mailbox unconditionally, regardless of whether
   cpu@N nodes have an `enable-method` property.
 - Add a reference to the ACPI specification. (Rafael)

Changes since v2:
 - Added extra sanity checks when parsing the mailbox node.
 - Probe the mailbox using its `compatible` property
 - Setup the Wakeup Mailbox if the `enable-method` is found in the CPU
   nodes.
 - Cleaned up unneeded ifdeffery.
 - Clarified the mechanisms used to override the wakeup_secondary_64()
   callback to not use the mailbox when not desired. (Michael)
 - Edited the commit message for clarity.

Changes since v1:
 - Disabled CPU offlining.
 - Modified dtb_parse_mp_wake() to return the address of the mailbox.
---
 arch/x86/Kconfig             |  2 +-
 arch/x86/kernel/devicetree.c | 47 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index e3009cb59928..027f8ae878ec 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1116,7 +1116,7 @@ config X86_LOCAL_APIC
 
 config X86_MAILBOX_WAKEUP
 	def_bool y
-	depends on ACPI_MADT_WAKEUP
+	depends on OF || ACPI_MADT_WAKEUP
 	depends on X86_64
 	depends on SMP
 	depends on X86_LOCAL_APIC
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index dd8748c45529..494a560614a8 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -17,6 +17,7 @@
 #include <linux/pci.h>
 #include <linux/of_pci.h>
 #include <linux/initrd.h>
+#include <linux/smp.h>
 
 #include <asm/irqdomain.h>
 #include <asm/hpet.h>
@@ -125,6 +126,51 @@ static void __init dtb_setup_hpet(void)
 #endif
 }
 
+#if defined(CONFIG_X86_64) && defined(CONFIG_SMP)
+
+#define WAKEUP_MAILBOX_SIZE	0x1000
+#define WAKEUP_MAILBOX_ALIGN	0x1000
+
+/** dtb_wakeup_mailbox_setup() - Parse the wakeup mailbox from the device tree
+ *
+ * Look for the presence of a wakeup mailbox in the DeviceTree. The mailbox is
+ * expected to follow the structure and operation described in the Multiprocessor
+ * Wakeup Structure of the ACPI specification.
+ */
+static void __init dtb_wakeup_mailbox_setup(void)
+{
+	struct device_node *node;
+	struct resource res;
+
+	node = of_find_compatible_node(NULL, NULL, "intel,wakeup-mailbox");
+	if (!node)
+		return;
+
+	if (of_address_to_resource(node, 0, &res))
+		goto done;
+
+	/* The mailbox is a 4KB-aligned region.*/
+	if (res.start & (WAKEUP_MAILBOX_ALIGN - 1))
+		goto done;
+
+	/* The mailbox has a size of 4KB. */
+	if (res.end - res.start + 1 != WAKEUP_MAILBOX_SIZE)
+		goto done;
+
+	/* Not supported when the mailbox is used. */
+	cpu_hotplug_disable_offlining();
+
+	acpi_setup_mp_wakeup_mailbox(res.start);
+done:
+	of_node_put(node);
+}
+#else /* !CONFIG_X86_64 || !CONFIG_SMP */
+static inline int dtb_wakeup_mailbox_setup(void)
+{
+	return -EOPNOTSUPP;
+}
+#endif /* CONFIG_X86_64 && CONFIG_SMP */
+
 #ifdef CONFIG_X86_LOCAL_APIC
 
 static void __init dtb_cpu_setup(void)
@@ -287,6 +333,7 @@ static void __init x86_dtb_parse_smp_config(void)
 
 	dtb_setup_hpet();
 	dtb_apic_setup();
+	dtb_wakeup_mailbox_setup();
 }
 
 void __init x86_flattree_get_config(void)

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 03/10] dt-bindings: reserved-memory: Wakeup Mailbox for Intel processors
From: Ricardo Neri @ 2025-06-28  3:35 UTC (permalink / raw)
  To: x86, Krzysztof Kozlowski, Conor Dooley, Rob Herring,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Michael Kelley, Rafael J. Wysocki
  Cc: Saurabh Sengar, Chris Oo, Kirill A. Shutemov, linux-hyperv,
	devicetree, linux-acpi, linux-kernel, Ricardo Neri, Yunhong Jiang,
	Ricardo Neri
In-Reply-To: <20250627-rneri-wakeup-mailbox-v5-0-df547b1d196e@linux.intel.com>

Add DeviceTree bindings to enumerate the wakeup mailbox used in platform
firmware for Intel processors.

x86 platforms commonly boot secondary CPUs using an INIT assert, de-assert
followed by Start-Up IPI messages. The wakeup mailbox can be used when this
mechanism is unavailable.

The wakeup mailbox offers more control to the operating system to boot
secondary CPUs than a spin-table. It allows the reuse of same wakeup vector
for all CPUs while maintaining control over which CPUs to boot and when.
While it is possible to achieve the same level of control using a spin-
table, it would require to specify a separate `cpu-release-addr` for each
secondary CPU.

The operation and structure of the mailbox is described in the
Multiprocessor Wakeup Structure defined in the ACPI specification. Note
that this structure does not specify how to publish the mailbox to the
operating system (ACPI-based platform firmware uses a separate table). No
ACPI table is needed in DeviceTree-based firmware to enumerate the mailbox.

Add a `compatible` property that the operating system can use to discover
the mailbox. Nodes wanting to refer to the reserved memory usually define a
`memory-region` property. /cpus/cpu* nodes would want to refer to the
mailbox, but they do not have such property defined in the DeviceTree
specification. Moreover, it would imply that there is a memory region per
CPU.

Co-developed-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes since v4:
 - Specified the version and section of the ACPI spec in which the
   wakeup mailbox is defined. (Rafael)
 - Fixed a warning from yamllint about line lengths of URLs.

Changes since v3:
 - Removed redefinitions of the mailbox and instead referred to ACPI
   specification as per discussion on LKML.
 - Clarified that DeviceTree-based firmware do not require the use of
   ACPI tables to enumerate the mailbox. (Rob)
 - Described the need of using a `compatible` property.
 - Dropped the `alignment` property. (Krzysztof, Rafael)
 - Used a real address for the mailbox node. (Krzysztof)

Changes since v2:
 - Implemented the mailbox as a reserved-memory node. Add to it a
   `compatible` property. (Krzysztof)
 - Explained the relationship between the mailbox and the `enable-mehod`
   property of the CPU nodes.
 - Expanded the documentation of the binding.

Changes since v1:
 - Added more details to the description of the binding.
 - Added requirement a new requirement for cpu@N nodes to add an
   `enable-method`.
---
 .../reserved-memory/intel,wakeup-mailbox.yaml      | 50 ++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/Documentation/devicetree/bindings/reserved-memory/intel,wakeup-mailbox.yaml b/Documentation/devicetree/bindings/reserved-memory/intel,wakeup-mailbox.yaml
new file mode 100644
index 000000000000..a80d3bac44c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/intel,wakeup-mailbox.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reserved-memory/intel,wakeup-mailbox.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Wakeup Mailbox for Intel processors
+
+description: |
+  The Wakeup Mailbox provides a mechanism for the operating system to wake up
+  secondary CPUs on Intel processors. It is an alternative to the INIT-!INIT-
+  SIPI sequence used on most x86 systems.
+
+  The structure and operation of the mailbox is described in the Multiprocessor
+  Wakeup Structure of the ACPI specification version 6.6 section 5.2.12.19 [1].
+
+  The implementation of the mailbox in platform firmware is described in the
+  Intel TDX Virtual Firmware Design Guide section 4.3.5 [2].
+
+  1: https://uefi.org/specs/ACPI/6.6/05_ACPI_Software_Programming_Model.html#multiprocessor-wakeup-structure
+  2: https://www.intel.com/content/www/us/en/content-details/733585/intel-tdx-virtual-firmware-design-guide.html
+
+
+maintainers:
+  - Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
+
+allOf:
+  - $ref: reserved-memory.yaml
+
+properties:
+  compatible:
+    const: intel,wakeup-mailbox
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    reserved-memory {
+        #address-cells = <2>;
+        #size-cells = <1>;
+
+        wakeup-mailbox@ffff0000 {
+            compatible = "intel,wakeup-mailbox";
+            reg = <0x0 0xffff0000 0x1000>;
+        };
+    };

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 02/10] x86/acpi: Move acpi_wakeup_cpu() and helpers to smpwakeup.c
From: Ricardo Neri @ 2025-06-28  3:35 UTC (permalink / raw)
  To: x86, Krzysztof Kozlowski, Conor Dooley, Rob Herring,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Michael Kelley, Rafael J. Wysocki
  Cc: Saurabh Sengar, Chris Oo, Kirill A. Shutemov, linux-hyperv,
	devicetree, linux-acpi, linux-kernel, Ricardo Neri, Yunhong Jiang,
	Ricardo Neri
In-Reply-To: <20250627-rneri-wakeup-mailbox-v5-0-df547b1d196e@linux.intel.com>

The bootstrap processor uses acpi_wakeup_cpu() to indicate to firmware that
it wants to boot a secondary CPU using a mailbox as described in the
Multiprocessor Wakeup Structure of the ACPI specification.

The platform firmware may implement the mailbox as described in the ACPI
specification but enumerate it using a DeviceTree graph. An example of
this is OpenHCL paravisor.

Move the code used to setup and use the mailbox for CPU wakeup out of the
ACPI directory into a new smpwakeup.c file that both ACPI and DeviceTree
can use.

No functional changes are intended.

Co-developed-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes since v4:
 - Removed dependency on CONFIG_OF. It will be added in a later patch.
   (Rafael)
 - Rebased on v6.16-rc3.

Changes since v3:
 - Create a new file smpwakeup.c instead of relocating it to smpboot.c.
   (Rafael)

Changes since v2:
 - Only move to smpboot.c the portions of the code that configure and
   use the mailbox. This also resolved the compile warnings about unused
   functions that Michael Kelley reported.
 - Edited the commit message for clarity.

Changes since v1:
 - None.
---
 arch/x86/Kconfig                   |  7 ++++
 arch/x86/kernel/Makefile           |  1 +
 arch/x86/kernel/acpi/madt_wakeup.c | 76 ----------------------------------
 arch/x86/kernel/smpwakeup.c        | 83 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 91 insertions(+), 76 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 71019b3b54ea..e3009cb59928 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1114,6 +1114,13 @@ config X86_LOCAL_APIC
 	depends on X86_64 || SMP || X86_UP_APIC || PCI_MSI
 	select IRQ_DOMAIN_HIERARCHY
 
+config X86_MAILBOX_WAKEUP
+	def_bool y
+	depends on ACPI_MADT_WAKEUP
+	depends on X86_64
+	depends on SMP
+	depends on X86_LOCAL_APIC
+
 config ACPI_MADT_WAKEUP
 	def_bool y
 	depends on X86_64
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 0d2a6d953be9..1fce3d20cf2d 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -94,6 +94,7 @@ apm-y				:= apm_32.o
 obj-$(CONFIG_APM)		+= apm.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SMP)		+= smpboot.o
+obj-$(CONFIG_X86_MAILBOX_WAKEUP) += smpwakeup.o
 obj-$(CONFIG_X86_TSC)		+= tsc_sync.o
 obj-$(CONFIG_SMP)		+= setup_percpu.o
 obj-$(CONFIG_X86_MPPARSE)	+= mpparse.o
diff --git a/arch/x86/kernel/acpi/madt_wakeup.c b/arch/x86/kernel/acpi/madt_wakeup.c
index c3ac5ecf3e7d..a7e0158269b0 100644
--- a/arch/x86/kernel/acpi/madt_wakeup.c
+++ b/arch/x86/kernel/acpi/madt_wakeup.c
@@ -2,12 +2,10 @@
 #include <linux/acpi.h>
 #include <linux/cpu.h>
 #include <linux/delay.h>
-#include <linux/io.h>
 #include <linux/kexec.h>
 #include <linux/memblock.h>
 #include <linux/pgtable.h>
 #include <linux/sched/hotplug.h>
-#include <asm/apic.h>
 #include <asm/barrier.h>
 #include <asm/init.h>
 #include <asm/intel_pt.h>
@@ -15,12 +13,6 @@
 #include <asm/processor.h>
 #include <asm/reboot.h>
 
-/* Physical address of the Multiprocessor Wakeup Structure mailbox */
-static u64 acpi_mp_wake_mailbox_paddr __ro_after_init;
-
-/* Virtual address of the Multiprocessor Wakeup Structure mailbox */
-static struct acpi_madt_multiproc_wakeup_mailbox *acpi_mp_wake_mailbox;
-
 static u64 acpi_mp_pgd __ro_after_init;
 static u64 acpi_mp_reset_vector_paddr __ro_after_init;
 
@@ -127,63 +119,6 @@ static int __init acpi_mp_setup_reset(u64 reset_vector)
 	return 0;
 }
 
-static int acpi_wakeup_cpu(u32 apicid, unsigned long start_ip, unsigned int cpu)
-{
-	if (!acpi_mp_wake_mailbox_paddr) {
-		pr_warn_once("No MADT mailbox: cannot bringup secondary CPUs. Booting with kexec?\n");
-		return -EOPNOTSUPP;
-	}
-
-	/*
-	 * Remap mailbox memory only for the first call to acpi_wakeup_cpu().
-	 *
-	 * Wakeup of secondary CPUs is fully serialized in the core code.
-	 * No need to protect acpi_mp_wake_mailbox from concurrent accesses.
-	 */
-	if (!acpi_mp_wake_mailbox) {
-		acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
-						sizeof(*acpi_mp_wake_mailbox),
-						MEMREMAP_WB);
-	}
-
-	/*
-	 * Mailbox memory is shared between the firmware and OS. Firmware will
-	 * listen on mailbox command address, and once it receives the wakeup
-	 * command, the CPU associated with the given apicid will be booted.
-	 *
-	 * The value of 'apic_id' and 'wakeup_vector' must be visible to the
-	 * firmware before the wakeup command is visible.  smp_store_release()
-	 * ensures ordering and visibility.
-	 */
-	acpi_mp_wake_mailbox->apic_id	    = apicid;
-	acpi_mp_wake_mailbox->wakeup_vector = start_ip;
-	smp_store_release(&acpi_mp_wake_mailbox->command,
-			  ACPI_MP_WAKE_COMMAND_WAKEUP);
-
-	/*
-	 * Wait for the CPU to wake up.
-	 *
-	 * The CPU being woken up is essentially in a spin loop waiting to be
-	 * woken up. It should not take long for it wake up and acknowledge by
-	 * zeroing out ->command.
-	 *
-	 * ACPI specification doesn't provide any guidance on how long kernel
-	 * has to wait for a wake up acknowledgment. It also doesn't provide
-	 * a way to cancel a wake up request if it takes too long.
-	 *
-	 * In TDX environment, the VMM has control over how long it takes to
-	 * wake up secondary. It can postpone scheduling secondary vCPU
-	 * indefinitely. Giving up on wake up request and reporting error opens
-	 * possible attack vector for VMM: it can wake up a secondary CPU when
-	 * kernel doesn't expect it. Wait until positive result of the wake up
-	 * request.
-	 */
-	while (READ_ONCE(acpi_mp_wake_mailbox->command))
-		cpu_relax();
-
-	return 0;
-}
-
 static void acpi_mp_disable_offlining(struct acpi_madt_multiproc_wakeup *mp_wake)
 {
 	cpu_hotplug_disable_offlining();
@@ -246,14 +181,3 @@ int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
 
 	return 0;
 }
-
-void __init acpi_setup_mp_wakeup_mailbox(u64 mailbox_paddr)
-{
-	acpi_mp_wake_mailbox_paddr = mailbox_paddr;
-	apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
-}
-
-struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void)
-{
-	return acpi_mp_wake_mailbox;
-}
diff --git a/arch/x86/kernel/smpwakeup.c b/arch/x86/kernel/smpwakeup.c
new file mode 100644
index 000000000000..5089bcda615d
--- /dev/null
+++ b/arch/x86/kernel/smpwakeup.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+#include <asm/apic.h>
+#include <asm/barrier.h>
+#include <asm/processor.h>
+
+/* Physical address of the Multiprocessor Wakeup Structure mailbox */
+static u64 acpi_mp_wake_mailbox_paddr __ro_after_init;
+
+/* Virtual address of the Multiprocessor Wakeup Structure mailbox */
+static struct acpi_madt_multiproc_wakeup_mailbox *acpi_mp_wake_mailbox;
+
+static int acpi_wakeup_cpu(u32 apicid, unsigned long start_ip, unsigned int cpu)
+{
+	if (!acpi_mp_wake_mailbox_paddr) {
+		pr_warn_once("No MADT mailbox: cannot bringup secondary CPUs. Booting with kexec?\n");
+		return -EOPNOTSUPP;
+	}
+
+	/*
+	 * Remap mailbox memory only for the first call to acpi_wakeup_cpu().
+	 *
+	 * Wakeup of secondary CPUs is fully serialized in the core code.
+	 * No need to protect acpi_mp_wake_mailbox from concurrent accesses.
+	 */
+	if (!acpi_mp_wake_mailbox) {
+		acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
+						sizeof(*acpi_mp_wake_mailbox),
+						MEMREMAP_WB);
+	}
+
+	/*
+	 * Mailbox memory is shared between the firmware and OS. Firmware will
+	 * listen on mailbox command address, and once it receives the wakeup
+	 * command, the CPU associated with the given apicid will be booted.
+	 *
+	 * The value of 'apic_id' and 'wakeup_vector' must be visible to the
+	 * firmware before the wakeup command is visible.  smp_store_release()
+	 * ensures ordering and visibility.
+	 */
+	acpi_mp_wake_mailbox->apic_id	    = apicid;
+	acpi_mp_wake_mailbox->wakeup_vector = start_ip;
+	smp_store_release(&acpi_mp_wake_mailbox->command,
+			  ACPI_MP_WAKE_COMMAND_WAKEUP);
+
+	/*
+	 * Wait for the CPU to wake up.
+	 *
+	 * The CPU being woken up is essentially in a spin loop waiting to be
+	 * woken up. It should not take long for it wake up and acknowledge by
+	 * zeroing out ->command.
+	 *
+	 * ACPI specification doesn't provide any guidance on how long kernel
+	 * has to wait for a wake up acknowledgment. It also doesn't provide
+	 * a way to cancel a wake up request if it takes too long.
+	 *
+	 * In TDX environment, the VMM has control over how long it takes to
+	 * wake up secondary. It can postpone scheduling secondary vCPU
+	 * indefinitely. Giving up on wake up request and reporting error opens
+	 * possible attack vector for VMM: it can wake up a secondary CPU when
+	 * kernel doesn't expect it. Wait until positive result of the wake up
+	 * request.
+	 */
+	while (READ_ONCE(acpi_mp_wake_mailbox->command))
+		cpu_relax();
+
+	return 0;
+}
+
+void __init acpi_setup_mp_wakeup_mailbox(u64 mailbox_paddr)
+{
+	acpi_mp_wake_mailbox_paddr = mailbox_paddr;
+	apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
+}
+
+struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void)
+{
+	return acpi_mp_wake_mailbox;
+}

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 01/10] x86/acpi: Add a helper functions to setup and access the wakeup mailbox
From: Ricardo Neri @ 2025-06-28  3:35 UTC (permalink / raw)
  To: x86, Krzysztof Kozlowski, Conor Dooley, Rob Herring,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Michael Kelley, Rafael J. Wysocki
  Cc: Saurabh Sengar, Chris Oo, Kirill A. Shutemov, linux-hyperv,
	devicetree, linux-acpi, linux-kernel, Ricardo Neri, Ricardo Neri
In-Reply-To: <20250627-rneri-wakeup-mailbox-v5-0-df547b1d196e@linux.intel.com>

In preparation to move the functionality to wake secondary CPUs up out of
the ACPI code, add two helper functions.

The function acpi_setup_mp_wakeup_mailbox() stores the physical address of
the mailbox and updates the wakeup_secondary_cpu_64() APIC callback.

There is a slight change in behavior: now the APIC callback is updated
before configuring CPU hotplug offline behavior. This is fine as the APIC
callback continues to be updated unconditionally, regardless of the
restriction on CPU offlining.

The function acpi_madt_multiproc_wakeup_mailbox() returns a pointer to the
mailbox. Use this helper function only in the portions of the code for
which the variable acpi_mp_wake_mailbox will be out of scope once it is
relocated out of the ACPI directory.

The wakeup mailbox is only supported for CONFIG_X86_64 and needed only with
CONFIG_SMP=y.

Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes since v4:
 - None

Changes since v3:
 - Squashed the two first patches of the series into one, both introduce
   helper functions. (Rafael)
 - Renamed setup_mp_wakeup_mailbox() as acpi_setup_mp_wakeup_mailbox().
   (Rafael)
 - Dropped the function prototype for !CONFIG_X86_64. (Rafael)

Changes since v2:
 - Introduced this patch.

Changes since v1:
 - N/A
---
 arch/x86/include/asm/smp.h         |  3 +++
 arch/x86/kernel/acpi/madt_wakeup.c | 20 +++++++++++++++-----
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index 0c1c68039d6f..77dce560a70a 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -146,6 +146,9 @@ static inline struct cpumask *cpu_l2c_shared_mask(int cpu)
 	return per_cpu(cpu_l2c_shared_map, cpu);
 }
 
+void acpi_setup_mp_wakeup_mailbox(u64 addr);
+struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void);
+
 #else /* !CONFIG_SMP */
 #define wbinvd_on_cpu(cpu)     wbinvd()
 static inline int wbinvd_on_all_cpus(void)
diff --git a/arch/x86/kernel/acpi/madt_wakeup.c b/arch/x86/kernel/acpi/madt_wakeup.c
index 6d7603511f52..c3ac5ecf3e7d 100644
--- a/arch/x86/kernel/acpi/madt_wakeup.c
+++ b/arch/x86/kernel/acpi/madt_wakeup.c
@@ -37,6 +37,7 @@ static void acpi_mp_play_dead(void)
 
 static void acpi_mp_cpu_die(unsigned int cpu)
 {
+	struct acpi_madt_multiproc_wakeup_mailbox *mailbox = acpi_get_mp_wakeup_mailbox();
 	u32 apicid = per_cpu(x86_cpu_to_apicid, cpu);
 	unsigned long timeout;
 
@@ -46,13 +47,13 @@ static void acpi_mp_cpu_die(unsigned int cpu)
 	 *
 	 * BIOS has to clear 'command' field of the mailbox.
 	 */
-	acpi_mp_wake_mailbox->apic_id = apicid;
-	smp_store_release(&acpi_mp_wake_mailbox->command,
+	mailbox->apic_id = apicid;
+	smp_store_release(&mailbox->command,
 			  ACPI_MP_WAKE_COMMAND_TEST);
 
 	/* Don't wait longer than a second. */
 	timeout = USEC_PER_SEC;
-	while (READ_ONCE(acpi_mp_wake_mailbox->command) && --timeout)
+	while (READ_ONCE(mailbox->command) && --timeout)
 		udelay(1);
 
 	if (!timeout)
@@ -227,7 +228,7 @@ int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
 
 	acpi_table_print_madt_entry(&header->common);
 
-	acpi_mp_wake_mailbox_paddr = mp_wake->mailbox_address;
+	acpi_setup_mp_wakeup_mailbox(mp_wake->mailbox_address);
 
 	if (mp_wake->version >= ACPI_MADT_MP_WAKEUP_VERSION_V1 &&
 	    mp_wake->header.length >= ACPI_MADT_MP_WAKEUP_SIZE_V1) {
@@ -243,7 +244,16 @@ int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
 		acpi_mp_disable_offlining(mp_wake);
 	}
 
+	return 0;
+}
+
+void __init acpi_setup_mp_wakeup_mailbox(u64 mailbox_paddr)
+{
+	acpi_mp_wake_mailbox_paddr = mailbox_paddr;
 	apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
+}
 
-	return 0;
+struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void)
+{
+	return acpi_mp_wake_mailbox;
 }

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 00/10] x86/hyperv/hv_vtl: Use a wakeup mailbox to boot secondary CPUs
From: Ricardo Neri @ 2025-06-28  3:35 UTC (permalink / raw)
  To: x86, Krzysztof Kozlowski, Conor Dooley, Rob Herring,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Michael Kelley, Rafael J. Wysocki
  Cc: Saurabh Sengar, Chris Oo, Kirill A. Shutemov, linux-hyperv,
	devicetree, linux-acpi, linux-kernel, Ricardo Neri, Ricardo Neri,
	Yunhong Jiang, Thomas Gleixner

Hi,

Here is a new version of this series. Thanks to Rafael for his feedback!
I incorporated his feedback in this updated version. Please see the
changelog for details.

If the DeviceTree bindings look good, then the patches should be ready for
review by the x86, ACPI, and Hyper-V maintainers.

I did not change the cover letter but I included it here for completeness.

Thanks in advance for your feedback!

...

This patchset adds functionality to use a wakeup mailbox to boot secondary
CPUs in Hyper-V VTL level 2 TDX guests with virtual firmware that describes
hardware using a DeviceTree graph. Although this is the target use case,
the use of the mailbox depends solely on it being enumerated in the
DeviceTree.

On x86 platforms, secondary CPUs are typically booted using INIT assert,
de-assert followed by Start-Up IPI messages. Virtual machines can also make
hypercalls to bring up secondary CPUs to a desired execution state. These
two mechanisms require support from the hypervisor. Confidential computing
VMs in a TDX environment cannot use this mechanism because the hypervisor
is considered an untrusted entity.

Linux already supports the ACPI Multiprocessor Wakeup Structure in which
the guest platform firmware boots the secondary CPUs and transfers control
to the kernel using a mailbox. This mechanism does not need involvement
of the VMM. It can be used in a Hyper-V VTL level 2 TDX guest.

Currently, this mechanism can only be used on x86 platforms with firmware
that supports ACPI. There are platforms that use DeviceTree (e.g., OpenHCL
[5]) instead of ACPI to describe the hardware.

Provided that the wakeup mailbox enumerated in a DeviceTree-based platform
firmware is implemented as described in the ACPI specification, the kernel
can used common code for both DeviceTree and ACPI systems. The DeviceTree
firmware does not need to use any ACPI table to publish the mailbox.

This patcheset is structured as follows:

   * Relocate portions of the code handling the ACPI Multiprocessor Wakeup
     Structure code to a common location. (patches 1, 2)
   * Define DeviceTree bindings to enumerate a mailbox as described in
     the ACPI specification. (patch 3)
   * Find and setup the wakeup mailbox if found in the DeviceTree graph.
     (patch 4)
   * Prepare Hyper-V VTL2 TDX guests to use the Wakeup Mailbox to boot
     secondary CPUs when available. (patches 5-10)

I have tested this patchset on a Hyper-V host with VTL2 OpenHCL, QEMU, and
physical hardware.

Changes in v5:
- Referred in the DeviceTree binding documentation the section and
  section of the ACPI specification that defines the wakeup mailbox.
- Moved the dependency on CONFIG_OF to patch 4, where the flattened
  DeviceTree is parsed for the mailbox.
- Fixed a warning from yamllint regarding line lengths.
- Link to v4: https://lore.kernel.org/r/20250603-rneri-wakeup-mailbox-v4-0-d533272b7232@linux.intel.com

Changes in v4:
- Added Reviewed-by: tags from Michael Kelley. Thanks!
- Relocated the common wakeup code from acpi/madt_wakeup.c to a new
  smpwakeup.c to be used in DeviceTree- and ACPI-based systems.
- Dropped the x86 CPU bindings as they are not a good fit to document
  firmware features.
- Dropped the code that parsed and validated of the `enable-method`
  property for cpu@N nodes in x86. Instead, unconditionally parse and use
  the wakeup mailbox when found.
- Updated the wakeup mailbox schema to avoid redefing the structure and
  operation of the mailbox. Instead, refer to the ACPI specification.
  Also clarified that the enumeration of the mailbox is done separately.
- Prefixed helper functions of wakeup code with acpi_.
- Link to v3: https://lore.kernel.org/r/20250503191515.24041-1-ricardo.neri-calderon@linux.intel.com

Changes in v3:
- Only move out of the acpi directory acpi_wakeup_cpu() and its
  accessory variables. Use helper functions to access the mailbox as
  needed. This also fixed the warnings about unused code with CONFIG_
  ACPI=n that Michael reported.
- Major rework of the DeviceTree bindings and schema. Now there is a
  reserved-memory binding for the mailbox as well as a new x86 CPU
  bindings. Both have `compatible` properties.
- Rework of the code parsing the DeviceTree bindings for the mailbox.
  Now configuring the mailbox depends solely on its enumeration in the
  DeviceTree and not on Hyper-V VTL2 TDX guest.
- Do not make reserving the first 1MB of memory optional. It is not
  needed and may introduce bugs.
- Prepare Hyper-V VTL2 guests to unconditionally use the mailbox in TDX
  environments. If the mailbox is not available, booting secondary CPUs
  will fail gracefully.
- Link to v2: https://lore.kernel.org/r/20240823232327.2408869-1-yunhong.jiang@linux.intel.com

Changes in v2:
- Fix the cover letter's summary phrase.
- Fix the DT binding document to pass validation.
- Change the DT binding document to be ACPI independent.
- Move ACPI-only functions into the #ifdef CONFIG_ACPI.
- Change dtb_parse_mp_wake() to return mailbox physical address.
- Rework the hv_is_private_mmio_tdx().
- Remove unrelated real mode change from the patch that marks mailbox
  page private.
- Check hv_isolation_type_tdx() instead of wakeup_mailbox_addr in
  hv_vtl_init_platform() because wakeup_mailbox_addr is not parsed yet.
- Add memory range support to reserve_real_mode.
- Remove realmode_reserve callback and use the memory range.
- Move setting the real_mode_header to hv_vtl_init_platform.
- Update comments and commit messages.
- Minor style changes.
- Link to v1: https://lore.kernel.org/r/20240806221237.1634126-1-yunhong.jiang@linux.intel.com

[1]. https://openvmm.dev/guide/user_guide/openhcl.html
--
2.43.0

---
Ricardo Neri (6):
      x86/acpi: Add a helper functions to setup and access the wakeup mailbox
      x86/acpi: Move acpi_wakeup_cpu() and helpers to smpwakeup.c
      dt-bindings: reserved-memory: Wakeup Mailbox for Intel processors
      x86/dt: Parse the Wakeup Mailbox for Intel processors
      x86/smpwakeup: Add a helper get the address of the wakeup mailbox
      x86/hyperv/vtl: Use the wakeup mailbox to boot secondary CPUs

Yunhong Jiang (4):
      x86/hyperv/vtl: Set real_mode_header in hv_vtl_init_platform()
      x86/realmode: Make the location of the trampoline configurable
      x86/hyperv/vtl: Setup the 64-bit trampoline for TDX guests
      x86/hyperv/vtl: Mark the wakeup mailbox page as private

 .../reserved-memory/intel,wakeup-mailbox.yaml      | 50 ++++++++++++
 arch/x86/Kconfig                                   |  7 ++
 arch/x86/hyperv/hv_vtl.c                           | 35 ++++++++-
 arch/x86/include/asm/smp.h                         |  4 +
 arch/x86/include/asm/x86_init.h                    |  3 +
 arch/x86/kernel/Makefile                           |  1 +
 arch/x86/kernel/acpi/madt_wakeup.c                 | 76 ++-----------------
 arch/x86/kernel/devicetree.c                       | 47 ++++++++++++
 arch/x86/kernel/smpwakeup.c                        | 88 ++++++++++++++++++++++
 arch/x86/kernel/x86_init.c                         |  3 +
 arch/x86/realmode/init.c                           |  7 +-
 11 files changed, 242 insertions(+), 79 deletions(-)
---
base-commit: e51a38e71974982abb3f2f16141763a1511f7a3f
change-id: 20250602-rneri-wakeup-mailbox-328efe72803f

Best regards,
-- 
Ricardo Neri <ricardo.neri-calderon@linux.intel.com>


^ permalink raw reply

* [PATCH v5 1/1] tools/hv: fcopy: Fix incorrect file path conversion
From: yasuenag @ 2025-06-28  2:22 UTC (permalink / raw)
  To: namjain
  Cc: eahariha, kys, haiyangz, wei.liu, decui, linux-hyperv, ssengar,
	Yasumasa Suenaga
In-Reply-To: <20250628022217.1514-1-yasuenag@gmail.com>

From: Yasumasa Suenaga <yasuenag@gmail.com>

The hv_fcopy_uio_daemon fails to correctly handle file copy requests
from Windows hosts (e.g. via Copy-VMFile) due to wchar_t size
differences between Windows and Linux. On Linux, wchar_t is 32 bit,
whereas Windows uses 16 bit wide characters.

Fix this by ensuring that file transfers from host to Linux guest
succeed with correctly decoded file names and paths.

- Treats file name and path as __u16 arrays, not wchar_t*.
- Allocates fixed-size buffers (W_MAX_PATH) for converted strings
  instead of using malloc.
- Adds a check for target path length to prevent snprintf() buffer
  overflow.

Fixes: 82b0945ce2c2 ("tools: hv: Add new fcopy application based on uio driver")
Signed-off-by: Yasumasa Suenaga <yasuenag@gmail.com>
---
 tools/hv/hv_fcopy_uio_daemon.c | 37 +++++++++++++---------------------
 1 file changed, 14 insertions(+), 23 deletions(-)

diff --git a/tools/hv/hv_fcopy_uio_daemon.c b/tools/hv/hv_fcopy_uio_daemon.c
index 0198321d1..4b09ed6b6 100644
--- a/tools/hv/hv_fcopy_uio_daemon.c
+++ b/tools/hv/hv_fcopy_uio_daemon.c
@@ -62,8 +62,11 @@ static int hv_fcopy_create_file(char *file_name, char *path_name, __u32 flags)
 
 	filesize = 0;
 	p = path_name;
-	snprintf(target_fname, sizeof(target_fname), "%s/%s",
-		 path_name, file_name);
+	if (snprintf(target_fname, sizeof(target_fname), "%s/%s",
+		     path_name, file_name) >= sizeof(target_fname)) {
+		syslog(LOG_ERR, "target file name is too long: %s/%s", path_name, file_name);
+		goto done;
+	}
 
 	/*
 	 * Check to see if the path is already in place; if not,
@@ -270,7 +273,7 @@ static void wcstoutf8(char *dest, const __u16 *src, size_t dest_size)
 {
 	size_t len = 0;
 
-	while (len < dest_size) {
+	while (len < dest_size && *src) {
 		if (src[len] < 0x80)
 			dest[len++] = (char)(*src++);
 		else
@@ -282,27 +285,15 @@ static void wcstoutf8(char *dest, const __u16 *src, size_t dest_size)
 
 static int hv_fcopy_start(struct hv_start_fcopy *smsg_in)
 {
-	setlocale(LC_ALL, "en_US.utf8");
-	size_t file_size, path_size;
-	char *file_name, *path_name;
-	char *in_file_name = (char *)smsg_in->file_name;
-	char *in_path_name = (char *)smsg_in->path_name;
-
-	file_size = wcstombs(NULL, (const wchar_t *restrict)in_file_name, 0) + 1;
-	path_size = wcstombs(NULL, (const wchar_t *restrict)in_path_name, 0) + 1;
-
-	file_name = (char *)malloc(file_size * sizeof(char));
-	path_name = (char *)malloc(path_size * sizeof(char));
-
-	if (!file_name || !path_name) {
-		free(file_name);
-		free(path_name);
-		syslog(LOG_ERR, "Can't allocate memory for file name and/or path name");
-		return HV_E_FAIL;
-	}
+	/*
+	 * file_name and path_name should have same length with appropriate
+	 * member of hv_start_fcopy.
+	 */
+	char file_name[W_MAX_PATH], path_name[W_MAX_PATH];
 
-	wcstoutf8(file_name, (__u16 *)in_file_name, file_size);
-	wcstoutf8(path_name, (__u16 *)in_path_name, path_size);
+	setlocale(LC_ALL, "en_US.utf8");
+	wcstoutf8(file_name, smsg_in->file_name, W_MAX_PATH - 1);
+	wcstoutf8(path_name, smsg_in->path_name, W_MAX_PATH - 1);
 
 	return hv_fcopy_create_file(file_name, path_name, smsg_in->copy_flags);
 }
-- 
2.49.0


^ permalink raw reply related

* [PATCH v5 0/1] tools/hv: fcopy: Fix incorrect file path conversion
From: yasuenag @ 2025-06-28  2:22 UTC (permalink / raw)
  To: namjain
  Cc: eahariha, kys, haiyangz, wei.liu, decui, linux-hyperv, ssengar,
	Yasumasa Suenaga

From: Yasumasa Suenaga <yasuenag@gmail.com>

Hi Naman,

Thanks a lot for your advise!
I updated commit message. This version does not have any code changes
from v4.

I hope this patch would go well.


Best regards,

Yasumasa


Yasumasa Suenaga (1):
  tools/hv: fcopy: Fix incorrect file path conversion

 tools/hv/hv_fcopy_uio_daemon.c | 37 +++++++++++++---------------------
 1 file changed, 14 insertions(+), 23 deletions(-)

-- 
2.49.0


^ permalink raw reply

* Re: [PATCH 1/1] x86/hyperv: Switch to msi_create_parent_irq_domain()
From: kernel test robot @ 2025-06-27 21:03 UTC (permalink / raw)
  To: Nam Cao, K . Y . Srinivasan, Marc Zyngier, Haiyang Zhang, Wei Liu,
	Dexuan Cui, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H . Peter Anvin, linux-hyperv, linux-kernel
  Cc: oe-kbuild-all, Nam Cao
In-Reply-To: <0eafade05acb51022242635750cd4990f3adb0ac.1750947640.git.namcao@linutronix.de>

Hi Nam,

kernel test robot noticed the following build errors:

[auto build test ERROR on tip/master]
[also build test ERROR on linus/master v6.16-rc3 next-20250627]
[cannot apply to tip/x86/core tip/auto-latest]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Nam-Cao/x86-hyperv-Switch-to-msi_create_parent_irq_domain/20250626-225420
base:   tip/master
patch link:    https://lore.kernel.org/r/0eafade05acb51022242635750cd4990f3adb0ac.1750947640.git.namcao%40linutronix.de
patch subject: [PATCH 1/1] x86/hyperv: Switch to msi_create_parent_irq_domain()
config: i386-randconfig-014-20250628 (https://download.01.org/0day-ci/archive/20250628/202506280404.eZJ6vN93-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14+deb12u1) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250628/202506280404.eZJ6vN93-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/202506280404.eZJ6vN93-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   In file included from drivers/irqchip/irq-msi-lib.c:7:
>> include/linux/irqchip/irq-msi-lib.h:25:39: warning: 'struct msi_domain_info' declared inside parameter list will not be visible outside of this definition or declaration
      25 |                                struct msi_domain_info *info);
         |                                       ^~~~~~~~~~~~~~~
>> drivers/irqchip/irq-msi-lib.c:28:39: warning: 'struct msi_domain_info' declared inside parameter list will not be visible outside of this definition or declaration
      28 |                                struct msi_domain_info *info)
         |                                       ^~~~~~~~~~~~~~~
>> drivers/irqchip/irq-msi-lib.c:26:6: error: conflicting types for 'msi_lib_init_dev_msi_info'; have 'bool(struct device *, struct irq_domain *, struct irq_domain *, struct msi_domain_info *)' {aka '_Bool(struct device *, struct irq_domain *, struct irq_domain *, struct msi_domain_info *)'}
      26 | bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/irqchip/irq-msi-lib.h:23:6: note: previous declaration of 'msi_lib_init_dev_msi_info' with type 'bool(struct device *, struct irq_domain *, struct irq_domain *, struct msi_domain_info *)' {aka '_Bool(struct device *, struct irq_domain *, struct irq_domain *, struct msi_domain_info *)'}
      23 | bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/irqchip/irq-msi-lib.c: In function 'msi_lib_init_dev_msi_info':
>> drivers/irqchip/irq-msi-lib.c:30:56: error: 'struct irq_domain' has no member named 'msi_parent_ops'
      30 |         const struct msi_parent_ops *pops = real_parent->msi_parent_ops;
         |                                                        ^~
>> drivers/irqchip/irq-msi-lib.c:31:37: error: invalid use of undefined type 'struct msi_domain_info'
      31 |         struct irq_chip *chip = info->chip;
         |                                     ^~
>> drivers/irqchip/irq-msi-lib.c:43:38: error: invalid use of undefined type 'const struct msi_parent_ops'
      43 |         if (domain->bus_token == pops->bus_select_token) {
         |                                      ^~
   drivers/irqchip/irq-msi-lib.c:51:30: error: invalid use of undefined type 'const struct msi_parent_ops'
      51 |         required_flags = pops->required_flags;
         |                              ^~
   drivers/irqchip/irq-msi-lib.c:54:20: error: invalid use of undefined type 'struct msi_domain_info'
      54 |         switch(info->bus_token) {
         |                    ^~
   In file included from arch/x86/include/asm/bug.h:103,
                    from arch/x86/include/asm/alternative.h:9,
                    from arch/x86/include/asm/barrier.h:5,
                    from include/asm-generic/bitops/generic-non-atomic.h:7,
                    from include/linux/bitops.h:28,
                    from include/linux/of.h:15,
                    from include/linux/irqdomain.h:14,
                    from include/linux/irqchip/irq-msi-lib.h:9:
   drivers/irqchip/irq-msi-lib.c:68:38: error: invalid use of undefined type 'struct msi_domain_info'
      68 |                 if (WARN_ON_ONCE(info->flags))
         |                                      ^~
   include/asm-generic/bug.h:117:32: note: in definition of macro 'WARN_ON_ONCE'
     117 |         int __ret_warn_on = !!(condition);                      \
         |                                ^~~~~~~~~
   drivers/irqchip/irq-msi-lib.c:72:21: error: invalid use of undefined type 'struct msi_domain_info'
      72 |                 info->flags = MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS;
         |                     ^~
>> drivers/irqchip/irq-msi-lib.c:72:31: error: 'MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS' undeclared (first use in this function)
      72 |                 info->flags = MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS;
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/irqchip/irq-msi-lib.c:72:31: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/irqchip/irq-msi-lib.c:72:65: error: 'MSI_FLAG_FREE_MSI_DESCS' undeclared (first use in this function)
      72 |                 info->flags = MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS;
         |                                                                 ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/irqchip/irq-msi-lib.c:76:36: error: 'MSI_FLAG_PCI_MSI_MASK_PARENT' undeclared (first use in this function)
      76 |                 required_flags &= ~MSI_FLAG_PCI_MSI_MASK_PARENT;
         |                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/irqchip/irq-msi-lib.c:91:13: error: invalid use of undefined type 'struct msi_domain_info'
      91 |         info->flags                     &= pops->supported_flags;
         |             ^~
   drivers/irqchip/irq-msi-lib.c:91:48: error: invalid use of undefined type 'const struct msi_parent_ops'
      91 |         info->flags                     &= pops->supported_flags;
         |                                                ^~
   drivers/irqchip/irq-msi-lib.c:93:13: error: invalid use of undefined type 'struct msi_domain_info'
      93 |         info->flags                     |= required_flags;
         |             ^~
   drivers/irqchip/irq-msi-lib.c:96:36: error: invalid use of undefined type 'const struct msi_parent_ops'
      96 |         if (!chip->irq_eoi && (pops->chip_flags & MSI_CHIP_FLAG_SET_EOI))
         |                                    ^~
>> drivers/irqchip/irq-msi-lib.c:96:51: error: 'MSI_CHIP_FLAG_SET_EOI' undeclared (first use in this function)
      96 |         if (!chip->irq_eoi && (pops->chip_flags & MSI_CHIP_FLAG_SET_EOI))
         |                                                   ^~~~~~~~~~~~~~~~~~~~~
   drivers/irqchip/irq-msi-lib.c:98:36: error: invalid use of undefined type 'const struct msi_parent_ops'
      98 |         if (!chip->irq_ack && (pops->chip_flags & MSI_CHIP_FLAG_SET_ACK))
         |                                    ^~
>> drivers/irqchip/irq-msi-lib.c:98:51: error: 'MSI_CHIP_FLAG_SET_ACK' undeclared (first use in this function)
      98 |         if (!chip->irq_ack && (pops->chip_flags & MSI_CHIP_FLAG_SET_ACK))
         |                                                   ^~~~~~~~~~~~~~~~~~~~~
   drivers/irqchip/irq-msi-lib.c:113:46: error: invalid use of undefined type 'struct msi_domain_info'
     113 |         if (!chip->irq_set_affinity && !(info->flags & MSI_FLAG_NO_AFFINITY))
         |                                              ^~
>> drivers/irqchip/irq-msi-lib.c:113:56: error: 'MSI_FLAG_NO_AFFINITY' undeclared (first use in this function)
     113 |         if (!chip->irq_set_affinity && !(info->flags & MSI_FLAG_NO_AFFINITY))
         |                                                        ^~~~~~~~~~~~~~~~~~~~
>> drivers/irqchip/irq-msi-lib.c:114:42: error: 'msi_domain_set_affinity' undeclared (first use in this function); did you mean 'msi_domain_get_virq'?
     114 |                 chip->irq_set_affinity = msi_domain_set_affinity;
         |                                          ^~~~~~~~~~~~~~~~~~~~~~~
         |                                          msi_domain_get_virq
   In file included from drivers/irqchip/irq-msi-lib.c:5:
   drivers/irqchip/irq-msi-lib.c: At top level:
   drivers/irqchip/irq-msi-lib.c:117:19: error: conflicting types for 'msi_lib_init_dev_msi_info'; have 'bool(struct device *, struct irq_domain *, struct irq_domain *, struct msi_domain_info *)' {aka '_Bool(struct device *, struct irq_domain *, struct irq_domain *, struct msi_domain_info *)'}
     117 | EXPORT_SYMBOL_GPL(msi_lib_init_dev_msi_info);
         |                   ^~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/export.h:76:28: note: in definition of macro '__EXPORT_SYMBOL'
      76 |         extern typeof(sym) sym;                                 \
         |                            ^~~
   include/linux/export.h:90:41: note: in expansion of macro '_EXPORT_SYMBOL'
      90 | #define EXPORT_SYMBOL_GPL(sym)          _EXPORT_SYMBOL(sym, "GPL")
         |                                         ^~~~~~~~~~~~~~
   drivers/irqchip/irq-msi-lib.c:117:1: note: in expansion of macro 'EXPORT_SYMBOL_GPL'
     117 | EXPORT_SYMBOL_GPL(msi_lib_init_dev_msi_info);
         | ^~~~~~~~~~~~~~~~~
   include/linux/irqchip/irq-msi-lib.h:23:6: note: previous declaration of 'msi_lib_init_dev_msi_info' with type 'bool(struct device *, struct irq_domain *, struct irq_domain *, struct msi_domain_info *)' {aka '_Bool(struct device *, struct irq_domain *, struct irq_domain *, struct msi_domain_info *)'}
      23 | bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/irqchip/irq-msi-lib.c: In function 'msi_lib_irq_domain_select':
   drivers/irqchip/irq-msi-lib.c:134:45: error: 'struct irq_domain' has no member named 'msi_parent_ops'
     134 |         const struct msi_parent_ops *ops = d->msi_parent_ops;
         |                                             ^~
   drivers/irqchip/irq-msi-lib.c:144:29: error: invalid use of undefined type 'const struct msi_parent_ops'
     144 |         if (bus_token == ops->bus_select_token)
         |                             ^~
   drivers/irqchip/irq-msi-lib.c:147:22: error: invalid use of undefined type 'const struct msi_parent_ops'
     147 |         return !!(ops->bus_select_mask & busmask);
         |                      ^~
>> drivers/irqchip/irq-msi-lib.c:148:1: warning: control reaches end of non-void function [-Wreturn-type]
     148 | }
         | ^


vim +26 drivers/irqchip/irq-msi-lib.c

72e257c6f05803 Thomas Gleixner   2024-06-23    8  
72e257c6f05803 Thomas Gleixner   2024-06-23    9  /**
72e257c6f05803 Thomas Gleixner   2024-06-23   10   * msi_lib_init_dev_msi_info - Domain info setup for MSI domains
72e257c6f05803 Thomas Gleixner   2024-06-23   11   * @dev:		The device for which the domain is created for
72e257c6f05803 Thomas Gleixner   2024-06-23   12   * @domain:		The domain providing this callback
72e257c6f05803 Thomas Gleixner   2024-06-23   13   * @real_parent:	The real parent domain of the domain to be initialized
72e257c6f05803 Thomas Gleixner   2024-06-23   14   *			which might be a domain built on top of @domain or
72e257c6f05803 Thomas Gleixner   2024-06-23   15   *			@domain itself
72e257c6f05803 Thomas Gleixner   2024-06-23   16   * @info:		The domain info for the domain to be initialize
72e257c6f05803 Thomas Gleixner   2024-06-23   17   *
72e257c6f05803 Thomas Gleixner   2024-06-23   18   * This function is to be used for all types of MSI domains above the root
72e257c6f05803 Thomas Gleixner   2024-06-23   19   * parent domain and any intermediates. The topmost parent domain specific
72e257c6f05803 Thomas Gleixner   2024-06-23   20   * functionality is determined via @real_parent.
72e257c6f05803 Thomas Gleixner   2024-06-23   21   *
72e257c6f05803 Thomas Gleixner   2024-06-23   22   * All intermediate domains between the root and the device domain must
72e257c6f05803 Thomas Gleixner   2024-06-23   23   * have either msi_parent_ops.init_dev_msi_info = msi_parent_init_dev_msi_info
72e257c6f05803 Thomas Gleixner   2024-06-23   24   * or invoke it down the line.
72e257c6f05803 Thomas Gleixner   2024-06-23   25   */
72e257c6f05803 Thomas Gleixner   2024-06-23  @26  bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
72e257c6f05803 Thomas Gleixner   2024-06-23   27  			       struct irq_domain *real_parent,
72e257c6f05803 Thomas Gleixner   2024-06-23  @28  			       struct msi_domain_info *info)
72e257c6f05803 Thomas Gleixner   2024-06-23   29  {
72e257c6f05803 Thomas Gleixner   2024-06-23  @30  	const struct msi_parent_ops *pops = real_parent->msi_parent_ops;
1c000dcaad2bef Thomas Gleixner   2025-02-17  @31  	struct irq_chip *chip = info->chip;
8c41ccec839c62 Thomas Gleixner   2024-06-23   32  	u32 required_flags;
72e257c6f05803 Thomas Gleixner   2024-06-23   33  
72e257c6f05803 Thomas Gleixner   2024-06-23   34  	/* Parent ops available? */
72e257c6f05803 Thomas Gleixner   2024-06-23   35  	if (WARN_ON_ONCE(!pops))
72e257c6f05803 Thomas Gleixner   2024-06-23   36  		return false;
72e257c6f05803 Thomas Gleixner   2024-06-23   37  
72e257c6f05803 Thomas Gleixner   2024-06-23   38  	/*
72e257c6f05803 Thomas Gleixner   2024-06-23   39  	 * MSI parent domain specific settings. For now there is only the
72e257c6f05803 Thomas Gleixner   2024-06-23   40  	 * root parent domain, e.g. NEXUS, acting as a MSI parent, but it is
72e257c6f05803 Thomas Gleixner   2024-06-23   41  	 * possible to stack MSI parents. See x86 vector -> irq remapping
72e257c6f05803 Thomas Gleixner   2024-06-23   42  	 */
72e257c6f05803 Thomas Gleixner   2024-06-23  @43  	if (domain->bus_token == pops->bus_select_token) {
72e257c6f05803 Thomas Gleixner   2024-06-23   44  		if (WARN_ON_ONCE(domain != real_parent))
72e257c6f05803 Thomas Gleixner   2024-06-23   45  			return false;
72e257c6f05803 Thomas Gleixner   2024-06-23   46  	} else {
72e257c6f05803 Thomas Gleixner   2024-06-23   47  		WARN_ON_ONCE(1);
72e257c6f05803 Thomas Gleixner   2024-06-23   48  		return false;
72e257c6f05803 Thomas Gleixner   2024-06-23   49  	}
72e257c6f05803 Thomas Gleixner   2024-06-23   50  
8c41ccec839c62 Thomas Gleixner   2024-06-23   51  	required_flags = pops->required_flags;
8c41ccec839c62 Thomas Gleixner   2024-06-23   52  
72e257c6f05803 Thomas Gleixner   2024-06-23   53  	/* Is the target domain bus token supported? */
72e257c6f05803 Thomas Gleixner   2024-06-23   54  	switch(info->bus_token) {
8c41ccec839c62 Thomas Gleixner   2024-06-23   55  	case DOMAIN_BUS_PCI_DEVICE_MSI:
8c41ccec839c62 Thomas Gleixner   2024-06-23   56  	case DOMAIN_BUS_PCI_DEVICE_MSIX:
8c41ccec839c62 Thomas Gleixner   2024-06-23   57  		if (WARN_ON_ONCE(!IS_ENABLED(CONFIG_PCI_MSI)))
8c41ccec839c62 Thomas Gleixner   2024-06-23   58  			return false;
8c41ccec839c62 Thomas Gleixner   2024-06-23   59  
496436f4a514a3 Thomas Gleixner   2024-06-23   60  		break;
496436f4a514a3 Thomas Gleixner   2024-06-23   61  	case DOMAIN_BUS_DEVICE_MSI:
496436f4a514a3 Thomas Gleixner   2024-06-23   62  		/*
496436f4a514a3 Thomas Gleixner   2024-06-23   63  		 * Per device MSI should never have any MSI feature bits
496436f4a514a3 Thomas Gleixner   2024-06-23   64  		 * set. It's sole purpose is to create a dumb interrupt
496436f4a514a3 Thomas Gleixner   2024-06-23   65  		 * chip which has a device specific irq_write_msi_msg()
496436f4a514a3 Thomas Gleixner   2024-06-23   66  		 * callback.
496436f4a514a3 Thomas Gleixner   2024-06-23   67  		 */
496436f4a514a3 Thomas Gleixner   2024-06-23   68  		if (WARN_ON_ONCE(info->flags))
496436f4a514a3 Thomas Gleixner   2024-06-23   69  			return false;
496436f4a514a3 Thomas Gleixner   2024-06-23   70  
496436f4a514a3 Thomas Gleixner   2024-06-23   71  		/* Core managed MSI descriptors */
496436f4a514a3 Thomas Gleixner   2024-06-23  @72  		info->flags = MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS;
64a855324311dd Thomas Gleixner   2024-06-23   73  		fallthrough;
64a855324311dd Thomas Gleixner   2024-06-23   74  	case DOMAIN_BUS_WIRED_TO_MSI:
496436f4a514a3 Thomas Gleixner   2024-06-23   75  		/* Remove PCI specific flags */
496436f4a514a3 Thomas Gleixner   2024-06-23  @76  		required_flags &= ~MSI_FLAG_PCI_MSI_MASK_PARENT;
8c41ccec839c62 Thomas Gleixner   2024-06-23   77  		break;
72e257c6f05803 Thomas Gleixner   2024-06-23   78  	default:
72e257c6f05803 Thomas Gleixner   2024-06-23   79  		/*
72e257c6f05803 Thomas Gleixner   2024-06-23   80  		 * This should never be reached. See
72e257c6f05803 Thomas Gleixner   2024-06-23   81  		 * msi_lib_irq_domain_select()
72e257c6f05803 Thomas Gleixner   2024-06-23   82  		 */
72e257c6f05803 Thomas Gleixner   2024-06-23   83  		WARN_ON_ONCE(1);
72e257c6f05803 Thomas Gleixner   2024-06-23   84  		return false;
72e257c6f05803 Thomas Gleixner   2024-06-23   85  	}
72e257c6f05803 Thomas Gleixner   2024-06-23   86  
72e257c6f05803 Thomas Gleixner   2024-06-23   87  	/*
72e257c6f05803 Thomas Gleixner   2024-06-23   88  	 * Mask out the domain specific MSI feature flags which are not
72e257c6f05803 Thomas Gleixner   2024-06-23   89  	 * supported by the real parent.
72e257c6f05803 Thomas Gleixner   2024-06-23   90  	 */
72e257c6f05803 Thomas Gleixner   2024-06-23   91  	info->flags			&= pops->supported_flags;
72e257c6f05803 Thomas Gleixner   2024-06-23   92  	/* Enforce the required flags */
8c41ccec839c62 Thomas Gleixner   2024-06-23   93  	info->flags			|= required_flags;
72e257c6f05803 Thomas Gleixner   2024-06-23   94  
72e257c6f05803 Thomas Gleixner   2024-06-23   95  	/* Chip updates for all child bus types */
1c000dcaad2bef Thomas Gleixner   2025-02-17  @96  	if (!chip->irq_eoi && (pops->chip_flags & MSI_CHIP_FLAG_SET_EOI))
1c000dcaad2bef Thomas Gleixner   2025-02-17   97  		chip->irq_eoi = irq_chip_eoi_parent;
1c000dcaad2bef Thomas Gleixner   2025-02-17  @98  	if (!chip->irq_ack && (pops->chip_flags & MSI_CHIP_FLAG_SET_ACK))
1c000dcaad2bef Thomas Gleixner   2025-02-17   99  		chip->irq_ack = irq_chip_ack_parent;
72e257c6f05803 Thomas Gleixner   2024-06-23  100  
72e257c6f05803 Thomas Gleixner   2024-06-23  101  	/*
72e257c6f05803 Thomas Gleixner   2024-06-23  102  	 * The device MSI domain can never have a set affinity callback. It
72e257c6f05803 Thomas Gleixner   2024-06-23  103  	 * always has to rely on the parent domain to handle affinity
72e257c6f05803 Thomas Gleixner   2024-06-23  104  	 * settings. The device MSI domain just has to write the resulting
72e257c6f05803 Thomas Gleixner   2024-06-23  105  	 * MSI message into the hardware which is the whole purpose of the
72e257c6f05803 Thomas Gleixner   2024-06-23  106  	 * device MSI domain aside of mask/unmask which is provided e.g. by
72e257c6f05803 Thomas Gleixner   2024-06-23  107  	 * PCI/MSI device domains.
06526443a34c06 Marc Zyngier      2025-05-13  108  	 *
06526443a34c06 Marc Zyngier      2025-05-13  109  	 * The exception to the rule is when the underlying domain
06526443a34c06 Marc Zyngier      2025-05-13  110  	 * tells you that affinity is not a thing -- for example when
06526443a34c06 Marc Zyngier      2025-05-13  111  	 * everything is muxed behind a single interrupt.
72e257c6f05803 Thomas Gleixner   2024-06-23  112  	 */
06526443a34c06 Marc Zyngier      2025-05-13 @113  	if (!chip->irq_set_affinity && !(info->flags & MSI_FLAG_NO_AFFINITY))
1c000dcaad2bef Thomas Gleixner   2025-02-17 @114  		chip->irq_set_affinity = msi_domain_set_affinity;
72e257c6f05803 Thomas Gleixner   2024-06-23  115  	return true;
72e257c6f05803 Thomas Gleixner   2024-06-23  116  }
72e257c6f05803 Thomas Gleixner   2024-06-23  117  EXPORT_SYMBOL_GPL(msi_lib_init_dev_msi_info);
72e257c6f05803 Thomas Gleixner   2024-06-23  118  
72e257c6f05803 Thomas Gleixner   2024-06-23  119  /**
72e257c6f05803 Thomas Gleixner   2024-06-23  120   * msi_lib_irq_domain_select - Shared select function for NEXUS domains
72e257c6f05803 Thomas Gleixner   2024-06-23  121   * @d:		Pointer to the irq domain on which select is invoked
72e257c6f05803 Thomas Gleixner   2024-06-23  122   * @fwspec:	Firmware spec describing what is searched
72e257c6f05803 Thomas Gleixner   2024-06-23  123   * @bus_token:	The bus token for which a matching irq domain is looked up
72e257c6f05803 Thomas Gleixner   2024-06-23  124   *
72e257c6f05803 Thomas Gleixner   2024-06-23  125   * Returns:	%0 if @d is not what is being looked for
72e257c6f05803 Thomas Gleixner   2024-06-23  126   *
72e257c6f05803 Thomas Gleixner   2024-06-23  127   *		%1 if @d is either the domain which is directly searched for or
72e257c6f05803 Thomas Gleixner   2024-06-23  128   *		   if @d is providing the parent MSI domain for the functionality
72e257c6f05803 Thomas Gleixner   2024-06-23  129   *			 requested with @bus_token.
72e257c6f05803 Thomas Gleixner   2024-06-23  130   */
72e257c6f05803 Thomas Gleixner   2024-06-23  131  int msi_lib_irq_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec,
72e257c6f05803 Thomas Gleixner   2024-06-23  132  			      enum irq_domain_bus_token bus_token)
72e257c6f05803 Thomas Gleixner   2024-06-23  133  {
72e257c6f05803 Thomas Gleixner   2024-06-23  134  	const struct msi_parent_ops *ops = d->msi_parent_ops;
72e257c6f05803 Thomas Gleixner   2024-06-23  135  	u32 busmask = BIT(bus_token);
72e257c6f05803 Thomas Gleixner   2024-06-23  136  
880799fc7a3a12 Maxime Chevallier 2024-08-23  137  	if (!ops)
880799fc7a3a12 Maxime Chevallier 2024-08-23  138  		return 0;
880799fc7a3a12 Maxime Chevallier 2024-08-23  139  
72e257c6f05803 Thomas Gleixner   2024-06-23  140  	if (fwspec->fwnode != d->fwnode || fwspec->param_count != 0)
72e257c6f05803 Thomas Gleixner   2024-06-23  141  		return 0;
72e257c6f05803 Thomas Gleixner   2024-06-23  142  
72e257c6f05803 Thomas Gleixner   2024-06-23  143  	/* Handle pure domain searches */
72e257c6f05803 Thomas Gleixner   2024-06-23  144  	if (bus_token == ops->bus_select_token)
72e257c6f05803 Thomas Gleixner   2024-06-23  145  		return 1;
72e257c6f05803 Thomas Gleixner   2024-06-23  146  
880799fc7a3a12 Maxime Chevallier 2024-08-23  147  	return !!(ops->bus_select_mask & busmask);
72e257c6f05803 Thomas Gleixner   2024-06-23 @148  }

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

^ permalink raw reply

* [PATCH net-next] net: mana: Handle Reset Request from MANA NIC
From: Haiyang Zhang @ 2025-06-27 20:26 UTC (permalink / raw)
  To: linux-hyperv, netdev
  Cc: haiyangz, decui, stephen, kys, paulros, olaf, vkuznets, davem,
	wei.liu, edumazet, kuba, pabeni, leon, longli, ssengar,
	linux-rdma, daniel, john.fastabend, bpf, ast, hawk, tglx,
	shradhagupta, andrew+netdev, kotaranov, horms, linux-kernel

From: Haiyang Zhang <haiyangz@microsoft.com>

Upon receiving the Reset Request, pause the connection and clean up
queues, wait for the specified period, then resume the NIC.
In the cleanup phase, the HWC is no longer responding, so set hwc_timeout
to zero to skip waiting on the response.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 .../net/ethernet/microsoft/mana/gdma_main.c   | 127 ++++++++++++++----
 .../net/ethernet/microsoft/mana/hw_channel.c  |   4 +-
 drivers/net/ethernet/microsoft/mana/mana_en.c |  37 +++--
 include/net/mana/gdma.h                       |  10 ++
 4 files changed, 143 insertions(+), 35 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index ac2f39853bf4..4e344ff44ac1 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -10,6 +10,7 @@
 #include <linux/irqdomain.h>
 
 #include <net/mana/mana.h>
+#include <net/mana/hw_channel.h>
 
 struct dentry *mana_debugfs_root;
 
@@ -65,6 +66,24 @@ static void mana_gd_init_registers(struct pci_dev *pdev)
 		mana_gd_init_vf_regs(pdev);
 }
 
+/* Suppress logging when we set timeout to zero */
+bool mana_need_log(struct gdma_context *gc, int err)
+{
+	struct hw_channel_context *hwc;
+
+	if (err != -ETIMEDOUT)
+		return true;
+
+	if (!gc)
+		return true;
+
+	hwc = gc->hwc.driver_data;
+	if (hwc && hwc->hwc_timeout == 0)
+		return false;
+
+	return true;
+}
+
 static int mana_gd_query_max_resources(struct pci_dev *pdev)
 {
 	struct gdma_context *gc = pci_get_drvdata(pdev);
@@ -275,8 +294,9 @@ static int mana_gd_disable_queue(struct gdma_queue *queue)
 
 	err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
 	if (err || resp.hdr.status) {
-		dev_err(gc->dev, "Failed to disable queue: %d, 0x%x\n", err,
-			resp.hdr.status);
+		if (mana_need_log(gc, err))
+			dev_err(gc->dev, "Failed to disable queue: %d, 0x%x\n", err,
+				resp.hdr.status);
 		return err ? err : -EPROTO;
 	}
 
@@ -363,25 +383,12 @@ EXPORT_SYMBOL_NS(mana_gd_ring_cq, "NET_MANA");
 
 #define MANA_SERVICE_PERIOD 10
 
-struct mana_serv_work {
-	struct work_struct serv_work;
-	struct pci_dev *pdev;
-};
-
-static void mana_serv_func(struct work_struct *w)
+static void mana_serv_fpga(struct pci_dev *pdev)
 {
-	struct mana_serv_work *mns_wk;
 	struct pci_bus *bus, *parent;
-	struct pci_dev *pdev;
-
-	mns_wk = container_of(w, struct mana_serv_work, serv_work);
-	pdev = mns_wk->pdev;
 
 	pci_lock_rescan_remove();
 
-	if (!pdev)
-		goto out;
-
 	bus = pdev->bus;
 	if (!bus) {
 		dev_err(&pdev->dev, "MANA service: no bus\n");
@@ -402,7 +409,74 @@ static void mana_serv_func(struct work_struct *w)
 
 out:
 	pci_unlock_rescan_remove();
+}
+
+static void mana_serv_reset(struct pci_dev *pdev)
+{
+	struct gdma_context *gc = pci_get_drvdata(pdev);
+	struct hw_channel_context *hwc;
+
+	if (!gc) {
+		dev_err(&pdev->dev, "MANA service: no GC\n");
+		return;
+	}
+
+	hwc = gc->hwc.driver_data;
+	if (!hwc) {
+		dev_err(&pdev->dev, "MANA service: no HWC\n");
+		goto out;
+	}
+
+	/* HWC is not responding in this case, so don't wait */
+	hwc->hwc_timeout = 0;
+
+	dev_info(&pdev->dev, "MANA reset cycle start\n");
 
+	mana_gd_suspend(pdev, PMSG_SUSPEND);
+
+	msleep(MANA_SERVICE_PERIOD * 1000);
+
+	mana_gd_resume(pdev);
+
+	dev_info(&pdev->dev, "MANA reset cycle completed\n");
+
+out:
+	gc->in_service = false;
+}
+
+struct mana_serv_work {
+	struct work_struct serv_work;
+	struct pci_dev *pdev;
+	enum gdma_eqe_type type;
+};
+
+static void mana_serv_func(struct work_struct *w)
+{
+	struct mana_serv_work *mns_wk;
+	struct pci_dev *pdev;
+
+	mns_wk = container_of(w, struct mana_serv_work, serv_work);
+	pdev = mns_wk->pdev;
+
+	if (!pdev)
+		goto out;
+
+	switch (mns_wk->type) {
+	case GDMA_EQE_HWC_FPGA_RECONFIG:
+		mana_serv_fpga(pdev);
+		break;
+
+	case GDMA_EQE_HWC_RESET_REQUEST:
+		mana_serv_reset(pdev);
+		break;
+
+	default:
+		dev_err(&pdev->dev, "MANA service: unknown type %d\n",
+			mns_wk->type);
+		break;
+	}
+
+out:
 	pci_dev_put(pdev);
 	kfree(mns_wk);
 	module_put(THIS_MODULE);
@@ -459,6 +533,7 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)
 		break;
 
 	case GDMA_EQE_HWC_FPGA_RECONFIG:
+	case GDMA_EQE_HWC_RESET_REQUEST:
 		dev_info(gc->dev, "Recv MANA service type:%d\n", type);
 
 		if (gc->in_service) {
@@ -480,6 +555,7 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)
 		dev_info(gc->dev, "Start MANA service type:%d\n", type);
 		gc->in_service = true;
 		mns_wk->pdev = to_pci_dev(gc->dev);
+		mns_wk->type = type;
 		pci_dev_get(mns_wk->pdev);
 		INIT_WORK(&mns_wk->serv_work, mana_serv_func);
 		schedule_work(&mns_wk->serv_work);
@@ -631,7 +707,8 @@ int mana_gd_test_eq(struct gdma_context *gc, struct gdma_queue *eq)
 
 	err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
 	if (err) {
-		dev_err(dev, "test_eq failed: %d\n", err);
+		if (mana_need_log(gc, err))
+			dev_err(dev, "test_eq failed: %d\n", err);
 		goto out;
 	}
 
@@ -666,7 +743,7 @@ static void mana_gd_destroy_eq(struct gdma_context *gc, bool flush_evenets,
 
 	if (flush_evenets) {
 		err = mana_gd_test_eq(gc, queue);
-		if (err)
+		if (err && mana_need_log(gc, err))
 			dev_warn(gc->dev, "Failed to flush EQ: %d\n", err);
 	}
 
@@ -812,8 +889,9 @@ int mana_gd_destroy_dma_region(struct gdma_context *gc, u64 dma_region_handle)
 
 	err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
 	if (err || resp.hdr.status) {
-		dev_err(gc->dev, "Failed to destroy DMA region: %d, 0x%x\n",
-			err, resp.hdr.status);
+		if (mana_need_log(gc, err))
+			dev_err(gc->dev, "Failed to destroy DMA region: %d, 0x%x\n",
+				err, resp.hdr.status);
 		return -EPROTO;
 	}
 
@@ -1113,8 +1191,9 @@ int mana_gd_deregister_device(struct gdma_dev *gd)
 
 	err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
 	if (err || resp.hdr.status) {
-		dev_err(gc->dev, "Failed to deregister device: %d, 0x%x\n",
-			err, resp.hdr.status);
+		if (mana_need_log(gc, err))
+			dev_err(gc->dev, "Failed to deregister device: %d, 0x%x\n",
+				err, resp.hdr.status);
 		if (!err)
 			err = -EPROTO;
 	}
@@ -1912,7 +1991,7 @@ static void mana_gd_remove(struct pci_dev *pdev)
 }
 
 /* The 'state' parameter is not used. */
-static int mana_gd_suspend(struct pci_dev *pdev, pm_message_t state)
+int mana_gd_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct gdma_context *gc = pci_get_drvdata(pdev);
 
@@ -1928,7 +2007,7 @@ static int mana_gd_suspend(struct pci_dev *pdev, pm_message_t state)
  * fail -- if this happens, it's safer to just report an error than try to undo
  * what has been done.
  */
-static int mana_gd_resume(struct pci_dev *pdev)
+int mana_gd_resume(struct pci_dev *pdev)
 {
 	struct gdma_context *gc = pci_get_drvdata(pdev);
 	int err;
diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index 650d22654d49..ef072e24c46d 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -880,7 +880,9 @@ int mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len,
 
 	if (!wait_for_completion_timeout(&ctx->comp_event,
 					 (msecs_to_jiffies(hwc->hwc_timeout)))) {
-		dev_err(hwc->dev, "HWC: Request timed out!\n");
+		if (hwc->hwc_timeout != 0)
+			dev_err(hwc->dev, "HWC: Request timed out!\n");
+
 		err = -ETIMEDOUT;
 		goto out;
 	}
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 016fd808ccad..a7973651ae51 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -47,6 +47,15 @@ static const struct file_operations mana_dbg_q_fops = {
 	.read   = mana_dbg_q_read,
 };
 
+static bool mana_en_need_log(struct mana_port_context *apc, int err)
+{
+	if (apc && apc->ac && apc->ac->gdma_dev &&
+	    apc->ac->gdma_dev->gdma_context)
+		return mana_need_log(apc->ac->gdma_dev->gdma_context, err);
+	else
+		return true;
+}
+
 /* Microsoft Azure Network Adapter (MANA) functions */
 
 static int mana_open(struct net_device *ndev)
@@ -854,7 +863,8 @@ static int mana_send_request(struct mana_context *ac, void *in_buf,
 		if (err == -EOPNOTSUPP)
 			return err;
 
-		if (req->req.msg_type != MANA_QUERY_PHY_STAT)
+		if (req->req.msg_type != MANA_QUERY_PHY_STAT &&
+		    mana_need_log(gc, err))
 			dev_err(dev, "Failed to send mana message: %d, 0x%x\n",
 				err, resp->status);
 		return err ? err : -EPROTO;
@@ -931,8 +941,10 @@ static void mana_pf_deregister_hw_vport(struct mana_port_context *apc)
 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
 				sizeof(resp));
 	if (err) {
-		netdev_err(apc->ndev, "Failed to unregister hw vPort: %d\n",
-			   err);
+		if (mana_en_need_log(apc, err))
+			netdev_err(apc->ndev, "Failed to unregister hw vPort: %d\n",
+				   err);
+
 		return;
 	}
 
@@ -987,8 +999,10 @@ static void mana_pf_deregister_filter(struct mana_port_context *apc)
 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
 				sizeof(resp));
 	if (err) {
-		netdev_err(apc->ndev, "Failed to unregister filter: %d\n",
-			   err);
+		if (mana_en_need_log(apc, err))
+			netdev_err(apc->ndev, "Failed to unregister filter: %d\n",
+				   err);
+
 		return;
 	}
 
@@ -1218,7 +1232,9 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc,
 	err = mana_send_request(apc->ac, req, req_buf_size, &resp,
 				sizeof(resp));
 	if (err) {
-		netdev_err(ndev, "Failed to configure vPort RX: %d\n", err);
+		if (mana_en_need_log(apc, err))
+			netdev_err(ndev, "Failed to configure vPort RX: %d\n", err);
+
 		goto out;
 	}
 
@@ -1402,7 +1418,9 @@ void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type,
 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
 				sizeof(resp));
 	if (err) {
-		netdev_err(ndev, "Failed to destroy WQ object: %d\n", err);
+		if (mana_en_need_log(apc, err))
+			netdev_err(ndev, "Failed to destroy WQ object: %d\n", err);
+
 		return;
 	}
 
@@ -3067,11 +3085,10 @@ static int mana_dealloc_queues(struct net_device *ndev)
 
 	apc->rss_state = TRI_STATE_FALSE;
 	err = mana_config_rss(apc, TRI_STATE_FALSE, false, false);
-	if (err) {
+	if (err && mana_en_need_log(apc, err))
 		netdev_err(ndev, "Failed to disable vPort: %d\n", err);
-		return err;
-	}
 
+	/* Even in err case, still need to cleanup the vPort */
 	mana_destroy_vport(apc);
 
 	return 0;
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 92ab85061df0..57df78cfbf82 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -62,6 +62,7 @@ enum gdma_eqe_type {
 	GDMA_EQE_HWC_FPGA_RECONFIG	= 132,
 	GDMA_EQE_HWC_SOC_RECONFIG_DATA	= 133,
 	GDMA_EQE_HWC_SOC_SERVICE	= 134,
+	GDMA_EQE_HWC_RESET_REQUEST	= 135,
 	GDMA_EQE_RNIC_QP_FATAL		= 176,
 };
 
@@ -584,6 +585,9 @@ enum {
 /* Driver supports dynamic MSI-X vector allocation */
 #define GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT BIT(13)
 
+/* Driver can self reset on EQE notification */
+#define GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE BIT(14)
+
 /* Driver can self reset on FPGA Reconfig EQE notification */
 #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17)
 
@@ -594,6 +598,7 @@ enum {
 	 GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT | \
 	 GDMA_DRV_CAP_FLAG_1_DEV_LIST_HOLES_SUP | \
 	 GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \
+	 GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \
 	 GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE)
 
 #define GDMA_DRV_CAP_FLAGS2 0
@@ -921,4 +926,9 @@ void mana_unregister_debugfs(void);
 
 int mana_rdma_service_event(struct gdma_context *gc, enum gdma_service_type event);
 
+int mana_gd_suspend(struct pci_dev *pdev, pm_message_t state);
+int mana_gd_resume(struct pci_dev *pdev);
+
+bool mana_need_log(struct gdma_context *gc, int err);
+
 #endif /* _GDMA_H */
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH net-next v3 1/3] vsock: Add support for SIOCINQ ioctl
From: Xuewei Niu @ 2025-06-27 11:42 UTC (permalink / raw)
  To: decui
  Cc: davem, fupan.lfp, haiyangz, jasowang, kvm, kys, leonardi,
	linux-hyperv, linux-kernel, mst, netdev, niuxuewei.nxw,
	niuxuewei97, pabeni, sgarzare, stefanha, virtualization, wei.liu,
	xuanzhuo
In-Reply-To: <BL1PR21MB3115D30477067C46F5AC86C3BF45A@BL1PR21MB3115.namprd21.prod.outlook.com>

> > From: Xuewei Niu <niuxuewei97@gmail.com>
> > Sent: Wednesday, June 25, 2025 10:02 PM
> > > ...
> > > Maybe when you have it tested, post it here as proper patch, and Xuewei
> > > can include it in the next version of this series (of course with you as
> > > author, etc.). In this way will be easy to test/merge, since they are
> > > related.
> > >
> > > @Xuewei @Dexuan Is it okay for you?
> > 
> > Yeah, sounds good to me!
> > 
> > Thanks,
> > Xuewei
> 
> Hi Xuewei, Stefano, I posted the patch here:
> https://lore.kernel.org/virtualization/1751013889-4951-1-git-send-email-decui@microsoft.com/T/#u
> 
> Xuewei, please help to re-post this patch with the next version of your patchset.
> Feel free to add your Signed-off-by, if you need. 

I'll update my patchset and send it out. Thanks for your work!

Thanks,
Xuewei

> Thanks,
> Dexuan

^ permalink raw reply

* Re: [EXTERNAL] Re: [PATCH net-next v3 1/3] vsock: Add support for SIOCINQ ioctl
From: Stefano Garzarella @ 2025-06-27 11:01 UTC (permalink / raw)
  To: Dexuan Cui
  Cc: Xuewei Niu, davem@davemloft.net, fupan.lfp@antgroup.com,
	Haiyang Zhang, jasowang@redhat.com, kvm@vger.kernel.org,
	KY Srinivasan, leonardi@redhat.com, linux-hyperv@vger.kernel.org,
	linux-kernel@vger.kernel.org, mst@redhat.com,
	netdev@vger.kernel.org, niuxuewei.nxw@antgroup.com,
	pabeni@redhat.com, stefanha@redhat.com,
	virtualization@lists.linux.dev, wei.liu@kernel.org,
	xuanzhuo@linux.alibaba.com
In-Reply-To: <BL1PR21MB3115D30477067C46F5AC86C3BF45A@BL1PR21MB3115.namprd21.prod.outlook.com>

On Fri, Jun 27, 2025 at 08:50:46AM +0000, Dexuan Cui wrote:
>> From: Xuewei Niu <niuxuewei97@gmail.com>
>> Sent: Wednesday, June 25, 2025 10:02 PM
>> > ...
>> > Maybe when you have it tested, post it here as proper patch, and Xuewei
>> > can include it in the next version of this series (of course with you as
>> > author, etc.). In this way will be easy to test/merge, since they are
>> > related.
>> >
>> > @Xuewei @Dexuan Is it okay for you?
>>
>> Yeah, sounds good to me!
>>
>> Thanks,
>> Xuewei
>
>Hi Xuewei, Stefano, I posted the patch here:
>https://lore.kernel.org/virtualization/1751013889-4951-1-git-send-email-decui@microsoft.com/T/#u

Great, thanks!

>
>Xuewei, please help to re-post this patch with the next version of your patchset.
>Feel free to add your Signed-off-by, if you need.
>
>Thanks,
>Dexuan
>


^ permalink raw reply

* Re: [PATCH] firmware: smccc: support both conduits for getting hyp UUID
From: Sudeep Holla @ 2025-06-27  9:59 UTC (permalink / raw)
  To: Mark Rutland, Lorenzo Pieralisi, Anirudh Rayabharam
  Cc: Sudeep Holla, linux-hyperv, linux-arm-kernel, linux-kernel
In-Reply-To: <20250521094049.960056-1-anirudh@anirudhrb.com>

On Wed, 21 May 2025 09:40:48 +0000, Anirudh Rayabharam wrote:
> When Linux is running as the root partition under Microsoft Hypervisor
> (MSHV) a.k.a Hyper-V, smc is used as the conduit for smc calls.
> 
> Extend arm_smccc_hypervisor_has_uuid() to support this usecase. Use
> arm_smccc_1_1_invoke to retrieve and use the appropriate conduit instead
> of supporting only hvc.
> 
> [...]

Applied to sudeep.holla/linux (for-next/smccc/updates), thanks!

[1/1] firmware: smccc: support both conduits for getting hyp UUID
      https://git.kernel.org/sudeep.holla/c/1733432638f3
--
Regards,
Sudeep


^ permalink raw reply

* RE: [EXTERNAL] Re: [PATCH net-next v3 1/3] vsock: Add support for SIOCINQ ioctl
From: Dexuan Cui @ 2025-06-27  8:50 UTC (permalink / raw)
  To: Xuewei Niu, sgarzare@redhat.com
  Cc: davem@davemloft.net, fupan.lfp@antgroup.com, Haiyang Zhang,
	jasowang@redhat.com, kvm@vger.kernel.org, KY Srinivasan,
	leonardi@redhat.com, linux-hyperv@vger.kernel.org,
	linux-kernel@vger.kernel.org, mst@redhat.com,
	netdev@vger.kernel.org, niuxuewei.nxw@antgroup.com,
	pabeni@redhat.com, stefanha@redhat.com,
	virtualization@lists.linux.dev, wei.liu@kernel.org,
	xuanzhuo@linux.alibaba.com
In-Reply-To: <20250626050219.1847316-1-niuxuewei.nxw@antgroup.com>

> From: Xuewei Niu <niuxuewei97@gmail.com>
> Sent: Wednesday, June 25, 2025 10:02 PM
> > ...
> > Maybe when you have it tested, post it here as proper patch, and Xuewei
> > can include it in the next version of this series (of course with you as
> > author, etc.). In this way will be easy to test/merge, since they are
> > related.
> >
> > @Xuewei @Dexuan Is it okay for you?
> 
> Yeah, sounds good to me!
> 
> Thanks,
> Xuewei

Hi Xuewei, Stefano, I posted the patch here:
https://lore.kernel.org/virtualization/1751013889-4951-1-git-send-email-decui@microsoft.com/T/#u

Xuewei, please help to re-post this patch with the next version of your patchset.
Feel free to add your Signed-off-by, if you need. 

Thanks,
Dexuan

^ permalink raw reply

* [PATCH] hv_sock: Return the readable bytes in hvs_stream_has_data()
From: Dexuan Cui @ 2025-06-27  8:44 UTC (permalink / raw)
  To: niuxuewei97, kys, haiyangz, wei.liu, decui, sgarzare, davem,
	edumazet, kuba, pabeni, horms, linux-hyperv, virtualization,
	netdev, linux-kernel

When hv_sock was originally added, __vsock_stream_recvmsg() and
vsock_stream_has_data() actually only needed to know whether there
is any readable data or not, so hvs_stream_has_data() was written to
return 1 or 0 for simplicity.

However, now hvs_stream_has_data() should return the readable bytes
because vsock_data_ready() -> vsock_stream_has_data() needs to know the
actual bytes rather than a boolean value of 1 or 0.

The SIOCINQ ioctl support also needs hvs_stream_has_data() to return
the readable bytes.

Let hvs_stream_has_data() return the readable bytes of the payload in
the next host-to-guest VMBus hv_sock packet.

Note: there may be multpile incoming hv_sock packets pending in the
VMBus channel's ringbuffer, but so far there is not a VMBus API that
allows us to know all the readable bytes in total without reading and
caching the payload of the multiple packets, so let's just return the
readable bytes of the next single packet. In the future, we'll either
add a VMBus API that allows us to know the total readable bytes without
touching the data in the ringbuffer, or the hv_sock driver needs to
understand the VMBus packet format and parse the packets directly.

Signed-off-by: Dexuan Cui <decui@microsoft.com>
---

Hi maintainers, please don't take the patch for now.

Hi Xuewei Niu, please help to re-post this patch with the next version
of your patchset "vsock: Introduce SIOCINQ ioctl support". See
https://lore.kernel.org/virtualization/BL1PR21MB3115F69C544B0FAA145FA4EABF7BA@BL1PR21MB3115.namprd21.prod.outlook.com/#t
https://lore.kernel.org/virtualization/20250626050219.1847316-1-niuxuewei.nxw@antgroup.com/
Feel free to add your Signed-off-by, if you need.

 net/vmw_vsock/hyperv_transport.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c
index 31342ab502b4..64f1290a9ae7 100644
--- a/net/vmw_vsock/hyperv_transport.c
+++ b/net/vmw_vsock/hyperv_transport.c
@@ -694,15 +694,25 @@ static ssize_t hvs_stream_enqueue(struct vsock_sock *vsk, struct msghdr *msg,
 static s64 hvs_stream_has_data(struct vsock_sock *vsk)
 {
 	struct hvsock *hvs = vsk->trans;
+	bool need_refill = !hvs->recv_desc;
 	s64 ret;
 
 	if (hvs->recv_data_len > 0)
-		return 1;
+		return hvs->recv_data_len;
 
 	switch (hvs_channel_readable_payload(hvs->chan)) {
 	case 1:
-		ret = 1;
-		break;
+		if (!need_refill)
+			return -EIO;
+
+		hvs->recv_desc = hv_pkt_iter_first(hvs->chan);
+		if (!hvs->recv_desc)
+			return -ENOBUFS;
+
+		ret = hvs_update_recv_data(hvs);
+		if (ret)
+			return ret;
+		return hvs->recv_data_len;
 	case 0:
 		vsk->peer_shutdown |= SEND_SHUTDOWN;
 		ret = 0;
-- 
2.49.0


^ permalink raw reply related

* Re: [RFC PATCH 1/1] KVM: VMX: Use Hyper-V EPT flush for local TLB flushes
From: Vitaly Kuznetsov @ 2025-06-27  8:31 UTC (permalink / raw)
  To: Jeremi Piotrowski, Sean Christopherson, Paolo Bonzini, kvm
  Cc: Dave Hansen, linux-kernel, alanjiang, chinang.ma,
	andrea.pellegrini, Kevin Tian, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, linux-hyperv, Jeremi Piotrowski
In-Reply-To: <4266fc8f76c152a3ffcbb2d2ebafd608aa0fb949.1750432368.git.jpiotrowski@linux.microsoft.com>

Jeremi Piotrowski <jpiotrowski@linux.microsoft.com> writes:

> Use Hyper-V's HvCallFlushGuestPhysicalAddressSpace for local TLB flushes.
> This makes any KVM_REQ_TLB_FLUSH_CURRENT (such as on root alloc) visible to
> all CPUs which means we no longer need to do a KVM_REQ_TLB_FLUSH on CPU
> migration.
>
> The goal is to avoid invept-global in KVM_REQ_TLB_FLUSH. Hyper-V uses a
> shadow page table for the nested hypervisor (KVM) and has to invalidate all
> EPT roots when invept-global is issued. This has a performance impact on
> all nested VMs.  KVM issues KVM_REQ_TLB_FLUSH on CPU migration, and under
> load the performance hit causes vCPUs to use up more of their slice of CPU
> time, leading to more CPU migrations. This has a snowball effect and causes
> CPU usage spikes.
>
> By issuing the hypercall we are now guaranteed that any root modification
> that requires a local TLB flush becomes visible to all CPUs. The same
> hypercall is already used in kvm_arch_flush_remote_tlbs and
> kvm_arch_flush_remote_tlbs_range.  The KVM expectation is that roots are
> flushed locally on alloc and we achieve consistency on migration by
> flushing all roots - the new behavior of achieving consistency on alloc on
> Hyper-V is a superset of the expected guarantees. This makes the
> KVM_REQ_TLB_FLUSH on CPU migration no longer necessary on Hyper-V.

Sounds reasonable overall, my only concern (not sure if valid or not) is
that using the hypercall for local flushes is going to be more expensive
than invept-context we do today and thus while the performance is
improved for the scenario when vCPUs are migrating a lot, we will take a
hit in other cases.

>
> Coincidentally - we now match the behavior of SVM on Hyper-V.
>
> Signed-off-by: Jeremi Piotrowski <jpiotrowski@linux.microsoft.com>
> ---
>  arch/x86/include/asm/kvm_host.h |  1 +
>  arch/x86/kvm/vmx/vmx.c          | 20 +++++++++++++++++---
>  arch/x86/kvm/vmx/vmx_onhyperv.h |  6 ++++++
>  arch/x86/kvm/x86.c              |  3 +++
>  4 files changed, 27 insertions(+), 3 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index b4a391929cdb..d3acab19f425 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1077,6 +1077,7 @@ struct kvm_vcpu_arch {
>  
>  #if IS_ENABLED(CONFIG_HYPERV)
>  	hpa_t hv_root_tdp;
> +	bool hv_vmx_use_flush_guest_mapping;
>  #endif
>  };
>  
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 4953846cb30d..f537e0df56fc 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1485,8 +1485,12 @@ void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu)
>  		/*
>  		 * Flush all EPTP/VPID contexts, the new pCPU may have stale
>  		 * TLB entries from its previous association with the vCPU.
> +		 * Unless we are running on Hyper-V where we promotes local TLB

s,promotes,promote, or, as Sean doesn't like pronouns, 

"... where local TLB flushes are promoted ..."

> +		 * flushes to be visible across all CPUs so no need to do again
> +		 * on migration.
>  		 */
> -		kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
> +		if (!vmx_hv_use_flush_guest_mapping(vcpu))
> +			kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
>  
>  		/*
>  		 * Linux uses per-cpu TSS and GDT, so set these when switching
> @@ -3243,11 +3247,21 @@ void vmx_flush_tlb_current(struct kvm_vcpu *vcpu)
>  	if (!VALID_PAGE(root_hpa))
>  		return;
>  
> -	if (enable_ept)
> +	if (enable_ept) {
> +		/*
> +		 * hyperv_flush_guest_mapping() has the semantics of
> +		 * invept-single across all pCPUs. This makes root
> +		 * modifications consistent across pCPUs, so an invept-global
> +		 * on migration is no longer required.
> +		 */
> +		if (vmx_hv_use_flush_guest_mapping(vcpu))
> +			return (void)WARN_ON_ONCE(hyperv_flush_guest_mapping(root_hpa));
> +

HvCallFlushGuestPhysicalAddressSpace sounds like a heavy operation as it
affects all processors. Is there any visible perfomance impact of this
change when there are no migrations (e.g. with vCPU pinning)? Or do we
believe that Hyper-V actually handles invept-context the exact same way?

>  		ept_sync_context(construct_eptp(vcpu, root_hpa,
>  						mmu->root_role.level));
> -	else
> +	} else {
>  		vpid_sync_context(vmx_get_current_vpid(vcpu));
> +	}
>  }
>  
>  void vmx_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr)
> diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h
> index cdf8cbb69209..a5c64c90e49e 100644
> --- a/arch/x86/kvm/vmx/vmx_onhyperv.h
> +++ b/arch/x86/kvm/vmx/vmx_onhyperv.h
> @@ -119,6 +119,11 @@ static inline void evmcs_load(u64 phys_addr)
>  }
>  
>  void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
> +
> +static inline bool vmx_hv_use_flush_guest_mapping(struct kvm_vcpu *vcpu)
> +{
> +	return vcpu->arch.hv_vmx_use_flush_guest_mapping;
> +}
>  #else /* !IS_ENABLED(CONFIG_HYPERV) */
>  static __always_inline bool kvm_is_using_evmcs(void) { return false; }
>  static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
> @@ -128,6 +133,7 @@ static __always_inline u64 evmcs_read64(unsigned long field) { return 0; }
>  static __always_inline u32 evmcs_read32(unsigned long field) { return 0; }
>  static __always_inline u16 evmcs_read16(unsigned long field) { return 0; }
>  static inline void evmcs_load(u64 phys_addr) {}
> +static inline bool vmx_hv_use_flush_guest_mapping(struct kvm_vcpu *vcpu) { return false; }
>  #endif /* IS_ENABLED(CONFIG_HYPERV) */
>  
>  #endif /* __ARCH_X86_KVM_VMX_ONHYPERV_H__ */
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index b58a74c1722d..cbde795096a6 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -25,6 +25,7 @@
>  #include "tss.h"
>  #include "kvm_cache_regs.h"
>  #include "kvm_emulate.h"
> +#include "kvm_onhyperv.h"
>  #include "mmu/page_track.h"
>  #include "x86.h"
>  #include "cpuid.h"
> @@ -12390,6 +12391,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
>  
>  #if IS_ENABLED(CONFIG_HYPERV)
>  	vcpu->arch.hv_root_tdp = INVALID_PAGE;
> +	vcpu->arch.hv_vmx_use_flush_guest_mapping =
> +		(kvm_x86_ops.flush_remote_tlbs == hv_flush_remote_tlbs);
>  #endif
>  
>  	r = kvm_x86_call(vcpu_create)(vcpu);

-- 
Vitaly


^ permalink raw reply

* Re: [PATCH net-next v2] net: mana: Fix build errors when CONFIG_NET_SHAPER is disabled
From: patchwork-bot+netdevbpf @ 2025-06-27  0:20 UTC (permalink / raw)
  To: Erni Sri Satya Vennela
  Cc: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
	kuba, pabeni, linux-hyperv, netdev, linux-kernel
In-Reply-To: <1750851355-8067-1-git-send-email-ernis@linux.microsoft.com>

Hello:

This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Wed, 25 Jun 2025 04:35:55 -0700 you wrote:
> Fix build errors when CONFIG_NET_SHAPER is disabled, including:
> 
> drivers/net/ethernet/microsoft/mana/mana_en.c:804:10: error:
> 'const struct net_device_ops' has no member named 'net_shaper_ops'
> 
>      804 |         .net_shaper_ops         = &mana_shaper_ops,
> 
> [...]

Here is the summary with links:
  - [net-next,v2] net: mana: Fix build errors when CONFIG_NET_SHAPER is disabled
    https://git.kernel.org/netdev/net-next/c/11cd02069872

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* [PATCH 16/16] PCI: vmd: Switch to msi_create_parent_irq_domain()
From: Nam Cao @ 2025-06-26 14:48 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, linux-pci, linux-kernel, Karthikeyan Mitran,
	Hou Zhiqiang, Thomas Petazzoni, Pali Rohár,
	K . Y . Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Joyce Ooi,
	Jim Quinlan, Nicolas Saenz Julienne, Florian Fainelli,
	Broadcom internal kernel review list, Ray Jui, Scott Branden,
	Ryder Lee, Jianjun Wang, Marek Vasut, Yoshihiro Shimoda,
	Michal Simek, Daire McNamara, Nirmal Patel, Jonathan Derrick,
	Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
	linux-hyperv, linux-rpi-kernel, linux-mediatek, linux-renesas-soc
  Cc: Nam Cao
In-Reply-To: <cover.1750858083.git.namcao@linutronix.de>

Move away from the legacy MSI domain setup, switch to use
msi_create_parent_irq_domain().

Signed-off-by: Nam Cao <namcao@linutronix.de>
---
Cc: Nirmal Patel <nirmal.patel@linux.intel.com>
Cc: Jonathan Derrick <jonathan.derrick@linux.dev>
---
 drivers/pci/controller/Kconfig |   1 +
 drivers/pci/controller/vmd.c   | 160 +++++++++++++++++----------------
 2 files changed, 82 insertions(+), 79 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 8f56ffd029ba2..41748d083b933 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -156,6 +156,7 @@ config PCI_IXP4XX
 config VMD
 	depends on PCI_MSI && X86_64 && !UML
 	tristate "Intel Volume Management Device Driver"
+	select IRQ_MSI_LIB
 	help
 	  Adds support for the Intel Volume Management Device (VMD). VMD is a
 	  secondary PCI host bridge that allows PCI Express root ports,
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index d9b893bf4e456..38693a9487d9b 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -7,6 +7,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqchip/irq-msi-lib.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/msi.h>
@@ -174,9 +175,6 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 	msg->arch_addr_lo.destid_0_7 = index_from_irqs(vmd, irq);
 }
 
-/*
- * We rely on MSI_FLAG_USE_DEF_CHIP_OPS to set the IRQ mask/unmask ops.
- */
 static void vmd_irq_enable(struct irq_data *data)
 {
 	struct vmd_irq *vmdirq = data->chip_data;
@@ -186,7 +184,11 @@ static void vmd_irq_enable(struct irq_data *data)
 		list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
 		vmdirq->enabled = true;
 	}
+}
 
+static void vmd_pci_msi_enable(struct irq_data *data)
+{
+	vmd_irq_enable(data->parent_data);
 	data->chip->irq_unmask(data);
 }
 
@@ -194,8 +196,6 @@ static void vmd_irq_disable(struct irq_data *data)
 {
 	struct vmd_irq *vmdirq = data->chip_data;
 
-	data->chip->irq_mask(data);
-
 	scoped_guard(raw_spinlock_irqsave, &list_lock) {
 		if (vmdirq->enabled) {
 			list_del_rcu(&vmdirq->node);
@@ -204,19 +204,17 @@ static void vmd_irq_disable(struct irq_data *data)
 	}
 }
 
+static void vmd_pci_msi_disable(struct irq_data *data)
+{
+	data->chip->irq_mask(data);
+	vmd_irq_disable(data->parent_data);
+}
+
 static struct irq_chip vmd_msi_controller = {
 	.name			= "VMD-MSI",
-	.irq_enable		= vmd_irq_enable,
-	.irq_disable		= vmd_irq_disable,
 	.irq_compose_msi_msg	= vmd_compose_msi_msg,
 };
 
-static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
-				     msi_alloc_info_t *arg)
-{
-	return 0;
-}
-
 /*
  * XXX: We can be even smarter selecting the best IRQ once we solve the
  * affinity problem.
@@ -250,100 +248,110 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
 	return &vmd->irqs[best];
 }
 
-static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
-			unsigned int virq, irq_hw_number_t hwirq,
-			msi_alloc_info_t *arg)
+static void vmd_msi_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs);
+
+static int vmd_msi_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs,
+			 void *arg)
 {
-	struct msi_desc *desc = arg->desc;
-	struct vmd_dev *vmd = vmd_from_bus(msi_desc_to_pci_dev(desc)->bus);
-	struct vmd_irq *vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
+	struct msi_desc *desc = ((msi_alloc_info_t *)arg)->desc;
+	struct vmd_dev *vmd = domain->host_data;
+	struct vmd_irq *vmdirq;
 
-	if (!vmdirq)
-		return -ENOMEM;
+	for (int i = 0; i < nr_irqs; ++i) {
+		vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
+		if (!vmdirq) {
+			vmd_msi_free(domain, virq, i);
+			return -ENOMEM;
+		}
 
-	INIT_LIST_HEAD(&vmdirq->node);
-	vmdirq->irq = vmd_next_irq(vmd, desc);
-	vmdirq->virq = virq;
+		INIT_LIST_HEAD(&vmdirq->node);
+		vmdirq->irq = vmd_next_irq(vmd, desc);
+		vmdirq->virq = virq + i;
+
+		irq_domain_set_info(domain, virq + i, vmdirq->irq->virq, &vmd_msi_controller,
+				    vmdirq, handle_untracked_irq, vmd, NULL);
+	}
 
-	irq_domain_set_info(domain, virq, vmdirq->irq->virq, info->chip, vmdirq,
-			    handle_untracked_irq, vmd, NULL);
 	return 0;
 }
 
-static void vmd_msi_free(struct irq_domain *domain,
-			struct msi_domain_info *info, unsigned int virq)
+static void vmd_msi_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs)
 {
 	struct vmd_irq *vmdirq = irq_get_chip_data(virq);
 
-	synchronize_srcu(&vmdirq->irq->srcu);
+	for (int i = 0; i < nr_irqs; ++i) {
+		synchronize_srcu(&vmdirq->irq->srcu);
 
-	/* XXX: Potential optimization to rebalance */
-	scoped_guard(raw_spinlock_irq, &list_lock)
-		vmdirq->irq->count--;
+		/* XXX: Potential optimization to rebalance */
+		scoped_guard(raw_spinlock_irq, &list_lock)
+			vmdirq->irq->count--;
 
-	kfree(vmdirq);
+		kfree(vmdirq);
+	}
 }
 
-static int vmd_msi_prepare(struct irq_domain *domain, struct device *dev,
-			   int nvec, msi_alloc_info_t *arg)
+static const struct irq_domain_ops vmd_msi_domain_ops = {
+	.alloc		= vmd_msi_alloc,
+	.free		= vmd_msi_free,
+};
+
+static bool vmd_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+				  struct irq_domain *real_parent, struct msi_domain_info *info)
 {
-	struct pci_dev *pdev = to_pci_dev(dev);
-	struct vmd_dev *vmd = vmd_from_bus(pdev->bus);
+	if (WARN_ON_ONCE(info->bus_token != DOMAIN_BUS_PCI_DEVICE_MSIX))
+		return false;
 
-	if (nvec > vmd->msix_count)
-		return vmd->msix_count;
+	if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
+		return false;
 
-	memset(arg, 0, sizeof(*arg));
-	return 0;
+	info->chip->irq_enable		= vmd_pci_msi_enable;
+	info->chip->irq_disable		= vmd_pci_msi_disable;
+	return true;
 }
 
-static void vmd_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
-{
-	arg->desc = desc;
-}
+#define VMD_MSI_FLAGS_SUPPORTED		(MSI_GENERIC_FLAGS_MASK | MSI_FLAG_PCI_MSIX)
+#define VMD_MSI_FLAGS_REQUIRED		(MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_NO_AFFINITY)
 
-static struct msi_domain_ops vmd_msi_domain_ops = {
-	.get_hwirq	= vmd_get_hwirq,
-	.msi_init	= vmd_msi_init,
-	.msi_free	= vmd_msi_free,
-	.msi_prepare	= vmd_msi_prepare,
-	.set_desc	= vmd_set_desc,
+static const struct msi_parent_ops vmd_msi_parent_ops = {
+	.supported_flags	= VMD_MSI_FLAGS_SUPPORTED,
+	.required_flags		= VMD_MSI_FLAGS_REQUIRED,
+	.bus_select_token	= DOMAIN_BUS_VMD_MSI,
+	.bus_select_mask	= MATCH_PCI_MSI,
+	.prefix			= "VMD-",
+	.init_dev_msi_info	= vmd_init_dev_msi_info,
 };
 
-static struct msi_domain_info vmd_msi_domain_info = {
-	.flags		= MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-			  MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX,
-	.ops		= &vmd_msi_domain_ops,
-	.chip		= &vmd_msi_controller,
-};
-
-static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable)
-{
-	u16 reg;
-
-	pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, &reg);
-	reg = enable ? (reg & ~VMCONFIG_MSI_REMAP) :
-		       (reg | VMCONFIG_MSI_REMAP);
-	pci_write_config_word(vmd->dev, PCI_REG_VMCONFIG, reg);
-}
-
 static int vmd_create_irq_domain(struct vmd_dev *vmd)
 {
-	struct fwnode_handle *fn;
+	struct irq_domain_info info = {
+		.size		= vmd->msix_count,
+		.ops		= &vmd_msi_domain_ops,
+		.host_data	= vmd,
+	};
 
-	fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);
-	if (!fn)
+	info.fwnode = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);
+	if (!info.fwnode)
 		return -ENODEV;
 
-	vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, NULL);
+	vmd->irq_domain = msi_create_parent_irq_domain(&info, &vmd_msi_parent_ops);
 	if (!vmd->irq_domain) {
-		irq_domain_free_fwnode(fn);
+		irq_domain_free_fwnode(info.fwnode);
 		return -ENODEV;
 	}
 
 	return 0;
 }
 
+static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable)
+{
+	u16 reg;
+
+	pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, &reg);
+	reg = enable ? (reg & ~VMCONFIG_MSI_REMAP) :
+		       (reg | VMCONFIG_MSI_REMAP);
+	pci_write_config_word(vmd->dev, PCI_REG_VMCONFIG, reg);
+}
+
 static void vmd_remove_irq_domain(struct vmd_dev *vmd)
 {
 	/*
@@ -874,12 +882,6 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
 		ret = vmd_create_irq_domain(vmd);
 		if (ret)
 			return ret;
-
-		/*
-		 * Override the IRQ domain bus token so the domain can be
-		 * distinguished from a regular PCI/MSI domain.
-		 */
-		irq_domain_update_bus_token(vmd->irq_domain, DOMAIN_BUS_VMD_MSI);
 	} else {
 		vmd_set_msi_remapping(vmd, false);
 	}
-- 
2.39.5


^ permalink raw reply related

* [PATCH 15/16] PCI: vmd: Convert to lock guards
From: Nam Cao @ 2025-06-26 14:48 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, linux-pci, linux-kernel, Karthikeyan Mitran,
	Hou Zhiqiang, Thomas Petazzoni, Pali Rohár,
	K . Y . Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Joyce Ooi,
	Jim Quinlan, Nicolas Saenz Julienne, Florian Fainelli,
	Broadcom internal kernel review list, Ray Jui, Scott Branden,
	Ryder Lee, Jianjun Wang, Marek Vasut, Yoshihiro Shimoda,
	Michal Simek, Daire McNamara, Nirmal Patel, Jonathan Derrick,
	Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
	linux-hyperv, linux-rpi-kernel, linux-mediatek, linux-renesas-soc
  Cc: Nam Cao
In-Reply-To: <cover.1750858083.git.namcao@linutronix.de>

Convert lock/unlock pairs to lock guard and tidy up the code.

Signed-off-by: Nam Cao <namcao@linutronix.de>
---
Cc: Nirmal Patel <nirmal.patel@linux.intel.com>
Cc: Jonathan Derrick <jonathan.derrick@linux.dev>
---
 drivers/pci/controller/vmd.c | 73 ++++++++++++++----------------------
 1 file changed, 29 insertions(+), 44 deletions(-)

diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index 375ce9d6d9f6a..d9b893bf4e456 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -180,13 +180,12 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 static void vmd_irq_enable(struct irq_data *data)
 {
 	struct vmd_irq *vmdirq = data->chip_data;
-	unsigned long flags;
 
-	raw_spin_lock_irqsave(&list_lock, flags);
-	WARN_ON(vmdirq->enabled);
-	list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
-	vmdirq->enabled = true;
-	raw_spin_unlock_irqrestore(&list_lock, flags);
+	scoped_guard(raw_spinlock_irqsave, &list_lock) {
+		WARN_ON(vmdirq->enabled);
+		list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
+		vmdirq->enabled = true;
+	}
 
 	data->chip->irq_unmask(data);
 }
@@ -194,16 +193,15 @@ static void vmd_irq_enable(struct irq_data *data)
 static void vmd_irq_disable(struct irq_data *data)
 {
 	struct vmd_irq *vmdirq = data->chip_data;
-	unsigned long flags;
 
 	data->chip->irq_mask(data);
 
-	raw_spin_lock_irqsave(&list_lock, flags);
-	if (vmdirq->enabled) {
-		list_del_rcu(&vmdirq->node);
-		vmdirq->enabled = false;
+	scoped_guard(raw_spinlock_irqsave, &list_lock) {
+		if (vmdirq->enabled) {
+			list_del_rcu(&vmdirq->node);
+			vmdirq->enabled = false;
+		}
 	}
-	raw_spin_unlock_irqrestore(&list_lock, flags);
 }
 
 static struct irq_chip vmd_msi_controller = {
@@ -225,7 +223,6 @@ static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
  */
 static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *desc)
 {
-	unsigned long flags;
 	int i, best;
 
 	if (vmd->msix_count == 1 + vmd->first_vec)
@@ -242,13 +239,13 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
 		return &vmd->irqs[vmd->first_vec];
 	}
 
-	raw_spin_lock_irqsave(&list_lock, flags);
-	best = vmd->first_vec + 1;
-	for (i = best; i < vmd->msix_count; i++)
-		if (vmd->irqs[i].count < vmd->irqs[best].count)
-			best = i;
-	vmd->irqs[best].count++;
-	raw_spin_unlock_irqrestore(&list_lock, flags);
+	scoped_guard(raw_spinlock_irq, &list_lock) {
+		best = vmd->first_vec + 1;
+		for (i = best; i < vmd->msix_count; i++)
+			if (vmd->irqs[i].count < vmd->irqs[best].count)
+				best = i;
+		vmd->irqs[best].count++;
+	}
 
 	return &vmd->irqs[best];
 }
@@ -277,14 +274,12 @@ static void vmd_msi_free(struct irq_domain *domain,
 			struct msi_domain_info *info, unsigned int virq)
 {
 	struct vmd_irq *vmdirq = irq_get_chip_data(virq);
-	unsigned long flags;
 
 	synchronize_srcu(&vmdirq->irq->srcu);
 
 	/* XXX: Potential optimization to rebalance */
-	raw_spin_lock_irqsave(&list_lock, flags);
-	vmdirq->irq->count--;
-	raw_spin_unlock_irqrestore(&list_lock, flags);
+	scoped_guard(raw_spinlock_irq, &list_lock)
+		vmdirq->irq->count--;
 
 	kfree(vmdirq);
 }
@@ -387,29 +382,24 @@ static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg,
 {
 	struct vmd_dev *vmd = vmd_from_bus(bus);
 	void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
-	unsigned long flags;
-	int ret = 0;
 
 	if (!addr)
 		return -EFAULT;
 
-	raw_spin_lock_irqsave(&vmd->cfg_lock, flags);
+	guard(raw_spinlock_irqsave)(&vmd->cfg_lock);
 	switch (len) {
 	case 1:
 		*value = readb(addr);
-		break;
+		return 0;
 	case 2:
 		*value = readw(addr);
-		break;
+		return 0;
 	case 4:
 		*value = readl(addr);
-		break;
+		return 0;
 	default:
-		ret = -EINVAL;
-		break;
+		return -EINVAL;
 	}
-	raw_spin_unlock_irqrestore(&vmd->cfg_lock, flags);
-	return ret;
 }
 
 /*
@@ -422,32 +412,27 @@ static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg,
 {
 	struct vmd_dev *vmd = vmd_from_bus(bus);
 	void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
-	unsigned long flags;
-	int ret = 0;
 
 	if (!addr)
 		return -EFAULT;
 
-	raw_spin_lock_irqsave(&vmd->cfg_lock, flags);
+	guard(raw_spinlock_irqsave)(&vmd->cfg_lock);
 	switch (len) {
 	case 1:
 		writeb(value, addr);
 		readb(addr);
-		break;
+		return 0;
 	case 2:
 		writew(value, addr);
 		readw(addr);
-		break;
+		return 0;
 	case 4:
 		writel(value, addr);
 		readl(addr);
-		break;
+		return 0;
 	default:
-		ret = -EINVAL;
-		break;
+		return -EINVAL;
 	}
-	raw_spin_unlock_irqrestore(&vmd->cfg_lock, flags);
-	return ret;
 }
 
 static struct pci_ops vmd_ops = {
-- 
2.39.5


^ permalink raw reply related

* [PATCH 14/16] PCI: hv: Switch to msi_create_parent_irq_domain()
From: Nam Cao @ 2025-06-26 14:48 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, linux-pci, linux-kernel, Karthikeyan Mitran,
	Hou Zhiqiang, Thomas Petazzoni, Pali Rohár,
	K . Y . Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Joyce Ooi,
	Jim Quinlan, Nicolas Saenz Julienne, Florian Fainelli,
	Broadcom internal kernel review list, Ray Jui, Scott Branden,
	Ryder Lee, Jianjun Wang, Marek Vasut, Yoshihiro Shimoda,
	Michal Simek, Daire McNamara, Nirmal Patel, Jonathan Derrick,
	Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
	linux-hyperv, linux-rpi-kernel, linux-mediatek, linux-renesas-soc
  Cc: Nam Cao
In-Reply-To: <cover.1750858083.git.namcao@linutronix.de>

Move away from the legacy MSI domain setup, switch to use
msi_create_parent_irq_domain().

Signed-off-by: Nam Cao <namcao@linutronix.de>
---
Cc: K. Y. Srinivasan <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Wei Liu <wei.liu@kernel.org>
Cc: Dexuan Cui <decui@microsoft.com>
Cc: linux-hyperv@vger.kernel.org
---
 drivers/pci/Kconfig                 |  1 +
 drivers/pci/controller/pci-hyperv.c | 98 +++++++++++++++++++++++------
 2 files changed, 80 insertions(+), 19 deletions(-)

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 9c0e4aaf4e8cb..9a249c65aedcd 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -223,6 +223,7 @@ config PCI_HYPERV
 	tristate "Hyper-V PCI Frontend"
 	depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI && SYSFS
 	select PCI_HYPERV_INTERFACE
+	select IRQ_MSI_LIB
 	help
 	  The PCI device frontend driver allows the kernel to import arbitrary
 	  PCI devices from a PCI backend to support PCI driver domains.
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index ef5d655a0052c..3a24fadddb83b 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -44,6 +44,7 @@
 #include <linux/delay.h>
 #include <linux/semaphore.h>
 #include <linux/irq.h>
+#include <linux/irqchip/irq-msi-lib.h>
 #include <linux/msi.h>
 #include <linux/hyperv.h>
 #include <linux/refcount.h>
@@ -508,7 +509,6 @@ struct hv_pcibus_device {
 	struct list_head children;
 	struct list_head dr_list;
 
-	struct msi_domain_info msi_info;
 	struct irq_domain *irq_domain;
 
 	struct workqueue_struct *wq;
@@ -1687,7 +1687,7 @@ static void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info,
 	struct msi_desc *msi = irq_data_get_msi_desc(irq_data);
 
 	pdev = msi_desc_to_pci_dev(msi);
-	hbus = info->data;
+	hbus = domain->host_data;
 	int_desc = irq_data_get_irq_chip_data(irq_data);
 	if (!int_desc)
 		return;
@@ -1705,7 +1705,6 @@ static void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info,
 
 static void hv_irq_mask(struct irq_data *data)
 {
-	pci_msi_mask_irq(data);
 	if (data->parent_data->chip->irq_mask)
 		irq_chip_mask_parent(data);
 }
@@ -1716,7 +1715,6 @@ static void hv_irq_unmask(struct irq_data *data)
 
 	if (data->parent_data->chip->irq_unmask)
 		irq_chip_unmask_parent(data);
-	pci_msi_unmask_irq(data);
 }
 
 struct compose_comp_ctxt {
@@ -2101,6 +2099,44 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 	msg->data = 0;
 }
 
+static bool hv_pcie_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+				      struct irq_domain *real_parent, struct msi_domain_info *info)
+{
+	struct irq_chip *chip = info->chip;
+
+	if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
+		return false;
+
+	info->ops->msi_prepare = hv_msi_prepare;
+
+	chip->irq_set_affinity = irq_chip_set_affinity_parent;
+
+	if (IS_ENABLED(CONFIG_X86))
+		chip->flags |= IRQCHIP_MOVE_DEFERRED;
+
+	return true;
+}
+
+#define HV_PCIE_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS		| \
+				    MSI_FLAG_USE_DEF_CHIP_OPS		| \
+				    MSI_FLAG_PCI_MSI_MASK_PARENT)
+#define HV_PCIE_MSI_FLAGS_SUPPORTED (MSI_FLAG_MULTI_PCI_MSI		| \
+				     MSI_FLAG_PCI_MSIX			| \
+				     MSI_GENERIC_FLAGS_MASK)
+
+static const struct msi_parent_ops hv_pcie_msi_parent_ops = {
+	.required_flags		= HV_PCIE_MSI_FLAGS_REQUIRED,
+	.supported_flags	= HV_PCIE_MSI_FLAGS_SUPPORTED,
+	.bus_select_token	= DOMAIN_BUS_PCI_MSI,
+#ifdef CONFIG_X86
+	.chip_flags		= MSI_CHIP_FLAG_SET_ACK,
+#elif defined(CONFIG_ARM64)
+	.chip_flags		= MSI_CHIP_FLAG_SET_EOI,
+#endif
+	.prefix			= "HV-",
+	.init_dev_msi_info	= hv_pcie_init_dev_msi_info,
+};
+
 /* HW Interrupt Chip Descriptor */
 static struct irq_chip hv_msi_irq_chip = {
 	.name			= "Hyper-V PCIe MSI",
@@ -2108,7 +2144,6 @@ static struct irq_chip hv_msi_irq_chip = {
 	.irq_set_affinity	= irq_chip_set_affinity_parent,
 #ifdef CONFIG_X86
 	.irq_ack		= irq_chip_ack_parent,
-	.flags			= IRQCHIP_MOVE_DEFERRED,
 #elif defined(CONFIG_ARM64)
 	.irq_eoi		= irq_chip_eoi_parent,
 #endif
@@ -2116,9 +2151,37 @@ static struct irq_chip hv_msi_irq_chip = {
 	.irq_unmask		= hv_irq_unmask,
 };
 
-static struct msi_domain_ops hv_msi_ops = {
-	.msi_prepare	= hv_msi_prepare,
-	.msi_free	= hv_msi_free,
+static int hv_pcie_domain_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs,
+			       void *arg)
+{
+	/* TODO: move the content of hv_compose_msi_msg() in here */
+	int ret;
+
+	ret = irq_domain_alloc_irqs_parent(d, virq, nr_irqs, arg);
+	if (ret < 0)
+		return ret;
+
+	for (int i = 0; i < nr_irqs; i++) {
+		irq_domain_set_info(d, virq + i, 0, &hv_msi_irq_chip, NULL, FLOW_HANDLER, NULL,
+				    FLOW_NAME);
+	}
+
+	return 0;
+}
+
+static void hv_pcie_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs)
+{
+	struct msi_domain_info *info = d->host_data;
+
+	for (int i = 0; i < nr_irqs; i++)
+		hv_msi_free(d, info, virq + i);
+
+	irq_domain_free_irqs_top(d, virq, nr_irqs);
+}
+
+static const struct irq_domain_ops hv_pcie_domain_ops = {
+	.alloc	= hv_pcie_domain_alloc,
+	.free	= hv_pcie_domain_free,
 };
 
 /**
@@ -2136,17 +2199,14 @@ static struct msi_domain_ops hv_msi_ops = {
  */
 static int hv_pcie_init_irq_domain(struct hv_pcibus_device *hbus)
 {
-	hbus->msi_info.chip = &hv_msi_irq_chip;
-	hbus->msi_info.ops = &hv_msi_ops;
-	hbus->msi_info.flags = (MSI_FLAG_USE_DEF_DOM_OPS |
-		MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI |
-		MSI_FLAG_PCI_MSIX);
-	hbus->msi_info.handler = FLOW_HANDLER;
-	hbus->msi_info.handler_name = FLOW_NAME;
-	hbus->msi_info.data = hbus;
-	hbus->irq_domain = pci_msi_create_irq_domain(hbus->fwnode,
-						     &hbus->msi_info,
-						     hv_pci_get_root_domain());
+	struct irq_domain_info info = {
+		.fwnode		= hbus->fwnode,
+		.ops		= &hv_pcie_domain_ops,
+		.host_data	= hbus,
+		.parent		= hv_pci_get_root_domain(),
+	};
+
+	hbus->irq_domain = msi_create_parent_irq_domain(&info, &hv_pcie_msi_parent_ops);
 	if (!hbus->irq_domain) {
 		dev_err(&hbus->hdev->device,
 			"Failed to build an MSI IRQ domain\n");
-- 
2.39.5


^ permalink raw reply related

* [PATCH 13/16] PCI: plda: Switch to msi_create_parent_irq_domain()
From: Nam Cao @ 2025-06-26 14:48 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, linux-pci, linux-kernel, Karthikeyan Mitran,
	Hou Zhiqiang, Thomas Petazzoni, Pali Rohár,
	K . Y . Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Joyce Ooi,
	Jim Quinlan, Nicolas Saenz Julienne, Florian Fainelli,
	Broadcom internal kernel review list, Ray Jui, Scott Branden,
	Ryder Lee, Jianjun Wang, Marek Vasut, Yoshihiro Shimoda,
	Michal Simek, Daire McNamara, Nirmal Patel, Jonathan Derrick,
	Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
	linux-hyperv, linux-rpi-kernel, linux-mediatek, linux-renesas-soc
  Cc: Nam Cao
In-Reply-To: <cover.1750858083.git.namcao@linutronix.de>

Move away from the legacy MSI domain setup, switch to use
msi_create_parent_irq_domain().

Signed-off-by: Nam Cao <namcao@linutronix.de>
---
Cc: Daire McNamara <daire.mcnamara@microchip.com>
---
 drivers/pci/controller/plda/Kconfig          |  1 +
 drivers/pci/controller/plda/pcie-plda-host.c | 44 ++++++++++----------
 drivers/pci/controller/plda/pcie-plda.h      |  1 -
 3 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/pci/controller/plda/Kconfig b/drivers/pci/controller/plda/Kconfig
index c0e14146d7e45..62120101139cb 100644
--- a/drivers/pci/controller/plda/Kconfig
+++ b/drivers/pci/controller/plda/Kconfig
@@ -5,6 +5,7 @@ menu "PLDA-based PCIe controllers"
 
 config PCIE_PLDA_HOST
 	bool
+	select IRQ_MSI_LIB
 
 config PCIE_MICROCHIP_HOST
 	tristate "Microchip AXI PCIe controller"
diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
index 3abedf723215c..92866840875e3 100644
--- a/drivers/pci/controller/plda/pcie-plda-host.c
+++ b/drivers/pci/controller/plda/pcie-plda-host.c
@@ -11,6 +11,7 @@
 #include <linux/align.h>
 #include <linux/bitfield.h>
 #include <linux/irqchip/chained_irq.h>
+#include <linux/irqchip/irq-msi-lib.h>
 #include <linux/irqdomain.h>
 #include <linux/msi.h>
 #include <linux/pci_regs.h>
@@ -134,17 +135,19 @@ static const struct irq_domain_ops msi_domain_ops = {
 	.free	= plda_irq_msi_domain_free,
 };
 
-static struct irq_chip plda_msi_irq_chip = {
-	.name = "PLDA PCIe MSI",
-	.irq_ack = irq_chip_ack_parent,
-	.irq_mask = pci_msi_mask_irq,
-	.irq_unmask = pci_msi_unmask_irq,
-};
-
-static struct msi_domain_info plda_msi_domain_info = {
-	.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-		 MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX,
-	.chip = &plda_msi_irq_chip,
+#define PLDA_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS	| \
+				 MSI_FLAG_USE_DEF_CHIP_OPS	| \
+				 MSI_FLAG_NO_AFFINITY)
+#define PLDA_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK	| \
+				  MSI_FLAG_PCI_MSIX)
+
+static const struct msi_parent_ops plda_msi_parent_ops = {
+	.required_flags		= PLDA_MSI_FLAGS_REQUIRED,
+	.supported_flags	= PLDA_MSI_FLAGS_SUPPORTED,
+	.chip_flags		= MSI_CHIP_FLAG_SET_ACK,
+	.bus_select_token	= DOMAIN_BUS_PCI_MSI,
+	.prefix			= "PLDA-",
+	.init_dev_msi_info	= msi_lib_init_dev_msi_info,
 };
 
 static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
@@ -155,21 +158,19 @@ static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
 
 	mutex_init(&port->msi.lock);
 
-	msi->dev_domain = irq_domain_create_linear(NULL, msi->num_vectors, &msi_domain_ops, port);
+	struct irq_domain_info info = {
+		.fwnode		= fwnode,
+		.ops		= &msi_domain_ops,
+		.host_data	= port,
+		.size		= msi->num_vectors,
+	};
+
+	msi->dev_domain = msi_create_parent_irq_domain(&info, &plda_msi_parent_ops);
 	if (!msi->dev_domain) {
 		dev_err(dev, "failed to create IRQ domain\n");
 		return -ENOMEM;
 	}
 
-	msi->msi_domain = pci_msi_create_irq_domain(fwnode,
-						    &plda_msi_domain_info,
-						    msi->dev_domain);
-	if (!msi->msi_domain) {
-		dev_err(dev, "failed to create MSI domain\n");
-		irq_domain_remove(msi->dev_domain);
-		return -ENOMEM;
-	}
-
 	return 0;
 }
 
@@ -563,7 +564,6 @@ static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie)
 	irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
 	irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
 
-	irq_domain_remove(pcie->msi.msi_domain);
 	irq_domain_remove(pcie->msi.dev_domain);
 
 	irq_domain_remove(pcie->intx_domain);
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index 61ece26065ea0..6b8665df7bf0f 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -164,7 +164,6 @@ struct plda_pcie_host_ops {
 
 struct plda_msi {
 	struct mutex lock;		/* Protect used bitmap */
-	struct irq_domain *msi_domain;
 	struct irq_domain *dev_domain;
 	u32 num_vectors;
 	u64 vector_phy;
-- 
2.39.5


^ permalink raw reply related

* [PATCH 12/16] PCI: xilinx: Switch to msi_create_parent_irq_domain()
From: Nam Cao @ 2025-06-26 14:48 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, linux-pci, linux-kernel, Karthikeyan Mitran,
	Hou Zhiqiang, Thomas Petazzoni, Pali Rohár,
	K . Y . Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Joyce Ooi,
	Jim Quinlan, Nicolas Saenz Julienne, Florian Fainelli,
	Broadcom internal kernel review list, Ray Jui, Scott Branden,
	Ryder Lee, Jianjun Wang, Marek Vasut, Yoshihiro Shimoda,
	Michal Simek, Daire McNamara, Nirmal Patel, Jonathan Derrick,
	Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
	linux-hyperv, linux-rpi-kernel, linux-mediatek, linux-renesas-soc
  Cc: Nam Cao
In-Reply-To: <cover.1750858083.git.namcao@linutronix.de>

Move away from the legacy MSI domain setup, switch to use
msi_create_parent_irq_domain().

Signed-off-by: Nam Cao <namcao@linutronix.de>
---
Cc: Michal Simek <michal.simek@amd.com>
Cc: linux-arm-kernel@lists.infradead.org
---
 drivers/pci/controller/Kconfig       |  1 +
 drivers/pci/controller/pcie-xilinx.c | 55 ++++++++++++++++------------
 2 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 118ff622fa69e..8f56ffd029ba2 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -322,6 +322,7 @@ config PCIE_XILINX
 	bool "Xilinx AXI PCIe controller"
 	depends on OF
 	depends on PCI_MSI
+	select IRQ_MSI_LIB
 	help
 	  Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
 	  Host Bridge driver.
diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
index e36aa874bae92..ddc2ab6c48b9b 100644
--- a/drivers/pci/controller/pcie-xilinx.c
+++ b/drivers/pci/controller/pcie-xilinx.c
@@ -12,6 +12,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqchip/irq-msi-lib.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -203,11 +204,6 @@ static void xilinx_msi_top_irq_ack(struct irq_data *d)
 	 */
 }
 
-static struct irq_chip xilinx_msi_top_chip = {
-	.name		= "PCIe MSI",
-	.irq_ack	= xilinx_msi_top_irq_ack,
-};
-
 static void xilinx_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
 	struct xilinx_pcie *pcie = irq_data_get_irq_chip_data(data);
@@ -264,29 +260,43 @@ static const struct irq_domain_ops xilinx_msi_domain_ops = {
 	.free	= xilinx_msi_domain_free,
 };
 
-static struct msi_domain_info xilinx_msi_info = {
-	.flags	= MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-		  MSI_FLAG_NO_AFFINITY,
-	.chip	= &xilinx_msi_top_chip,
+static bool xilinx_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+				     struct irq_domain *real_parent, struct msi_domain_info *info)
+{
+	struct irq_chip *chip = info->chip;
+
+	if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
+		return false;
+
+	chip->irq_ack = xilinx_msi_top_irq_ack;
+	return true;
+}
+
+#define XILINX_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS	| \
+				   MSI_FLAG_USE_DEF_CHIP_OPS	| \
+				   MSI_FLAG_NO_AFFINITY)
+
+static const struct msi_parent_ops xilinx_msi_parent_ops = {
+	.required_flags		= XILINX_MSI_FLAGS_REQUIRED,
+	.supported_flags	= MSI_GENERIC_FLAGS_MASK,
+	.bus_select_token	= DOMAIN_BUS_PCI_MSI,
+	.prefix			= "xilinx-",
+	.init_dev_msi_info	= xilinx_init_dev_msi_info,
 };
 
 static int xilinx_allocate_msi_domains(struct xilinx_pcie *pcie)
 {
 	struct fwnode_handle *fwnode = dev_fwnode(pcie->dev);
-	struct irq_domain *parent;
-
-	parent = irq_domain_create_linear(fwnode, XILINX_NUM_MSI_IRQS,
-					  &xilinx_msi_domain_ops, pcie);
-	if (!parent) {
-		dev_err(pcie->dev, "failed to create IRQ domain\n");
-		return -ENOMEM;
-	}
-	irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS);
-
-	pcie->msi_domain = pci_msi_create_irq_domain(fwnode, &xilinx_msi_info, parent);
+	struct irq_domain_info info = {
+		.fwnode		= fwnode,
+		.ops		= &xilinx_msi_domain_ops,
+		.host_data	= pcie,
+		.size		= XILINX_NUM_MSI_IRQS,
+	};
+
+	pcie->msi_domain = msi_create_parent_irq_domain(&info, &xilinx_msi_parent_ops);
 	if (!pcie->msi_domain) {
 		dev_err(pcie->dev, "failed to create MSI domain\n");
-		irq_domain_remove(parent);
 		return -ENOMEM;
 	}
 
@@ -295,10 +305,7 @@ static int xilinx_allocate_msi_domains(struct xilinx_pcie *pcie)
 
 static void xilinx_free_msi_domains(struct xilinx_pcie *pcie)
 {
-	struct irq_domain *parent = pcie->msi_domain->parent;
-
 	irq_domain_remove(pcie->msi_domain);
-	irq_domain_remove(parent);
 }
 
 /* INTx Functions */
-- 
2.39.5


^ permalink raw reply related

* [PATCH 11/16] PCI: xilinx-nwl: Switch to msi_create_parent_irq_domain()
From: Nam Cao @ 2025-06-26 14:48 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, linux-pci, linux-kernel, Karthikeyan Mitran,
	Hou Zhiqiang, Thomas Petazzoni, Pali Rohár,
	K . Y . Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Joyce Ooi,
	Jim Quinlan, Nicolas Saenz Julienne, Florian Fainelli,
	Broadcom internal kernel review list, Ray Jui, Scott Branden,
	Ryder Lee, Jianjun Wang, Marek Vasut, Yoshihiro Shimoda,
	Michal Simek, Daire McNamara, Nirmal Patel, Jonathan Derrick,
	Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
	linux-hyperv, linux-rpi-kernel, linux-mediatek, linux-renesas-soc
  Cc: Nam Cao
In-Reply-To: <cover.1750858083.git.namcao@linutronix.de>

Move away from the legacy MSI domain setup, switch to use
msi_create_parent_irq_domain().

Signed-off-by: Nam Cao <namcao@linutronix.de>
---
Cc: Michal Simek <michal.simek@amd.com>
Cc: linux-arm-kernel@lists.infradead.org
---
 drivers/pci/controller/Kconfig           |  1 +
 drivers/pci/controller/pcie-xilinx-nwl.c | 45 ++++++++++++------------
 2 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index c9b6180239732..118ff622fa69e 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -342,6 +342,7 @@ config PCIE_XILINX_NWL
 	bool "Xilinx NWL PCIe controller"
 	depends on ARCH_ZYNQMP || COMPILE_TEST
 	depends on PCI_MSI
+	select IRQ_MSI_LIB
 	help
 	 Say 'Y' here if you want kernel support for Xilinx
 	 NWL PCIe controller. The controller can act as Root Port
diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c
index c8b05477b7198..de76c836915f0 100644
--- a/drivers/pci/controller/pcie-xilinx-nwl.c
+++ b/drivers/pci/controller/pcie-xilinx-nwl.c
@@ -10,6 +10,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqchip/irq-msi-lib.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -145,7 +146,6 @@
 #define LINK_WAIT_USLEEP_MAX           100000
 
 struct nwl_msi {			/* MSI information */
-	struct irq_domain *msi_domain;
 	DECLARE_BITMAP(bitmap, INT_PCI_MSI_NR);
 	struct irq_domain *dev_domain;
 	struct mutex lock;		/* protect bitmap variable */
@@ -418,19 +418,22 @@ static const struct irq_domain_ops intx_domain_ops = {
 };
 
 #ifdef CONFIG_PCI_MSI
-static struct irq_chip nwl_msi_irq_chip = {
-	.name = "nwl_pcie:msi",
-	.irq_enable = pci_msi_unmask_irq,
-	.irq_disable = pci_msi_mask_irq,
-	.irq_mask = pci_msi_mask_irq,
-	.irq_unmask = pci_msi_unmask_irq,
-};
 
-static struct msi_domain_info nwl_msi_domain_info = {
-	.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-		 MSI_FLAG_NO_AFFINITY | MSI_FLAG_MULTI_PCI_MSI,
-	.chip = &nwl_msi_irq_chip,
+#define NWL_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS	| \
+				MSI_FLAG_USE_DEF_CHIP_OPS	| \
+				MSI_FLAG_NO_AFFINITY)
+
+#define NWL_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK		| \
+				 MSI_FLAG_MULTI_PCI_MSI)
+
+static const struct msi_parent_ops nwl_msi_parent_ops = {
+	.required_flags		= NWL_MSI_FLAGS_REQUIRED,
+	.supported_flags	= NWL_MSI_FLAGS_SUPPORTED,
+	.bus_select_token	= DOMAIN_BUS_PCI_MSI,
+	.prefix			= "nwl-",
+	.init_dev_msi_info	= msi_lib_init_dev_msi_info,
 };
+
 #endif
 
 static void nwl_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
@@ -497,20 +500,18 @@ static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie)
 	struct device *dev = pcie->dev;
 	struct fwnode_handle *fwnode = of_fwnode_handle(dev->of_node);
 	struct nwl_msi *msi = &pcie->msi;
-
-	msi->dev_domain = irq_domain_create_linear(NULL, INT_PCI_MSI_NR, &dev_msi_domain_ops, pcie);
+	struct irq_domain_info info = {
+		.fwnode		= fwnode,
+		.ops		= &dev_msi_domain_ops,
+		.host_data	= pcie,
+		.size		= INT_PCI_MSI_NR,
+	};
+
+	msi->dev_domain  = msi_create_parent_irq_domain(&info, &nwl_msi_parent_ops);
 	if (!msi->dev_domain) {
 		dev_err(dev, "failed to create dev IRQ domain\n");
 		return -ENOMEM;
 	}
-	msi->msi_domain = pci_msi_create_irq_domain(fwnode,
-						    &nwl_msi_domain_info,
-						    msi->dev_domain);
-	if (!msi->msi_domain) {
-		dev_err(dev, "failed to create msi IRQ domain\n");
-		irq_domain_remove(msi->dev_domain);
-		return -ENOMEM;
-	}
 #endif
 	return 0;
 }
-- 
2.39.5


^ permalink raw reply related


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