cx82310_eth: re-enable ethernet mode after router reboot
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> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
bc081a693a
commit
ca139d76b0
@ -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 @@ end:
|
||||
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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user