* [PATCH net-next, v2] net: mana: Force full-page RX buffers for 4K page size on specific systems.
From: Dipayaan Roy @ 2026-03-06 13:33 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, dipayanroy
On certain systems configured with 4K PAGE_SIZE, utilizing page_pool
fragments for RX buffers results in a significant throughput regression.
Profiling reveals that this regression correlates with high overhead in the
fragment allocation and reference counting paths on these specific
platforms, rendering the multi-buffer-per-page strategy counterproductive.
To mitigate this, bypass the page_pool fragment path and force a single RX
packet per page allocation when all the following conditions are met:
1. The system is configured with a 4K PAGE_SIZE.
2. A processor-specific quirk is detected via SMBIOS Type 4 data.
This approach restores expected line-rate performance by ensuring
predictable RX refill behavior on affected hardware.
There is no behavioral change for systems using larger page sizes
(16K/64K), or platforms where this processor-specific quirk do not
apply.
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
Changes in v2:
- separate reading string index and the string, remove inline.
---
---
.../net/ethernet/microsoft/mana/gdma_main.c | 133 ++++++++++++++++++
drivers/net/ethernet/microsoft/mana/mana_en.c | 23 ++-
include/net/mana/gdma.h | 9 ++
3 files changed, 163 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index aef8612b73cb..05fecc00a90c 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -9,6 +9,7 @@
#include <linux/msi.h>
#include <linux/irqdomain.h>
#include <linux/export.h>
+#include <linux/dmi.h>
#include <net/mana/mana.h>
#include <net/mana/hw_channel.h>
@@ -1959,6 +1960,128 @@ static bool mana_is_pf(unsigned short dev_id)
return dev_id == MANA_PF_DEVICE_ID;
}
+/*
+ * Table for Processor Version strings found from SMBIOS Type 4 information,
+ * for processors that needs to force single RX buffer per page quirk for
+ * meeting line rate performance with ARM64 + 4K pages.
+ * Note: These strings are exactly matched with version fetched from SMBIOS.
+ */
+static const char * const mana_single_rxbuf_per_page_quirk_tbl[] = {
+ "Cobalt 200",
+};
+
+/* On some systems with 4K PAGE_SIZE, page_pool RX fragments can
+ * trigger a throughput regression. Hence identify those processors
+ * from the extracted SMBIOS table and apply the quirk to forces one
+ * RX buffer per page to avoid the fragment allocation/refcounting
+ * overhead in the RX refill path for those processors only.
+ */
+static bool mana_needs_single_rxbuf_per_page(struct gdma_context *gc)
+{
+ int i = 0;
+ const char *ver = gc->processor_version;
+
+ if (!ver)
+ return false;
+
+ if (PAGE_SIZE != SZ_4K)
+ return false;
+
+ while (i < ARRAY_SIZE(mana_single_rxbuf_per_page_quirk_tbl)) {
+ if (!strcmp(ver, mana_single_rxbuf_per_page_quirk_tbl[i]))
+ return true;
+ i++;
+ }
+
+ return false;
+}
+
+static void mana_get_proc_ver_strno(const struct dmi_header *hdr, void *data)
+{
+ struct gdma_context *gc = data;
+ const u8 *d = (const u8 *)hdr;
+
+ /* We are only looking for Type 4: Processor Information */
+ if (hdr->type != SMBIOS_TYPE_4_PROCESSOR_INFO)
+ return;
+
+ /* Ensure the record is long enough to contain the Processor Version
+ * field
+ */
+ if (hdr->length <= SMBIOS_TYPE4_PROC_VERSION_OFFSET)
+ return;
+
+ /* The 'Processor Version' string is located at index pointed by
+ * SMBIOS_TYPE4_PROC_VERSION_OFFSET. Make a copy of the index.
+ * There could be multiple Type 4 tables so read and store the
+ * processor version index found the first time.
+ */
+ if (gc->proc_ver_strno)
+ return;
+
+ gc->proc_ver_strno = d[SMBIOS_TYPE4_PROC_VERSION_OFFSET];
+}
+
+static const char *mana_dmi_string_nosave(const struct dmi_header *hdr, u8 s)
+{
+ const char *bp = (const char *)hdr + hdr->length;
+
+ if (!s)
+ return NULL;
+
+ /* String numbers start at 1 */
+ while (--s > 0 && *bp)
+ bp += strlen(bp) + 1;
+
+ if (!*bp)
+ return NULL;
+
+ return bp;
+}
+
+static void mana_fetch_proc_ver_string(const struct dmi_header *hdr,
+ void *data)
+{
+ struct gdma_context *gc = data;
+ const char *ver;
+
+ /* We are only looking for Type 4: Processor Information */
+ if (hdr->type != SMBIOS_TYPE_4_PROCESSOR_INFO)
+ return;
+
+ /* Extract proc version found the first time only */
+ if (!gc->proc_ver_strno || gc->processor_version)
+ return;
+
+ ver = mana_dmi_string_nosave(hdr, gc->proc_ver_strno);
+ if (ver)
+ gc->processor_version = kstrdup(ver, GFP_KERNEL);
+}
+
+/* Check and initialize all processor optimizations/quirks here */
+static bool mana_init_processor_optimization(struct gdma_context *gc)
+{
+ bool opt_initialized = false;
+
+ gc->proc_ver_strno = 0;
+ gc->processor_version = NULL;
+
+ dmi_walk(mana_get_proc_ver_strno, gc);
+ if (!gc->proc_ver_strno)
+ return false;
+
+ dmi_walk(mana_fetch_proc_ver_string, gc);
+ if (!gc->processor_version)
+ return false;
+
+ if (mana_needs_single_rxbuf_per_page(gc)) {
+ gc->force_full_page_rx_buffer = true;
+ opt_initialized = true;
+ }
+
+ return opt_initialized;
+}
+
static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct gdma_context *gc;
@@ -2013,6 +2136,11 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
gc->mana_pci_debugfs = debugfs_create_dir(pci_slot_name(pdev->slot),
mana_debugfs_root);
+ if (mana_init_processor_optimization(gc))
+ dev_info(&pdev->dev,
+ "Processor specific optimization initialized on: %s\n",
+ gc->processor_version);
+
err = mana_gd_setup(pdev);
if (err)
goto unmap_bar;
@@ -2055,6 +2183,8 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_iounmap(pdev, bar0_va);
free_gc:
pci_set_drvdata(pdev, NULL);
+ kfree(gc->processor_version);
+ gc->processor_version = NULL;
vfree(gc);
release_region:
pci_release_regions(pdev);
@@ -2110,6 +2240,9 @@ static void mana_gd_remove(struct pci_dev *pdev)
pci_iounmap(pdev, gc->bar0_va);
+ kfree(gc->processor_version);
+ gc->processor_version = NULL;
+
vfree(gc);
pci_release_regions(pdev);
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index a868c28c8280..38f94f7619ad 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -744,6 +744,26 @@ static void *mana_get_rxbuf_pre(struct mana_rxq *rxq, dma_addr_t *da)
return va;
}
+static bool
+mana_use_single_rxbuf_per_page(struct mana_port_context *apc, u32 mtu)
+{
+ struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
+
+ /* On some systems with 4K PAGE_SIZE, page_pool RX fragments can
+ * trigger a throughput regression. Hence forces one RX buffer per page
+ * to avoid the fragment allocation/refcounting overhead in the RX
+ * refill path for those processors only.
+ */
+ if (gc->force_full_page_rx_buffer)
+ return true;
+
+ /* For xdp and jumbo frames make sure only one packet fits per page. */
+ if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc))
+ return true;
+
+ return false;
+}
+
/* Get RX buffer's data size, alloc size, XDP headroom based on MTU */
static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
int mtu, u32 *datasize, u32 *alloc_size,
@@ -754,8 +774,7 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
/* Calculate datasize first (consistent across all cases) */
*datasize = mtu + ETH_HLEN;
- /* For xdp and jumbo frames make sure only one packet fits per page */
- if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc)) {
+ if (mana_use_single_rxbuf_per_page(apc, mtu)) {
if (mana_xdp_get(apc)) {
*headroom = XDP_PACKET_HEADROOM;
*alloc_size = PAGE_SIZE;
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index ec17004b10c0..be56b347f3f6 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -9,6 +9,12 @@
#include "shm_channel.h"
+/* SMBIOS Type 4: Processor Information table */
+#define SMBIOS_TYPE_4_PROCESSOR_INFO 4
+
+/* Byte offset containing the Processor Version string number.*/
+#define SMBIOS_TYPE4_PROC_VERSION_OFFSET 0x10
+
#define GDMA_STATUS_MORE_ENTRIES 0x00000105
#define GDMA_STATUS_CMD_UNSUPPORTED 0xffffffff
@@ -444,6 +450,9 @@ struct gdma_context {
struct workqueue_struct *service_wq;
unsigned long flags;
+ u8 *processor_version;
+ u8 proc_ver_strno;
+ bool force_full_page_rx_buffer;
};
static inline bool mana_gd_is_mana(struct gdma_dev *gd)
--
2.34.1
^ permalink raw reply related
* Re: [PATCH net-next] net: mana: Force full-page RX buffers for 4K page size on specific systems.
From: Dipayaan Roy @ 2026-03-06 13:25 UTC (permalink / raw)
To: Paolo Abeni
Cc: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, leon, longli, kotaranov, horms, shradhagupta, ssengar,
ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, dipayanroy
In-Reply-To: <03ac38dc-69c5-4641-98ea-5679465c0b7f@redhat.com>
On Tue, Mar 03, 2026 at 12:56:35PM +0100, Paolo Abeni wrote:
> On 2/27/26 11:15 AM, Dipayaan Roy wrote:
> > diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
> > index 91c418097284..a53a8921050b 100644
> > --- a/drivers/net/ethernet/microsoft/mana/mana_en.c
> > +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
> > @@ -748,6 +748,26 @@ static void *mana_get_rxbuf_pre(struct mana_rxq *rxq, dma_addr_t *da)
> > return va;
> > }
> >
> > +static inline bool
> > +mana_use_single_rxbuf_per_page(struct mana_port_context *apc, u32 mtu)
> > +{
>
> I almost forgot: please avoid the 'inline' keyword in .c files. This is
> function used only once, should be inlined by the compiler anyway.
>
Ack, will remove it in v2.
> > + struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
> > +
> > + /* On some systems with 4K PAGE_SIZE, page_pool RX fragments can
> > + * trigger a throughput regression. Hence forces one RX buffer per page
> > + * to avoid the fragment allocation/refcounting overhead in the RX
> > + * refill path for those processors only.
> > + */
> > + if (gc->force_full_page_rx_buffer)
> > + return true;
>
> Side note: since you could keep the above flag up2date according to the
> current mtu and xdp configuration and just test it in the data path.
>
If not an issue, would like to keep it this way for better readability.
> /P
>
Regrads
^ permalink raw reply
* Re: [PATCH net-next] net: mana: Force full-page RX buffers for 4K page size on specific systems.
From: Dipayaan Roy @ 2026-03-06 13:12 UTC (permalink / raw)
To: Paolo Abeni
Cc: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, leon, longli, kotaranov, horms, shradhagupta, ssengar,
ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, dipayanroy
In-Reply-To: <81b7e296-0cfe-4c24-ac97-7f6c712aa0e9@redhat.com>
On Tue, Mar 03, 2026 at 11:56:29AM +0100, Paolo Abeni wrote:
> On 2/27/26 11:15 AM, Dipayaan Roy wrote:
> > On certain systems configured with 4K PAGE_SIZE, utilizing page_pool
> > fragments for RX buffers results in a significant throughput regression.
> > Profiling reveals that this regression correlates with high overhead in the
> > fragment allocation and reference counting paths on these specific
> > platforms, rendering the multi-buffer-per-page strategy counterproductive.
> >
> > To mitigate this, bypass the page_pool fragment path and force a single RX
> > packet per page allocation when all the following conditions are met:
> > 1. The system is configured with a 4K PAGE_SIZE.
> > 2. A processor-specific quirk is detected via SMBIOS Type 4 data.
> >
> > This approach restores expected line-rate performance by ensuring
> > predictable RX refill behavior on affected hardware.
> >
> > There is no behavioral change for systems using larger page sizes
> > (16K/64K), or platforms where this processor-specific quirk do not
> > apply.
> >
> > Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
> > ---
> > .../net/ethernet/microsoft/mana/gdma_main.c | 120 ++++++++++++++++++
> > drivers/net/ethernet/microsoft/mana/mana_en.c | 23 +++-
> > include/net/mana/gdma.h | 10 ++
> > 3 files changed, 151 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> > index 0055c231acf6..26bbe736a770 100644
> > --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> > +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> > @@ -9,6 +9,7 @@
> > #include <linux/msi.h>
> > #include <linux/irqdomain.h>
> > #include <linux/export.h>
> > +#include <linux/dmi.h>
> >
> > #include <net/mana/mana.h>
> > #include <net/mana/hw_channel.h>
> > @@ -1955,6 +1956,115 @@ static bool mana_is_pf(unsigned short dev_id)
> > return dev_id == MANA_PF_DEVICE_ID;
> > }
> >
> > +/*
> > + * Table for Processor Version strings found from SMBIOS Type 4 information,
> > + * for processors that needs to force single RX buffer per page quirk for
> > + * meeting line rate performance with ARM64 + 4K pages.
> > + * Note: These strings are exactly matched with version fetched from SMBIOS.
> > + */
> > +static const char * const mana_single_rxbuf_per_page_quirk_tbl[] = {
> > + "Cobalt 200",
> > +};
> > +
> > +static const char *smbios_get_string(const struct dmi_header *hdr, u8 idx)
> > +{
> > + const u8 *start, *end;
> > + u8 i;
> > +
> > + /* Indexing starts from 1. */
> > + if (!idx)
> > + return NULL;
> > +
> > + start = (const u8 *)hdr + hdr->length;
> > + end = start + SMBIOS_STR_AREA_MAX;
> > +
> > + for (i = 1; i < idx; i++) {
> > + while (start < end && *start)
> > + start++;
> > + if (start < end)
> > + start++;
> > + if (start + 1 < end && start[0] == 0 && start[1] == 0)
> > + return NULL;
> > + }
> > +
> > + if (start >= end || *start == 0)
> > + return NULL;
> > +
> > + return (const char *)start;
>
> If I read correctly, the above sort of duplicate dmi_decode_table().
>
Yes, its not exported.
> I think you are better of:
> - use the mana_get_proc_ver_from_smbios() decoder to store the
> SMBIOS_TYPE4_PROC_VERSION_OFFSET index into gd
> - do a 2nd walk with a different decoder to fetch the string at the
> specified index.
Sure, will implement the 2nd walk for fetching string in v2.
>
> /P
Thank you Paolo, for the comments, and apologies in my delay in response as this week I am on-call.
I will send out v2 with the changes suggested.
Regards
^ permalink raw reply
* RE: [PATCH 4/4] mshv: Pre-deposit pages for SLAT creation
From: mhklkml @ 2026-03-06 4:15 UTC (permalink / raw)
To: 'Michael Kelley', 'Stanislav Kinsburskii', kys,
haiyangz, wei.liu, decui, longli
Cc: linux-hyperv, linux-kernel
In-Reply-To: <SN6PR02MB4157C408547E59A469C5CE08D47DA@SN6PR02MB4157.namprd02.prod.outlook.com>
From: Michael Kelley <mhklinux@outlook.com> Sent: Thursday, March 5, 2026 11:45 AM
>
> From: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Sent: Tuesday, March
3, 2026 4:24 PM
> >
> > Deposit enough pages up front to avoid guest address space region creation
> > failures due to low memory. This also speeds up guest creation.
> >
> > Calculate the required number of pages based on the guest's physical
> > address space size, rounded up to 1 GB chunks. Even the smallest guests are
> > assumed to need at least 1 GB worth of deposits. This is because every
> > guest requires tens of megabytes of deposited pages for hypervisor
> > overhead, making smaller deposits impractical.
> >
> > Estimating in 1 GB chunks prevents over-depositing for larger guests while
> > accepting some over-deposit for smaller ones. This trade-off keeps the
> > estimate close to actual needs for larger guests.
> >
> > Also withdraw the deposited pages if address space region creation fails.
> >
> > Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> > ---
> > drivers/hv/mshv_root_main.c | 25 +++++++++++++++++++++++--
> > 1 file changed, 23 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> > index 48c842b6938d..cb5b4505f8eb 100644
> > --- a/drivers/hv/mshv_root_main.c
> > +++ b/drivers/hv/mshv_root_main.c
> > @@ -39,6 +39,7 @@
> > #define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
> > #define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
> > #define MSHV_VP_DEPOSIT_PAGES (1 * SZ_1M >> PAGE_SHIFT)
> > +#define MSHV_1G_DEPOSIT_PAGES (6 * SZ_1M >> PAGE_SHIFT)
> >
> > MODULE_AUTHOR("Microsoft");
> > MODULE_LICENSE("GPL");
> > @@ -1324,6 +1325,18 @@ static int mshv_prepare_pinned_region(struct
mshv_mem_region *region)
> > return ret;
> > }
> >
> > +static u64
> > +mshv_region_deposit_slat_pages(struct mshv_mem_region *region)
>
> Same nit about the function name. This one seems like it will "deposit slat pages".
>
> > +{
> > + u64 region_in_gbs, slat_pages;
> > +
> > + /* SLAT needs 6 MB per 1 GB of address space. */
> > + region_in_gbs = DIV_ROUND_UP(region->nr_pages << HV_HYP_PAGE_SHIFT, SZ_1G);
>
> This local variable "region_in_gbs" is computed in units of bytes.
Ignore this comment and the following one in this function. I saw the
ROUND_UP(), but somehow failed to see that it was DIV_ROUND_UP(). :-(
Michael
>
> > + slat_pages = region_in_gbs * MSHV_1G_DEPOSIT_PAGES;
>
> But here region_in_gbs is used as if it were in units of Gbytes. So the
> slat_pages return value is much larger than intended.
>
> > +
> > + return slat_pages;
> > +}
> > +
> > /*
> > * This maps two things: guest RAM and for pci passthru mmio space.
> > *
> > @@ -1364,6 +1377,11 @@ mshv_map_user_memory(struct mshv_partition *partition,
> > if (ret)
> > return ret;
> >
> > + ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
> > + mshv_region_deposit_slat_pages(region));
> > + if (ret)
> > + goto free_region;
> > +
> > switch (region->mreg_type) {
> > case MSHV_REGION_TYPE_MEM_PINNED:
> > ret = mshv_prepare_pinned_region(region);
> > @@ -1392,7 +1410,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
> > region->hv_map_flags, ret);
> >
> > if (ret)
> > - goto errout;
> > + goto withdraw_memory;
> >
> > spin_lock(&partition->pt_mem_regions_lock);
> > hlist_add_head(®ion->hnode, &partition->pt_mem_regions);
> > @@ -1400,7 +1418,10 @@ mshv_map_user_memory(struct mshv_partition *partition,
> >
> > return 0;
> >
> > -errout:
> > +withdraw_memory:
> > + hv_call_withdraw_memory(mshv_region_deposit_slat_pages(region),
> > + NUMA_NO_NODE, partition->pt_id);
>
> Again, for an L1VH partition, the actual number of pages deposited would
> be 2x what mshv_region_deposit_slat_pages() returns.
>
> > +free_region:
> > vfree(region);
> > return ret;
> > }
> >
> >
>
^ permalink raw reply
* Re: [PATCH 4/4] mshv: Pre-deposit pages for SLAT creation
From: Mukesh R @ 2026-03-06 3:54 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys, haiyangz, wei.liu, decui, longli
Cc: linux-hyperv, linux-kernel
In-Reply-To: <177258383107.229866.16867493994305727391.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
On 3/3/26 16:23, Stanislav Kinsburskii wrote:
> Deposit enough pages up front to avoid guest address space region creation
> failures due to low memory. This also speeds up guest creation.
>
> Calculate the required number of pages based on the guest's physical
> address space size, rounded up to 1 GB chunks. Even the smallest guests are
> assumed to need at least 1 GB worth of deposits. This is because every
> guest requires tens of megabytes of deposited pages for hypervisor
> overhead, making smaller deposits impractical.
>
> Estimating in 1 GB chunks prevents over-depositing for larger guests while
> accepting some over-deposit for smaller ones. This trade-off keeps the
> estimate close to actual needs for larger guests.
>
> Also withdraw the deposited pages if address space region creation fails.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/mshv_root_main.c | 25 +++++++++++++++++++++++--
> 1 file changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index 48c842b6938d..cb5b4505f8eb 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -39,6 +39,7 @@
> #define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
> #define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
> #define MSHV_VP_DEPOSIT_PAGES (1 * SZ_1M >> PAGE_SHIFT)
> +#define MSHV_1G_DEPOSIT_PAGES (6 * SZ_1M >> PAGE_SHIFT)
>
> MODULE_AUTHOR("Microsoft");
> MODULE_LICENSE("GPL");
> @@ -1324,6 +1325,18 @@ static int mshv_prepare_pinned_region(struct mshv_mem_region *region)
> return ret;
> }
>
> +static u64
> +mshv_region_deposit_slat_pages(struct mshv_mem_region *region)
> +{
> + u64 region_in_gbs, slat_pages;
> +
> + /* SLAT needs 6 MB per 1 GB of address space. */
> + region_in_gbs = DIV_ROUND_UP(region->nr_pages << HV_HYP_PAGE_SHIFT, SZ_1G);
> + slat_pages = region_in_gbs * MSHV_1G_DEPOSIT_PAGES;
> +
> + return slat_pages;
> +}
> +
> /*
> * This maps two things: guest RAM and for pci passthru mmio space.
> *
> @@ -1364,6 +1377,11 @@ mshv_map_user_memory(struct mshv_partition *partition,
> if (ret)
> return ret;
>
> + ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
> + mshv_region_deposit_slat_pages(region));
> + if (ret)
> + goto free_region;
> +
Also, for MSHV_REGION_TYPE_MEM_PINNED, deposit is not needed.
> switch (region->mreg_type) {
> case MSHV_REGION_TYPE_MEM_PINNED:
> ret = mshv_prepare_pinned_region(region);
> @@ -1392,7 +1410,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
> region->hv_map_flags, ret);
>
> if (ret)
> - goto errout;
> + goto withdraw_memory;
>
> spin_lock(&partition->pt_mem_regions_lock);
> hlist_add_head(®ion->hnode, &partition->pt_mem_regions);
> @@ -1400,7 +1418,10 @@ mshv_map_user_memory(struct mshv_partition *partition,
>
> return 0;
>
> -errout:
> +withdraw_memory:
> + hv_call_withdraw_memory(mshv_region_deposit_slat_pages(region),
> + NUMA_NO_NODE, partition->pt_id);
> +free_region:
> vfree(region);
> return ret;
> }
>
>
^ permalink raw reply
* Re: [PATCH 0/4] mshv: Fix and improve memory pre-depositing
From: Mukesh R @ 2026-03-06 3:44 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys, haiyangz, wei.liu, decui, longli
Cc: linux-hyperv, linux-kernel
In-Reply-To: <177258296744.229866.4926075663598294228.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
On 3/3/26 16:23, Stanislav Kinsburskii wrote:
> This series fixes and improves memory pre-depositing in the Microsoft
> Hypervisor (MSHV) driver to avoid partition and virtual processor
> creation failures due to insufficient deposited memory, and to speed
> up guest creation.
>
> The first patch converts hv_call_deposit_pages() into a wrapper that
> supports arbitrarily large deposit requests by splitting them into
> HV_DEPOSIT_MAX-sized chunks. It also doubles the deposit amount for
> L1 virtual hypervisor (L1VH) partitions to reserve memory for
> Hypervisor Hot Restart (HHR), since L1VH guests cannot request
> additional memory from the root partition during HHR.
>
> The second patch moves partition initialization page depositing from
> the hypercall wrapper to the partition initialization ioctl. The
> required number of pages is determined empirically. Partitions with
> nested virtualization capability require significantly more pages
> (20 MB) to accommodate the nested hypervisor. The partition creation
> flags are saved in the partition structure to allow selecting the
> correct deposit size at initialization time.
>
> The third patch moves virtual processor page depositing from
> hv_call_create_vp() to mshv_partition_ioctl_create_vp(). A fixed
> deposit of 1 MB per VP is used, which covers both regular and nested
> virtualization cases. Deposited memory is now properly withdrawn if
> VP creation fails.
>
> The fourth patch adds pre-depositing of pages for guest address space
> (SLAT) region creation. The deposit size is calculated based on the
> region size rounded up to 1 GB chunks, with 6 MB deposited per GB of
> address space. Deposited pages are withdrawn on failure.
Can't we just get away with changing deposit for most cases to just
2M? My theory is with that we won't really find any measurable
performance hits, and it keeps things simple.
Thanks,
-Mukesh
> ---
>
> Stanislav Kinsburskii (4):
> mshv: Support larger memory deposits
> mshv: Fix pre-depositing of pages for partition initialization
> mshv: Fix pre-depositing of pages for virtual processor initialization
> mshv: Pre-deposit pages for SLAT creation
>
>
> drivers/hv/hv_proc.c | 58 +++++++++++++++++++++++++++++++++------
> drivers/hv/mshv_root.h | 1 +
> drivers/hv/mshv_root_hv_call.c | 6 ----
> drivers/hv/mshv_root_main.c | 59 +++++++++++++++++++++++++++++++++++++---
> 4 files changed, 104 insertions(+), 20 deletions(-)
>
^ permalink raw reply
* Re: [PATCH 4/4] mshv: Pre-deposit pages for SLAT creation
From: Mukesh R @ 2026-03-06 3:41 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys, haiyangz, wei.liu, decui, longli
Cc: linux-hyperv, linux-kernel
In-Reply-To: <177258383107.229866.16867493994305727391.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
On 3/3/26 16:23, Stanislav Kinsburskii wrote:
> Deposit enough pages up front to avoid guest address space region creation
> failures due to low memory. This also speeds up guest creation.
Does this imply that some hypercall fails and has no return of
insufficient memory?
> Calculate the required number of pages based on the guest's physical
> address space size, rounded up to 1 GB chunks. Even the smallest guests are
> assumed to need at least 1 GB worth of deposits. This is because every
> guest requires tens of megabytes of deposited pages for hypervisor
> overhead, making smaller deposits impractical.
>
> Estimating in 1 GB chunks prevents over-depositing for larger guests while
> accepting some over-deposit for smaller ones. This trade-off keeps the
> estimate close to actual needs for larger guests.
>
> Also withdraw the deposited pages if address space region creation fails.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/mshv_root_main.c | 25 +++++++++++++++++++++++--
> 1 file changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index 48c842b6938d..cb5b4505f8eb 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -39,6 +39,7 @@
> #define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
> #define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
> #define MSHV_VP_DEPOSIT_PAGES (1 * SZ_1M >> PAGE_SHIFT)
> +#define MSHV_1G_DEPOSIT_PAGES (6 * SZ_1M >> PAGE_SHIFT)
>
> MODULE_AUTHOR("Microsoft");
> MODULE_LICENSE("GPL");
> @@ -1324,6 +1325,18 @@ static int mshv_prepare_pinned_region(struct mshv_mem_region *region)
> return ret;
> }
>
> +static u64
> +mshv_region_deposit_slat_pages(struct mshv_mem_region *region)
I don't think it is accurate to say slat pages, because in case of
overdeposit, they may be used for non-slat purposes according to my
understanding.
> +{
> + u64 region_in_gbs, slat_pages;
> +
> + /* SLAT needs 6 MB per 1 GB of address space. */
> + region_in_gbs = DIV_ROUND_UP(region->nr_pages << HV_HYP_PAGE_SHIFT, SZ_1G);
> + slat_pages = region_in_gbs * MSHV_1G_DEPOSIT_PAGES;
> +
> + return slat_pages;
> +}
> +
Again, unconditionally depositing for each region is not good because
that is empirical, and hyp will reuse the leftover ram.
/*
> * This maps two things: guest RAM and for pci passthru mmio space.
> *
> @@ -1364,6 +1377,11 @@ mshv_map_user_memory(struct mshv_partition *partition,
> if (ret)
> return ret;
>
> + ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
> + mshv_region_deposit_slat_pages(region));
> + if (ret)
> + goto free_region;
> +
> switch (region->mreg_type) {
> case MSHV_REGION_TYPE_MEM_PINNED:
> ret = mshv_prepare_pinned_region(region);
> @@ -1392,7 +1410,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
> region->hv_map_flags, ret);
>
> if (ret)
> - goto errout;
> + goto withdraw_memory;
>
> spin_lock(&partition->pt_mem_regions_lock);
> hlist_add_head(®ion->hnode, &partition->pt_mem_regions);
> @@ -1400,7 +1418,10 @@ mshv_map_user_memory(struct mshv_partition *partition,
>
> return 0;
>
> -errout:
> +withdraw_memory:
> + hv_call_withdraw_memory(mshv_region_deposit_slat_pages(region),
> + NUMA_NO_NODE, partition->pt_id);
> +free_region:
> vfree(region);
> return ret;
> }
>
>
^ permalink raw reply
* Re: [PATCH 3/4] mshv: Fix pre-depositing of pages for virtual processor initialization
From: Mukesh R @ 2026-03-06 3:33 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys, haiyangz, wei.liu, decui, longli
Cc: linux-hyperv, linux-kernel
In-Reply-To: <177258382549.229866.5072213647599344057.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
On 3/3/26 16:23, Stanislav Kinsburskii wrote:
> Deposit enough pages up front to avoid virtual processor creation failures
> due to low memory. This also speeds up guest creation. A VP uses 25% more
> pages in a partition with nested virtualization enabled, but the exact
> number doesn't vary much, so deposit a fixed number of pages per VP that
> works for nested virtualization.
>
> Move page depositing from the hypercall wrapper to the virtual processor
> creation code. The required number of pages is based on empirical data.
> This logic fits better in the virtual processor creation code than in the
> hypercall wrapper.
>
> Also withdraw the deposited memory if virtual processor creation fails.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/hv_proc.c | 8 --------
> drivers/hv/mshv_root_main.c | 11 ++++++++++-
> 2 files changed, 10 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/hv/hv_proc.c b/drivers/hv/hv_proc.c
> index 0f84a70def30..3d41f52efd9a 100644
> --- a/drivers/hv/hv_proc.c
> +++ b/drivers/hv/hv_proc.c
> @@ -251,14 +251,6 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
> unsigned long irq_flags;
> int ret = 0;
>
> - /* Root VPs don't seem to need pages deposited */
> - if (partition_id != hv_current_partition_id) {
> - /* The value 90 is empirically determined. It may change. */
> - ret = hv_call_deposit_pages(node, partition_id, 90);
> - if (ret)
> - return ret;
> - }
> -
> do {
> local_irq_save(irq_flags);
>
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index fbfc50de332c..48c842b6938d 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -38,6 +38,7 @@
> /* The deposit values below are empirical and may need to be adjusted. */
> #define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
> #define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
> +#define MSHV_VP_DEPOSIT_PAGES (1 * SZ_1M >> PAGE_SHIFT)
This seems to assume that each vp will use up total of 1M, and I don't
think that is the case. My understanding, hyp will reuse remaining chunks.
IOW, 6M maybe enought for 8 vcpus.
> MODULE_AUTHOR("Microsoft");
> MODULE_LICENSE("GPL");
> @@ -1077,10 +1078,15 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
> if (partition->pt_vp_array[args.vp_index])
> return -EEXIST;
>
> + ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
> + MSHV_VP_DEPOSIT_PAGES);
> + if (ret)
> + return ret;
> +
> ret = hv_call_create_vp(NUMA_NO_NODE, partition->pt_id, args.vp_index,
> 0 /* Only valid for root partition VPs */);
> if (ret)
> - return ret;
> + goto withdraw_mem;
>
> ret = hv_map_vp_state_page(partition->pt_id, args.vp_index,
> HV_VP_STATE_PAGE_INTERCEPT_MESSAGE,
> @@ -1177,6 +1183,9 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
> intercept_msg_page, input_vtl_zero);
> destroy_vp:
> hv_call_delete_vp(partition->pt_id, args.vp_index);
> +withdraw_mem:
> + hv_call_withdraw_memory(MSHV_VP_DEPOSIT_PAGES, NUMA_NO_NODE,
> + partition->pt_id);
> out:
> trace_mshv_create_vp(partition->pt_id, args.vp_index, ret);
> return ret;
>
>
^ permalink raw reply
* Re: [PATCH 2/4] mshv: Fix pre-depositing of pages for partition initialization
From: Mukesh R @ 2026-03-06 3:26 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys, haiyangz, wei.liu, decui, longli
Cc: linux-hyperv, linux-kernel
In-Reply-To: <177258381999.229866.4628731518107275272.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
On 3/3/26 16:23, Stanislav Kinsburskii wrote:
> Deposit enough pages upfront to avoid partition initialization failures due
> to low memory. This also speeds up partition initialization.
I am curious what kinda of failures are observerd. Normally, hypercall
would fail with insuff memory, and we continue to deposit till it
succeeds, right? Is there an issue there that some calls are not looping
in the deposit path?
> Move page depositing from the hypercall wrapper to the partition
> initialization code. The required number of pages is empirical. This logic
> fits better in the partition initialization code than in the hypercall
> wrapper.
>
> A partition with nested capability requires 40x more pages (20 MB) to
> accommodate the nested MSHV hypervisor. This may be improved in the future.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/mshv_root.h | 1 +
> drivers/hv/mshv_root_hv_call.c | 6 ------
> drivers/hv/mshv_root_main.c | 23 +++++++++++++++++++++--
> 3 files changed, 22 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
> index 947dfb76bb19..40cf7bdbd62f 100644
> --- a/drivers/hv/mshv_root.h
> +++ b/drivers/hv/mshv_root.h
> @@ -106,6 +106,7 @@ struct mshv_partition {
>
> struct hlist_node pt_hnode;
> u64 pt_id;
> + u64 pt_flags;
> refcount_t pt_ref_count;
> struct mutex pt_mutex;
>
> diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
> index bdcb8de7fb47..b8d199f95299 100644
> --- a/drivers/hv/mshv_root_hv_call.c
> +++ b/drivers/hv/mshv_root_hv_call.c
> @@ -15,7 +15,6 @@
> #include "mshv_root.h"
>
> /* Determined empirically */
> -#define HV_INIT_PARTITION_DEPOSIT_PAGES 208
> #define HV_UMAP_GPA_PAGES 512
>
> #define HV_PAGE_COUNT_2M_ALIGNED(pg_count) (!((pg_count) & (0x200 - 1)))
> @@ -139,11 +138,6 @@ int hv_call_initialize_partition(u64 partition_id)
>
> input.partition_id = partition_id;
>
> - ret = hv_call_deposit_pages(NUMA_NO_NODE, partition_id,
> - HV_INIT_PARTITION_DEPOSIT_PAGES);
> - if (ret)
> - return ret;
> -
> do {
> status = hv_do_fast_hypercall8(HVCALL_INITIALIZE_PARTITION,
> *(u64 *)&input);
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index d753f41d3b57..fbfc50de332c 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -35,6 +35,10 @@
> #include "mshv.h"
> #include "mshv_root.h"
>
> +/* The deposit values below are empirical and may need to be adjusted. */
> +#define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
> +#define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
This suggests action rather than count. imo, much better would be:
#define MSHV_PT_NUM_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
#define MSHV_PT_NUM_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
+
> MODULE_AUTHOR("Microsoft");
> MODULE_LICENSE("GPL");
> MODULE_DESCRIPTION("Microsoft Hyper-V root partition VMM interface /dev/mshv");
> @@ -1587,6 +1591,15 @@ mshv_partition_ioctl_set_msi_routing(struct mshv_partition *partition,
> return ret;
> }
>
> +static u64
> +mshv_partition_deposit_pages(struct mshv_partition *partition)
> +{
> + if (partition->pt_flags &
> + HV_PARTITION_CREATION_FLAG_NESTED_VIRTUALIZATION_CAPABLE)
> + return MSHV_PARTITION_DEPOSIT_PAGES_NESTED;
> + return MSHV_PARTITION_DEPOSIT_PAGES;
> +}
> +
> static long
> mshv_partition_ioctl_initialize(struct mshv_partition *partition)
> {
> @@ -1595,6 +1608,11 @@ mshv_partition_ioctl_initialize(struct mshv_partition *partition)
> if (partition->pt_initialized)
> return 0;
>
> + ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
> + mshv_partition_deposit_pages(partition));
> + if (ret)
> + goto withdraw_mem;
> +
> ret = hv_call_initialize_partition(partition->pt_id);
> if (ret)
> goto withdraw_mem;
> @@ -1610,8 +1628,8 @@ mshv_partition_ioctl_initialize(struct mshv_partition *partition)
> finalize_partition:
> hv_call_finalize_partition(partition->pt_id);
> withdraw_mem:
> - hv_call_withdraw_memory(U64_MAX, NUMA_NO_NODE, partition->pt_id);
> -
> + hv_call_withdraw_memory(MSHV_PARTITION_DEPOSIT_PAGES,
> + NUMA_NO_NODE, partition->pt_id);
> return ret;
> }
>
> @@ -2032,6 +2050,7 @@ mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev)
> return -ENOMEM;
>
> partition->pt_module_dev = module_dev;
> + partition->pt_flags = creation_flags;
> partition->isolation_type = isolation_properties.isolation_type;
>
> refcount_set(&partition->pt_ref_count, 1);
>
>
^ permalink raw reply
* Re: [PATCH 1/4] mshv: Support larger memory deposits
From: Mukesh R @ 2026-03-06 3:19 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys, haiyangz, wei.liu, decui, longli
Cc: linux-hyperv, linux-kernel
In-Reply-To: <177258381446.229866.108795434668770412.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
On 3/3/26 16:23, Stanislav Kinsburskii wrote:
> Convert hv_call_deposit_pages() into a wrapper supporting arbitrary number
> of pages, and use it in the memory deposit code paths.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/hv_proc.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 49 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hv/hv_proc.c b/drivers/hv/hv_proc.c
> index 5f4fd9c3231c..0f84a70def30 100644
> --- a/drivers/hv/hv_proc.c
> +++ b/drivers/hv/hv_proc.c
> @@ -16,7 +16,7 @@
> #define HV_DEPOSIT_MAX (HV_HYP_PAGE_SIZE / sizeof(u64) - 1)
>
> /* Deposits exact number of pages. Must be called with interrupts enabled. */
> -int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> +static int __hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> {
> struct page **pages, *page;
> int *counts;
> @@ -108,6 +108,54 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> kfree(counts);
> return ret;
> }
> +
> +/**
> + * hv_call_deposit_pages - Deposit memory pages to a partition
> + * @node : NUMA node from which to allocate pages
> + * @partition_id: Target partition ID to deposit pages to
> + * @num_pages : Number of pages to deposit
> + *
> + * Deposits memory pages to the specified partition. The deposit is
> + * performed in chunks of HV_DEPOSIT_MAX pages to handle large requests
> + * efficiently.
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> +{
> + u32 done;
> + int ret = 0;
> +
> + /*
> + * Do a double deposit for L1VH. This reserves enough memory for
> + * Hypervisor Hot Restart (HHR).
> + *
> + * During HHR, every data structure must be recreated in the new
> + * ("proto") hypervisor. Memory is required by the proto hypervisor
> + * to do this work.
> + *
> + * For regular L1 partitions, more memory can be requested from the
> + * root during HHR by sending an asynchronous message. But this is
> + * not supported for L1VHs. A guest must not be allowed to block
> + * HHR by refusing to deposit more memory.
> + *
> + * So for L1VH a deposit is always required for both current needs
> + * and future HHR work.
> + */
> + if (hv_l1vh_partition())
> + num_pages *= 2;
I'm not sure if it is a good idea to just do this unconditionally for
all cases of l1vh. I'd like to experiment to see if this is actually
truy for all the passthru and interrupt related hypercalls that fail
with insuff memory.
> +
> + for (done = 0; done < num_pages; done += HV_DEPOSIT_MAX) {
> + u32 to_deposit = min(num_pages - done, HV_DEPOSIT_MAX);
> +
> + ret = __hv_call_deposit_pages(node, partition_id,
> + to_deposit);
> + if (ret)
> + break;
> + }
> +
> + return ret;
> +}
> EXPORT_SYMBOL_GPL(hv_call_deposit_pages);
>
> int hv_deposit_memory_node(int node, u64 partition_id,
>
>
^ permalink raw reply
* [PATCH net-next] net: mana: Expose hardware diagnostic info via debugfs
From: Erni Sri Satya Vennela @ 2026-03-05 20:52 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, longli, andrew+netdev, davem,
edumazet, kuba, pabeni, kotaranov, horms, shradhagupta,
dipayanroy, yury.norov, kees, ernis, ssengar, shirazsaleem,
linux-hyperv, netdev, linux-kernel, linux-rdma
Add debugfs entries to expose hardware configuration and diagnostic
information that aids in debugging driver initialization and runtime
operations without adding noise to dmesg.
Device-level entries (under /sys/kernel/debug/mana/<slot>/):
- num_msix_usable, max_num_queues: Max resources from hardware
- gdma_protocol_ver, pf_cap_flags1: VF version negotiation results
- num_vports, bm_hostmode: Device configuration
- port_handle: Hardware vPort handle
- max_sq, max_rq: Max queues from vPort config
- indir_table_sz: Indirection table size
- steer_rx, steer_rss, steer_update_tab, steer_cqe_coalescing:
Last applied steering configuration parameters
Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
---
.../net/ethernet/microsoft/mana/gdma_main.c | 12 +++++++
drivers/net/ethernet/microsoft/mana/mana_en.c | 31 +++++++++++++++++++
include/net/mana/gdma.h | 1 +
include/net/mana/mana.h | 8 +++++
4 files changed, 52 insertions(+)
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 0055c231acf6..2ba8d224fd26 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -152,6 +152,11 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev)
if (gc->max_num_queues > gc->num_msix_usable - 1)
gc->max_num_queues = gc->num_msix_usable - 1;
+ debugfs_create_u32("num_msix_usable", 0400, gc->mana_pci_debugfs,
+ &gc->num_msix_usable);
+ debugfs_create_u32("max_num_queues", 0400, gc->mana_pci_debugfs,
+ &gc->max_num_queues);
+
return 0;
}
@@ -1221,6 +1226,13 @@ int mana_gd_verify_vf_version(struct pci_dev *pdev)
return err ? err : -EPROTO;
}
gc->pf_cap_flags1 = resp.pf_cap_flags1;
+ gc->gdma_protocol_ver = resp.gdma_protocol_ver;
+
+ debugfs_create_x64("gdma_protocol_ver", 0400, gc->mana_pci_debugfs,
+ &gc->gdma_protocol_ver);
+ debugfs_create_x64("pf_cap_flags1", 0400, gc->mana_pci_debugfs,
+ &gc->pf_cap_flags1);
+
if (resp.pf_cap_flags1 & GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG) {
err = mana_gd_query_hwc_timeout(pdev, &hwc->hwc_timeout);
if (err) {
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 53f24244de75..25ce81283e92 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1265,6 +1265,9 @@ static int mana_query_vport_cfg(struct mana_port_context *apc, u32 vport_index,
apc->port_handle = resp.vport;
ether_addr_copy(apc->mac_addr, resp.mac_addr);
+ apc->vport_max_sq = *max_sq;
+ apc->vport_max_rq = *max_rq;
+
return 0;
}
@@ -1411,6 +1414,11 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc,
netdev_info(ndev, "Configured steering vPort %llu entries %u\n",
apc->port_handle, apc->indir_table_sz);
+
+ apc->steer_rx = rx;
+ apc->steer_rss = apc->rss_state;
+ apc->steer_update_tab = update_tab;
+ apc->steer_cqe_coalescing = req->cqe_coalescing_enable;
out:
kfree(req);
return err;
@@ -3102,6 +3110,24 @@ static int mana_init_port(struct net_device *ndev)
eth_hw_addr_set(ndev, apc->mac_addr);
sprintf(vport, "vport%d", port_idx);
apc->mana_port_debugfs = debugfs_create_dir(vport, gc->mana_pci_debugfs);
+
+ debugfs_create_u64("port_handle", 0400, apc->mana_port_debugfs,
+ &apc->port_handle);
+ debugfs_create_u32("max_sq", 0400, apc->mana_port_debugfs,
+ &apc->vport_max_sq);
+ debugfs_create_u32("max_rq", 0400, apc->mana_port_debugfs,
+ &apc->vport_max_rq);
+ debugfs_create_u32("indir_table_sz", 0400, apc->mana_port_debugfs,
+ &apc->indir_table_sz);
+ debugfs_create_u32("steer_rx", 0400, apc->mana_port_debugfs,
+ &apc->steer_rx);
+ debugfs_create_u32("steer_rss", 0400, apc->mana_port_debugfs,
+ &apc->steer_rss);
+ debugfs_create_u32("steer_update_tab", 0400, apc->mana_port_debugfs,
+ &apc->steer_update_tab);
+ debugfs_create_u32("steer_cqe_coalescing", 0400, apc->mana_port_debugfs,
+ &apc->steer_cqe_coalescing);
+
return 0;
reset_apc:
@@ -3587,6 +3613,11 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
ac->num_ports = num_ports;
INIT_WORK(&ac->link_change_work, mana_link_state_handle);
+
+ debugfs_create_u16("num_vports", 0400, gc->mana_pci_debugfs,
+ &ac->num_ports);
+ debugfs_create_u8("bm_hostmode", 0400, gc->mana_pci_debugfs,
+ &ac->bm_hostmode);
} else {
if (ac->num_ports != num_ports) {
dev_err(dev, "The number of vPorts changed: %d->%d\n",
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 766f4fb25e26..9bbb7fb0c964 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -434,6 +434,7 @@ struct gdma_context {
struct gdma_dev mana_ib;
u64 pf_cap_flags1;
+ u64 gdma_protocol_ver;
struct workqueue_struct *service_wq;
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index a078af283bdd..83f6de67c0cc 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -563,6 +563,14 @@ struct mana_port_context {
/* Debugfs */
struct dentry *mana_port_debugfs;
+
+ /* Cached vport/steering config for debugfs */
+ u32 vport_max_sq;
+ u32 vport_max_rq;
+ u32 steer_rx;
+ u32 steer_rss;
+ u32 steer_update_tab;
+ u32 steer_cqe_coalescing;
};
netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev);
--
2.34.1
^ permalink raw reply related
* RE: [PATCH 4/4] mshv: Pre-deposit pages for SLAT creation
From: Michael Kelley @ 2026-03-05 19:44 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys@microsoft.com, haiyangz@microsoft.com,
wei.liu@kernel.org, decui@microsoft.com, longli@microsoft.com
Cc: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <177258383107.229866.16867493994305727391.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
From: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Sent: Tuesday, March 3, 2026 4:24 PM
>
> Deposit enough pages up front to avoid guest address space region creation
> failures due to low memory. This also speeds up guest creation.
>
> Calculate the required number of pages based on the guest's physical
> address space size, rounded up to 1 GB chunks. Even the smallest guests are
> assumed to need at least 1 GB worth of deposits. This is because every
> guest requires tens of megabytes of deposited pages for hypervisor
> overhead, making smaller deposits impractical.
>
> Estimating in 1 GB chunks prevents over-depositing for larger guests while
> accepting some over-deposit for smaller ones. This trade-off keeps the
> estimate close to actual needs for larger guests.
>
> Also withdraw the deposited pages if address space region creation fails.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/mshv_root_main.c | 25 +++++++++++++++++++++++--
> 1 file changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index 48c842b6938d..cb5b4505f8eb 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -39,6 +39,7 @@
> #define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
> #define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
> #define MSHV_VP_DEPOSIT_PAGES (1 * SZ_1M >> PAGE_SHIFT)
> +#define MSHV_1G_DEPOSIT_PAGES (6 * SZ_1M >> PAGE_SHIFT)
>
> MODULE_AUTHOR("Microsoft");
> MODULE_LICENSE("GPL");
> @@ -1324,6 +1325,18 @@ static int mshv_prepare_pinned_region(struct mshv_mem_region *region)
> return ret;
> }
>
> +static u64
> +mshv_region_deposit_slat_pages(struct mshv_mem_region *region)
Same nit about the function name. This one seems like it will "deposit slat pages".
> +{
> + u64 region_in_gbs, slat_pages;
> +
> + /* SLAT needs 6 MB per 1 GB of address space. */
> + region_in_gbs = DIV_ROUND_UP(region->nr_pages << HV_HYP_PAGE_SHIFT, SZ_1G);
This local variable "region_in_gbs" is computed in units of bytes.
> + slat_pages = region_in_gbs * MSHV_1G_DEPOSIT_PAGES;
But here region_in_gbs is used as if it were in units of Gbytes. So the
slat_pages return value is much larger than intended.
> +
> + return slat_pages;
> +}
> +
> /*
> * This maps two things: guest RAM and for pci passthru mmio space.
> *
> @@ -1364,6 +1377,11 @@ mshv_map_user_memory(struct mshv_partition *partition,
> if (ret)
> return ret;
>
> + ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
> + mshv_region_deposit_slat_pages(region));
> + if (ret)
> + goto free_region;
> +
> switch (region->mreg_type) {
> case MSHV_REGION_TYPE_MEM_PINNED:
> ret = mshv_prepare_pinned_region(region);
> @@ -1392,7 +1410,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
> region->hv_map_flags, ret);
>
> if (ret)
> - goto errout;
> + goto withdraw_memory;
>
> spin_lock(&partition->pt_mem_regions_lock);
> hlist_add_head(®ion->hnode, &partition->pt_mem_regions);
> @@ -1400,7 +1418,10 @@ mshv_map_user_memory(struct mshv_partition *partition,
>
> return 0;
>
> -errout:
> +withdraw_memory:
> + hv_call_withdraw_memory(mshv_region_deposit_slat_pages(region),
> + NUMA_NO_NODE, partition->pt_id);
Again, for an L1VH partition, the actual number of pages deposited would
be 2x what mshv_region_deposit_slat_pages() returns.
> +free_region:
> vfree(region);
> return ret;
> }
>
>
^ permalink raw reply
* RE: [PATCH 3/4] mshv: Fix pre-depositing of pages for virtual processor initialization
From: Michael Kelley @ 2026-03-05 19:44 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys@microsoft.com, haiyangz@microsoft.com,
wei.liu@kernel.org, decui@microsoft.com, longli@microsoft.com
Cc: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <177258382549.229866.5072213647599344057.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
From: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Sent: Tuesday, March 3, 2026 4:24 PM
>
> Deposit enough pages up front to avoid virtual processor creation failures
> due to low memory. This also speeds up guest creation. A VP uses 25% more
> pages in a partition with nested virtualization enabled, but the exact
> number doesn't vary much, so deposit a fixed number of pages per VP that
> works for nested virtualization.
>
> Move page depositing from the hypercall wrapper to the virtual processor
> creation code. The required number of pages is based on empirical data.
> This logic fits better in the virtual processor creation code than in the
> hypercall wrapper.
>
> Also withdraw the deposited memory if virtual processor creation fails.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/hv_proc.c | 8 --------
> drivers/hv/mshv_root_main.c | 11 ++++++++++-
> 2 files changed, 10 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/hv/hv_proc.c b/drivers/hv/hv_proc.c
> index 0f84a70def30..3d41f52efd9a 100644
> --- a/drivers/hv/hv_proc.c
> +++ b/drivers/hv/hv_proc.c
> @@ -251,14 +251,6 @@ int hv_call_create_vp(int node, u64 partition_id, u32
> vp_index, u32 flags)
> unsigned long irq_flags;
> int ret = 0;
>
> - /* Root VPs don't seem to need pages deposited */
> - if (partition_id != hv_current_partition_id) {
> - /* The value 90 is empirically determined. It may change. */
> - ret = hv_call_deposit_pages(node, partition_id, 90);
> - if (ret)
> - return ret;
> - }
> -
> do {
> local_irq_save(irq_flags);
>
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index fbfc50de332c..48c842b6938d 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -38,6 +38,7 @@
> /* The deposit values below are empirical and may need to be adjusted. */
> #define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
> #define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
> +#define MSHV_VP_DEPOSIT_PAGES (1 * SZ_1M >> PAGE_SHIFT)
>
> MODULE_AUTHOR("Microsoft");
> MODULE_LICENSE("GPL");
> @@ -1077,10 +1078,15 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
> if (partition->pt_vp_array[args.vp_index])
> return -EEXIST;
>
> + ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
> + MSHV_VP_DEPOSIT_PAGES);
> + if (ret)
> + return ret;
> +
> ret = hv_call_create_vp(NUMA_NO_NODE, partition->pt_id, args.vp_index,
> 0 /* Only valid for root partition VPs */);
> if (ret)
> - return ret;
> + goto withdraw_mem;
>
> ret = hv_map_vp_state_page(partition->pt_id, args.vp_index,
> HV_VP_STATE_PAGE_INTERCEPT_MESSAGE,
> @@ -1177,6 +1183,9 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
> intercept_msg_page, input_vtl_zero);
> destroy_vp:
> hv_call_delete_vp(partition->pt_id, args.vp_index);
> +withdraw_mem:
> + hv_call_withdraw_memory(MSHV_VP_DEPOSIT_PAGES, NUMA_NO_NODE,
> + partition->pt_id);
If the partition is an L1VH partition, hv_call_deposit_pages() will have deposited
2 * MSHV_VP_DEPOSIT_PAGES, but here in the failure case you are withdrawing
only MSHV_VP_DEPOSIT_PAGES.
> out:
> trace_mshv_create_vp(partition->pt_id, args.vp_index, ret);
> return ret;
>
>
^ permalink raw reply
* RE: [PATCH 2/4] mshv: Fix pre-depositing of pages for partition initialization
From: Michael Kelley @ 2026-03-05 19:43 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys@microsoft.com, haiyangz@microsoft.com,
wei.liu@kernel.org, decui@microsoft.com, longli@microsoft.com
Cc: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <177258381999.229866.4628731518107275272.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
From: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Sent: Tuesday, March 3, 2026 4:24 PM
>
> Deposit enough pages upfront to avoid partition initialization failures due
> to low memory. This also speeds up partition initialization.
>
> Move page depositing from the hypercall wrapper to the partition
> initialization code. The required number of pages is empirical. This logic
> fits better in the partition initialization code than in the hypercall
> wrapper.
>
> A partition with nested capability requires 40x more pages (20 MB) to
> accommodate the nested MSHV hypervisor. This may be improved in the future.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/mshv_root.h | 1 +
> drivers/hv/mshv_root_hv_call.c | 6 ------
> drivers/hv/mshv_root_main.c | 23 +++++++++++++++++++++--
> 3 files changed, 22 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
> index 947dfb76bb19..40cf7bdbd62f 100644
> --- a/drivers/hv/mshv_root.h
> +++ b/drivers/hv/mshv_root.h
> @@ -106,6 +106,7 @@ struct mshv_partition {
>
> struct hlist_node pt_hnode;
> u64 pt_id;
> + u64 pt_flags;
> refcount_t pt_ref_count;
> struct mutex pt_mutex;
>
> diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
> index bdcb8de7fb47..b8d199f95299 100644
> --- a/drivers/hv/mshv_root_hv_call.c
> +++ b/drivers/hv/mshv_root_hv_call.c
> @@ -15,7 +15,6 @@
> #include "mshv_root.h"
>
> /* Determined empirically */
I think the above comment applies to HV_INIT_PARTITION_DEPOSIT_PAGES
(not to HV_UMAP_GPA_PAGES) and should be removed.
> -#define HV_INIT_PARTITION_DEPOSIT_PAGES 208
> #define HV_UMAP_GPA_PAGES 512
>
> #define HV_PAGE_COUNT_2M_ALIGNED(pg_count) (!((pg_count) & (0x200 - 1)))
> @@ -139,11 +138,6 @@ int hv_call_initialize_partition(u64 partition_id)
>
> input.partition_id = partition_id;
>
> - ret = hv_call_deposit_pages(NUMA_NO_NODE, partition_id,
> - HV_INIT_PARTITION_DEPOSIT_PAGES);
> - if (ret)
> - return ret;
> -
> do {
> status = hv_do_fast_hypercall8(HVCALL_INITIALIZE_PARTITION,
> *(u64 *)&input);
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index d753f41d3b57..fbfc50de332c 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -35,6 +35,10 @@
> #include "mshv.h"
> #include "mshv_root.h"
>
> +/* The deposit values below are empirical and may need to be adjusted. */
> +#define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
> +#define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
Nit: The placement of these #defines *above* the MODULE_* notations seems
a bit odd to me.
> +
> MODULE_AUTHOR("Microsoft");
> MODULE_LICENSE("GPL");
> MODULE_DESCRIPTION("Microsoft Hyper-V root partition VMM interface /dev/mshv");
> @@ -1587,6 +1591,15 @@ mshv_partition_ioctl_set_msi_routing(struct
> mshv_partition *partition,
> return ret;
> }
>
> +static u64
> +mshv_partition_deposit_pages(struct mshv_partition *partition)
Nit: This function name makes it seem like it will "deposit pages". Maybe
mshv_partition_get_deposit_cnt(), or something similar, would be better?
> +{
> + if (partition->pt_flags &
> + HV_PARTITION_CREATION_FLAG_NESTED_VIRTUALIZATION_CAPABLE)
> + return MSHV_PARTITION_DEPOSIT_PAGES_NESTED;
> + return MSHV_PARTITION_DEPOSIT_PAGES;
> +}
> +
> static long
> mshv_partition_ioctl_initialize(struct mshv_partition *partition)
> {
> @@ -1595,6 +1608,11 @@ mshv_partition_ioctl_initialize(struct mshv_partition *partition)
> if (partition->pt_initialized)
> return 0;
>
> + ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
> + mshv_partition_deposit_pages(partition));
> + if (ret)
> + goto withdraw_mem;
> +
> ret = hv_call_initialize_partition(partition->pt_id);
> if (ret)
> goto withdraw_mem;
> @@ -1610,8 +1628,8 @@ mshv_partition_ioctl_initialize(struct mshv_partition *partition)
> finalize_partition:
> hv_call_finalize_partition(partition->pt_id);
> withdraw_mem:
> - hv_call_withdraw_memory(U64_MAX, NUMA_NO_NODE, partition->pt_id);
> -
> + hv_call_withdraw_memory(MSHV_PARTITION_DEPOSIT_PAGES,
> + NUMA_NO_NODE, partition->pt_id);
What's the strategy here for withdrawing memory after a failure? As I noted in
Patch 1 of the series, there's no way to know how many pages were deposited.
Might have been zero, or significantly more than MSHV_PARTITION_DEPOSIT_PAGES.
And in Patches 3 and 4 of the series, there's no attempt to withdraw pages if
hv_call_deposit_pages() fails, which seems inconsistent.
> return ret;
> }
>
> @@ -2032,6 +2050,7 @@ mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev)
> return -ENOMEM;
>
> partition->pt_module_dev = module_dev;
> + partition->pt_flags = creation_flags;
> partition->isolation_type = isolation_properties.isolation_type;
>
> refcount_set(&partition->pt_ref_count, 1);
>
>
^ permalink raw reply
* RE: [PATCH 1/4] mshv: Support larger memory deposits
From: Michael Kelley @ 2026-03-05 19:43 UTC (permalink / raw)
To: Stanislav Kinsburskii, kys@microsoft.com, haiyangz@microsoft.com,
wei.liu@kernel.org, decui@microsoft.com, longli@microsoft.com
Cc: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <177258381446.229866.108795434668770412.stgit@skinsburskii-cloud-desktop.internal.cloudapp.net>
From: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Sent: Tuesday, March 3, 2026 4:24 PM
>
> Convert hv_call_deposit_pages() into a wrapper supporting arbitrary number
> of pages, and use it in the memory deposit code paths.
>
> Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
> ---
> drivers/hv/hv_proc.c | 50
> +++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 49 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hv/hv_proc.c b/drivers/hv/hv_proc.c
> index 5f4fd9c3231c..0f84a70def30 100644
> --- a/drivers/hv/hv_proc.c
> +++ b/drivers/hv/hv_proc.c
> @@ -16,7 +16,7 @@
> #define HV_DEPOSIT_MAX (HV_HYP_PAGE_SIZE / sizeof(u64) - 1)
>
> /* Deposits exact number of pages. Must be called with interrupts enabled. */
> -int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> +static int __hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> {
> struct page **pages, *page;
> int *counts;
> @@ -108,6 +108,54 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> kfree(counts);
> return ret;
> }
> +
> +/**
> + * hv_call_deposit_pages - Deposit memory pages to a partition
> + * @node : NUMA node from which to allocate pages
> + * @partition_id: Target partition ID to deposit pages to
> + * @num_pages : Number of pages to deposit
> + *
> + * Deposits memory pages to the specified partition. The deposit is
> + * performed in chunks of HV_DEPOSIT_MAX pages to handle large requests
> + * efficiently.
> + *
> + * Return: 0 on success, negative error code on failure
For the failure case, a key fact seems to be that there's no attempt to
withdraw any pages that might have been successfully deposited. In
such failure case, the caller has no information about how many pages
were, or were not, deposited. The 2x for L1VH further muddies the
picture.
__hv_call_deposit_pages() apparently assumes that if the underlying
hypercall fails, none of the pages were deposited. So it frees all the
allocated pages. But I wonder if that's really true. The hypercall is
a rep hypercall, which can get partly through the list, return to the
guest, then restart where it left off. If there's a failure after a
restart, I wonder if the hypercall goes back and withdraws any
pages that were successfully deposited before the restart. The
restart behaves like a new invocation of the hypercall.
> + */
> +int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
Perhaps the num_pages parameter should be a u64. The u32 imposes
a limit of 8 Tbytes on the amount of memory that can be deposited
(allowing for the 2x multiplier for L1VH partitions). Azure has VM sizes
today with up to 30 Tbytes of memory, so it's certainly possible.
> +{
> + u32 done;
Same here. Use u64.
> + int ret = 0;
> +
> + /*
> + * Do a double deposit for L1VH. This reserves enough memory for
> + * Hypervisor Hot Restart (HHR).
> + *
> + * During HHR, every data structure must be recreated in the new
> + * ("proto") hypervisor. Memory is required by the proto hypervisor
> + * to do this work.
> + *
> + * For regular L1 partitions, more memory can be requested from the
> + * root during HHR by sending an asynchronous message. But this is
> + * not supported for L1VHs. A guest must not be allowed to block
> + * HHR by refusing to deposit more memory.
> + *
> + * So for L1VH a deposit is always required for both current needs
> + * and future HHR work.
> + */
> + if (hv_l1vh_partition())
> + num_pages *= 2;
> +
> + for (done = 0; done < num_pages; done += HV_DEPOSIT_MAX) {
> + u32 to_deposit = min(num_pages - done, HV_DEPOSIT_MAX);
> +
> + ret = __hv_call_deposit_pages(node, partition_id,
> + to_deposit);
> + if (ret)
> + break;
> + }
> +
> + return ret;
> +}
> EXPORT_SYMBOL_GPL(hv_call_deposit_pages);
>
> int hv_deposit_memory_node(int node, u64 partition_id,
>
>
^ permalink raw reply
* [PATCH AUTOSEL 6.19-5.10] scsi: storvsc: Fix scheduling while atomic on PREEMPT_RT
From: Sasha Levin @ 2026-03-05 15:36 UTC (permalink / raw)
To: patches, stable
Cc: Jan Kiszka, Florian Bezdeka, Michael Kelley, Martin K. Petersen,
Sasha Levin, kys, haiyangz, wei.liu, decui, longli,
James.Bottomley, linux-hyperv, linux-scsi, linux-kernel
In-Reply-To: <20260305153704.106918-1-sashal@kernel.org>
From: Jan Kiszka <jan.kiszka@siemens.com>
[ Upstream commit 57297736c08233987e5d29ce6584c6ca2a831b12 ]
This resolves the follow splat and lock-up when running with PREEMPT_RT
enabled on Hyper-V:
[ 415.140818] BUG: scheduling while atomic: stress-ng-iomix/1048/0x00000002
[ 415.140822] INFO: lockdep is turned off.
[ 415.140823] Modules linked in: intel_rapl_msr intel_rapl_common intel_uncore_frequency_common intel_pmc_core pmt_telemetry pmt_discovery pmt_class intel_pmc_ssram_telemetry intel_vsec ghash_clmulni_intel aesni_intel rapl binfmt_misc nls_ascii nls_cp437 vfat fat snd_pcm hyperv_drm snd_timer drm_client_lib drm_shmem_helper snd sg soundcore drm_kms_helper pcspkr hv_balloon hv_utils evdev joydev drm configfs efi_pstore nfnetlink vsock_loopback vmw_vsock_virtio_transport_common hv_sock vmw_vsock_vmci_transport vsock vmw_vmci efivarfs autofs4 ext4 crc16 mbcache jbd2 sr_mod sd_mod cdrom hv_storvsc serio_raw hid_generic scsi_transport_fc hid_hyperv scsi_mod hid hv_netvsc hyperv_keyboard scsi_common
[ 415.140846] Preemption disabled at:
[ 415.140847] [<ffffffffc0656171>] storvsc_queuecommand+0x2e1/0xbe0 [hv_storvsc]
[ 415.140854] CPU: 8 UID: 0 PID: 1048 Comm: stress-ng-iomix Not tainted 6.19.0-rc7 #30 PREEMPT_{RT,(full)}
[ 415.140856] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 09/04/2024
[ 415.140857] Call Trace:
[ 415.140861] <TASK>
[ 415.140861] ? storvsc_queuecommand+0x2e1/0xbe0 [hv_storvsc]
[ 415.140863] dump_stack_lvl+0x91/0xb0
[ 415.140870] __schedule_bug+0x9c/0xc0
[ 415.140875] __schedule+0xdf6/0x1300
[ 415.140877] ? rtlock_slowlock_locked+0x56c/0x1980
[ 415.140879] ? rcu_is_watching+0x12/0x60
[ 415.140883] schedule_rtlock+0x21/0x40
[ 415.140885] rtlock_slowlock_locked+0x502/0x1980
[ 415.140891] rt_spin_lock+0x89/0x1e0
[ 415.140893] hv_ringbuffer_write+0x87/0x2a0
[ 415.140899] vmbus_sendpacket_mpb_desc+0xb6/0xe0
[ 415.140900] ? rcu_is_watching+0x12/0x60
[ 415.140902] storvsc_queuecommand+0x669/0xbe0 [hv_storvsc]
[ 415.140904] ? HARDIRQ_verbose+0x10/0x10
[ 415.140908] ? __rq_qos_issue+0x28/0x40
[ 415.140911] scsi_queue_rq+0x760/0xd80 [scsi_mod]
[ 415.140926] __blk_mq_issue_directly+0x4a/0xc0
[ 415.140928] blk_mq_issue_direct+0x87/0x2b0
[ 415.140931] blk_mq_dispatch_queue_requests+0x120/0x440
[ 415.140933] blk_mq_flush_plug_list+0x7a/0x1a0
[ 415.140935] __blk_flush_plug+0xf4/0x150
[ 415.140940] __submit_bio+0x2b2/0x5c0
[ 415.140944] ? submit_bio_noacct_nocheck+0x272/0x360
[ 415.140946] submit_bio_noacct_nocheck+0x272/0x360
[ 415.140951] ext4_read_bh_lock+0x3e/0x60 [ext4]
[ 415.140995] ext4_block_write_begin+0x396/0x650 [ext4]
[ 415.141018] ? __pfx_ext4_da_get_block_prep+0x10/0x10 [ext4]
[ 415.141038] ext4_da_write_begin+0x1c4/0x350 [ext4]
[ 415.141060] generic_perform_write+0x14e/0x2c0
[ 415.141065] ext4_buffered_write_iter+0x6b/0x120 [ext4]
[ 415.141083] vfs_write+0x2ca/0x570
[ 415.141087] ksys_write+0x76/0xf0
[ 415.141089] do_syscall_64+0x99/0x1490
[ 415.141093] ? rcu_is_watching+0x12/0x60
[ 415.141095] ? finish_task_switch.isra.0+0xdf/0x3d0
[ 415.141097] ? rcu_is_watching+0x12/0x60
[ 415.141098] ? lock_release+0x1f0/0x2a0
[ 415.141100] ? rcu_is_watching+0x12/0x60
[ 415.141101] ? finish_task_switch.isra.0+0xe4/0x3d0
[ 415.141103] ? rcu_is_watching+0x12/0x60
[ 415.141104] ? __schedule+0xb34/0x1300
[ 415.141106] ? hrtimer_try_to_cancel+0x1d/0x170
[ 415.141109] ? do_nanosleep+0x8b/0x160
[ 415.141111] ? hrtimer_nanosleep+0x89/0x100
[ 415.141114] ? __pfx_hrtimer_wakeup+0x10/0x10
[ 415.141116] ? xfd_validate_state+0x26/0x90
[ 415.141118] ? rcu_is_watching+0x12/0x60
[ 415.141120] ? do_syscall_64+0x1e0/0x1490
[ 415.141121] ? do_syscall_64+0x1e0/0x1490
[ 415.141123] ? rcu_is_watching+0x12/0x60
[ 415.141124] ? do_syscall_64+0x1e0/0x1490
[ 415.141125] ? do_syscall_64+0x1e0/0x1490
[ 415.141127] ? irqentry_exit+0x140/0x7e0
[ 415.141129] entry_SYSCALL_64_after_hwframe+0x76/0x7e
get_cpu() disables preemption while the spinlock hv_ringbuffer_write is
using is converted to an rt-mutex under PREEMPT_RT.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Tested-by: Florian Bezdeka <florian.bezdeka@siemens.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Tested-by: Michael Kelley <mhklinux@outlook.com>
Link: https://patch.msgid.link/0c7fb5cd-fb21-4760-8593-e04bade84744@siemens.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Now I have enough context to analyze this commit thoroughly.
## Analysis
### 1. Problem Description
The commit fixes a **"BUG: scheduling while atomic"** crash and
**lockup** on Hyper-V VMs running with `PREEMPT_RT` enabled. The stack
trace in the commit message clearly shows the issue:
- `storvsc_queuecommand()` calls `get_cpu()` which disables preemption
- It then calls `storvsc_do_io()` → `vmbus_sendpacket_mpb_desc()` →
`hv_ringbuffer_write()`
- `hv_ringbuffer_write()` takes a spinlock that, under PREEMPT_RT, is
converted to an rt-mutex
- rt-mutexes can sleep/schedule, but preemption is disabled →
**scheduling while atomic BUG**
### 2. The Fix
The fix replaces:
```c
ret = storvsc_do_io(dev, cmd_request, get_cpu());
put_cpu();
```
with:
```c
migrate_disable();
ret = storvsc_do_io(dev, cmd_request, smp_processor_id());
migrate_enable();
```
The purpose of `get_cpu()` here was to get a stable CPU number to use as
a channel index in `storvsc_do_io()`. The actual requirement is just to
prevent migration (so the CPU number stays valid), not to disable
preemption entirely. `migrate_disable()` achieves this while allowing
scheduling under PREEMPT_RT.
### 3. Correctness
- `migrate_disable()` prevents the task from being migrated to another
CPU, so `smp_processor_id()` remains valid throughout the call
- On non-PREEMPT_RT kernels, this is functionally equivalent
(migrate_disable maps to preempt_disable)
- On PREEMPT_RT, it allows the rt-mutex in `hv_ringbuffer_write()` to
sleep as needed
### 4. Scope and Risk
- **3 lines changed** - extremely small and surgical
- Only affects `storvsc_queuecommand()` in the Hyper-V storage driver
- Well-understood transformation pattern
(`get_cpu()`→`migrate_disable()`+`smp_processor_id()`) used
extensively across the kernel for PREEMPT_RT fixes
- Has been **Tested-by** two people and **Reviewed-by** the Hyper-V
subsystem expert (Michael Kelley)
### 5. User Impact
- **Hyper-V VMs with PREEMPT_RT**: This is a hard crash/lockup during
normal I/O operations (ext4 writes), making the system completely
unusable
- PREEMPT_RT is increasingly used in enterprise and embedded
deployments, including on Hyper-V/Azure
- Without this fix, PREEMPT_RT kernels on Hyper-V are effectively broken
for any storage I/O
### 6. Stable Criteria Assessment
- **Obviously correct**: Yes - standard PREEMPT_RT fix pattern
- **Fixes a real bug**: Yes - kernel BUG + lockup
- **Important issue**: Yes - system lockup during normal I/O
- **Small and contained**: Yes - 3-line change in one file
- **No new features**: Correct - pure bug fix
- **Tested**: Yes - two Tested-by tags
### Verification
- Read `storvsc_drv.c:1858` confirming the old code uses
`get_cpu()`/`put_cpu()` (matches the diff)
- Read `storvsc_do_io()` at line 1453: confirms `q_num` is used as a CPU
index into `stor_chns[]` array and passed to
`cpumask_of_node(cpu_to_node(q_num))` - only needs migration
stability, not preemption disabled
- Confirmed the call chain: `storvsc_do_io()` →
`vmbus_sendpacket_mpb_desc()` (line 1547) → `hv_ringbuffer_write()`
which takes a spinlock (as shown in the stack trace)
- The stack trace shows `rt_spin_lock` → `rtlock_slowlock_locked` →
`schedule_rtlock` confirming the spinlock-to-rt-mutex conversion is
the trigger
- `git log` confirmed this is in a well-maintained driver with recent
activity
**YES**
drivers/scsi/storvsc_drv.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index b43d876747b76..68c837146b9ea 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1855,8 +1855,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
cmd_request->payload_sz = payload_sz;
/* Invokes the vsc to start an IO */
- ret = storvsc_do_io(dev, cmd_request, get_cpu());
- put_cpu();
+ migrate_disable();
+ ret = storvsc_do_io(dev, cmd_request, smp_processor_id());
+ migrate_enable();
if (ret)
scsi_dma_unmap(scmnd);
--
2.51.0
^ permalink raw reply related
* Re: [PATCH net-next v5] net: mana: Add MAC address to vPort logs and clarify error messages
From: patchwork-bot+netdevbpf @ 2026-03-05 11:30 UTC (permalink / raw)
To: Erni Sri Satya Vennela
Cc: kys, haiyangz, wei.liu, decui, longli, andrew+netdev, davem,
edumazet, kuba, pabeni, dipayanroy, shirazsaleem, kees,
shradhagupta, gargaditya, linux-hyperv, netdev, linux-kernel
In-Reply-To: <20260302174204.234837-1-ernis@linux.microsoft.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Mon, 2 Mar 2026 09:41:52 -0800 you wrote:
> Add MAC address to vPort configuration success message and update error
> message to be more specific about HWC message errors in
> mana_send_request.
>
> Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
> ---
> Changes in v5:
> * Remove __func__ and __LINE__ from error logs in hw_channel.c
> Changes in v4:
> * Remove logs that do not add value in hw_channel.c.
> Changes in v3:
> * Remove the changes from v2 and Update commit message.
> * Use "Enabled vPort ..." instead of "Configured vPort" in
> mana_cfg_vport.
> * Update error logs in mana_hwc_send_request.
> Changes in v2:
> * Update commit message.
> * Use "Enabled vPort ..." instead of "Configured vPort" in
> mana_cfg_vport.
> * Add info log in mana_uncfg_vport, mana_gd_verify_vf_version,
> mana_gd_query_max_resources, mana_query_device_cfg and
> mana_query_vport_cfg.
>
> [...]
Here is the summary with links:
- [net-next,v5] net: mana: Add MAC address to vPort logs and clarify error messages
https://git.kernel.org/netdev/net-next/c/0172f8d80220
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next v5] net: mana: Add MAC address to vPort logs and clarify error messages
From: Simon Horman @ 2026-03-05 9:19 UTC (permalink / raw)
To: Erni Sri Satya Vennela
Cc: kys, haiyangz, wei.liu, decui, longli, andrew+netdev, davem,
edumazet, kuba, pabeni, dipayanroy, shirazsaleem, kees,
shradhagupta, gargaditya, linux-hyperv, netdev, linux-kernel
In-Reply-To: <20260302174204.234837-1-ernis@linux.microsoft.com>
On Mon, Mar 02, 2026 at 09:41:52AM -0800, Erni Sri Satya Vennela wrote:
> Add MAC address to vPort configuration success message and update error
> message to be more specific about HWC message errors in
> mana_send_request.
>
> Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
> ---
> Changes in v5:
> * Remove __func__ and __LINE__ from error logs in hw_channel.c
Thanks for the update.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* [PATCH v9 10/10] x86/hyperv/vtl: Use the wakeup mailbox to boot secondary CPUs
From: Ricardo Neri @ 2026-03-04 23:41 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: <20260304-rneri-wakeup-mailbox-v9-0-a5c6845e6251@linux.intel.com>
The hypervisor is an untrusted entity for TDX guests. It cannot be used
to boot secondary CPUs. The function hv_vtl_wakeup_secondary_cpu() cannot
be used.
Instead, the virtual firmware boots the secondary CPUs and places them in
a state to transfer control to the kernel using the wakeup mailbox. The
firmware enumerates the mailbox via either an ACPI table or a DeviceTree
node.
If the wakeup mailbox is present, the kernel updates the APIC callback
wakeup_secondary_cpu_64() to use it.
Reviewed-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes in v9:
- None
Changes in v8:
- None
Changes in v7:
- None
Changes in v6:
- Added Reviewed-by tag from Dexuan. Thanks!
Changes in v5:
- None
Changes in v4:
- Added Reviewed-by tag from Michael. Thanks!
Changes in v3:
- Unconditionally use the wakeup mailbox in a TDX confidential VM.
(Michael).
- Edited the commit message for clarity.
Changes in v2:
- None
---
arch/x86/hyperv/hv_vtl.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c
index 1e2f5b3ea772..07fac3d687c3 100644
--- a/arch/x86/hyperv/hv_vtl.c
+++ b/arch/x86/hyperv/hv_vtl.c
@@ -274,7 +274,15 @@ 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");
- apic_update_callback(wakeup_secondary_cpu_64, hv_vtl_wakeup_secondary_cpu);
+ /*
+ * TDX confidential VMs do not trust the hypervisor and cannot use it to
+ * boot secondary CPUs. Instead, they will be booted using the wakeup
+ * mailbox if detected during boot. See setup_arch().
+ *
+ * There is no paravisor present if we are here.
+ */
+ if (!hv_isolation_type_tdx())
+ apic_update_callback(wakeup_secondary_cpu_64, hv_vtl_wakeup_secondary_cpu);
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v9 09/10] x86/hyperv/vtl: Mark the wakeup mailbox page as private
From: Ricardo Neri @ 2026-03-04 23:41 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: <20260304-rneri-wakeup-mailbox-v9-0-a5c6845e6251@linux.intel.com>
From: Yunhong Jiang <yunhong.jiang@linux.intel.com>
The current code maps MMIO devices as shared (decrypted) by default in a
confidential computing VM.
In a TDX environment, secondary CPUs are booted using the Multiprocessor
Wakeup Structure defined in the ACPI specification. The virtual firmware
and the operating system function in the guest context, without
intervention from the VMM. Map the physical memory of the mailbox as
private. Use the is_private_mmio() callback.
Signed-off-by: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes in v9:
- None
Changes in v8:
- Included linux/acpi.h to add missing definitions that caused build
breaks (kernel test robot)
Changes in v7:
- Dropped check for !CONFIG_X86_MAILBOX_WAKEUP. The symbol is no longer
valid and now we have a stub for !CONFIG_ACPI.
- Dropped Reviewed-by tags from Dexuan and Michael as this patch
changed.
Changes in v6:
- Fixed a compile error with !CONFIG_X86_MAILBOX_WAKEUP.
- Added Reviewed-by tag from Dexuan. Thanks!
Changes in v5:
- None
Changes in v4:
- Updated to use the renamed function acpi_get_mp_wakeup_mailbox_paddr().
- Added Reviewed-by tag from Michael. Thanks!
Changes in v3:
- Use the new helper function get_mp_wakeup_mailbox_paddr().
- Edited the commit message for clarity.
Changes in v2:
- Added the helper function within_page() to improve readability
- Override the is_private_mmio() callback when detecting a TDX
environment. The address of the mailbox is checked in
hv_is_private_mmio_tdx().
---
arch/x86/hyperv/hv_vtl.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c
index b94fffa67312..1e2f5b3ea772 100644
--- a/arch/x86/hyperv/hv_vtl.c
+++ b/arch/x86/hyperv/hv_vtl.c
@@ -6,6 +6,9 @@
* Saurabh Sengar <ssengar@microsoft.com>
*/
+#include <linux/acpi.h>
+
+#include <asm/acpi.h>
#include <asm/apic.h>
#include <asm/boot.h>
#include <asm/desc.h>
@@ -59,6 +62,18 @@ static void __noreturn hv_vtl_restart(char __maybe_unused *cmd)
hv_vtl_emergency_restart();
}
+static inline bool within_page(u64 addr, u64 start)
+{
+ return addr >= start && addr < (start + PAGE_SIZE);
+}
+
+static bool hv_vtl_is_private_mmio_tdx(u64 addr)
+{
+ u64 mb_addr = acpi_get_mp_wakeup_mailbox_paddr();
+
+ return mb_addr && within_page(addr, mb_addr);
+}
+
void __init hv_vtl_init_platform(void)
{
/*
@@ -71,6 +86,8 @@ void __init hv_vtl_init_platform(void)
/* There is no paravisor present if we are here. */
if (hv_isolation_type_tdx()) {
x86_init.resources.realmode_limit = SZ_4G;
+ x86_platform.hyper.is_private_mmio = hv_vtl_is_private_mmio_tdx;
+
} else {
x86_platform.realmode_reserve = x86_init_noop;
x86_platform.realmode_init = x86_init_noop;
--
2.43.0
^ permalink raw reply related
* [PATCH v9 08/10] x86/acpi: Add a helper get the address of the wakeup mailbox
From: Ricardo Neri @ 2026-03-04 23:41 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: <20260304-rneri-wakeup-mailbox-v9-0-a5c6845e6251@linux.intel.com>
A Hyper-V VTL level 2 guest in a TDX environment needs to map the physical
page of the ACPI Multiprocessor Wakeup Structure as private (encrypted). It
needs to know the physical address of this structure. Add a helper function
to retrieve the address.
Suggested-by: Michael Kelley <mhklinux@outlook.com>
Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
Changes in v9:
- None
Changes in v8:
- Added Acked-by tag from Rafael. Thanks!
Changes in v7:
- Moved the added function to arch/x86/kernel/acpi/madt_wakeup.c
- Dropped Reviewed-by tags from Dexuan and Michael as this patch
changed.
Changes in v6:
- Added Reviewed-by tag from Dexuan. Thanks!
Changes in v5:
- None
Changes in v4:
- Renamed function to acpi_get_mp_wakeup_mailbox_paddr().
- Added Reviewed-by tag from Michael. Thanks!
Changes in v3:
- Introduced this patch
Changes in v2:
- N/A
---
arch/x86/include/asm/acpi.h | 6 ++++++
arch/x86/kernel/acpi/madt_wakeup.c | 5 +++++
2 files changed, 11 insertions(+)
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 820df375df79..c4e6459bd56b 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -184,6 +184,7 @@ void __iomem *x86_acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
void acpi_setup_mp_wakeup_mailbox(u64 addr);
struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void);
+u64 acpi_get_mp_wakeup_mailbox_paddr(void);
#else /* !CONFIG_ACPI */
@@ -210,6 +211,11 @@ static inline struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mail
return NULL;
}
+static inline u64 acpi_get_mp_wakeup_mailbox_paddr(void)
+{
+ return 0;
+}
+
#endif /* !CONFIG_ACPI */
#define ARCH_HAS_POWER_INIT 1
diff --git a/arch/x86/kernel/acpi/madt_wakeup.c b/arch/x86/kernel/acpi/madt_wakeup.c
index 82caf44b45e3..48734e4a6e8f 100644
--- a/arch/x86/kernel/acpi/madt_wakeup.c
+++ b/arch/x86/kernel/acpi/madt_wakeup.c
@@ -258,3 +258,8 @@ struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void)
{
return acpi_mp_wake_mailbox;
}
+
+u64 acpi_get_mp_wakeup_mailbox_paddr(void)
+{
+ return acpi_mp_wake_mailbox_paddr;
+}
--
2.43.0
^ permalink raw reply related
* [PATCH v9 06/10] x86/realmode: Make the location of the trampoline configurable
From: Ricardo Neri @ 2026-03-04 23:41 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, Thomas Gleixner
In-Reply-To: <20260304-rneri-wakeup-mailbox-v9-0-a5c6845e6251@linux.intel.com>
From: Yunhong Jiang <yunhong.jiang@linux.intel.com>
x86 CPUs boot in real mode. This mode uses a 1MB address space. The
trampoline must reside below this 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 a mechanism is the ACPI Multiprocessor Wakeup Structure.
In this scenario there is no restriction on locating the trampoline under
1MB memory. Moreover, certain platforms (for example, Hyper-V VTL guests)
may not have memory available for allocation below 1MB.
Add a new member to struct x86_init_resources to specify the upper bound
for the location of the trampoline memory. Preserve the default upper bound
of 1MB to conserve the current behavior.
Reviewed-by: Dexuan Cui <decui@microsoft.com>
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 in v9:
- None
Changes in v8:
- None
Changes in v7:
- None
Changes in v6:
- Added Reviewed-by tag from Dexuan. Thanks!
Changes in v5:
- None
Changes in v4:
- Added Reviewed-by tag from Michael. Thanks!
Changes in v3:
- 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 in v2:
- 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 6c8a6ead84f6..953d3199408a 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 ebefb77c37bb..252c5827d063 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 v9 07/10] x86/hyperv/vtl: Setup the 64-bit trampoline for TDX guests
From: Ricardo Neri @ 2026-03-04 23:41 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: <20260304-rneri-wakeup-mailbox-v9-0-a5c6845e6251@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 nor 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: Dexuan Cui <decui@microsoft.com>
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 in v9:
- None
Changes in v8:
- None
Changes in v7:
- None
Changes in v6:
- Added Reviewed-by tag from Dexuan. Thanks!
Changes in v5:
- None
Changes in v4:
- Added Reviewed-by tag from Michael. Thanks!
Changes in v3:
- Added a note regarding there is no need to check for a present
paravisor.
- Edited commit message for clarity.
Changes in v2:
- 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 e045bf3a2c59..b94fffa67312 100644
--- a/arch/x86/hyperv/hv_vtl.c
+++ b/arch/x86/hyperv/hv_vtl.c
@@ -68,9 +68,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 v9 05/10] x86/hyperv/vtl: Set real_mode_header in hv_vtl_init_platform()
From: Ricardo Neri @ 2026-03-04 23:41 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, Thomas Gleixner
In-Reply-To: <20260304-rneri-wakeup-mailbox-v9-0-a5c6845e6251@linux.intel.com>
From: Yunhong Jiang <yunhong.jiang@linux.intel.com>
Hyper-V VTL clears x86_platform.realmode_{init(), reserve()} in
hv_vtl_init_platform() whereas it sets real_mode_header later in
hv_vtl_early_init(). There is no need to deal with the settings of real
mode memory in two places. Also, both functions are called much earlier
than x86_platform.realmode_init() (via an early_initcall), where the
real_mode_header is needed.
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 a
environment.
Reviewed-by: Dexuan Cui <decui@microsoft.com>
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 in v9:
- None
Changes in v8:
- None
Changes in v7:
- None
Changes in v6:
- Corrected reference to hv_vtl_init_platform() in the changelog.
(Dexuan)
- Added Reviewed-by tag from Dexuan. Thanks!
Changes in v5:
- None
Changes in v4:
- Added Reviewed-by tag from Michael. Thanks!
Changes in v3:
- Edited the commit message for clarity.
Changes in v2:
- 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 9b6a9bc4ab76..e045bf3a2c59 100644
--- a/arch/x86/hyperv/hv_vtl.c
+++ b/arch/x86/hyperv/hv_vtl.c
@@ -70,6 +70,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;
@@ -251,7 +252,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 v9 03/10] dt-bindings: reserved-memory: Wakeup Mailbox for Intel processors
From: Ricardo Neri @ 2026-03-04 23:41 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,
Rafael J. Wysocki (Intel), Yunhong Jiang, Ricardo Neri
In-Reply-To: <20260304-rneri-wakeup-mailbox-v9-0-a5c6845e6251@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 the 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 specifying a separate `cpu-release-addr` for
each secondary CPU.
The operation and structure of the mailbox are 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.
Nodes that want 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. Instead, add a `compatible` property that the operating system can use
to discover the mailbox.
Reviewed-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Acked-by: Rafael J. Wysocki (Intel) <rafael.j.wysocki@intel.com>
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 in v9:
- Removed a spurious empty line. (Rob's bot)
Changes in v8:
- None
Changes in v7:
- Fixed Acked-by tag from Rafael to include the "(Intel)" suffix.
Changes in v6:
- Reworded the changelog for clarity.
- Added Acked-by tag from Rafael. Thanks!
- Added Reviewed-by tag from Rob. Thanks!
- Added Reviewed-by tag from Dexuan. Thanks!
Changes in v5:
- 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 in v4:
- 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 in v3:
- 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 in v2:
- 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 | 49 ++++++++++++++++++++++
1 file changed, 49 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..4362bc058df4
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/intel,wakeup-mailbox.yaml
@@ -0,0 +1,49 @@
+# 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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox