[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251231065109.43378-8-slark_xiao@163.com>
Date: Wed, 31 Dec 2025 14:51:08 +0800
From: Slark Xiao <slark_xiao@....com>
To: loic.poulain@....qualcomm.com,
ryazanov.s.a@...il.com,
johannes@...solutions.net,
andrew+netdev@...n.ch,
davem@...emloft.net,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
mani@...nel.org
Cc: netdev@...r.kernel.org,
linux-kernel@...r.kernel.org,
Daniele Palmas <dnlplm@...il.com>
Subject: [net-next v3 7/8] net: wwan: prevent premature device unregister when NMEA port is present
From: Loic Poulain <loic.poulain@....qualcomm.com>
The WWAN core unregisters the device when it has no remaining WWAN ops
or child devices. For NMEA port types, the child is registered under
the GNSS class instead of WWAN, so the core incorrectly assumes there
are no children and unregisters the WWAN device too early. This leads
to a second unregister attempt after the NMEA device is removed.
To fix this issue, we register a virtual WWAN port device along the
GNSS device, this ensures the WWAN device remains registered until
all associated ports, including NMEA, are properly removed.
Reported-by: Daniele Palmas <dnlplm@...il.com>
Closes: https://lore.kernel.org/netdev/CAGRyCJE28yf-rrfkFbzu44ygLEvoUM7fecK1vnrghjG_e9UaRA@mail.gmail.com/
Signed-off-by: Loic Poulain <loic.poulain@....qualcomm.com>
---
drivers/net/wwan/wwan_core.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c
index 93998b498454..40a57fb0aa0b 100644
--- a/drivers/net/wwan/wwan_core.c
+++ b/drivers/net/wwan/wwan_core.c
@@ -455,7 +455,7 @@ static int __wwan_port_dev_assign_name(struct wwan_port *port, const char *fmt)
}
/* Register a regular WWAN port device (e.g. AT, MBIM, etc.) */
-static int wwan_port_register_wwan(struct wwan_port *port)
+static int wwan_port_register_wwan(struct wwan_port *port, bool cdev)
{
struct wwan_device *wwandev = to_wwan_dev(port->dev.parent);
char namefmt[0x20];
@@ -467,7 +467,8 @@ static int wwan_port_register_wwan(struct wwan_port *port)
return minor;
port->dev.class = &wwan_class;
- port->dev.devt = MKDEV(wwan_major, minor);
+ if (cdev)
+ port->dev.devt = MKDEV(wwan_major, minor);
/* allocate unique name based on wwan device id, port type and number */
snprintf(namefmt, sizeof(namefmt), "wwan%u%s%%d", wwandev->id,
@@ -625,6 +626,7 @@ struct wwan_port *wwan_create_port(struct device *parent,
struct wwan_port_caps *caps,
void *drvdata)
{
+ bool cdev = (type == WWAN_PORT_NMEA) ? false : true;
struct wwan_device *wwandev;
struct wwan_port *port;
int err;
@@ -659,16 +661,20 @@ struct wwan_port *wwan_create_port(struct device *parent,
dev_set_drvdata(&port->dev, drvdata);
device_initialize(&port->dev);
- if (port->type == WWAN_PORT_NMEA)
- err = wwan_port_register_gnss(port);
- else
- err = wwan_port_register_wwan(port);
-
+ err = wwan_port_register_wwan(port, cdev);
if (err)
goto error_put_device;
+ if (type == WWAN_PORT_NMEA) {
+ err = wwan_port_register_gnss(port);
+ if (err)
+ goto error_port_unregister;
+ }
+
return port;
+error_port_unregister:
+ wwan_port_unregister_wwan(port);
error_put_device:
put_device(&port->dev);
error_wwandev_remove:
@@ -695,8 +701,8 @@ void wwan_remove_port(struct wwan_port *port)
if (port->type == WWAN_PORT_NMEA)
wwan_port_unregister_gnss(port);
- else
- wwan_port_unregister_wwan(port);
+
+ wwan_port_unregister_wwan(port);
put_device(&port->dev);
--
2.25.1
Powered by blists - more mailing lists