Skip to content

Commit

Permalink
cdc_subset: deal with a device that needs reset for timeout
Browse files Browse the repository at this point in the history
This device needs to be reset to recover from a timeout.
Unfortunately this can be handled only at the level of
the subdrivers.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Oliver Neukum authored and David S. Miller committed Jul 29, 2014
1 parent 40eea80 commit 20fbe3a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
27 changes: 27 additions & 0 deletions drivers/net/usb/cdc_subset.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,34 @@ static int always_connected (struct usbnet *dev)
*
*-------------------------------------------------------------------------*/

static void m5632_recover(struct usbnet *dev)
{
struct usb_device *udev = dev->udev;
struct usb_interface *intf = dev->intf;
int r;

r = usb_lock_device_for_reset(udev, intf);
if (r < 0)
return;

usb_reset_device(udev);
usb_unlock_device(udev);
}

static int dummy_prereset(struct usb_interface *intf)
{
return 0;
}

static int dummy_postreset(struct usb_interface *intf)
{
return 0;
}

static const struct driver_info ali_m5632_info = {
.description = "ALi M5632",
.flags = FLAG_POINTTOPOINT,
.recover = m5632_recover,
};

#endif
Expand Down Expand Up @@ -332,6 +357,8 @@ static struct usb_driver cdc_subset_driver = {
.probe = usbnet_probe,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.pre_reset = dummy_prereset,
.post_reset = dummy_postreset,
.disconnect = usbnet_disconnect,
.id_table = products,
.disable_hub_initiated_lpm = 1,
Expand Down
8 changes: 6 additions & 2 deletions drivers/net/usb/usbnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1218,8 +1218,12 @@ void usbnet_tx_timeout (struct net_device *net)

unlink_urbs (dev, &dev->txq);
tasklet_schedule (&dev->bh);

// FIXME: device recovery -- reset?
/* this needs to be handled individually because the generic layer
* doesn't know what is sufficient and could not restore private
* information if a remedy of an unconditional reset were used.
*/
if (dev->driver_info->recover)
(dev->driver_info->recover)(dev);
}
EXPORT_SYMBOL_GPL(usbnet_tx_timeout);

Expand Down
3 changes: 3 additions & 0 deletions include/linux/usb/usbnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ struct driver_info {
struct sk_buff *(*tx_fixup)(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags);

/* recover from timeout */
void (*recover)(struct usbnet *dev);

/* early initialization code, can sleep. This is for minidrivers
* having 'subminidrivers' that need to do extra initialization
* right after minidriver have initialized hardware. */
Expand Down

0 comments on commit 20fbe3a

Please sign in to comment.