* RE: [PATCH net-next v5 1/2] net: mana: Handle SKB if TX SGEs exceed hardware limit
From: Haiyang Zhang @ 2025-11-16 21:36 UTC (permalink / raw)
To: Aditya Garg, KY Srinivasan, wei.liu@kernel.org, Dexuan Cui,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, Long Li, Konstantin Taranov,
horms@kernel.org, shradhagupta@linux.microsoft.com,
ssengar@linux.microsoft.com, ernis@linux.microsoft.com,
dipayanroy@linux.microsoft.com, Shiraz Saleem, leon@kernel.org,
mlevitsk@redhat.com, yury.norov@gmail.com, sbhatta@marvell.com,
linux-hyperv@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-rdma@vger.kernel.org,
Aditya Garg
In-Reply-To: <1763155003-21503-2-git-send-email-gargaditya@linux.microsoft.com>
> -----Original Message-----
> From: Aditya Garg <gargaditya@linux.microsoft.com>
> Sent: Friday, November 14, 2025 4:17 PM
> To: KY Srinivasan <kys@microsoft.com>; Haiyang Zhang
> <haiyangz@microsoft.com>; wei.liu@kernel.org; Dexuan Cui
> <DECUI@microsoft.com>; andrew+netdev@lunn.ch; davem@davemloft.net;
> edumazet@google.com; kuba@kernel.org; pabeni@redhat.com; Long Li
> <longli@microsoft.com>; Konstantin Taranov <kotaranov@microsoft.com>;
> horms@kernel.org; shradhagupta@linux.microsoft.com;
> ssengar@linux.microsoft.com; ernis@linux.microsoft.com;
> dipayanroy@linux.microsoft.com; Shiraz Saleem
> <shirazsaleem@microsoft.com>; leon@kernel.org; mlevitsk@redhat.com;
> yury.norov@gmail.com; sbhatta@marvell.com; linux-hyperv@vger.kernel.org;
> netdev@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> rdma@vger.kernel.org; Aditya Garg <gargaditya@microsoft.com>
> Cc: Aditya Garg <gargaditya@linux.microsoft.com>
> Subject: [PATCH net-next v5 1/2] net: mana: Handle SKB if TX SGEs exceed
> hardware limit
>
> The MANA hardware supports a maximum of 30 scatter-gather entries (SGEs)
> per TX WQE. Exceeding this limit can cause TX failures.
> Add ndo_features_check() callback to validate SKB layout before
> transmission. For GSO SKBs that would exceed the hardware SGE limit, clear
> NETIF_F_GSO_MASK to enforce software segmentation in the stack.
> Add a fallback in mana_start_xmit() to linearize non-GSO SKBs that still
> exceed the SGE limit.
>
> Also, Add ethtool counter for SKBs linearized
>
> Co-developed-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
> Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
> Signed-off-by: Aditya Garg <gargaditya@linux.microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
^ permalink raw reply
* RE: [patch net-next] net: mana: Handle hardware reset events when probing the device
From: Haiyang Zhang @ 2025-11-16 16:36 UTC (permalink / raw)
To: longli@linux.microsoft.com, KY Srinivasan, Wei Liu, Dexuan Cui,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Shradha Gupta, Simon Horman, Konstantin Taranov,
Souradeep Chakrabarti, Erick Archer, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-rdma@vger.kernel.org
Cc: Long Li
In-Reply-To: <1763173729-28430-1-git-send-email-longli@linux.microsoft.com>
> -----Original Message-----
> From: longli@linux.microsoft.com <longli@linux.microsoft.com>
> Sent: Friday, November 14, 2025 9:29 PM
> To: KY Srinivasan <kys@microsoft.com>; Haiyang Zhang
> <haiyangz@microsoft.com>; Wei Liu <wei.liu@kernel.org>; Dexuan Cui
> <DECUI@microsoft.com>; David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo Abeni
> <pabeni@redhat.com>; Shradha Gupta <shradhagupta@linux.microsoft.com>;
> Simon Horman <horms@kernel.org>; Konstantin Taranov
> <kotaranov@microsoft.com>; Souradeep Chakrabarti
> <schakrabarti@linux.microsoft.com>; Erick Archer
> <erick.archer@outlook.com>; linux-hyperv@vger.kernel.org;
> netdev@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> rdma@vger.kernel.org
> Cc: Long Li <longli@microsoft.com>
> Subject: [patch net-next] net: mana: Handle hardware reset events when
> probing the device
>
> From: Long Li <longli@microsoft.com>
>
> When MANA is being probed, it's possible that hardware is in recovery
> mode and the device may get GDMA_EQE_HWC_RESET_REQUEST over HWC in the
> middle of the probe. Detect such condition and go through the recovery
> service procedure.
>
> Fixes: fbe346ce9d62 ("net: mana: Handle Reset Request from MANA NIC")
> Signed-off-by: Long Li <longli@microsoft.com>
> ---
> .../net/ethernet/microsoft/mana/gdma_main.c | 131 +++++++++++++++---
> include/net/mana/gdma.h | 9 +-
> 2 files changed, 122 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> index effe0a2f207a..1d9c2beb22b2 100644
> --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> @@ -15,6 +15,12 @@
>
> struct dentry *mana_debugfs_root;
>
> +static struct mana_serv_delayed_work {
> + struct delayed_work work;
> + struct pci_dev *pdev;
> + enum gdma_eqe_type type;
> +} mns_delayed_wk;
> +
> static u32 mana_gd_r32(struct gdma_context *g, u64 offset)
> {
> return readl(g->bar0_va + offset);
> @@ -387,6 +393,25 @@ EXPORT_SYMBOL_NS(mana_gd_ring_cq, "NET_MANA");
>
> #define MANA_SERVICE_PERIOD 10
>
> +static void mana_serv_rescan(struct pci_dev *pdev)
> +{
> + struct pci_bus *parent;
> +
> + pci_lock_rescan_remove();
> +
> + parent = pdev->bus;
> + if (!parent) {
> + dev_err(&pdev->dev, "MANA service: no parent bus\n");
> + goto out;
> + }
> +
> + pci_stop_and_remove_bus_device(pdev);
> + pci_rescan_bus(parent);
> +
> +out:
> + pci_unlock_rescan_remove();
> +}
> +
> static void mana_serv_fpga(struct pci_dev *pdev)
> {
> struct pci_bus *bus, *parent;
> @@ -419,9 +444,12 @@ static void mana_serv_reset(struct pci_dev *pdev)
> {
> struct gdma_context *gc = pci_get_drvdata(pdev);
> struct hw_channel_context *hwc;
> + int ret;
>
> if (!gc) {
> - dev_err(&pdev->dev, "MANA service: no GC\n");
> + /* Perform PCI rescan on device if GC is not set up */
> + dev_err(&pdev->dev, "MANA service: GC not setup,
> rescanning\n");
> + mana_serv_rescan(pdev);
> return;
> }
>
> @@ -440,9 +468,18 @@ static void mana_serv_reset(struct pci_dev *pdev)
>
> msleep(MANA_SERVICE_PERIOD * 1000);
>
> - mana_gd_resume(pdev);
> + ret = mana_gd_resume(pdev);
> + if (ret == -ETIMEDOUT || ret == -EPROTO) {
> + /* Perform PCI rescan on device if we failed on HWC */
> + dev_err(&pdev->dev, "MANA service: resume failed,
> rescanning\n");
> + mana_serv_rescan(pdev);
> + goto out;
> + }
>
> - dev_info(&pdev->dev, "MANA reset cycle completed\n");
> + if (ret)
> + dev_info(&pdev->dev, "MANA reset cycle failed err %d\n", ret);
> + else
> + dev_info(&pdev->dev, "MANA reset cycle completed\n");
>
> out:
> gc->in_service = false;
> @@ -454,18 +491,9 @@ struct mana_serv_work {
> enum gdma_eqe_type type;
> };
>
> -static void mana_serv_func(struct work_struct *w)
> +static void mana_do_service(enum gdma_eqe_type type, struct pci_dev
> *pdev)
> {
> - struct mana_serv_work *mns_wk;
> - struct pci_dev *pdev;
> -
> - mns_wk = container_of(w, struct mana_serv_work, serv_work);
> - pdev = mns_wk->pdev;
> -
> - if (!pdev)
> - goto out;
> -
> - switch (mns_wk->type) {
> + switch (type) {
> case GDMA_EQE_HWC_FPGA_RECONFIG:
> mana_serv_fpga(pdev);
> break;
> @@ -475,12 +503,36 @@ static void mana_serv_func(struct work_struct *w)
> break;
>
> default:
> - dev_err(&pdev->dev, "MANA service: unknown type %d\n",
> - mns_wk->type);
> + dev_err(&pdev->dev, "MANA service: unknown type %d\n", type);
> break;
> }
> +}
> +
> +static void mana_serv_delayed_func(struct work_struct *w)
> +{
> + struct mana_serv_delayed_work *dwork;
> + struct pci_dev *pdev;
> +
> + dwork = container_of(w, struct mana_serv_delayed_work, work.work);
> + pdev = dwork->pdev;
> +
> + if (pdev)
> + mana_do_service(dwork->type, pdev);
> +
> + pci_dev_put(pdev);
> +}
> +
> +static void mana_serv_func(struct work_struct *w)
> +{
> + struct mana_serv_work *mns_wk;
> + struct pci_dev *pdev;
> +
> + mns_wk = container_of(w, struct mana_serv_work, serv_work);
> + pdev = mns_wk->pdev;
> +
> + if (pdev)
> + mana_do_service(mns_wk->type, pdev);
>
> -out:
> pci_dev_put(pdev);
> kfree(mns_wk);
> module_put(THIS_MODULE);
> @@ -541,6 +593,17 @@ static void mana_gd_process_eqe(struct gdma_queue
> *eq)
> case GDMA_EQE_HWC_RESET_REQUEST:
> dev_info(gc->dev, "Recv MANA service type:%d\n", type);
>
> + if (atomic_inc_return(&gc->in_probe) == 1) {
Since we don't care about how many times it entered probe/service,
test_and_set_bit() should be sufficient here.
> + /*
> + * Device is in probe and we received an hardware reset
> + * event, probe() will detect that "in_probe" has
> + * changed and perform service procedure.
> + */
> + dev_info(gc->dev,
> + "Service is to be processed in probe\n");
> + break;
> + }
> +
> if (gc->in_service) {
> dev_info(gc->dev, "Already in service\n");
> break;
> @@ -1930,6 +1993,8 @@ 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);
>
> + atomic_set(&gc->in_probe, 0);
> +
> err = mana_gd_setup(pdev);
> if (err)
> goto unmap_bar;
> @@ -1942,8 +2007,19 @@ static int mana_gd_probe(struct pci_dev *pdev,
> const struct pci_device_id *ent)
> if (err)
> goto cleanup_mana;
>
> + /*
> + * If a hardware reset event has occurred over HWC during probe,
> + * rollback and perform hardware reset procedure.
> + */
> + if (atomic_inc_return(&gc->in_probe) > 1) {
> + err = -EPROTO;
> + goto cleanup_mana_rdma;
> + }
> +
> return 0;
>
> +cleanup_mana_rdma:
> + mana_rdma_remove(&gc->mana_ib);
> cleanup_mana:
> mana_remove(&gc->mana, false);
> cleanup_gd:
> @@ -1967,6 +2043,25 @@ static int mana_gd_probe(struct pci_dev *pdev,
> const struct pci_device_id *ent)
> disable_dev:
> pci_disable_device(pdev);
> dev_err(&pdev->dev, "gdma probe failed: err = %d\n", err);
> +
> + /*
> + * Hardware could be in recovery mode and the HWC returns TIMEDOUT
> or
> + * EPROTO from mana_gd_setup(), mana_probe() or mana_rdma_probe(),
> or
> + * we received a hardware reset event over HWC interrupt. In this
> case,
> + * perform the device recovery procedure after MANA_SERVICE_PERIOD
> + * seconds.
> + */
> + if (err == -ETIMEDOUT || err == -EPROTO) {
> + dev_info(&pdev->dev, "Start MANA recovery mode\n");
> +
> + mns_delayed_wk.pdev = pci_dev_get(pdev);
> + mns_delayed_wk.type = GDMA_EQE_HWC_RESET_REQUEST;
> +
> + INIT_DELAYED_WORK(&mns_delayed_wk.work,
> mana_serv_delayed_func);
To avoid INIT_DELAYED_WORK potentially multiple times this should be in
the mana_driver_init()
> + schedule_delayed_work(&mns_delayed_wk.work,
> + secs_to_jiffies(MANA_SERVICE_PERIOD));
> + }
> +
> return err;
> }
>
> @@ -2084,6 +2179,8 @@ static int __init mana_driver_init(void)
>
> static void __exit mana_driver_exit(void)
> {
> + cancel_delayed_work_sync(&mns_delayed_wk.work);
I think we should call disable_delayed_work_sync() to prevent the work
scheduled again after this line.
> +
> pci_unregister_driver(&mana_driver);
>
> debugfs_remove(mana_debugfs_root);
> diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
> index 637f42485dba..1bb4c6ada2b6 100644
> --- a/include/net/mana/gdma.h
> +++ b/include/net/mana/gdma.h
> @@ -430,6 +430,9 @@ struct gdma_context {
> u64 pf_cap_flags1;
>
> struct workqueue_struct *service_wq;
> +
> + /* Count how many times we have finished probe or HWC events */
> + atomic_t in_probe;
> };
>
> static inline bool mana_gd_is_mana(struct gdma_dev *gd)
> @@ -592,6 +595,9 @@ enum {
> #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17)
> #define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6)
>
> +/* Driver can handle hardware reset events during probe */
> +#define GDMA_DRV_CAP_FLAG_1_RECOVER_PROBE BIT(22)
> +
> #define GDMA_DRV_CAP_FLAGS1 \
> (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
> GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
> @@ -601,7 +607,8 @@ enum {
> GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \
> GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \
> GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \
> - GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE)
> + GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \
> + GDMA_DRV_CAP_FLAG_1_RECOVER_PROBE)
>
> #define GDMA_DRV_CAP_FLAGS2 0
>
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH] Drivers: hv: ioctl for self targeted passthrough hvcalls
From: kernel test robot @ 2025-11-16 8:17 UTC (permalink / raw)
To: Anirudh Rayabharam, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li
Cc: llvm, oe-kbuild-all, anirudh, linux-hyperv, linux-kernel
In-Reply-To: <20251114095853.3482596-1-anirudh@anirudhrb.com>
Hi Anirudh,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v6.18-rc5]
[cannot apply to next-20251114]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Anirudh-Rayabharam/Drivers-hv-ioctl-for-self-targeted-passthrough-hvcalls/20251114-182039
base: linus/master
patch link: https://lore.kernel.org/r/20251114095853.3482596-1-anirudh%40anirudhrb.com
patch subject: [PATCH] Drivers: hv: ioctl for self targeted passthrough hvcalls
config: x86_64-buildonly-randconfig-005-20251116 (https://download.01.org/0day-ci/archive/20251116/202511161617.KcDzR4sA-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251116/202511161617.KcDzR4sA-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511161617.KcDzR4sA-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/hv/mshv_root_main.c:125:2: error: use of undeclared identifier 'HVCALL_GET_PARTITION_PROPERTY_EX'
125 | HVCALL_GET_PARTITION_PROPERTY_EX,
| ^
>> drivers/hv/mshv_root_main.c:175:18: error: invalid application of 'sizeof' to an incomplete type 'u16[]' (aka 'unsigned short[]')
175 | for (i = 0; i < ARRAY_SIZE(mshv_passthru_hvcalls); ++i)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/array_size.h:11:32: note: expanded from macro 'ARRAY_SIZE'
11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
| ^~~~~
drivers/hv/mshv_root_main.c:179:11: error: invalid application of 'sizeof' to an incomplete type 'u16[]' (aka 'unsigned short[]')
179 | if (i >= ARRAY_SIZE(mshv_passthru_hvcalls))
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/array_size.h:11:32: note: expanded from macro 'ARRAY_SIZE'
11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
| ^
include/linux/compiler.h:55:47: note: expanded from macro 'if'
55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
| ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:57:52: note: expanded from macro '__trace_if_var'
57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ^~~~
drivers/hv/mshv_root_main.c:179:11: error: invalid application of 'sizeof' to an incomplete type 'u16[]' (aka 'unsigned short[]')
179 | if (i >= ARRAY_SIZE(mshv_passthru_hvcalls))
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/array_size.h:11:32: note: expanded from macro 'ARRAY_SIZE'
11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
| ^
include/linux/compiler.h:55:47: note: expanded from macro 'if'
55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
| ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:57:61: note: expanded from macro '__trace_if_var'
57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ^~~~
drivers/hv/mshv_root_main.c:179:11: error: invalid application of 'sizeof' to an incomplete type 'u16[]' (aka 'unsigned short[]')
179 | if (i >= ARRAY_SIZE(mshv_passthru_hvcalls))
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/array_size.h:11:32: note: expanded from macro 'ARRAY_SIZE'
11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
| ^
include/linux/compiler.h:55:47: note: expanded from macro 'if'
55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
| ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:57:86: note: expanded from macro '__trace_if_var'
57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
| ~~~~~~~~~~~~~~~~~^~~~~
include/linux/compiler.h:68:3: note: expanded from macro '__trace_if_value'
68 | (cond) ? \
| ^~~~
5 errors generated.
vim +/HVCALL_GET_PARTITION_PROPERTY_EX +125 drivers/hv/mshv_root_main.c
117
118 /*
119 * Only allow hypercalls that have a u64 partition id as the first member of
120 * the input structure.
121 * These are sorted by value.
122 */
123 static u16 mshv_passthru_hvcalls[] = {
124 HVCALL_GET_PARTITION_PROPERTY,
> 125 HVCALL_GET_PARTITION_PROPERTY_EX,
126 HVCALL_SET_PARTITION_PROPERTY,
127 HVCALL_INSTALL_INTERCEPT,
128 HVCALL_GET_VP_REGISTERS,
129 HVCALL_SET_VP_REGISTERS,
130 HVCALL_TRANSLATE_VIRTUAL_ADDRESS,
131 HVCALL_CLEAR_VIRTUAL_INTERRUPT,
132 HVCALL_REGISTER_INTERCEPT_RESULT,
133 HVCALL_ASSERT_VIRTUAL_INTERRUPT,
134 HVCALL_GET_GPA_PAGES_ACCESS_STATES,
135 HVCALL_SIGNAL_EVENT_DIRECT,
136 HVCALL_POST_MESSAGE_DIRECT,
137 HVCALL_GET_VP_CPUID_VALUES,
138 };
139
140 static bool mshv_hvcall_is_async(u16 code)
141 {
142 switch (code) {
143 case HVCALL_SET_PARTITION_PROPERTY:
144 return true;
145 default:
146 break;
147 }
148 return false;
149 }
150
151 static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
152 bool partition_locked,
153 void __user *user_args)
154 {
155 u64 status;
156 int ret = 0, i;
157 bool is_async;
158 struct mshv_root_hvcall args;
159 struct page *page;
160 unsigned int pages_order;
161 void *input_pg = NULL;
162 void *output_pg = NULL;
163 u64 pt_id = partition ? partition->pt_id : HV_PARTITION_ID_SELF;
164
165 if (copy_from_user(&args, user_args, sizeof(args)))
166 return -EFAULT;
167
168 if (args.status || !args.in_ptr || args.in_sz < sizeof(u64) ||
169 mshv_field_nonzero(args, rsvd) || args.in_sz > HV_HYP_PAGE_SIZE)
170 return -EINVAL;
171
172 if (args.out_ptr && (!args.out_sz || args.out_sz > HV_HYP_PAGE_SIZE))
173 return -EINVAL;
174
> 175 for (i = 0; i < ARRAY_SIZE(mshv_passthru_hvcalls); ++i)
176 if (args.code == mshv_passthru_hvcalls[i])
177 break;
178
179 if (i >= ARRAY_SIZE(mshv_passthru_hvcalls))
180 return -EINVAL;
181
182 is_async = mshv_hvcall_is_async(args.code);
183 if (is_async) {
184 /* async hypercalls can only be called from partition fd */
185 if (!partition || !partition_locked)
186 return -EINVAL;
187 ret = mshv_init_async_handler(partition);
188 if (ret)
189 return ret;
190 }
191
192 pages_order = args.out_ptr ? 1 : 0;
193 page = alloc_pages(GFP_KERNEL, pages_order);
194 if (!page)
195 return -ENOMEM;
196 input_pg = page_address(page);
197
198 if (args.out_ptr)
199 output_pg = (char *)input_pg + PAGE_SIZE;
200 else
201 output_pg = NULL;
202
203 if (copy_from_user(input_pg, (void __user *)args.in_ptr,
204 args.in_sz)) {
205 ret = -EFAULT;
206 goto free_pages_out;
207 }
208
209 /*
210 * NOTE: This only works because all the allowed hypercalls' input
211 * structs begin with a u64 partition_id field.
212 */
213 *(u64 *)input_pg = pt_id;
214
215 if (args.reps)
216 status = hv_do_rep_hypercall(args.code, args.reps, 0,
217 input_pg, output_pg);
218 else
219 status = hv_do_hypercall(args.code, input_pg, output_pg);
220
221 if (hv_result(status) == HV_STATUS_CALL_PENDING) {
222 if (is_async) {
223 mshv_async_hvcall_handler(partition, &status);
224 } else { /* Paranoia check. This shouldn't happen! */
225 ret = -EBADFD;
226 goto free_pages_out;
227 }
228 }
229
230 if (hv_result(status) == HV_STATUS_INSUFFICIENT_MEMORY) {
231 ret = hv_call_deposit_pages(NUMA_NO_NODE, pt_id, 1);
232 if (!ret)
233 ret = -EAGAIN;
234 } else if (!hv_result_success(status)) {
235 ret = hv_result_to_errno(status);
236 }
237
238 /*
239 * Always return the status and output data regardless of result.
240 * The VMM may need it to determine how to proceed. E.g. the status may
241 * contain the number of reps completed if a rep hypercall partially
242 * succeeded.
243 */
244 args.status = hv_result(status);
245 args.reps = args.reps ? hv_repcomp(status) : 0;
246 if (copy_to_user(user_args, &args, sizeof(args)))
247 ret = -EFAULT;
248
249 if (output_pg &&
250 copy_to_user((void __user *)args.out_ptr, output_pg, args.out_sz))
251 ret = -EFAULT;
252
253 free_pages_out:
254 free_pages((unsigned long)input_pg, pages_order);
255
256 return ret;
257 }
258
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: Bug#1120602: [REGRESSION 6.12.y] hyper-v: BUG: kernel NULL pointer dereference, address: 00000000000000a0: RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
From: Naman Jain @ 2025-11-15 9:03 UTC (permalink / raw)
To: Salvatore Bonaccorso, 1120602
Cc: Peter Morrow, Long Li, linux-hyperv, linux-kernel, regressions,
stable, John Starks, Michael Kelley, Tianyu Lan, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Greg Kroah-Hartman
In-Reply-To: <aRei1DGOWy13GqvE@eldamar.lan>
On 11/15/2025 3:14 AM, Salvatore Bonaccorso wrote:
> Hi,
>
> On Fri, Nov 14, 2025 at 08:05:55PM +0530, Naman Jain wrote:
>>
>>
>> On 11/14/2025 5:19 PM, Peter Morrow wrote:
>>> Hi Naman,
>>>
>>> On Fri, 14 Nov 2025 at 06:03, Naman Jain <namjain@linux.microsoft.com> wrote:
>>>>
>>>>
>>>>
>>>> On 11/13/2025 11:59 PM, Salvatore Bonaccorso wrote:
>>>>> Peter Morrow reported in Debian a regression, reported in
>>>>> https://bugs.debian.org/1120602 . The regression was seen after
>>>>> updating, to 6.12.57-1 in Debian, but details on the offending commit
>>>>> follows.
>>>>>
>>>>> His report was as follows:
>>>>>
>>>>>> Dear Maintainer,
>>>>>>
>>>>>> I'm seeing a kernel crash quite soon after boot on a debian trixie based
>>>>>> system running 6.12.57+deb13-amd64, unfortunately the kernel panics before
>>>>>> I can access the system to gather more information. Thus I'll provide details
>>>>>> of the system using a previously known good version. The panic is happening
>>>>>> 100% of the time unfortunately. I have access to the serial console however
>>>>>> so can enable any required verbose logging during boot if necessary.
>>>>>>
>>>>>> Crucially the crash is not seen with kernel version 6.12.41+deb13-amd64 with the
>>>>>> same userspace. We had pinned to that version until very recently to in order
>>>>>> to work around https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1109676
>>>>>>
>>>>>> I'm running a dpdk application here (VPP) on Azure, VM form factor is a
>>>>>> "Standard DS3 v2 (4 vcpus, 14 GiB memory)".
>>>>>>
>>>>>> The only relevant upstream commit in this area (as far as I can see) is:
>>>>>>
>>>>>> https://lore.kernel.org/linux-hyperv/1bb599ee-fe28-409d-b430-2fc086268936@linux.microsoft.com/
>>>>>>
>>>>>> The comment regarding avoiding races at start adds a bit more weight behind this
>>>>>> hunch, though it's only a hunch as I am most definitely nowhere near an expert
>>>>>> in this area.
>>>>>>
>>>>>> -- Package-specific info:
>>>>>>
>>>>>> [ 19.625535] BUG: kernel NULL pointer dereference, address: 00000000000000a0
>>>>>> [ 19.628874] #PF: supervisor read access in kernel mode
>>>>>> [ 19.630841] #PF: error_code(0x0000) - not-present page
>>>>>> [ 19.632788] PGD 0 P4D 0
>>>>>> [ 19.633905] Oops: Oops: 0000 [#1] PREEMPT SMP PTI
>>>>>> [ 19.635586] CPU: 3 UID: 0 PID: 0 Comm: swapper/3 Not tainted 6.12.57+deb13-amd64 #1 Debian 6.12.57-1
>>>>>> [ 19.640216] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 09/28/2024
>>>>>> [ 19.644514] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
>>>>>> [ 19.646994] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
>>>>>> [ 19.654377] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
>>>>>> [ 19.656385] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
>>>>>> [ 19.659240] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
>>>>>> [ 19.662168] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
>>>>>> [ 19.665239] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
>>>>>> [ 19.668193] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
>>>>>> [ 19.671106] FS: 0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
>>>>>> [ 19.674281] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>>>>> [ 19.676533] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
>>>>>> [ 19.679385] Call Trace:
>>>>>> [ 19.680361] <IRQ>
>>>>>> [ 19.681181] vmbus_isr+0x1a5/0x210 [hv_vmbus]
>>>>>> [ 19.682916] __sysvec_hyperv_callback+0x32/0x60
>>>>>> [ 19.684991] sysvec_hyperv_callback+0x6c/0x90
>>>>>> [ 19.686665] </IRQ>
>>>>>> [ 19.687509] <TASK>
>>>>>> [ 19.688366] asm_sysvec_hyperv_callback+0x1a/0x20
>>>>>> [ 19.690262] RIP: 0010:pv_native_safe_halt+0xf/0x20
>>>>>> [ 19.692067] Code: 09 e9 c5 08 01 00 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 66 90 0f 00 2d e5 3b 31 00 fb f4 <c3> cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90
>>>>>> [ 19.699119] RSP: 0018:ffffb15ac0103ed8 EFLAGS: 00000246
>>>>>> [ 19.701412] RAX: 0000000000000003 RBX: ffff8ff5403b1fc0 RCX: ffff8ff54c64ce30
>>>>>> [ 19.704328] RDX: 0000000000000000 RSI: 0000000000000003 RDI: 000000000001f894
>>>>>> [ 19.706910] RBP: 0000000000000003 R08: 000000000bb760d9 R09: 00fca75150b080e9
>>>>>> [ 19.709762] R10: 0000000000000003 R11: 0000000000000001 R12: 0000000000000000
>>>>>> [ 19.712510] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
>>>>>> [ 19.715173] default_idle+0x9/0x20
>>>>>> [ 19.716846] default_idle_call+0x29/0x100
>>>>>> [ 19.718623] do_idle+0x1fe/0x240
>>>>>> [ 19.720045] cpu_startup_entry+0x29/0x30
>>>>>> [ 19.721595] start_secondary+0x11e/0x140
>>>>>> [ 19.723080] common_startup_64+0x13e/0x141
>>>>>> [ 19.725222] </TASK>
>>>>>> [ 19.726387] Modules linked in: isofs cdrom uio_hv_generic uio binfmt_misc intel_rapl_msr intel_rapl_common intel_uncore_frequency_common isst_if_mbox_msr isst_if_common rpcrdma skx_edac_common nfit sunrpc libnvdimm crct10dif_pclmul ghash_clmulni_intel sha512_ssse3 sha256_ssse3 rdma_ucm ib_iser sha1_ssse3 rdma_cm aesni_intel iw_cm gf128mul crypto_simd libiscsi cryptd ib_umad ib_ipoib scsi_transport_iscsi ib_cm rapl sg hv_utils hv_balloon evdev pcspkr joydev mpls_router ip_tunnel ramoops configfs pstore_blk efi_pstore pstore_zone nfnetlink vsock_loopback vmw_vsock_virtio_transport_common hv_sock vmw_vsock_vmci_transport vsock vmw_vmci efivarfs ip_tables x_tables autofs4 overlay squashfs dm_verity dm_bufio reed_solomon dm_mod loop ext4 crc16 mbcache jbd2 crc32c_generic mlx5_ib ib_uverbs ib_core mlx5_core mlxfw pci_hyperv pci_hyperv_intf hyperv_drm drm_shmem_helper sd_mod drm_kms_helper hv_storvsc scsi_transport_fc drm scsi_mod hid_generic hid_hyperv hid serio_raw hv_netvsc hyperv_keyboard scsi_common hv_vmbus
>>>>>> [ 19.726466] crc32_pclmul crc32c_intel
>>>>>> [ 19.765771] CR2: 00000000000000a0
>>>>>> [ 19.767524] ---[ end trace 0000000000000000 ]---
>>>>>> [ 19.800433] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
>>>>>> [ 19.803170] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
>>>>>> [ 19.811041] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
>>>>>> [ 19.813466] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
>>>>>> [ 19.816504] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
>>>>>> [ 19.819484] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
>>>>>> [ 19.822625] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
>>>>>> [ 19.825569] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
>>>>>> [ 19.828804] FS: 0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
>>>>>> [ 19.832214] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>>>>> [ 19.834709] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
>>>>>> [ 19.837976] Kernel panic - not syncing: Fatal exception in interrupt
>>>>>> [ 19.841825] Kernel Offset: 0x28a00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
>>>>>> [ 19.896620] ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---
>>>>>>
>>>>
>>>> <snip>
>>>>
>>>>> The offending commit appers to be the backport of b15b7d2a1b09
>>>>> ("uio_hv_generic: Let userspace take care of interrupt mask") for
>>>>> 6.12.y.
>>>>>
>>>>> Peter confirmed that reverting this commit on top of 6.12.57-1 as
>>>>> packaged in Debian resolves indeed the issue. Interestingly the issue
>>>>> is *not* seen with 6.17.7 based kernel in Debian.
>>>>>
>>>>> #regzbot introduced: 37bd91f22794dc05436130d6983302cb90ecfe7e
>>>>> #regzbot monitor: https://bugs.debian.org/1120602
>>>>>
>>>>> Thank you already!
>>>>>
>>>>> Regards,
>>>>> Salvatore
>>>>
>>>> Hi Peter, Salvatore,
>>>> Thanks for reporting this crash, and sorry for the trouble. Here is my
>>>> analysis.
>>>>
>>>> On 6.17.7, where commit d062463edf17 ("uio_hv_generic: Set event for all
>>>> channels on the device") is present, hv_uio_irqcontrol() supports
>>>> setting of interrupt mask from userspace for sub-channels as well.
>>>>
>>>> This aligns with commit e29587c07537 ("uio_hv_generic: Let userspace
>>>> take care of interrupt mask") which relies on userspace to manage
>>>> interrupt mask, so it safely removes the interrupt mask management logic
>>>> in the driver.
>>>>
>>>> However, in 6.12.57, the first commit is not present, but the second one
>>>> is, so there is no way to disable interrupt mask for sub-channels and
>>>> interrupt_mask stays 0, which means interrupts are not masked. So we may
>>>> be having an interrupt callback being handled for a sub-channel, where
>>>> we do not expect it to come. This may be causing this issue.
>>>>
>>>> This would have led to a crash in hv_uio_channel_cb() for sub-channels:
>>>> struct hv_device *hv_dev = chan->device_obj;
>>>>
>>>>
>>>> I have ported commit d062463edf17 ("uio_hv_generic: Set event for all
>>>> channels on the device") on 6.12.57, and resolved some merge conflicts.
>>>> Could you please help with testing this, if it works for you.
>>>
>>> Applying the patch against the debian 6.12.57 kernel worked, I am no
>>> longer seeing that panic on boot:
>>>
>>> gnos@vEdge:~$ uname -a
>>> Linux vEdge 6.12+unreleased-amd64 #1 SMP PREEMPT_DYNAMIC Debian
>>> 6.12.57-1a~test (2025-11-14) x86_64 GNU/Linux
>>> gnos@vEdge:~$ uptime
>>> 11:46:33 up 4 min, 1 user, load average: 3.31, 2.07, 0.89
>>> gnos@vEdge:~$ sudo dmidecode -t system
>>> # dmidecode 3.6
>>> Getting SMBIOS data from sysfs.
>>> SMBIOS 3.1.0 present.
>>>
>>> Handle 0x0001, DMI type 1, 27 bytes
>>> System Information
>>> Manufacturer: Microsoft Corporation
>>> Product Name: Virtual Machine
>>> Version: Hyper-V UEFI Release v4.1
>>> Serial Number: 0000-0002-8036-1108-7588-3134-50
>>> UUID: 26e86d6e-140c-496a-862c-a3b3bbcd16ad
>>> Wake-up Type: Power Switch
>>> SKU Number: None
>>> Family: Virtual Machine
>>>
>>> Handle 0x0010, DMI type 32, 11 bytes
>>> System Boot Information
>>> Status: No errors detected
>>>
>>> gnos@vEdge:~$
>>>
>>> Thanks a lot for the quick analysis!
>>>
>>> Peter.
>>
>> Hi Peter,
>>
>> Thanks for confirming. I am discussing this with Long Li, to hear his
>> thoughts on this, and have kept the patch ready.
>> Porting the same on 6.6 and older kernels would be a little different since
>> we don't have commit 547fa4ffd799 ("uio_hv_generic: Enable interrupt for low
>> speed VMBus devices") on these kernels and this would lead to merge
>> conflicts, which needs to be handled separately.
>>
>> Meanwhile, if I should be including any tags in the fix patch for debian
>> bug, please let me know.
>
> Thank you very much for the quick analysis and fix.
>
> If you can add a Closes: https://bugs.debian.org/1120602 that would
> make our tracking for the fixes easier. But not sure if this is
> allowed for proposing the backport for a stable series, as it did not
> affect the upper releases.
>
> In any case your work is much appreciated!
>
> Regards,
> Salvatore
Hi,
I have sent the patches now to the list. Please consider adding your
tested-by if you find it alright.
Thanks.
Regards,
Naman
^ permalink raw reply
* Re: [PATCH 6.12] uio_hv_generic: Set event for all channels on the device
From: Naman Jain @ 2025-11-15 9:02 UTC (permalink / raw)
To: Wei Liu, Dexuan Cui, Greg Kroah-Hartman, Michael Kelley, Long Li,
Saurabh Sengar
Cc: K . Y . Srinivasan, Haiyang Zhang, Tianyu Lan, linux-hyperv,
linux-kernel, stable, Salvatore Bonaccorso, Peter Morrow
In-Reply-To: <20251115085730.2197-1-namjain@linux.microsoft.com>
On 11/15/2025 2:27 PM, Naman Jain wrote:
> From: Long Li <longli@microsoft.com>
>
> Hyper-V may offer a non latency sensitive device with subchannels without
> monitor bit enabled. The decision is entirely on the Hyper-V host not
> configurable within guest.
>
> When a device has subchannels, also signal events for the subchannel
> if its monitor bit is disabled.
>
> This patch also removes the memory barrier when monitor bit is enabled
> as it is not necessary. The memory barrier is only needed between
> setting up interrupt mask and calling vmbus_set_event() when monitor
> bit is disabled.
>
> This is a backport of the upstream commit
> d062463edf17 ("uio_hv_generic: Set event for all channels on the device")
> with minor modifications to resolve merge conflicts.
> Original change was not a fix, but it needs to be backported to fix a
> NULL pointer crash resulting from missing interrupt mask setting.
>
> Commit 37bd91f22794 ("uio_hv_generic: Let userspace take care of interrupt mask")
> removed the default setting of interrupt_mask for channels (including
> subchannels) in the uio_hv_generic driver, as it relies on the user space
> to take care of managing it. This approach works fine when user space
> can control this setting using the irqcontrol interface provided for uio
> devices. Support for setting the interrupt mask through this interface for
> subchannels came only after commit d062463edf17 ("uio_hv_generic: Set event
> for all channels on the device"). On older kernels, this change is not
> present. With uio_hv_generic no longer setting the interrupt_mask, and
> userspace not having the capability to set it, it remains unset,
> and interrupts can come for the subchannels, which can result in a crash
> in hv_uio_channel_cb. Backport the change to older kernels, where this
> change was not present, to allow userspace to set the interrupt mask
> properly for subchannels. Additionally, this patch also adds certain
> checks for primary vs subchannels in the hv_uio_channel_cb, which can
> gracefully handle these two cases and prevent the NULL pointer crashes.
>
> Signed-off-by: Long Li <longli@microsoft.com>
> Reviewed-by: Michael Kelley <mhklinux@outlook.com>
> Reviewed-by: Saurabh Sengar <ssengar@linux.microsoft.com>
> Fixes: 37bd91f22794 ("uio_hv_generic: Let userspace take care of interrupt mask")
Sorry for missing this, please add Closes tag, if possible before merging.
Closes: https://bugs.debian.org/1120602
I have kept it in the other patch for 6.6 and prior kernels.
Regards,
Naman
> Cc: <stable@vger.kernel.org> # 6.12.x
> Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
> ---
Regards,
Naman
^ permalink raw reply
* [PATCH 6.6 and older] uio_hv_generic: Enable user space to manage interrupt_mask for subchannels
From: Naman Jain @ 2025-11-15 8:59 UTC (permalink / raw)
To: Wei Liu, Dexuan Cui, Greg Kroah-Hartman, Michael Kelley, Long Li,
Saurabh Sengar
Cc: K . Y . Srinivasan, Haiyang Zhang, Tianyu Lan, Naman Jain,
linux-hyperv, linux-kernel, stable, Salvatore Bonaccorso,
Peter Morrow
From: Long Li <longli@microsoft.com>
Enable the user space to manage interrupt_mask for subchannels through
irqcontrol interface for uio device. Also remove the memory barrier
when monitor bit is enabled as it is not necessary.
This is a backport of the upstream commit
d062463edf17 ("uio_hv_generic: Set event for all channels on the device")
with some modifications to resolve merge conflicts and take care of
missing support for slow devices on older kernels.
Original change was not a fix, but it needs to be backported to fix a
NULL pointer crash resulting from missing interrupt mask setting.
Commit 37bd91f22794 ("uio_hv_generic: Let userspace take care of interrupt mask")
removed the default setting of interrupt_mask for channels (including
subchannels) in the uio_hv_generic driver, as it relies on the user space
to take care of managing it. This approach works fine when user space
can control this setting using the irqcontrol interface provided for uio
devices. Support for setting the interrupt mask through this interface for
subchannels came only after commit d062463edf17 ("uio_hv_generic: Set event
for all channels on the device"). On older kernels, this change is not
present. With uio_hv_generic no longer setting the interrupt_mask, and
userspace not having the capability to set it, it remains unset,
and interrupts can come for the subchannels, which can result in a crash
in hv_uio_channel_cb. Backport the change to older kernels, where this
change was not present, to allow userspace to set the interrupt mask
properly for subchannels. Additionally, this patch also adds certain
checks for primary vs subchannels in the hv_uio_channel_cb, which can
gracefully handle these two cases and prevent the NULL pointer crashes.
Signed-off-by: Long Li <longli@microsoft.com>
Fixes: 37bd91f22794 ("uio_hv_generic: Let userspace take care of interrupt mask")
Closes: https://bugs.debian.org/1120602
Cc: <stable@vger.kernel.org> # 6.6.x and older
Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
---
Remove reviewed-by tags since the original code has changed quite a bit
while backporting.
Backported change for 6.12 kernel is sent separately.
---
drivers/uio/uio_hv_generic.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index 2724656bf634..69e5016ebd46 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -80,9 +80,15 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
{
struct hv_uio_private_data *pdata = info->priv;
struct hv_device *dev = pdata->device;
+ struct vmbus_channel *primary, *sc;
- dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state;
- virt_mb();
+ primary = dev->channel;
+ primary->inbound.ring_buffer->interrupt_mask = !irq_state;
+
+ mutex_lock(&vmbus_connection.channel_mutex);
+ list_for_each_entry(sc, &primary->sc_list, sc_list)
+ sc->inbound.ring_buffer->interrupt_mask = !irq_state;
+ mutex_unlock(&vmbus_connection.channel_mutex);
return 0;
}
@@ -93,11 +99,18 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
static void hv_uio_channel_cb(void *context)
{
struct vmbus_channel *chan = context;
- struct hv_device *hv_dev = chan->device_obj;
- struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
+ struct hv_device *hv_dev;
+ struct hv_uio_private_data *pdata;
virt_mb();
+ /*
+ * The callback may come from a subchannel, in which case look
+ * for the hv device in the primary channel
+ */
+ hv_dev = chan->primary_channel ?
+ chan->primary_channel->device_obj : chan->device_obj;
+ pdata = hv_get_drvdata(hv_dev);
uio_event_notify(&pdata->info);
}
--
2.34.1
^ permalink raw reply related
* [PATCH 6.12] uio_hv_generic: Set event for all channels on the device
From: Naman Jain @ 2025-11-15 8:57 UTC (permalink / raw)
To: Wei Liu, Dexuan Cui, Greg Kroah-Hartman, Michael Kelley, Long Li,
Saurabh Sengar
Cc: K . Y . Srinivasan, Haiyang Zhang, Tianyu Lan, Naman Jain,
linux-hyperv, linux-kernel, stable, Salvatore Bonaccorso,
Peter Morrow
From: Long Li <longli@microsoft.com>
Hyper-V may offer a non latency sensitive device with subchannels without
monitor bit enabled. The decision is entirely on the Hyper-V host not
configurable within guest.
When a device has subchannels, also signal events for the subchannel
if its monitor bit is disabled.
This patch also removes the memory barrier when monitor bit is enabled
as it is not necessary. The memory barrier is only needed between
setting up interrupt mask and calling vmbus_set_event() when monitor
bit is disabled.
This is a backport of the upstream commit
d062463edf17 ("uio_hv_generic: Set event for all channels on the device")
with minor modifications to resolve merge conflicts.
Original change was not a fix, but it needs to be backported to fix a
NULL pointer crash resulting from missing interrupt mask setting.
Commit 37bd91f22794 ("uio_hv_generic: Let userspace take care of interrupt mask")
removed the default setting of interrupt_mask for channels (including
subchannels) in the uio_hv_generic driver, as it relies on the user space
to take care of managing it. This approach works fine when user space
can control this setting using the irqcontrol interface provided for uio
devices. Support for setting the interrupt mask through this interface for
subchannels came only after commit d062463edf17 ("uio_hv_generic: Set event
for all channels on the device"). On older kernels, this change is not
present. With uio_hv_generic no longer setting the interrupt_mask, and
userspace not having the capability to set it, it remains unset,
and interrupts can come for the subchannels, which can result in a crash
in hv_uio_channel_cb. Backport the change to older kernels, where this
change was not present, to allow userspace to set the interrupt mask
properly for subchannels. Additionally, this patch also adds certain
checks for primary vs subchannels in the hv_uio_channel_cb, which can
gracefully handle these two cases and prevent the NULL pointer crashes.
Signed-off-by: Long Li <longli@microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Reviewed-by: Saurabh Sengar <ssengar@linux.microsoft.com>
Fixes: 37bd91f22794 ("uio_hv_generic: Let userspace take care of interrupt mask")
Cc: <stable@vger.kernel.org> # 6.12.x
Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
---
drivers/uio/uio_hv_generic.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index 0b414d1168dd..aa7593cea2e3 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -65,6 +65,16 @@ struct hv_uio_private_data {
char send_name[32];
};
+static void set_event(struct vmbus_channel *channel, s32 irq_state)
+{
+ channel->inbound.ring_buffer->interrupt_mask = !irq_state;
+ if (!channel->offermsg.monitor_allocated && irq_state) {
+ /* MB is needed for host to see the interrupt mask first */
+ virt_mb();
+ vmbus_set_event(channel);
+ }
+}
+
/*
* This is the irqcontrol callback to be registered to uio_info.
* It can be used to disable/enable interrupt from user space processes.
@@ -79,12 +89,15 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
{
struct hv_uio_private_data *pdata = info->priv;
struct hv_device *dev = pdata->device;
+ struct vmbus_channel *primary, *sc;
- dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state;
- virt_mb();
+ primary = dev->channel;
+ set_event(primary, irq_state);
- if (!dev->channel->offermsg.monitor_allocated && irq_state)
- vmbus_setevent(dev->channel);
+ mutex_lock(&vmbus_connection.channel_mutex);
+ list_for_each_entry(sc, &primary->sc_list, sc_list)
+ set_event(sc, irq_state);
+ mutex_unlock(&vmbus_connection.channel_mutex);
return 0;
}
@@ -95,11 +108,18 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
static void hv_uio_channel_cb(void *context)
{
struct vmbus_channel *chan = context;
- struct hv_device *hv_dev = chan->device_obj;
- struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
+ struct hv_device *hv_dev;
+ struct hv_uio_private_data *pdata;
virt_mb();
+ /*
+ * The callback may come from a subchannel, in which case look
+ * for the hv device in the primary channel
+ */
+ hv_dev = chan->primary_channel ?
+ chan->primary_channel->device_obj : chan->device_obj;
+ pdata = hv_get_drvdata(hv_dev);
uio_event_notify(&pdata->info);
}
--
2.34.1
^ permalink raw reply related
* Re: [PATCH] Drivers: hv: ioctl for self targeted passthrough hvcalls
From: Wei Liu @ 2025-11-15 7:46 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: Wei Liu, K. Y. Srinivasan, Haiyang Zhang, Dexuan Cui, Long Li,
linux-hyperv, linux-kernel
In-Reply-To: <vywh5euispm7c4emz2bma3upnldj2x7rthhsedwhjguv54pakz@5dy326il2de2>
On Sat, Nov 15, 2025 at 01:09:12PM +0530, Anirudh Rayabharam wrote:
> On Sat, Nov 15, 2025 at 06:22:40AM +0000, Wei Liu wrote:
> > On Fri, Nov 14, 2025 at 09:58:52AM +0000, Anirudh Rayabharam wrote:
> > > From: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
> > >
> > > Allow MSHV_ROOT_HVCALL IOCTL on the /dev/mshv fd. This IOCTL would
> > > execute a passthrough hypercall targeting the root/parent partition
> > > i.e. HV_PARTITION_ID_SELF.
> > >
> > > This will be useful for the VMM to query things like supported
> > > synthetic processor features, supported VMM capabiliites etc.
> > >
> > > While at it, add HVCALL_GET_PARTITION_PROPERTY_EX to the allowed list of
> > > passthrough hypercalls.
> > >
> > > Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
> >
> > This doesn't apply to hyperv-next. What's its base?
>
> Hmmm... I remember doing this on hyperv-next. This the parent I see:
>
> commit f2329fd987a0da4759c307c46fd27c4d05bb7433
> Author: Naman Jain <namjain@linux.microsoft.com>
> Date: Thu Nov 13 04:41:49 2025 +0000
>
> Drivers: hv: Introduce mshv_vtl driver
>
> No worries, I can rebase it on hyperv-next and send it again.
I pulled in some patches from hyperv-fixes to hyperv-next. That's
probably why. But you will see that eventually during a merge later
anyway, so it is good to just rebase and resend.
Wei
>
> Thanks,
> Anirudh.
>
^ permalink raw reply
* Re: [PATCH] Drivers: hv: ioctl for self targeted passthrough hvcalls
From: Anirudh Rayabharam @ 2025-11-15 7:39 UTC (permalink / raw)
To: Wei Liu
Cc: K. Y. Srinivasan, Haiyang Zhang, Dexuan Cui, Long Li,
linux-hyperv, linux-kernel
In-Reply-To: <20251115062240.GA1794663@liuwe-devbox-debian-v2.local>
On Sat, Nov 15, 2025 at 06:22:40AM +0000, Wei Liu wrote:
> On Fri, Nov 14, 2025 at 09:58:52AM +0000, Anirudh Rayabharam wrote:
> > From: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
> >
> > Allow MSHV_ROOT_HVCALL IOCTL on the /dev/mshv fd. This IOCTL would
> > execute a passthrough hypercall targeting the root/parent partition
> > i.e. HV_PARTITION_ID_SELF.
> >
> > This will be useful for the VMM to query things like supported
> > synthetic processor features, supported VMM capabiliites etc.
> >
> > While at it, add HVCALL_GET_PARTITION_PROPERTY_EX to the allowed list of
> > passthrough hypercalls.
> >
> > Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
>
> This doesn't apply to hyperv-next. What's its base?
Hmmm... I remember doing this on hyperv-next. This the parent I see:
commit f2329fd987a0da4759c307c46fd27c4d05bb7433
Author: Naman Jain <namjain@linux.microsoft.com>
Date: Thu Nov 13 04:41:49 2025 +0000
Drivers: hv: Introduce mshv_vtl driver
No worries, I can rebase it on hyperv-next and send it again.
Thanks,
Anirudh.
>
> Wei
>
> > ---
> > drivers/hv/mshv_root_main.c | 11 ++++++++---
> > 1 file changed, 8 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> > index 20eda00a1b5a..98f56322cd19 100644
> > --- a/drivers/hv/mshv_root_main.c
> > +++ b/drivers/hv/mshv_root_main.c
> > @@ -122,6 +122,7 @@ static struct miscdevice mshv_dev = {
> > */
> > static u16 mshv_passthru_hvcalls[] = {
> > HVCALL_GET_PARTITION_PROPERTY,
> > + HVCALL_GET_PARTITION_PROPERTY_EX,
> > HVCALL_SET_PARTITION_PROPERTY,
> > HVCALL_INSTALL_INTERCEPT,
> > HVCALL_GET_VP_REGISTERS,
> > @@ -159,6 +160,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
> > unsigned int pages_order;
> > void *input_pg = NULL;
> > void *output_pg = NULL;
> > + u64 pt_id = partition ? partition->pt_id : HV_PARTITION_ID_SELF;
> >
> > if (copy_from_user(&args, user_args, sizeof(args)))
> > return -EFAULT;
> > @@ -180,7 +182,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
> > is_async = mshv_hvcall_is_async(args.code);
> > if (is_async) {
> > /* async hypercalls can only be called from partition fd */
> > - if (!partition_locked)
> > + if (!partition || !partition_locked)
> > return -EINVAL;
> > ret = mshv_init_async_handler(partition);
> > if (ret)
> > @@ -208,7 +210,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
> > * NOTE: This only works because all the allowed hypercalls' input
> > * structs begin with a u64 partition_id field.
> > */
> > - *(u64 *)input_pg = partition->pt_id;
> > + *(u64 *)input_pg = pt_id;
> >
> > if (args.reps)
> > status = hv_do_rep_hypercall(args.code, args.reps, 0,
> > @@ -226,7 +228,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
> > }
> >
> > if (hv_result(status) == HV_STATUS_INSUFFICIENT_MEMORY) {
> > - ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id, 1);
> > + ret = hv_call_deposit_pages(NUMA_NO_NODE, pt_id, 1);
> > if (!ret)
> > ret = -EAGAIN;
> > } else if (!hv_result_success(status)) {
> > @@ -2048,6 +2050,9 @@ static long mshv_dev_ioctl(struct file *filp, unsigned int ioctl,
> > case MSHV_CREATE_PARTITION:
> > return mshv_ioctl_create_partition((void __user *)arg,
> > misc->this_device);
> > + case MSHV_ROOT_HVCALL:
> > + return mshv_ioctl_passthru_hvcall(NULL, false,
> > + (void __user *)arg);
> > }
> >
> > return -ENOTTY;
> > --
> > 2.34.1
> >
^ permalink raw reply
* Re: [PATCH] Drivers: hv: ioctl for self targeted passthrough hvcalls
From: Wei Liu @ 2025-11-15 6:22 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li,
linux-hyperv, linux-kernel
In-Reply-To: <20251114095853.3482596-1-anirudh@anirudhrb.com>
On Fri, Nov 14, 2025 at 09:58:52AM +0000, Anirudh Rayabharam wrote:
> From: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
>
> Allow MSHV_ROOT_HVCALL IOCTL on the /dev/mshv fd. This IOCTL would
> execute a passthrough hypercall targeting the root/parent partition
> i.e. HV_PARTITION_ID_SELF.
>
> This will be useful for the VMM to query things like supported
> synthetic processor features, supported VMM capabiliites etc.
>
> While at it, add HVCALL_GET_PARTITION_PROPERTY_EX to the allowed list of
> passthrough hypercalls.
>
> Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
This doesn't apply to hyperv-next. What's its base?
Wei
> ---
> drivers/hv/mshv_root_main.c | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index 20eda00a1b5a..98f56322cd19 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -122,6 +122,7 @@ static struct miscdevice mshv_dev = {
> */
> static u16 mshv_passthru_hvcalls[] = {
> HVCALL_GET_PARTITION_PROPERTY,
> + HVCALL_GET_PARTITION_PROPERTY_EX,
> HVCALL_SET_PARTITION_PROPERTY,
> HVCALL_INSTALL_INTERCEPT,
> HVCALL_GET_VP_REGISTERS,
> @@ -159,6 +160,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
> unsigned int pages_order;
> void *input_pg = NULL;
> void *output_pg = NULL;
> + u64 pt_id = partition ? partition->pt_id : HV_PARTITION_ID_SELF;
>
> if (copy_from_user(&args, user_args, sizeof(args)))
> return -EFAULT;
> @@ -180,7 +182,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
> is_async = mshv_hvcall_is_async(args.code);
> if (is_async) {
> /* async hypercalls can only be called from partition fd */
> - if (!partition_locked)
> + if (!partition || !partition_locked)
> return -EINVAL;
> ret = mshv_init_async_handler(partition);
> if (ret)
> @@ -208,7 +210,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
> * NOTE: This only works because all the allowed hypercalls' input
> * structs begin with a u64 partition_id field.
> */
> - *(u64 *)input_pg = partition->pt_id;
> + *(u64 *)input_pg = pt_id;
>
> if (args.reps)
> status = hv_do_rep_hypercall(args.code, args.reps, 0,
> @@ -226,7 +228,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
> }
>
> if (hv_result(status) == HV_STATUS_INSUFFICIENT_MEMORY) {
> - ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id, 1);
> + ret = hv_call_deposit_pages(NUMA_NO_NODE, pt_id, 1);
> if (!ret)
> ret = -EAGAIN;
> } else if (!hv_result_success(status)) {
> @@ -2048,6 +2050,9 @@ static long mshv_dev_ioctl(struct file *filp, unsigned int ioctl,
> case MSHV_CREATE_PARTITION:
> return mshv_ioctl_create_partition((void __user *)arg,
> misc->this_device);
> + case MSHV_ROOT_HVCALL:
> + return mshv_ioctl_passthru_hvcall(NULL, false,
> + (void __user *)arg);
> }
>
> return -ENOTTY;
> --
> 2.34.1
>
^ permalink raw reply
* [patch net-next] net: mana: Handle hardware reset events when probing the device
From: longli @ 2025-11-15 2:28 UTC (permalink / raw)
To: K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Shradha Gupta, Simon Horman, Konstantin Taranov,
Souradeep Chakrabarti, Erick Archer, linux-hyperv, netdev,
linux-kernel, linux-rdma
Cc: Long Li
From: Long Li <longli@microsoft.com>
When MANA is being probed, it's possible that hardware is in recovery
mode and the device may get GDMA_EQE_HWC_RESET_REQUEST over HWC in the
middle of the probe. Detect such condition and go through the recovery
service procedure.
Fixes: fbe346ce9d62 ("net: mana: Handle Reset Request from MANA NIC")
Signed-off-by: Long Li <longli@microsoft.com>
---
.../net/ethernet/microsoft/mana/gdma_main.c | 131 +++++++++++++++---
include/net/mana/gdma.h | 9 +-
2 files changed, 122 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index effe0a2f207a..1d9c2beb22b2 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -15,6 +15,12 @@
struct dentry *mana_debugfs_root;
+static struct mana_serv_delayed_work {
+ struct delayed_work work;
+ struct pci_dev *pdev;
+ enum gdma_eqe_type type;
+} mns_delayed_wk;
+
static u32 mana_gd_r32(struct gdma_context *g, u64 offset)
{
return readl(g->bar0_va + offset);
@@ -387,6 +393,25 @@ EXPORT_SYMBOL_NS(mana_gd_ring_cq, "NET_MANA");
#define MANA_SERVICE_PERIOD 10
+static void mana_serv_rescan(struct pci_dev *pdev)
+{
+ struct pci_bus *parent;
+
+ pci_lock_rescan_remove();
+
+ parent = pdev->bus;
+ if (!parent) {
+ dev_err(&pdev->dev, "MANA service: no parent bus\n");
+ goto out;
+ }
+
+ pci_stop_and_remove_bus_device(pdev);
+ pci_rescan_bus(parent);
+
+out:
+ pci_unlock_rescan_remove();
+}
+
static void mana_serv_fpga(struct pci_dev *pdev)
{
struct pci_bus *bus, *parent;
@@ -419,9 +444,12 @@ static void mana_serv_reset(struct pci_dev *pdev)
{
struct gdma_context *gc = pci_get_drvdata(pdev);
struct hw_channel_context *hwc;
+ int ret;
if (!gc) {
- dev_err(&pdev->dev, "MANA service: no GC\n");
+ /* Perform PCI rescan on device if GC is not set up */
+ dev_err(&pdev->dev, "MANA service: GC not setup, rescanning\n");
+ mana_serv_rescan(pdev);
return;
}
@@ -440,9 +468,18 @@ static void mana_serv_reset(struct pci_dev *pdev)
msleep(MANA_SERVICE_PERIOD * 1000);
- mana_gd_resume(pdev);
+ ret = mana_gd_resume(pdev);
+ if (ret == -ETIMEDOUT || ret == -EPROTO) {
+ /* Perform PCI rescan on device if we failed on HWC */
+ dev_err(&pdev->dev, "MANA service: resume failed, rescanning\n");
+ mana_serv_rescan(pdev);
+ goto out;
+ }
- dev_info(&pdev->dev, "MANA reset cycle completed\n");
+ if (ret)
+ dev_info(&pdev->dev, "MANA reset cycle failed err %d\n", ret);
+ else
+ dev_info(&pdev->dev, "MANA reset cycle completed\n");
out:
gc->in_service = false;
@@ -454,18 +491,9 @@ struct mana_serv_work {
enum gdma_eqe_type type;
};
-static void mana_serv_func(struct work_struct *w)
+static void mana_do_service(enum gdma_eqe_type type, struct pci_dev *pdev)
{
- struct mana_serv_work *mns_wk;
- struct pci_dev *pdev;
-
- mns_wk = container_of(w, struct mana_serv_work, serv_work);
- pdev = mns_wk->pdev;
-
- if (!pdev)
- goto out;
-
- switch (mns_wk->type) {
+ switch (type) {
case GDMA_EQE_HWC_FPGA_RECONFIG:
mana_serv_fpga(pdev);
break;
@@ -475,12 +503,36 @@ static void mana_serv_func(struct work_struct *w)
break;
default:
- dev_err(&pdev->dev, "MANA service: unknown type %d\n",
- mns_wk->type);
+ dev_err(&pdev->dev, "MANA service: unknown type %d\n", type);
break;
}
+}
+
+static void mana_serv_delayed_func(struct work_struct *w)
+{
+ struct mana_serv_delayed_work *dwork;
+ struct pci_dev *pdev;
+
+ dwork = container_of(w, struct mana_serv_delayed_work, work.work);
+ pdev = dwork->pdev;
+
+ if (pdev)
+ mana_do_service(dwork->type, pdev);
+
+ pci_dev_put(pdev);
+}
+
+static void mana_serv_func(struct work_struct *w)
+{
+ struct mana_serv_work *mns_wk;
+ struct pci_dev *pdev;
+
+ mns_wk = container_of(w, struct mana_serv_work, serv_work);
+ pdev = mns_wk->pdev;
+
+ if (pdev)
+ mana_do_service(mns_wk->type, pdev);
-out:
pci_dev_put(pdev);
kfree(mns_wk);
module_put(THIS_MODULE);
@@ -541,6 +593,17 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)
case GDMA_EQE_HWC_RESET_REQUEST:
dev_info(gc->dev, "Recv MANA service type:%d\n", type);
+ if (atomic_inc_return(&gc->in_probe) == 1) {
+ /*
+ * Device is in probe and we received an hardware reset
+ * event, probe() will detect that "in_probe" has
+ * changed and perform service procedure.
+ */
+ dev_info(gc->dev,
+ "Service is to be processed in probe\n");
+ break;
+ }
+
if (gc->in_service) {
dev_info(gc->dev, "Already in service\n");
break;
@@ -1930,6 +1993,8 @@ 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);
+ atomic_set(&gc->in_probe, 0);
+
err = mana_gd_setup(pdev);
if (err)
goto unmap_bar;
@@ -1942,8 +2007,19 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto cleanup_mana;
+ /*
+ * If a hardware reset event has occurred over HWC during probe,
+ * rollback and perform hardware reset procedure.
+ */
+ if (atomic_inc_return(&gc->in_probe) > 1) {
+ err = -EPROTO;
+ goto cleanup_mana_rdma;
+ }
+
return 0;
+cleanup_mana_rdma:
+ mana_rdma_remove(&gc->mana_ib);
cleanup_mana:
mana_remove(&gc->mana, false);
cleanup_gd:
@@ -1967,6 +2043,25 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
disable_dev:
pci_disable_device(pdev);
dev_err(&pdev->dev, "gdma probe failed: err = %d\n", err);
+
+ /*
+ * Hardware could be in recovery mode and the HWC returns TIMEDOUT or
+ * EPROTO from mana_gd_setup(), mana_probe() or mana_rdma_probe(), or
+ * we received a hardware reset event over HWC interrupt. In this case,
+ * perform the device recovery procedure after MANA_SERVICE_PERIOD
+ * seconds.
+ */
+ if (err == -ETIMEDOUT || err == -EPROTO) {
+ dev_info(&pdev->dev, "Start MANA recovery mode\n");
+
+ mns_delayed_wk.pdev = pci_dev_get(pdev);
+ mns_delayed_wk.type = GDMA_EQE_HWC_RESET_REQUEST;
+
+ INIT_DELAYED_WORK(&mns_delayed_wk.work, mana_serv_delayed_func);
+ schedule_delayed_work(&mns_delayed_wk.work,
+ secs_to_jiffies(MANA_SERVICE_PERIOD));
+ }
+
return err;
}
@@ -2084,6 +2179,8 @@ static int __init mana_driver_init(void)
static void __exit mana_driver_exit(void)
{
+ cancel_delayed_work_sync(&mns_delayed_wk.work);
+
pci_unregister_driver(&mana_driver);
debugfs_remove(mana_debugfs_root);
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 637f42485dba..1bb4c6ada2b6 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -430,6 +430,9 @@ struct gdma_context {
u64 pf_cap_flags1;
struct workqueue_struct *service_wq;
+
+ /* Count how many times we have finished probe or HWC events */
+ atomic_t in_probe;
};
static inline bool mana_gd_is_mana(struct gdma_dev *gd)
@@ -592,6 +595,9 @@ enum {
#define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17)
#define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6)
+/* Driver can handle hardware reset events during probe */
+#define GDMA_DRV_CAP_FLAG_1_RECOVER_PROBE BIT(22)
+
#define GDMA_DRV_CAP_FLAGS1 \
(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
@@ -601,7 +607,8 @@ enum {
GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \
GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \
GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \
- GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE)
+ GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \
+ GDMA_DRV_CAP_FLAG_1_RECOVER_PROBE)
#define GDMA_DRV_CAP_FLAGS2 0
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Paolo Bonzini @ 2025-11-14 23:33 UTC (permalink / raw)
To: Sean Christopherson, Vitaly Kuznetsov, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, kvm, linux-hyperv,
linux-kernel, Jim Mattson, Yosry Ahmed
In-Reply-To: <aRdPFEF0XS7Zz5Fx@google.com>
On 11/14/25 16:47, Sean Christopherson wrote:
> On Fri, Nov 14, 2025, Sean Christopherson wrote:
>> _and_ the hyperv_svm_test selftest fails. *sigh*
>
> And the weekend can't come soon enough. The kernel I'm testing doesn't even have
> these patches. /facepalm
Yep, my fault; I did the same mistake (in reverse) when preparing the
last pull request. Yosry wrote about this a few days ago.
Paolo
^ permalink raw reply
* Re: [PATCH 6/9] KVM: SVM: Filter out 64-bit exit codes when invoking exit handlers on bare metal
From: Paolo Bonzini @ 2025-11-14 23:32 UTC (permalink / raw)
To: Sean Christopherson, Vitaly Kuznetsov, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui
Cc: kvm, linux-hyperv, linux-kernel, Jim Mattson, Yosry Ahmed
In-Reply-To: <20251113225621.1688428-7-seanjc@google.com>
On 11/13/25 23:56, Sean Christopherson wrote:
> Explicitly filter out 64-bit exit codes when invoking exit handlers, as
> svm_exit_handlers[] will never be sized with entries that use bits 63:32.
>
> Processing the non-failing exit code as a 32-bit value will allow tracking
> exit_code as a single 64-bit value (which it is, architecturally). This
> will also allow hardening KVM against Spectre-like attacks without needing
> to do silly things to avoid build failures on 32-bit kernels
> (array_index_nospec() rightly asserts that the index fits in an "unsigned
> long").
>
> Omit the check when running as a VM, as KVM has historically failed to set
> bits 63:32 appropriately when synthesizing VM-Exits, i.e. KVM could get
> false positives when running as a VM on an older, broken KVM/kernel. From
> a functional perspective, omitting the check is "fine", as any unwanted
> collision between e.g. VMEXIT_INVALID and a 32-bit exit code will be
> fatal to KVM-on-KVM regardless of what KVM-as-L1 does.
>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
> arch/x86/kvm/svm/svm.c | 18 ++++++++++++++++--
> 1 file changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 202a4d8088a2..3b05476296d0 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -3433,8 +3433,22 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
> sev_free_decrypted_vmsa(vcpu, save);
> }
>
> -int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
> +int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 __exit_code)
> {
> + u32 exit_code = __exit_code;
> +
> + /*
> + * SVM uses negative values, i.e. 64-bit values, to indicate that VMRUN
> + * failed. Report all such errors to userspace (note, VMEXIT_INVALID,
> + * a.k.a. SVM_EXIT_ERR, is special cased by svm_handle_exit()). Skip
> + * the check when running as a VM, as KVM has historically left garbage
> + * in bits 63:32, i.e. running KVM-on-KVM would hit false positives if
> + * the underlying kernel is buggy.
> + */
> + if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR) &&
> + (u64)exit_code != __exit_code)
> + goto unexpected_vmexit;
I reviewed the series and it looks good, but with respect to this patch
and patch 8, is it really worth it? While there is a possibility that
code 0x00000000ffffffff is used, or that any high 32-bit values other
than all-zeros or all-ones are used, they'd be presumably enabled by
some control bits in the VMCB or some paravirt thing in the hypervisor.
What really matters is that SEV-ES's kvm_get_cached_sw_exit_code() is
reading the full 64 bits and discarding invalid codes before reaching
svm_invoke_exit_handler().
I totally agree, of course, with passing __exit_code as u64 and adding a
comment explaining what's going on with "u32 exit_code == (u32)__exit_code".
Paolo
> #ifdef CONFIG_MITIGATION_RETPOLINE
> if (exit_code == SVM_EXIT_MSR)
> return msr_interception(vcpu);
> @@ -3461,7 +3475,7 @@ int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
>
> unexpected_vmexit:
> dump_vmcb(vcpu);
> - kvm_prepare_unexpected_reason_exit(vcpu, exit_code);
> + kvm_prepare_unexpected_reason_exit(vcpu, __exit_code);
> return 0;
> }
>
^ permalink raw reply
* Re: [PATCH net-next v9 06/14] vsock/loopback: add netns support
From: Bobby Eshleman @ 2025-11-14 22:13 UTC (permalink / raw)
To: Stefano Garzarella
Cc: Shuah Khan, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Stefan Hajnoczi, Michael S. Tsirkin,
Jason Wang, Xuan Zhuo, Eugenio Pérez, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Bryan Tan, Vishnu Dasa,
Broadcom internal kernel review list, virtualization, netdev,
linux-kselftest, linux-kernel, kvm, linux-hyperv, Sargun Dhillon,
berrange, Bobby Eshleman
In-Reply-To: <kwgjzpxxqpkgwafydp65vlj6jlf7h7kcnhwgtwrrhzp2qtgkkq@z3xfl26ejspl>
On Fri, Nov 14, 2025 at 10:33:42AM +0100, Stefano Garzarella wrote:
> On Thu, Nov 13, 2025 at 10:26:04AM -0800, Bobby Eshleman wrote:
> > On Thu, Nov 13, 2025 at 04:24:44PM +0100, Stefano Garzarella wrote:
> > > On Wed, Nov 12, 2025 at 10:27:18AM -0800, Bobby Eshleman wrote:
> > > > On Wed, Nov 12, 2025 at 03:19:47PM +0100, Stefano Garzarella wrote:
> > > > > On Tue, Nov 11, 2025 at 10:54:48PM -0800, Bobby Eshleman wrote:
> > > > > > From: Bobby Eshleman <bobbyeshleman@meta.com>
> > > > > >
> > > > > > Add NS support to vsock loopback. Sockets in a global mode netns
> > > > > > communicate with each other, regardless of namespace. Sockets in a local
> > > > > > mode netns may only communicate with other sockets within the same
> > > > > > namespace.
> > > > > >
> > > > > > Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
> >
> > [...]
> >
> > > > > > @@ -131,7 +136,41 @@ static void vsock_loopback_work(struct work_struct *work)
> > > > > > */
> > > > > > virtio_transport_consume_skb_sent(skb, false);
> > > > > > virtio_transport_deliver_tap_pkt(skb);
> > > > > > - virtio_transport_recv_pkt(&loopback_transport, skb, NULL, 0);
> > > > > > +
> > > > > > + /* In the case of virtio_transport_reset_no_sock(), the skb
> > > > > > + * does not hold a reference on the socket, and so does not
> > > > > > + * transitively hold a reference on the net.
> > > > > > + *
> > > > > > + * There is an ABA race condition in this sequence:
> > > > > > + * 1. the sender sends a packet
> > > > > > + * 2. worker calls virtio_transport_recv_pkt(), using the
> > > > > > + * sender's net
> > > > > > + * 3. virtio_transport_recv_pkt() uses t->send_pkt() passing the
> > > > > > + * sender's net
> > > > > > + * 4. virtio_transport_recv_pkt() free's the skb, dropping the
> > > > > > + * reference to the socket
> > > > > > + * 5. the socket closes, frees its reference to the net
> > > > > > + * 6. Finally, the worker for the second t->send_pkt() call
> > > > > > + * processes the skb, and uses the now stale net pointer for
> > > > > > + * socket lookups.
> > > > > > + *
> > > > > > + * To prevent this, we acquire a net reference in vsock_loopback_send_pkt()
> > > > > > + * and hold it until virtio_transport_recv_pkt() completes.
> > > > > > + *
> > > > > > + * Additionally, we must grab a reference on the skb before
> > > > > > + * calling virtio_transport_recv_pkt() to prevent it from
> > > > > > + * freeing the skb before we have a chance to release the net.
> > > > > > + */
> > > > > > + net_mode = virtio_vsock_skb_net_mode(skb);
> > > > > > + net = virtio_vsock_skb_net(skb);
> > > > >
> > > > > Wait, we are adding those just for loopback (in theory used only for
> > > > > testing/debugging)? And only to support virtio_transport_reset_no_sock() use
> > > > > case?
> > > >
> > > > Yes, exactly, only loopback + reset_no_sock(). The issue doesn't exist
> > > > for vhost-vsock because vhost_vsock holds a net reference, and it
> > > > doesn't exist for non-reset_no_sock calls because after looking up the
> > > > socket we transfer skb ownership to it, which holds down the skb -> sk ->
> > > > net reference chain.
> > > >
> > > > >
> > > > > Honestly I don't like this, do we have any alternative?
> > > > >
> > > > > I'll also try to think something else.
> > > > >
> > > > > Stefano
> > > >
> > > >
> > > > I've been thinking about this all morning... maybe
> > > > we can do something like this:
> > > >
> > > > ```
> > > >
> > > > virtio_transport_recv_pkt(..., struct sock *reply_sk) {... }
> > > >
> > > > virtio_transport_reset_no_sock(..., reply_sk)
> > > > {
> > > > if (reply_sk)
> > > > skb_set_owner_sk_safe(reply, reply_sk)
> > >
> > > Interesting, but what about if we call skb_set_owner_sk_safe() in
> > > vsock_loopback.c just before calling virtio_transport_recv_pkt() for every
> > > skb?
> >
> > I think the issue with this is that at the time vsock_loopback calls
> > virtio_transport_recv_pkt() the reply skb hasn't yet been allocated by
> > virtio_transport_reset_no_sock() and we can't wait for it to return
> > because the original skb may be freed by then.
>
> Right!
>
> >
> > We might be able to keep it all in vsock_loopback if we removed the need
> > to use the original skb or sk by just using the net. But to do that we
> > would need to add a netns_tracker per net somewhere. I guess that would
> > end up in a list or hashmap in struct vsock_loopback.
> >
> > Another option that does simplify a little, but unfortunately still doesn't keep
> > everything in loopback:
> >
> > @@ -1205,7 +1205,7 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
> > if (!reply)
> > return -ENOMEM;
> >
> > - return t->send_pkt(reply, net, net_mode);
> > + return t->send_pkt(reply, net, net_mode, skb->sk);
> > }
> >
> > @@ -27,11 +27,16 @@ static u32 vsock_loopback_get_local_cid(void)
> > }
> >
> > static int vsock_loopback_send_pkt(struct sk_buff *skb, struct net *net,
> > - enum vsock_net_mode net_mode)
> > + enum vsock_net_mode net_mode,
> > + struct sock *rst_owner)
> > {
> > struct vsock_loopback *vsock = &the_vsock_loopback;
> > int len = skb->len;
> >
> > + if (!skb->sk && rst_owner)
> > + WARN_ONCE(!skb_set_owner_sk_safe(skb, rst_owner),
> > + "loopback socket has sk_refcnt == 0\n");
> > +
>
> This doesn't seem too bad IMO, but at this point, why we can't do that
> in virtio_transport_reset_no_sock() for any kind of transport?
>
> I mean, in any case the RST packet should be handled by the same net of the
> "sender", no?
>
> At this point, can we just put the `vsk` of the sender in the `info` and
> virtio_transport_alloc_skb() will already do that.
>
> WDYT?
> Am I missing something?
This is the right answer... I'm pretty sure this works out-of-the-box
for all transports.
I'll implement it and report back with a new rev if all good or come
back to this thread to discuss if any issues arise.
Have a good weekend!
Best,
Bobby
^ permalink raw reply
* Re: Bug#1120602: [REGRESSION 6.12.y] hyper-v: BUG: kernel NULL pointer dereference, address: 00000000000000a0: RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
From: Salvatore Bonaccorso @ 2025-11-14 21:44 UTC (permalink / raw)
To: Naman Jain, 1120602
Cc: Peter Morrow, Long Li, linux-hyperv, linux-kernel, regressions,
stable, John Starks, Michael Kelley, Tianyu Lan, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Greg Kroah-Hartman
In-Reply-To: <18bcf829-04f9-46ec-a874-7c2b9338cf3d@linux.microsoft.com>
Hi,
On Fri, Nov 14, 2025 at 08:05:55PM +0530, Naman Jain wrote:
>
>
> On 11/14/2025 5:19 PM, Peter Morrow wrote:
> > Hi Naman,
> >
> > On Fri, 14 Nov 2025 at 06:03, Naman Jain <namjain@linux.microsoft.com> wrote:
> > >
> > >
> > >
> > > On 11/13/2025 11:59 PM, Salvatore Bonaccorso wrote:
> > > > Peter Morrow reported in Debian a regression, reported in
> > > > https://bugs.debian.org/1120602 . The regression was seen after
> > > > updating, to 6.12.57-1 in Debian, but details on the offending commit
> > > > follows.
> > > >
> > > > His report was as follows:
> > > >
> > > > > Dear Maintainer,
> > > > >
> > > > > I'm seeing a kernel crash quite soon after boot on a debian trixie based
> > > > > system running 6.12.57+deb13-amd64, unfortunately the kernel panics before
> > > > > I can access the system to gather more information. Thus I'll provide details
> > > > > of the system using a previously known good version. The panic is happening
> > > > > 100% of the time unfortunately. I have access to the serial console however
> > > > > so can enable any required verbose logging during boot if necessary.
> > > > >
> > > > > Crucially the crash is not seen with kernel version 6.12.41+deb13-amd64 with the
> > > > > same userspace. We had pinned to that version until very recently to in order
> > > > > to work around https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1109676
> > > > >
> > > > > I'm running a dpdk application here (VPP) on Azure, VM form factor is a
> > > > > "Standard DS3 v2 (4 vcpus, 14 GiB memory)".
> > > > >
> > > > > The only relevant upstream commit in this area (as far as I can see) is:
> > > > >
> > > > > https://lore.kernel.org/linux-hyperv/1bb599ee-fe28-409d-b430-2fc086268936@linux.microsoft.com/
> > > > >
> > > > > The comment regarding avoiding races at start adds a bit more weight behind this
> > > > > hunch, though it's only a hunch as I am most definitely nowhere near an expert
> > > > > in this area.
> > > > >
> > > > > -- Package-specific info:
> > > > >
> > > > > [ 19.625535] BUG: kernel NULL pointer dereference, address: 00000000000000a0
> > > > > [ 19.628874] #PF: supervisor read access in kernel mode
> > > > > [ 19.630841] #PF: error_code(0x0000) - not-present page
> > > > > [ 19.632788] PGD 0 P4D 0
> > > > > [ 19.633905] Oops: Oops: 0000 [#1] PREEMPT SMP PTI
> > > > > [ 19.635586] CPU: 3 UID: 0 PID: 0 Comm: swapper/3 Not tainted 6.12.57+deb13-amd64 #1 Debian 6.12.57-1
> > > > > [ 19.640216] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 09/28/2024
> > > > > [ 19.644514] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
> > > > > [ 19.646994] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
> > > > > [ 19.654377] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
> > > > > [ 19.656385] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
> > > > > [ 19.659240] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
> > > > > [ 19.662168] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
> > > > > [ 19.665239] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
> > > > > [ 19.668193] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
> > > > > [ 19.671106] FS: 0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
> > > > > [ 19.674281] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > > > [ 19.676533] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
> > > > > [ 19.679385] Call Trace:
> > > > > [ 19.680361] <IRQ>
> > > > > [ 19.681181] vmbus_isr+0x1a5/0x210 [hv_vmbus]
> > > > > [ 19.682916] __sysvec_hyperv_callback+0x32/0x60
> > > > > [ 19.684991] sysvec_hyperv_callback+0x6c/0x90
> > > > > [ 19.686665] </IRQ>
> > > > > [ 19.687509] <TASK>
> > > > > [ 19.688366] asm_sysvec_hyperv_callback+0x1a/0x20
> > > > > [ 19.690262] RIP: 0010:pv_native_safe_halt+0xf/0x20
> > > > > [ 19.692067] Code: 09 e9 c5 08 01 00 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 66 90 0f 00 2d e5 3b 31 00 fb f4 <c3> cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90
> > > > > [ 19.699119] RSP: 0018:ffffb15ac0103ed8 EFLAGS: 00000246
> > > > > [ 19.701412] RAX: 0000000000000003 RBX: ffff8ff5403b1fc0 RCX: ffff8ff54c64ce30
> > > > > [ 19.704328] RDX: 0000000000000000 RSI: 0000000000000003 RDI: 000000000001f894
> > > > > [ 19.706910] RBP: 0000000000000003 R08: 000000000bb760d9 R09: 00fca75150b080e9
> > > > > [ 19.709762] R10: 0000000000000003 R11: 0000000000000001 R12: 0000000000000000
> > > > > [ 19.712510] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
> > > > > [ 19.715173] default_idle+0x9/0x20
> > > > > [ 19.716846] default_idle_call+0x29/0x100
> > > > > [ 19.718623] do_idle+0x1fe/0x240
> > > > > [ 19.720045] cpu_startup_entry+0x29/0x30
> > > > > [ 19.721595] start_secondary+0x11e/0x140
> > > > > [ 19.723080] common_startup_64+0x13e/0x141
> > > > > [ 19.725222] </TASK>
> > > > > [ 19.726387] Modules linked in: isofs cdrom uio_hv_generic uio binfmt_misc intel_rapl_msr intel_rapl_common intel_uncore_frequency_common isst_if_mbox_msr isst_if_common rpcrdma skx_edac_common nfit sunrpc libnvdimm crct10dif_pclmul ghash_clmulni_intel sha512_ssse3 sha256_ssse3 rdma_ucm ib_iser sha1_ssse3 rdma_cm aesni_intel iw_cm gf128mul crypto_simd libiscsi cryptd ib_umad ib_ipoib scsi_transport_iscsi ib_cm rapl sg hv_utils hv_balloon evdev pcspkr joydev mpls_router ip_tunnel ramoops configfs pstore_blk efi_pstore pstore_zone nfnetlink vsock_loopback vmw_vsock_virtio_transport_common hv_sock vmw_vsock_vmci_transport vsock vmw_vmci efivarfs ip_tables x_tables autofs4 overlay squashfs dm_verity dm_bufio reed_solomon dm_mod loop ext4 crc16 mbcache jbd2 crc32c_generic mlx5_ib ib_uverbs ib_core mlx5_core mlxfw pci_hyperv pci_hyperv_intf hyperv_drm drm_shmem_helper sd_mod drm_kms_helper hv_storvsc scsi_transport_fc drm scsi_mod hid_generic hid_hyperv hid serio_raw hv_netvsc hyperv_keyboard scsi_common hv_vmbus
> > > > > [ 19.726466] crc32_pclmul crc32c_intel
> > > > > [ 19.765771] CR2: 00000000000000a0
> > > > > [ 19.767524] ---[ end trace 0000000000000000 ]---
> > > > > [ 19.800433] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
> > > > > [ 19.803170] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
> > > > > [ 19.811041] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
> > > > > [ 19.813466] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
> > > > > [ 19.816504] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
> > > > > [ 19.819484] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
> > > > > [ 19.822625] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
> > > > > [ 19.825569] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
> > > > > [ 19.828804] FS: 0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
> > > > > [ 19.832214] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > > > [ 19.834709] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
> > > > > [ 19.837976] Kernel panic - not syncing: Fatal exception in interrupt
> > > > > [ 19.841825] Kernel Offset: 0x28a00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
> > > > > [ 19.896620] ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---
> > > > >
> > >
> > > <snip>
> > >
> > > > The offending commit appers to be the backport of b15b7d2a1b09
> > > > ("uio_hv_generic: Let userspace take care of interrupt mask") for
> > > > 6.12.y.
> > > >
> > > > Peter confirmed that reverting this commit on top of 6.12.57-1 as
> > > > packaged in Debian resolves indeed the issue. Interestingly the issue
> > > > is *not* seen with 6.17.7 based kernel in Debian.
> > > >
> > > > #regzbot introduced: 37bd91f22794dc05436130d6983302cb90ecfe7e
> > > > #regzbot monitor: https://bugs.debian.org/1120602
> > > >
> > > > Thank you already!
> > > >
> > > > Regards,
> > > > Salvatore
> > >
> > > Hi Peter, Salvatore,
> > > Thanks for reporting this crash, and sorry for the trouble. Here is my
> > > analysis.
> > >
> > > On 6.17.7, where commit d062463edf17 ("uio_hv_generic: Set event for all
> > > channels on the device") is present, hv_uio_irqcontrol() supports
> > > setting of interrupt mask from userspace for sub-channels as well.
> > >
> > > This aligns with commit e29587c07537 ("uio_hv_generic: Let userspace
> > > take care of interrupt mask") which relies on userspace to manage
> > > interrupt mask, so it safely removes the interrupt mask management logic
> > > in the driver.
> > >
> > > However, in 6.12.57, the first commit is not present, but the second one
> > > is, so there is no way to disable interrupt mask for sub-channels and
> > > interrupt_mask stays 0, which means interrupts are not masked. So we may
> > > be having an interrupt callback being handled for a sub-channel, where
> > > we do not expect it to come. This may be causing this issue.
> > >
> > > This would have led to a crash in hv_uio_channel_cb() for sub-channels:
> > > struct hv_device *hv_dev = chan->device_obj;
> > >
> > >
> > > I have ported commit d062463edf17 ("uio_hv_generic: Set event for all
> > > channels on the device") on 6.12.57, and resolved some merge conflicts.
> > > Could you please help with testing this, if it works for you.
> >
> > Applying the patch against the debian 6.12.57 kernel worked, I am no
> > longer seeing that panic on boot:
> >
> > gnos@vEdge:~$ uname -a
> > Linux vEdge 6.12+unreleased-amd64 #1 SMP PREEMPT_DYNAMIC Debian
> > 6.12.57-1a~test (2025-11-14) x86_64 GNU/Linux
> > gnos@vEdge:~$ uptime
> > 11:46:33 up 4 min, 1 user, load average: 3.31, 2.07, 0.89
> > gnos@vEdge:~$ sudo dmidecode -t system
> > # dmidecode 3.6
> > Getting SMBIOS data from sysfs.
> > SMBIOS 3.1.0 present.
> >
> > Handle 0x0001, DMI type 1, 27 bytes
> > System Information
> > Manufacturer: Microsoft Corporation
> > Product Name: Virtual Machine
> > Version: Hyper-V UEFI Release v4.1
> > Serial Number: 0000-0002-8036-1108-7588-3134-50
> > UUID: 26e86d6e-140c-496a-862c-a3b3bbcd16ad
> > Wake-up Type: Power Switch
> > SKU Number: None
> > Family: Virtual Machine
> >
> > Handle 0x0010, DMI type 32, 11 bytes
> > System Boot Information
> > Status: No errors detected
> >
> > gnos@vEdge:~$
> >
> > Thanks a lot for the quick analysis!
> >
> > Peter.
>
> Hi Peter,
>
> Thanks for confirming. I am discussing this with Long Li, to hear his
> thoughts on this, and have kept the patch ready.
> Porting the same on 6.6 and older kernels would be a little different since
> we don't have commit 547fa4ffd799 ("uio_hv_generic: Enable interrupt for low
> speed VMBus devices") on these kernels and this would lead to merge
> conflicts, which needs to be handled separately.
>
> Meanwhile, if I should be including any tags in the fix patch for debian
> bug, please let me know.
Thank you very much for the quick analysis and fix.
If you can add a Closes: https://bugs.debian.org/1120602 that would
make our tracking for the fixes easier. But not sure if this is
allowed for proposing the backport for a stable series, as it did not
affect the upper releases.
In any case your work is much appreciated!
Regards,
Salvatore
^ permalink raw reply
* Re: [PATCH net-next v5 1/2] net: mana: Handle SKB if TX SGEs exceed hardware limit
From: Eric Dumazet @ 2025-11-14 21:26 UTC (permalink / raw)
To: Aditya Garg
Cc: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, kuba, pabeni,
longli, kotaranov, horms, shradhagupta, ssengar, ernis,
dipayanroy, shirazsaleem, leon, mlevitsk, yury.norov, sbhatta,
linux-hyperv, netdev, linux-kernel, linux-rdma, gargaditya
In-Reply-To: <1763155003-21503-2-git-send-email-gargaditya@linux.microsoft.com>
On Fri, Nov 14, 2025 at 1:19 PM Aditya Garg
<gargaditya@linux.microsoft.com> wrote:
>
> The MANA hardware supports a maximum of 30 scatter-gather entries (SGEs)
> per TX WQE. Exceeding this limit can cause TX failures.
> Add ndo_features_check() callback to validate SKB layout before
> transmission. For GSO SKBs that would exceed the hardware SGE limit, clear
> NETIF_F_GSO_MASK to enforce software segmentation in the stack.
> Add a fallback in mana_start_xmit() to linearize non-GSO SKBs that still
> exceed the SGE limit.
>
> Also, Add ethtool counter for SKBs linearized
>
> Co-developed-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
> Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
> Signed-off-by: Aditya Garg <gargaditya@linux.microsoft.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* [PATCH net-next v5 2/2] net: mana: Drop TX skb on post_work_request failure and unmap resources
From: Aditya Garg @ 2025-11-14 21:16 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, longli, kotaranov, horms, shradhagupta, ssengar,
ernis, dipayanroy, shirazsaleem, leon, mlevitsk, yury.norov,
sbhatta, linux-hyperv, netdev, linux-kernel, linux-rdma,
gargaditya
Cc: Aditya Garg
In-Reply-To: <1763155003-21503-1-git-send-email-gargaditya@linux.microsoft.com>
Drop TX packets when posting the work request fails and ensure DMA
mappings are always cleaned up.
Signed-off-by: Aditya Garg <gargaditya@linux.microsoft.com>
---
Changes in v5:
* No change.
Changes in v4:
* Fix warning during build reported by kernel test robot
---
drivers/net/ethernet/microsoft/mana/gdma_main.c | 6 +-----
drivers/net/ethernet/microsoft/mana/mana_en.c | 7 +++----
include/net/mana/mana.h | 1 +
3 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index effe0a2f207a..8fd70b34807a 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -1300,7 +1300,6 @@ int mana_gd_post_work_request(struct gdma_queue *wq,
struct gdma_posted_wqe_info *wqe_info)
{
u32 client_oob_size = wqe_req->inline_oob_size;
- struct gdma_context *gc;
u32 sgl_data_size;
u32 max_wqe_size;
u32 wqe_size;
@@ -1330,11 +1329,8 @@ int mana_gd_post_work_request(struct gdma_queue *wq,
if (wqe_size > max_wqe_size)
return -EINVAL;
- if (wq->monitor_avl_buf && wqe_size > mana_gd_wq_avail_space(wq)) {
- gc = wq->gdma_dev->gdma_context;
- dev_err(gc->dev, "unsuccessful flow control!\n");
+ if (wq->monitor_avl_buf && wqe_size > mana_gd_wq_avail_space(wq))
return -ENOSPC;
- }
if (wqe_info)
wqe_info->wqe_size_in_bu = wqe_size / GDMA_WQE_BU_SIZE;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index d92069954fd9..d656c0882343 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -493,9 +493,9 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (err) {
(void)skb_dequeue_tail(&txq->pending_skbs);
+ mana_unmap_skb(skb, apc);
netdev_warn(ndev, "Failed to post TX OOB: %d\n", err);
- err = NETDEV_TX_BUSY;
- goto tx_busy;
+ goto free_sgl_ptr;
}
err = NETDEV_TX_OK;
@@ -515,7 +515,6 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
tx_stats->bytes += len + ((num_gso_seg - 1) * gso_hs);
u64_stats_update_end(&tx_stats->syncp);
-tx_busy:
if (netif_tx_queue_stopped(net_txq) && mana_can_tx(gdma_sq)) {
netif_tx_wake_queue(net_txq);
apc->eth_stats.wake_queue++;
@@ -1683,7 +1682,7 @@ static int mana_move_wq_tail(struct gdma_queue *wq, u32 num_units)
return 0;
}
-static void mana_unmap_skb(struct sk_buff *skb, struct mana_port_context *apc)
+void mana_unmap_skb(struct sk_buff *skb, struct mana_port_context *apc)
{
struct mana_skb_head *ash = (struct mana_skb_head *)skb->head;
struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 50a532fb30d6..d05457d3e1ab 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -585,6 +585,7 @@ int mana_set_bw_clamp(struct mana_port_context *apc, u32 speed,
void mana_query_phy_stats(struct mana_port_context *apc);
int mana_pre_alloc_rxbufs(struct mana_port_context *apc, int mtu, int num_queues);
void mana_pre_dealloc_rxbufs(struct mana_port_context *apc);
+void mana_unmap_skb(struct sk_buff *skb, struct mana_port_context *apc);
extern const struct ethtool_ops mana_ethtool_ops;
extern struct dentry *mana_debugfs_root;
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v5 1/2] net: mana: Handle SKB if TX SGEs exceed hardware limit
From: Aditya Garg @ 2025-11-14 21:16 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, longli, kotaranov, horms, shradhagupta, ssengar,
ernis, dipayanroy, shirazsaleem, leon, mlevitsk, yury.norov,
sbhatta, linux-hyperv, netdev, linux-kernel, linux-rdma,
gargaditya
Cc: Aditya Garg
In-Reply-To: <1763155003-21503-1-git-send-email-gargaditya@linux.microsoft.com>
The MANA hardware supports a maximum of 30 scatter-gather entries (SGEs)
per TX WQE. Exceeding this limit can cause TX failures.
Add ndo_features_check() callback to validate SKB layout before
transmission. For GSO SKBs that would exceed the hardware SGE limit, clear
NETIF_F_GSO_MASK to enforce software segmentation in the stack.
Add a fallback in mana_start_xmit() to linearize non-GSO SKBs that still
exceed the SGE limit.
Also, Add ethtool counter for SKBs linearized
Co-developed-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
Signed-off-by: Aditya Garg <gargaditya@linux.microsoft.com>
---
Changes in v5:
* Drop skb_is_gso() check for disabling GSO in mana_features_check().
* Register .ndo_features_check conditionally to avoid unnecessary call.
Changes in v4:
* No change.
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 41 ++++++++++++++++++-
.../ethernet/microsoft/mana/mana_ethtool.c | 2 +
include/net/mana/gdma.h | 8 +++-
include/net/mana/mana.h | 1 +
4 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index cccd5b63cee6..d92069954fd9 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -11,6 +11,7 @@
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/export.h>
+#include <linux/skbuff.h>
#include <net/checksum.h>
#include <net/ip6_checksum.h>
@@ -329,6 +330,22 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
cq = &apc->tx_qp[txq_idx].tx_cq;
tx_stats = &txq->stats;
+ BUILD_BUG_ON(MAX_TX_WQE_SGL_ENTRIES != MANA_MAX_TX_WQE_SGL_ENTRIES);
+#if (MAX_SKB_FRAGS + 2 > MANA_MAX_TX_WQE_SGL_ENTRIES)
+ if (skb_shinfo(skb)->nr_frags + 2 > MAX_TX_WQE_SGL_ENTRIES) {
+ /* GSO skb with Hardware SGE limit exceeded is not expected here
+ * as they are handled in mana_features_check() callback
+ */
+ if (skb_linearize(skb)) {
+ netdev_warn_once(ndev, "Failed to linearize skb with nr_frags=%d and is_gso=%d\n",
+ skb_shinfo(skb)->nr_frags,
+ skb_is_gso(skb));
+ goto tx_drop_count;
+ }
+ apc->eth_stats.linear_pkt_tx_cnt++;
+ }
+#endif
+
pkg.tx_oob.s_oob.vcq_num = cq->gdma_id;
pkg.tx_oob.s_oob.vsq_frame = txq->vsq_frame;
@@ -442,8 +459,6 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
}
- WARN_ON_ONCE(pkg.wqe_req.num_sge > MAX_TX_WQE_SGL_ENTRIES);
-
if (pkg.wqe_req.num_sge <= ARRAY_SIZE(pkg.sgl_array)) {
pkg.wqe_req.sgl = pkg.sgl_array;
} else {
@@ -518,6 +533,25 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_OK;
}
+#if (MAX_SKB_FRAGS + 2 > MANA_MAX_TX_WQE_SGL_ENTRIES)
+static netdev_features_t mana_features_check(struct sk_buff *skb,
+ struct net_device *ndev,
+ netdev_features_t features)
+{
+ if (skb_shinfo(skb)->nr_frags + 2 > MAX_TX_WQE_SGL_ENTRIES) {
+ /* Exceeds HW SGE limit.
+ * GSO case:
+ * Disable GSO so the stack will software-segment the skb
+ * into smaller skbs that fit the SGE budget.
+ * Non-GSO case:
+ * The xmit path will attempt skb_linearize() as a fallback.
+ */
+ features &= ~NETIF_F_GSO_MASK;
+ }
+ return features;
+}
+#endif
+
static void mana_get_stats64(struct net_device *ndev,
struct rtnl_link_stats64 *st)
{
@@ -878,6 +912,9 @@ static const struct net_device_ops mana_devops = {
.ndo_open = mana_open,
.ndo_stop = mana_close,
.ndo_select_queue = mana_select_queue,
+#if (MAX_SKB_FRAGS + 2 > MANA_MAX_TX_WQE_SGL_ENTRIES)
+ .ndo_features_check = mana_features_check,
+#endif
.ndo_start_xmit = mana_start_xmit,
.ndo_validate_addr = eth_validate_addr,
.ndo_get_stats64 = mana_get_stats64,
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index a1afa75a9463..fa5e1a2f06a9 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -71,6 +71,8 @@ static const struct mana_stats_desc mana_eth_stats[] = {
{"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)},
{"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
tx_cqe_unknown_type)},
+ {"linear_pkt_tx_cnt", offsetof(struct mana_ethtool_stats,
+ linear_pkt_tx_cnt)},
{"rx_coalesced_err", offsetof(struct mana_ethtool_stats,
rx_coalesced_err)},
{"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 637f42485dba..6dae78dc468f 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -489,6 +489,8 @@ struct gdma_wqe {
#define MAX_TX_WQE_SIZE 512
#define MAX_RX_WQE_SIZE 256
+#define MANA_MAX_TX_WQE_SGL_ENTRIES 30
+
#define MAX_TX_WQE_SGL_ENTRIES ((GDMA_MAX_SQE_SIZE - \
sizeof(struct gdma_sge) - INLINE_OOB_SMALL_SIZE) / \
sizeof(struct gdma_sge))
@@ -592,6 +594,9 @@ enum {
#define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17)
#define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6)
+/* Driver supports linearizing the skb when num_sge exceeds hardware limit */
+#define GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE BIT(20)
+
#define GDMA_DRV_CAP_FLAGS1 \
(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
@@ -601,7 +606,8 @@ enum {
GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \
GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \
GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \
- GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE)
+ GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \
+ GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE)
#define GDMA_DRV_CAP_FLAGS2 0
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 8906901535f5..50a532fb30d6 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -404,6 +404,7 @@ struct mana_ethtool_stats {
u64 hc_tx_err_gdma;
u64 tx_cqe_err;
u64 tx_cqe_unknown_type;
+ u64 linear_pkt_tx_cnt;
u64 rx_coalesced_err;
u64 rx_cqe_unknown_type;
};
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v5 0/2] net: mana: Enforce TX SGE limit and fix error cleanup
From: Aditya Garg @ 2025-11-14 21:16 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, longli, kotaranov, horms, shradhagupta, ssengar,
ernis, dipayanroy, shirazsaleem, leon, mlevitsk, yury.norov,
sbhatta, linux-hyperv, netdev, linux-kernel, linux-rdma,
gargaditya
Cc: Aditya Garg
Add pre-transmission checks to block SKBs that exceed the hardware's SGE
limit. Force software segmentation for GSO traffic and linearize non-GSO
packets as needed.
Update TX error handling to drop failed SKBs and unmap resources
immediately.
---
Changes in v5:
* Drop skb_is_gso() check for disabling GSO in mana_features_check().
* Register .ndo_features_check conditionally to avoid unnecessary call.
Changes in v4:
* Fix warning during build reported by kernel test robot
---
Aditya Garg (2):
net: mana: Handle SKB if TX SGEs exceed hardware limit
net: mana: Drop TX skb on post_work_request failure and unmap
resources
.../net/ethernet/microsoft/mana/gdma_main.c | 6 +--
drivers/net/ethernet/microsoft/mana/mana_en.c | 48 ++++++++++++++++---
.../ethernet/microsoft/mana/mana_ethtool.c | 2 +
include/net/mana/gdma.h | 8 +++-
include/net/mana/mana.h | 2 +
5 files changed, 54 insertions(+), 12 deletions(-)
--
2.43.0
^ permalink raw reply
* Re: [PATCH net-next v4 1/2] net: mana: Handle SKB if TX SGEs exceed hardware limit
From: Aditya Garg @ 2025-11-14 20:58 UTC (permalink / raw)
To: Eric Dumazet
Cc: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, kuba, pabeni,
longli, kotaranov, horms, shradhagupta, ssengar, ernis,
dipayanroy, shirazsaleem, leon, mlevitsk, yury.norov, sbhatta,
linux-hyperv, netdev, linux-kernel, linux-rdma, gargaditya
In-Reply-To: <CANn89iL-RJ84WB9W8SoZn6_UMko8sLBb_FEGjjGZTEO+9KOpAg@mail.gmail.com>
On 12-11-2025 19:25, Eric Dumazet wrote:
> On Wed, Nov 12, 2025 at 5:11 AM Aditya Garg
> <gargaditya@linux.microsoft.com> wrote:
>>
>> The MANA hardware supports a maximum of 30 scatter-gather entries (SGEs)
>> per TX WQE. Exceeding this limit can cause TX failures.
>> Add ndo_features_check() callback to validate SKB layout before
>> transmission. For GSO SKBs that would exceed the hardware SGE limit, clear
>> NETIF_F_GSO_MASK to enforce software segmentation in the stack.
>> Add a fallback in mana_start_xmit() to linearize non-GSO SKBs that still
>> exceed the SGE limit.
>>
>> Also, Add ethtool counter for SKBs linearized
>>
>> Co-developed-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
>> Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
>> Signed-off-by: Aditya Garg <gargaditya@linux.microsoft.com>
>> ---
>> drivers/net/ethernet/microsoft/mana/mana_en.c | 37 ++++++++++++++++++-
>> .../ethernet/microsoft/mana/mana_ethtool.c | 2 +
>> include/net/mana/gdma.h | 6 ++-
>> include/net/mana/mana.h | 1 +
>> 4 files changed, 43 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
>> index cccd5b63cee6..67ae5421f9ee 100644
>> --- a/drivers/net/ethernet/microsoft/mana/mana_en.c
>> +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
>> @@ -11,6 +11,7 @@
>> #include <linux/mm.h>
>> #include <linux/pci.h>
>> #include <linux/export.h>
>> +#include <linux/skbuff.h>
>>
>> #include <net/checksum.h>
>> #include <net/ip6_checksum.h>
>> @@ -329,6 +330,20 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>> cq = &apc->tx_qp[txq_idx].tx_cq;
>> tx_stats = &txq->stats;
>>
>> + if (MAX_SKB_FRAGS + 2 > MAX_TX_WQE_SGL_ENTRIES &&
>> + skb_shinfo(skb)->nr_frags + 2 > MAX_TX_WQE_SGL_ENTRIES) {
>> + /* GSO skb with Hardware SGE limit exceeded is not expected here
>> + * as they are handled in mana_features_check() callback
>> + */
>> + if (skb_linearize(skb)) {
>> + netdev_warn_once(ndev, "Failed to linearize skb with nr_frags=%d and is_gso=%d\n",
>> + skb_shinfo(skb)->nr_frags,
>> + skb_is_gso(skb));
>> + goto tx_drop_count;
>> + }
>> + apc->eth_stats.linear_pkt_tx_cnt++;
>> + }
>> +
>> pkg.tx_oob.s_oob.vcq_num = cq->gdma_id;
>> pkg.tx_oob.s_oob.vsq_frame = txq->vsq_frame;
>>
>> @@ -442,8 +457,6 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>> }
>> }
>>
>> - WARN_ON_ONCE(pkg.wqe_req.num_sge > MAX_TX_WQE_SGL_ENTRIES);
>> -
>> if (pkg.wqe_req.num_sge <= ARRAY_SIZE(pkg.sgl_array)) {
>> pkg.wqe_req.sgl = pkg.sgl_array;
>> } else {
>> @@ -518,6 +531,25 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>> return NETDEV_TX_OK;
>> }
>>
>
>
> #if MAX_SKB_FRAGS + 2 > MAX_TX_WQE_SGL_ENTRIES
>
>> +static netdev_features_t mana_features_check(struct sk_buff *skb,
>> + struct net_device *ndev,
>> + netdev_features_t features)
>> +{
>> + if (MAX_SKB_FRAGS + 2 > MAX_TX_WQE_SGL_ENTRIES &&
>> + skb_shinfo(skb)->nr_frags + 2 > MAX_TX_WQE_SGL_ENTRIES) {
>> + /* Exceeds HW SGE limit.
>> + * GSO case:
>> + * Disable GSO so the stack will software-segment the skb
>> + * into smaller skbs that fit the SGE budget.
>> + * Non-GSO case:
>> + * The xmit path will attempt skb_linearize() as a fallback.
>> + */
>> + if (skb_is_gso(skb))
>
> No need to test skb_is_gso(skb), you can clear bits, this will be a
> NOP if the packet is non GSO anyway.
>
>> + features &= ~NETIF_F_GSO_MASK;
>> + }
>> + return features;
>> +}
>
> #endif
>
>> +
>> static void mana_get_stats64(struct net_device *ndev,
>> struct rtnl_link_stats64 *st)
>> {
>> @@ -878,6 +910,7 @@ static const struct net_device_ops mana_devops = {
>> .ndo_open = mana_open,
>> .ndo_stop = mana_close,
>> .ndo_select_queue = mana_select_queue,
>> + .ndo_features_check = mana_features_check,
>
> Note that if your mana_features_check() is a nop if MAX_SKB_FRAGS is
> small enough,
> you could set a non NULL .ndo_features_check based on a preprocessor condition
>
> #if MAX_SKB_FRAGS + 2 > MAX_TX_WQE_SGL_ENTRIES
> .ndo_features_check = ....
> #endif
>
> This would avoid an expensive indirect call when possible.
>
>
>> .ndo_start_xmit = mana_start_xmit,
>> .ndo_validate_addr = eth_validate_addr,
>> .ndo_get_stats64 = mana_get_stats64,
>> diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
>> index a1afa75a9463..fa5e1a2f06a9 100644
>> --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
>> +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
>> @@ -71,6 +71,8 @@ static const struct mana_stats_desc mana_eth_stats[] = {
>> {"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)},
>> {"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
>> tx_cqe_unknown_type)},
>> + {"linear_pkt_tx_cnt", offsetof(struct mana_ethtool_stats,
>> + linear_pkt_tx_cnt)},
>> {"rx_coalesced_err", offsetof(struct mana_ethtool_stats,
>> rx_coalesced_err)},
>> {"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
>> diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
>> index 637f42485dba..84614ebe0f4c 100644
>> --- a/include/net/mana/gdma.h
>> +++ b/include/net/mana/gdma.h
>> @@ -592,6 +592,9 @@ enum {
>> #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17)
>> #define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6)
>>
>> +/* Driver supports linearizing the skb when num_sge exceeds hardware limit */
>> +#define GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE BIT(20)
>> +
>> #define GDMA_DRV_CAP_FLAGS1 \
>> (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
>> GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
>> @@ -601,7 +604,8 @@ enum {
>> GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \
>> GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \
>> GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \
>> - GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE)
>> + GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \
>> + GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE)
>>
>> #define GDMA_DRV_CAP_FLAGS2 0
>>
>> diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
>> index 8906901535f5..50a532fb30d6 100644
>> --- a/include/net/mana/mana.h
>> +++ b/include/net/mana/mana.h
>> @@ -404,6 +404,7 @@ struct mana_ethtool_stats {
>> u64 hc_tx_err_gdma;
>> u64 tx_cqe_err;
>> u64 tx_cqe_unknown_type;
>> + u64 linear_pkt_tx_cnt;
>> u64 rx_coalesced_err;
>> u64 rx_cqe_unknown_type;
>> };
>> --
>> 2.43.0
>>
Thanks for the review Eric. I will incorporate these changes in next
revision.
Regards,
Aditya
^ permalink raw reply
* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Wei Liu @ 2025-11-14 18:40 UTC (permalink / raw)
To: Sean Christopherson
Cc: Wei Liu, Michael Kelley, Paolo Bonzini, Vitaly Kuznetsov,
K. Y. Srinivasan, Haiyang Zhang, Dexuan Cui, Nuno Das Neves,
kvm@vger.kernel.org, linux-hyperv@vger.kernel.org,
linux-kernel@vger.kernel.org, Jim Mattson, Yosry Ahmed
In-Reply-To: <aRd2famvq_3frSEq@google.com>
On Fri, Nov 14, 2025 at 10:35:41AM -0800, Sean Christopherson wrote:
> On Fri, Nov 14, 2025, Wei Liu wrote:
> > On Fri, Nov 14, 2025 at 07:22:41AM -0800, Sean Christopherson wrote:
> > > Ah, my PDF copy is just stale, it's indeed
> > > defined as a synthetic exit.
> > >
> > > https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/nested-virtualization#synthetic-vm-exit
> > >
> > > Anyways, I'm in favor of making HV_SVM_EXITCODE_ENL an ull, though part of me
> > > wonders if we should do:
> > >
> > > #define HV_SVM_EXITCODE_ENL SVM_EXIT_SW
> >
> > I know this is very tempting, but these headers are supposed to mirror
> > Microsoft's internal headers, so we would like to keep them
> > self-contained for ease of tracking.
>
> Ya, no argument from me. Aha! Even better, what I can do is have KVM assert
> that HV_SVM_EXITCODE_ENL == SVM_EXIT_SW in the KVM Hyper-V code, because what I
> really want to do is connect the dots for KVM folks.
This sounds like a good plan.
Wei
^ permalink raw reply
* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Sean Christopherson @ 2025-11-14 18:35 UTC (permalink / raw)
To: Wei Liu
Cc: Michael Kelley, Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan,
Haiyang Zhang, Dexuan Cui, Nuno Das Neves, kvm@vger.kernel.org,
linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org,
Jim Mattson, Yosry Ahmed
In-Reply-To: <20251114182921.GB1725668@liuwe-devbox-debian-v2.local>
On Fri, Nov 14, 2025, Wei Liu wrote:
> On Fri, Nov 14, 2025 at 07:22:41AM -0800, Sean Christopherson wrote:
> > Ah, my PDF copy is just stale, it's indeed
> > defined as a synthetic exit.
> >
> > https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/nested-virtualization#synthetic-vm-exit
> >
> > Anyways, I'm in favor of making HV_SVM_EXITCODE_ENL an ull, though part of me
> > wonders if we should do:
> >
> > #define HV_SVM_EXITCODE_ENL SVM_EXIT_SW
>
> I know this is very tempting, but these headers are supposed to mirror
> Microsoft's internal headers, so we would like to keep them
> self-contained for ease of tracking.
Ya, no argument from me. Aha! Even better, what I can do is have KVM assert
that HV_SVM_EXITCODE_ENL == SVM_EXIT_SW in the KVM Hyper-V code, because what I
really want to do is connect the dots for KVM folks.
> It should be fine to add the "ull" suffix here. I briefly talked to a
> hypervisor developer and they agreed.
Nice, thanks much!
^ permalink raw reply
* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Wei Liu @ 2025-11-14 18:29 UTC (permalink / raw)
To: Sean Christopherson
Cc: Michael Kelley, Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Nuno Das Neves,
kvm@vger.kernel.org, linux-hyperv@vger.kernel.org,
linux-kernel@vger.kernel.org, Jim Mattson, Yosry Ahmed
In-Reply-To: <aRdJQQ7_j6RcHwjJ@google.com>
On Fri, Nov 14, 2025 at 07:22:41AM -0800, Sean Christopherson wrote:
> On Fri, Nov 14, 2025, Michael Kelley wrote:
> > From: Sean Christopherson <seanjc@google.com> Sent: Thursday, November 13, 2025 2:56 PM
> > >
> >
> > Adding Microsoft's Nuno Das Neves to the "To:" line since he
> > originated the work to keep the Linux headers such as hvgdk.h in
> > sync with the Windows counterparts from which they originate.
>
> ...
>
> > > /* Exit code reserved for hypervisor/software use */
> > > -#define SVM_EXIT_SW 0xf0000000
> > > +#define SVM_EXIT_SW 0xf0000000ull
> > >
> > > -#define SVM_EXIT_ERR -1
> > > +#define SVM_EXIT_ERR -1ull
> > >
> >
> > [snip]
> >
> > > diff --git a/include/hyperv/hvgdk.h b/include/hyperv/hvgdk.h
> > > index dd6d4939ea29..56b695873a72 100644
> > > --- a/include/hyperv/hvgdk.h
> > > +++ b/include/hyperv/hvgdk.h
> > > @@ -281,7 +281,7 @@ struct hv_vmcb_enlightenments {
> > > #define HV_VMCB_NESTED_ENLIGHTENMENTS 31
> > >
> > > /* Synthetic VM-Exit */
> > > -#define HV_SVM_EXITCODE_ENL 0xf0000000
> > > +#define HV_SVM_EXITCODE_ENL 0xf0000000u
> >
> > Is there a reason for making this Hyper-V code just "u", while
> > making the SVM_VMGEXIT_* values "ull"? I don't think
> > "u" vs. "ull" shouldn't make any difference when assigning to a
> > u64, but the inconsistency piqued my interest ....
>
> I hedged and went for a more "minimal" change because it isn't KVM code, and at
> the time because I thought the value isn't defined by the APM. Though looking
> again at the APM, it does reserve that value for software
>
> F000_000h Unused Reserved for Host.
>
> and I can't find anything in the TLFS. Ah, my PDF copy is just stale, it's indeed
> defined as a synthetic exit.
>
> https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/nested-virtualization#synthetic-vm-exit
>
> Anyways, I'm in favor of making HV_SVM_EXITCODE_ENL an ull, though part of me
> wonders if we should do:
>
> #define HV_SVM_EXITCODE_ENL SVM_EXIT_SW
I know this is very tempting, but these headers are supposed to mirror
Microsoft's internal headers, so we would like to keep them
self-contained for ease of tracking.
It should be fine to add the "ull" suffix here. I briefly talked to a
hypervisor developer and they agreed.
Thanks,
Wei
^ permalink raw reply
* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Sean Christopherson @ 2025-11-14 15:47 UTC (permalink / raw)
To: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson,
Yosry Ahmed
In-Reply-To: <aRdKa9jVMt0Rn5tj@google.com>
On Fri, Nov 14, 2025, Sean Christopherson wrote:
> _and_ the hyperv_svm_test selftest fails. *sigh*
And the weekend can't come soon enough. The kernel I'm testing doesn't even have
these patches. /facepalm
^ permalink raw reply
* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Sean Christopherson @ 2025-11-14 15:27 UTC (permalink / raw)
To: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson,
Yosry Ahmed
In-Reply-To: <20251113225621.1688428-8-seanjc@google.com>
On Thu, Nov 13, 2025, Sean Christopherson wrote:
> Fix KVM's long-standing buggy handling of SVM's exit_code as a 32-bit
> value. Per the APM and Xen commit d1bd157fbc ("Big merge the HVM
> full-virtualisation abstractions.") (which is arguably more trustworthy
> than KVM), offset 0x70 is a single 64-bit value:
>
> 070h 63:0 EXITCODE
>
> Track exit_code as a single u64 to prevent reintroducing bugs where KVM
> neglects to correctly set bits 63:32.
>
> Fixes: 6aa8b732ca01 ("[PATCH] kvm: userspace interface")
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
...
> diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
> index e79bc9cb7162..4c7a5cd10990 100644
> --- a/arch/x86/kvm/trace.h
> +++ b/arch/x86/kvm/trace.h
> @@ -781,7 +781,7 @@ TRACE_EVENT_KVM_EXIT(kvm_nested_vmexit);
> * Tracepoint for #VMEXIT reinjected to the guest
> */
> TRACE_EVENT(kvm_nested_vmexit_inject,
> - TP_PROTO(__u32 exit_code,
> + TP_PROTO(__u64 exit_code,
> __u64 exit_info1, __u64 exit_info2,
> __u32 exit_int_info, __u32 exit_int_info_err, __u32 isa),
> TP_ARGS(exit_code, exit_info1, exit_info2,
As pointed out by the test bot[*], the trace macro to print exit reasons needs
to use 64-bit variants to play nice with 32-bit builds.
And now I'm questioning all of my testing, because my build setup detects that
as well, _and_ the hyperv_svm_test selftest fails. *sigh*
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index 4c7a5cd10990..0fd72ce83926 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -383,10 +383,10 @@ TRACE_EVENT(kvm_apic,
#define kvm_print_exit_reason(exit_reason, isa) \
(isa == KVM_ISA_VMX) ? \
__print_symbolic(exit_reason & 0xffff, VMX_EXIT_REASONS) : \
- __print_symbolic(exit_reason, SVM_EXIT_REASONS), \
+ __print_symbolic64(exit_reason, SVM_EXIT_REASONS), \
(isa == KVM_ISA_VMX && exit_reason & ~0xffff) ? " " : "", \
(isa == KVM_ISA_VMX) ? \
- __print_flags(exit_reason & ~0xffff, " ", VMX_EXIT_REASON_FLAGS) : ""
+ __print_flags64(exit_reason & ~0xffff, " ", VMX_EXIT_REASON_FLAGS) : ""
#define TRACE_EVENT_KVM_EXIT(name) \
TRACE_EVENT(name,
[*] https://lore.kernel.org/all/202511141707.t4ad044J-lkp@intel.com
^ 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