public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] qmi_wwan: allow max_mtu above hard_mtu to control rx_urb_size
@ 2026-03-02 10:28 Laurent Vivier
  2026-03-04  8:43 ` Thorsten Leemhuis
  0 siblings, 1 reply; 2+ messages in thread
From: Laurent Vivier @ 2026-03-02 10:28 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: linux-kernel, Daniele Palmas, Stefano Brivio, Koen Vandeputte,
	linux-usb, netdev, Laurent Vivier

Commit c7159e960f14 ("usbnet: limit max_mtu based on device's hard_mtu")
capped net->max_mtu to the device's hard_mtu in usbnet_probe(). While
this correctly prevents oversized packets on standard USB network
devices, it breaks the qmi_wwan driver.

qmi_wwan relies on userspace (e.g. ModemManager) setting a large MTU on
the wwan0 interface to configure rx_urb_size via usbnet_change_mtu().
QMI modems negotiate USB transfer sizes of 16,383 or 32,767 bytes, and
the USB receive buffers must be sized accordingly. With max_mtu capped
to hard_mtu (~1500 bytes), userspace can no longer raise the MTU, the
receive buffers remain small, and download speeds drop from >300 Mbps
to ~0.8 Mbps.

Introduce a FLAG_NOMAXMTU driver flag that allows individual usbnet
drivers to opt out of the max_mtu cap. Set this flag in qmi_wwan's
driver_info structures to restore the previous behavior for QMI devices,
while keeping the safety fix in place for all other usbnet drivers.

Fixes: c7159e960f14 ("usbnet: limit max_mtu based on device's hard_mtu")
Reported-by: Koen Vandeputte <koen.vandeputte@citymesh.com>
Tested-by: Daniele Palmas <dnlplm@gmail.com>
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
 drivers/net/usb/qmi_wwan.c | 4 ++--
 drivers/net/usb/usbnet.c   | 7 ++++---
 include/linux/usb/usbnet.h | 1 +
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 3a4985b582cb..05acac10cd2b 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -928,7 +928,7 @@ static int qmi_wwan_resume(struct usb_interface *intf)
 
 static const struct driver_info	qmi_wwan_info = {
 	.description	= "WWAN/QMI device",
-	.flags		= FLAG_WWAN | FLAG_SEND_ZLP,
+	.flags		= FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
 	.bind		= qmi_wwan_bind,
 	.unbind		= qmi_wwan_unbind,
 	.manage_power	= qmi_wwan_manage_power,
@@ -937,7 +937,7 @@ static const struct driver_info	qmi_wwan_info = {
 
 static const struct driver_info	qmi_wwan_info_quirk_dtr = {
 	.description	= "WWAN/QMI device",
-	.flags		= FLAG_WWAN | FLAG_SEND_ZLP,
+	.flags		= FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
 	.bind		= qmi_wwan_bind,
 	.unbind		= qmi_wwan_unbind,
 	.manage_power	= qmi_wwan_manage_power,
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ed86ba87ca4e..b72ba0803392 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1829,11 +1829,12 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod)
 		if ((dev->driver_info->flags & FLAG_NOARP) != 0)
 			net->flags |= IFF_NOARP;
 
-		if (net->max_mtu > (dev->hard_mtu - net->hard_header_len))
+		if ((dev->driver_info->flags & FLAG_NOMAXMTU) == 0 &&
+		    net->max_mtu > (dev->hard_mtu - net->hard_header_len))
 			net->max_mtu = dev->hard_mtu - net->hard_header_len;
 
-		if (net->mtu > net->max_mtu)
-			net->mtu = net->max_mtu;
+		if (net->mtu > (dev->hard_mtu - net->hard_header_len))
+			net->mtu = dev->hard_mtu - net->hard_header_len;
 
 	} else if (!info->in || !info->out)
 		status = usbnet_get_endpoints(dev, udev);
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index b0e84896e6ac..bbf799ccf3b3 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -132,6 +132,7 @@ struct driver_info {
 #define FLAG_MULTI_PACKET	0x2000
 #define FLAG_RX_ASSEMBLE	0x4000	/* rx packets may span >1 frames */
 #define FLAG_NOARP		0x8000	/* device can't do ARP */
+#define FLAG_NOMAXMTU		0x10000	/* allow max_mtu above hard_mtu */
 
 	/* init device ... can sleep, or cause probe() failure */
 	int	(*bind)(struct usbnet *, struct usb_interface *);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] qmi_wwan: allow max_mtu above hard_mtu to control rx_urb_size
  2026-03-02 10:28 [PATCH] qmi_wwan: allow max_mtu above hard_mtu to control rx_urb_size Laurent Vivier
@ 2026-03-04  8:43 ` Thorsten Leemhuis
  0 siblings, 0 replies; 2+ messages in thread
From: Thorsten Leemhuis @ 2026-03-04  8:43 UTC (permalink / raw)
  To: Laurent Vivier, Jakub Kicinski
  Cc: linux-kernel, Daniele Palmas, Stefano Brivio, Koen Vandeputte,
	linux-usb, netdev, Linux kernel regressions list

On 3/2/26 11:28, Laurent Vivier wrote:
> Commit c7159e960f14 ("usbnet: limit max_mtu based on device's hard_mtu")
> capped net->max_mtu to the device's hard_mtu in usbnet_probe(). While
> this correctly prevents oversized packets on standard USB network
> devices, it breaks the qmi_wwan driver.
> 
> qmi_wwan relies on userspace (e.g. ModemManager) setting a large MTU on
> the wwan0 interface to configure rx_urb_size via usbnet_change_mtu().
> QMI modems negotiate USB transfer sizes of 16,383 or 32,767 bytes, and
> the USB receive buffers must be sized accordingly. With max_mtu capped
> to hard_mtu (~1500 bytes), userspace can no longer raise the MTU, the
> receive buffers remain small, and download speeds drop from >300 Mbps
> to ~0.8 Mbps.
> 
> Introduce a FLAG_NOMAXMTU driver flag that allows individual usbnet
> drivers to opt out of the max_mtu cap. Set this flag in qmi_wwan's
> driver_info structures to restore the previous behavior for QMI devices,
> while keeping the safety fix in place for all other usbnet drivers.
> 
> Fixes: c7159e960f14 ("usbnet: limit max_mtu based on device's hard_mtu")

[disclaimer: I'm not a reviewer, just someone that keeps and eye on
regressions]

Given that the regression afaics was found in a stable series with that
commit backported, would you maybe we willing to add a stable tag to
ensure fast backporting to all affected series? See
Documentation/process/stable-kernel-rules.rst for all details, but
normally this will do:

 Cc: stable@vger.kernel.org

> Reported-by: Koen Vandeputte <koen.vandeputte@citymesh.com>

While at it: please considered linking to the report using a Link or
Closes tag like this

 Link:
https://lore.kernel.org/lkml/CAPh3n803k8JcBPV5qEzUB-oKzWkAs-D5CU7z=Vd_nLRCr5ZqQg@mail.gmail.com/

That is something Linus really wants[1] and actually something that
Documentation/process/submitting-patches.rst and
Documentation/process/5.Posting.rst asks for.

[1] see here:
https://lore.kernel.org/all/CAHk-=wj2kJRPWx8B09AAtzj+_g+T6UBX11TP0ebs1WJdTtv=WQ@mail.gmail.com/
https://lore.kernel.org/all/CAHk-=wjMmSZzMJ3Xnskdg4+GGz=5p5p+GSYyFBTh0f-DgvdBWg@mail.gmail.com/
https://lore.kernel.org/all/CAHk-=wjxzafG-=J8oT30s7upn4RhBs6TX-uVFZ5rME+L5_DoJA@mail.gmail.com/

Ciao, Thorsten

> Tested-by: Daniele Palmas <dnlplm@gmail.com>
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> ---
>  drivers/net/usb/qmi_wwan.c | 4 ++--
>  drivers/net/usb/usbnet.c   | 7 ++++---
>  include/linux/usb/usbnet.h | 1 +
>  3 files changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
> index 3a4985b582cb..05acac10cd2b 100644
> --- a/drivers/net/usb/qmi_wwan.c
> +++ b/drivers/net/usb/qmi_wwan.c
> @@ -928,7 +928,7 @@ static int qmi_wwan_resume(struct usb_interface *intf)
>  
>  static const struct driver_info	qmi_wwan_info = {
>  	.description	= "WWAN/QMI device",
> -	.flags		= FLAG_WWAN | FLAG_SEND_ZLP,
> +	.flags		= FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
>  	.bind		= qmi_wwan_bind,
>  	.unbind		= qmi_wwan_unbind,
>  	.manage_power	= qmi_wwan_manage_power,
> @@ -937,7 +937,7 @@ static const struct driver_info	qmi_wwan_info = {
>  
>  static const struct driver_info	qmi_wwan_info_quirk_dtr = {
>  	.description	= "WWAN/QMI device",
> -	.flags		= FLAG_WWAN | FLAG_SEND_ZLP,
> +	.flags		= FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
>  	.bind		= qmi_wwan_bind,
>  	.unbind		= qmi_wwan_unbind,
>  	.manage_power	= qmi_wwan_manage_power,
> diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
> index ed86ba87ca4e..b72ba0803392 100644
> --- a/drivers/net/usb/usbnet.c
> +++ b/drivers/net/usb/usbnet.c
> @@ -1829,11 +1829,12 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod)
>  		if ((dev->driver_info->flags & FLAG_NOARP) != 0)
>  			net->flags |= IFF_NOARP;
>  
> -		if (net->max_mtu > (dev->hard_mtu - net->hard_header_len))
> +		if ((dev->driver_info->flags & FLAG_NOMAXMTU) == 0 &&
> +		    net->max_mtu > (dev->hard_mtu - net->hard_header_len))
>  			net->max_mtu = dev->hard_mtu - net->hard_header_len;
>  
> -		if (net->mtu > net->max_mtu)
> -			net->mtu = net->max_mtu;
> +		if (net->mtu > (dev->hard_mtu - net->hard_header_len))
> +			net->mtu = dev->hard_mtu - net->hard_header_len;
>  
>  	} else if (!info->in || !info->out)
>  		status = usbnet_get_endpoints(dev, udev);
> diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
> index b0e84896e6ac..bbf799ccf3b3 100644
> --- a/include/linux/usb/usbnet.h
> +++ b/include/linux/usb/usbnet.h
> @@ -132,6 +132,7 @@ struct driver_info {
>  #define FLAG_MULTI_PACKET	0x2000
>  #define FLAG_RX_ASSEMBLE	0x4000	/* rx packets may span >1 frames */
>  #define FLAG_NOARP		0x8000	/* device can't do ARP */
> +#define FLAG_NOMAXMTU		0x10000	/* allow max_mtu above hard_mtu */
>  
>  	/* init device ... can sleep, or cause probe() failure */
>  	int	(*bind)(struct usbnet *, struct usb_interface *);


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-03-04  8:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-02 10:28 [PATCH] qmi_wwan: allow max_mtu above hard_mtu to control rx_urb_size Laurent Vivier
2026-03-04  8:43 ` Thorsten Leemhuis

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