Skip to content

Commit 37dc3ea

Browse files
stm-at-esdmarckleinebudde
authored andcommitted
can: esd_usb: Avoid errors triggered from USB disconnect
The USB stack calls during disconnect the esd_usb_disconnect() callback. esd_usb_disconnect() calls netdev_unregister() for each network which in turn calls the net_device_ops::ndo_stop callback esd_usb_close() if the net device is up. The esd_usb_close() callback tries to disable all CAN Ids and to reset the CAN controller of the device sending appropriate control messages. Sending these messages in .disconnect() is moot and always fails because either the device is gone or the USB communication is already torn down by the USB stack in the course of a rmmod operation. Move the code that sends these control messages to a new function esd_usb_stop() which is approximately the counterpart of esd_usb_start() to make code structure less convoluted. Then change esd_usb_close() not to send the control messages at all if the ndo_stop() callback is executed from the USB .disconnect() callback. Add a new flag in_usb_disconnect to the struct esd_usb device structure to mark this condition which is checked by esd_usb_close() whether to skip the send operations in esd_usb_start(). Signed-off-by: Stefan Mätje <[email protected]> Link: https://patch.msgid.link/[email protected] [mkl: minor change patch description to imperative language] Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent c6e0752 commit 37dc3ea

File tree

1 file changed

+26
-8
lines changed

1 file changed

+26
-8
lines changed

drivers/net/can/usb/esd_usb.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ struct esd_usb {
275275
int net_count;
276276
u32 version;
277277
int rxinitdone;
278+
int in_usb_disconnect;
278279
void *rxbuf[ESD_USB_MAX_RX_URBS];
279280
dma_addr_t rxbuf_dma[ESD_USB_MAX_RX_URBS];
280281
};
@@ -947,9 +948,9 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
947948
return ret;
948949
}
949950

950-
static int esd_usb_close(struct net_device *netdev)
951+
/* Stop interface */
952+
static int esd_usb_stop(struct esd_usb_net_priv *priv)
951953
{
952-
struct esd_usb_net_priv *priv = netdev_priv(netdev);
953954
union esd_usb_msg *msg;
954955
int err;
955956
int i;
@@ -966,8 +967,10 @@ static int esd_usb_close(struct net_device *netdev)
966967
for (i = 0; i <= ESD_USB_MAX_ID_SEGMENT; i++)
967968
msg->filter.mask[i] = 0;
968969
err = esd_usb_send_msg(priv->usb, msg);
969-
if (err < 0)
970-
netdev_err(netdev, "sending idadd message failed: %pe\n", ERR_PTR(err));
970+
if (err < 0) {
971+
netdev_err(priv->netdev, "sending idadd message failed: %pe\n", ERR_PTR(err));
972+
goto bail;
973+
}
971974

972975
/* set CAN controller to reset mode */
973976
msg->hdr.len = sizeof(struct esd_usb_set_baudrate_msg) / sizeof(u32); /* # of 32bit words */
@@ -977,17 +980,31 @@ static int esd_usb_close(struct net_device *netdev)
977980
msg->setbaud.baud = cpu_to_le32(ESD_USB_NO_BAUDRATE);
978981
err = esd_usb_send_msg(priv->usb, msg);
979982
if (err < 0)
980-
netdev_err(netdev, "sending setbaud message failed: %pe\n", ERR_PTR(err));
983+
netdev_err(priv->netdev, "sending setbaud message failed: %pe\n", ERR_PTR(err));
984+
985+
bail:
986+
kfree(msg);
987+
988+
return err;
989+
}
990+
991+
static int esd_usb_close(struct net_device *netdev)
992+
{
993+
struct esd_usb_net_priv *priv = netdev_priv(netdev);
994+
int err = 0;
995+
996+
if (!priv->usb->in_usb_disconnect) {
997+
/* It's moot to try this in usb_disconnect()! */
998+
err = esd_usb_stop(priv);
999+
}
9811000

9821001
priv->can.state = CAN_STATE_STOPPED;
9831002

9841003
netif_stop_queue(netdev);
9851004

9861005
close_candev(netdev);
9871006

988-
kfree(msg);
989-
990-
return 0;
1007+
return err;
9911008
}
9921009

9931010
static const struct net_device_ops esd_usb_netdev_ops = {
@@ -1357,6 +1374,7 @@ static void esd_usb_disconnect(struct usb_interface *intf)
13571374
usb_set_intfdata(intf, NULL);
13581375

13591376
if (dev) {
1377+
dev->in_usb_disconnect = 1;
13601378
for (i = 0; i < dev->net_count; i++) {
13611379
if (dev->nets[i]) {
13621380
netdev = dev->nets[i]->netdev;

0 commit comments

Comments
 (0)