Linux-USB Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot
@ 2020-10-10 14:00 Ondrej Zary
  2020-10-10 14:00 ` [PATCH 2/2] cx82310_eth: use netdev_err instead of dev_err Ondrej Zary
  2020-10-11 22:55 ` [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot Jakub Kicinski
  0 siblings, 2 replies; 5+ messages in thread
From: Ondrej Zary @ 2020-10-10 14:00 UTC (permalink / raw)
  To: Oliver Neukum, netdev, linux-usb, linux-kernel

When the router is rebooted without a power cycle, the USB device
remains connected but its configuration is reset. This results in
a non-working ethernet connection with messages like this in syslog:
	usb 2-2: RX packet too long: 65535 B

Re-enable ethernet mode when receiving a packet with invalid size of
0xffff.

Signed-off-by: Ondrej Zary <linux@zary.sk>
---
 drivers/net/usb/cx82310_eth.c | 50 ++++++++++++++++++++++++++++++-----
 1 file changed, 44 insertions(+), 6 deletions(-)

diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c
index 32b08b18e120..043679311399 100644
--- a/drivers/net/usb/cx82310_eth.c
+++ b/drivers/net/usb/cx82310_eth.c
@@ -40,6 +40,11 @@ enum cx82310_status {
 #define CX82310_MTU	1514
 #define CMD_EP		0x01
 
+struct cx82310_priv {
+	struct work_struct reenable_work;
+	struct usbnet *dev;
+};
+
 /*
  * execute control command
  *  - optionally send some data (command parameters)
@@ -115,6 +120,23 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
 	return ret;
 }
 
+static int cx82310_enable_ethernet(struct usbnet *dev)
+{
+	int ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
+
+	if (ret)
+		netdev_err(dev->net, "unable to enable ethernet mode: %d\n",
+			   ret);
+	return ret;
+}
+
+static void cx82310_reenable_work(struct work_struct *work)
+{
+	struct cx82310_priv *priv = container_of(work, struct cx82310_priv,
+						 reenable_work);
+	cx82310_enable_ethernet(priv->dev);
+}
+
 #define partial_len	data[0]		/* length of partial packet data */
 #define partial_rem	data[1]		/* remaining (missing) data length */
 #define partial_data	data[2]		/* partial packet data */
@@ -126,6 +148,7 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
 	struct usb_device *udev = dev->udev;
 	u8 link[3];
 	int timeout = 50;
+	struct cx82310_priv *priv;
 
 	/* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */
 	if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0
@@ -152,6 +175,15 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
 	if (!dev->partial_data)
 		return -ENOMEM;
 
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto err_partial;
+	}
+	dev->driver_priv = priv;
+	INIT_WORK(&priv->reenable_work, cx82310_reenable_work);
+	priv->dev = dev;
+
 	/* wait for firmware to become ready (indicated by the link being up) */
 	while (--timeout) {
 		ret = cx82310_cmd(dev, CMD_GET_LINK_STATUS, true, NULL, 0,
@@ -168,12 +200,8 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
 	}
 
 	/* enable ethernet mode (?) */
-	ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
-	if (ret) {
-		dev_err(&udev->dev, "unable to enable ethernet mode: %d\n",
-			ret);
+	if (cx82310_enable_ethernet(dev))
 		goto err;
-	}
 
 	/* get the MAC address */
 	ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0,
@@ -190,13 +218,19 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
 
 	return 0;
 err:
+	kfree(dev->driver_priv);
+err_partial:
 	kfree((void *)dev->partial_data);
 	return ret;
 }
 
 static void cx82310_unbind(struct usbnet *dev, struct usb_interface *intf)
 {
+	struct cx82310_priv *priv = dev->driver_priv;
+
 	kfree((void *)dev->partial_data);
+	cancel_work_sync(&priv->reenable_work);
+	kfree(dev->driver_priv);
 }
 
 /*
@@ -211,6 +245,7 @@ static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
 	int len;
 	struct sk_buff *skb2;
+	struct cx82310_priv *priv = dev->driver_priv;
 
 	/*
 	 * If the last skb ended with an incomplete packet, this skb contains
@@ -245,7 +280,10 @@ static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 			break;
 		}
 
-		if (len > CX82310_MTU) {
+		if (len == 0xffff) {
+			netdev_info(dev->net, "router was rebooted, re-enabling ethernet mode");
+			schedule_work(&priv->reenable_work);
+		} else if (len > CX82310_MTU) {
 			dev_err(&dev->udev->dev, "RX packet too long: %d B\n",
 				len);
 			return 0;
-- 
Ondrej Zary


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

* [PATCH 2/2] cx82310_eth: use netdev_err instead of dev_err
  2020-10-10 14:00 [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot Ondrej Zary
@ 2020-10-10 14:00 ` Ondrej Zary
  2020-10-11 22:55 ` [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot Jakub Kicinski
  1 sibling, 0 replies; 5+ messages in thread
From: Ondrej Zary @ 2020-10-10 14:00 UTC (permalink / raw)
  To: Oliver Neukum, netdev, linux-usb, linux-kernel

Use netdev_err for better device identification in syslog.

Signed-off-by: Ondrej Zary <linux@zary.sk>
---
 drivers/net/usb/cx82310_eth.c | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c
index 043679311399..ca89d8258dd3 100644
--- a/drivers/net/usb/cx82310_eth.c
+++ b/drivers/net/usb/cx82310_eth.c
@@ -71,8 +71,8 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
 			   CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);
 	if (ret < 0) {
 		if (cmd != CMD_GET_LINK_STATUS)
-			dev_err(&dev->udev->dev, "send command %#x: error %d\n",
-				cmd, ret);
+			netdev_err(dev->net, "send command %#x: error %d\n",
+				   cmd, ret);
 		goto end;
 	}
 
@@ -84,30 +84,27 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
 					   CMD_TIMEOUT);
 			if (ret < 0) {
 				if (cmd != CMD_GET_LINK_STATUS)
-					dev_err(&dev->udev->dev,
-						"reply receive error %d\n",
-						ret);
+					netdev_err(dev->net, "reply receive error %d\n",
+						   ret);
 				goto end;
 			}
 			if (actual_len > 0)
 				break;
 		}
 		if (actual_len == 0) {
-			dev_err(&dev->udev->dev, "no reply to command %#x\n",
-				cmd);
+			netdev_err(dev->net, "no reply to command %#x\n", cmd);
 			ret = -EIO;
 			goto end;
 		}
 		if (buf[0] != cmd) {
-			dev_err(&dev->udev->dev,
-				"got reply to command %#x, expected: %#x\n",
-				buf[0], cmd);
+			netdev_err(dev->net, "got reply to command %#x, expected: %#x\n",
+				   buf[0], cmd);
 			ret = -EIO;
 			goto end;
 		}
 		if (buf[1] != STATUS_SUCCESS) {
-			dev_err(&dev->udev->dev, "command %#x failed: %#x\n",
-				cmd, buf[1]);
+			netdev_err(dev->net, "command %#x failed: %#x\n", cmd,
+				   buf[1]);
 			ret = -EIO;
 			goto end;
 		}
@@ -194,7 +191,7 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
 		msleep(500);
 	}
 	if (!timeout) {
-		dev_err(&udev->dev, "firmware not ready in time\n");
+		netdev_err(dev->net, "firmware not ready in time\n");
 		ret = -ETIMEDOUT;
 		goto err;
 	}
@@ -207,7 +204,7 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
 	ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0,
 			  dev->net->dev_addr, ETH_ALEN);
 	if (ret) {
-		dev_err(&udev->dev, "unable to read MAC address: %d\n", ret);
+		netdev_err(dev->net, "unable to read MAC address: %d\n", ret);
 		goto err;
 	}
 
@@ -284,8 +281,7 @@ static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 			netdev_info(dev->net, "router was rebooted, re-enabling ethernet mode");
 			schedule_work(&priv->reenable_work);
 		} else if (len > CX82310_MTU) {
-			dev_err(&dev->udev->dev, "RX packet too long: %d B\n",
-				len);
+			netdev_err(dev->net, "RX packet too long: %d B\n", len);
 			return 0;
 		}
 
-- 
Ondrej Zary


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

* Re: [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot
  2020-10-10 14:00 [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot Ondrej Zary
  2020-10-10 14:00 ` [PATCH 2/2] cx82310_eth: use netdev_err instead of dev_err Ondrej Zary
@ 2020-10-11 22:55 ` Jakub Kicinski
  2020-10-12 10:42   ` Ondrej Zary
  1 sibling, 1 reply; 5+ messages in thread
From: Jakub Kicinski @ 2020-10-11 22:55 UTC (permalink / raw)
  To: Ondrej Zary; +Cc: Oliver Neukum, netdev, linux-usb, linux-kernel

On Sat, 10 Oct 2020 16:00:46 +0200 Ondrej Zary wrote:
> When the router is rebooted without a power cycle, the USB device
> remains connected but its configuration is reset. This results in
> a non-working ethernet connection with messages like this in syslog:
> 	usb 2-2: RX packet too long: 65535 B
> 
> Re-enable ethernet mode when receiving a packet with invalid size of
> 0xffff.

Patch looks good, but could you explain what's a reboot without a power
cycle in this case? The modem gets reset but USB subsystem doesn't know
it and doesn't go though a unbind() + bind() cycle?

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

* Re: [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot
  2020-10-11 22:55 ` [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot Jakub Kicinski
@ 2020-10-12 10:42   ` Ondrej Zary
  2020-10-12 16:50     ` Jakub Kicinski
  0 siblings, 1 reply; 5+ messages in thread
From: Ondrej Zary @ 2020-10-12 10:42 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: Oliver Neukum, netdev, linux-usb, linux-kernel

On Monday 12 October 2020, Jakub Kicinski wrote:
> On Sat, 10 Oct 2020 16:00:46 +0200 Ondrej Zary wrote:
> > When the router is rebooted without a power cycle, the USB device
> > remains connected but its configuration is reset. This results in
> > a non-working ethernet connection with messages like this in syslog:
> > 	usb 2-2: RX packet too long: 65535 B
> >
> > Re-enable ethernet mode when receiving a packet with invalid size of
> > 0xffff.
>
> Patch looks good, but could you explain what's a reboot without a power
> cycle in this case? The modem gets reset but USB subsystem doesn't know
> it and doesn't go though a unbind() + bind() cycle?

The router can be rebooted through the web interface. The reboot does not 
disconnect the USB device - it remains connected as if nothing happened. Only 
wrong data starts to come in.

-- 
Ondrej Zary

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

* Re: [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot
  2020-10-12 10:42   ` Ondrej Zary
@ 2020-10-12 16:50     ` Jakub Kicinski
  0 siblings, 0 replies; 5+ messages in thread
From: Jakub Kicinski @ 2020-10-12 16:50 UTC (permalink / raw)
  To: Ondrej Zary; +Cc: Oliver Neukum, netdev, linux-usb, linux-kernel

On Mon, 12 Oct 2020 12:42:55 +0200 Ondrej Zary wrote:
> On Monday 12 October 2020, Jakub Kicinski wrote:
> > On Sat, 10 Oct 2020 16:00:46 +0200 Ondrej Zary wrote:  
> > > When the router is rebooted without a power cycle, the USB device
> > > remains connected but its configuration is reset. This results in
> > > a non-working ethernet connection with messages like this in syslog:
> > > 	usb 2-2: RX packet too long: 65535 B
> > >
> > > Re-enable ethernet mode when receiving a packet with invalid size of
> > > 0xffff.  
> >
> > Patch looks good, but could you explain what's a reboot without a power
> > cycle in this case? The modem gets reset but USB subsystem doesn't know
> > it and doesn't go though a unbind() + bind() cycle?  
> 
> The router can be rebooted through the web interface. The reboot does not 
> disconnect the USB device - it remains connected as if nothing happened. Only 
> wrong data starts to come in.

I see. Applied to net-next, thanks!

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

end of thread, back to index

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-10 14:00 [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot Ondrej Zary
2020-10-10 14:00 ` [PATCH 2/2] cx82310_eth: use netdev_err instead of dev_err Ondrej Zary
2020-10-11 22:55 ` [PATCH 1/2] cx82310_eth: re-enable ethernet mode after router reboot Jakub Kicinski
2020-10-12 10:42   ` Ondrej Zary
2020-10-12 16:50     ` Jakub Kicinski

Linux-USB Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-usb/0 linux-usb/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-usb linux-usb/ https://lore.kernel.org/linux-usb \
		linux-usb@vger.kernel.org
	public-inbox-index linux-usb

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-usb


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git