mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 18:30:06 +00:00
USB fixes for 5.1-rc8/final
Here are some small USB fixes for a bunch of warnings/errors that the syzbot has been finding with it's new-found ability to stress-test the USB layer. All of these are tiny, but fix real issues, and are marked for stable as well. All of these have had lots of testing in linux-next as well. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXMhb1Q8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykHdQCeMK3TfwWjqSSCcgvbTaxhvx8Fwg4AoJRLspLh FgVo+vaKf6SFlZdAVSJ8 =28RC -----END PGP SIGNATURE----- Merge tag 'usb-5.1-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are some small USB fixes for a bunch of warnings/errors that the syzbot has been finding with it's new-found ability to stress-test the USB layer. All of these are tiny, but fix real issues, and are marked for stable as well. All of these have had lots of testing in linux-next as well" * tag 'usb-5.1-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: USB: w1 ds2490: Fix bug caused by improper use of altsetting array USB: yurex: Fix protection fault after device removal usb: usbip: fix isoc packet num validation in get_pipe USB: core: Fix bug caused by duplicate interface PM usage counter USB: dummy-hcd: Fix failure to give back unlinked URBs USB: core: Fix unterminated string returned by usb_string()
This commit is contained in:
commit
bf3bd966df
10 changed files with 46 additions and 45 deletions
|
@ -370,11 +370,15 @@ autosuspend the interface's device. When the usage counter is = 0
|
|||
then the interface is considered to be idle, and the kernel may
|
||||
autosuspend the device.
|
||||
|
||||
Drivers need not be concerned about balancing changes to the usage
|
||||
counter; the USB core will undo any remaining "get"s when a driver
|
||||
is unbound from its interface. As a corollary, drivers must not call
|
||||
any of the ``usb_autopm_*`` functions after their ``disconnect``
|
||||
routine has returned.
|
||||
Drivers must be careful to balance their overall changes to the usage
|
||||
counter. Unbalanced "get"s will remain in effect when a driver is
|
||||
unbound from its interface, preventing the device from going into
|
||||
runtime suspend should the interface be bound to a driver again. On
|
||||
the other hand, drivers are allowed to achieve this balance by calling
|
||||
the ``usb_autopm_*`` functions even after their ``disconnect`` routine
|
||||
has returned -- say from within a work-queue routine -- provided they
|
||||
retain an active reference to the interface (via ``usb_get_intf`` and
|
||||
``usb_put_intf``).
|
||||
|
||||
Drivers using the async routines are responsible for their own
|
||||
synchronization and mutual exclusion.
|
||||
|
|
|
@ -473,11 +473,6 @@ static int usb_unbind_interface(struct device *dev)
|
|||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
|
||||
/* Undo any residual pm_autopm_get_interface_* calls */
|
||||
for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r)
|
||||
usb_autopm_put_interface_no_suspend(intf);
|
||||
atomic_set(&intf->pm_usage_cnt, 0);
|
||||
|
||||
if (!error)
|
||||
usb_autosuspend_device(udev);
|
||||
|
||||
|
@ -1633,7 +1628,6 @@ void usb_autopm_put_interface(struct usb_interface *intf)
|
|||
int status;
|
||||
|
||||
usb_mark_last_busy(udev);
|
||||
atomic_dec(&intf->pm_usage_cnt);
|
||||
status = pm_runtime_put_sync(&intf->dev);
|
||||
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
|
||||
__func__, atomic_read(&intf->dev.power.usage_count),
|
||||
|
@ -1662,7 +1656,6 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
|
|||
int status;
|
||||
|
||||
usb_mark_last_busy(udev);
|
||||
atomic_dec(&intf->pm_usage_cnt);
|
||||
status = pm_runtime_put(&intf->dev);
|
||||
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
|
||||
__func__, atomic_read(&intf->dev.power.usage_count),
|
||||
|
@ -1684,7 +1677,6 @@ void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
|
|||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
usb_mark_last_busy(udev);
|
||||
atomic_dec(&intf->pm_usage_cnt);
|
||||
pm_runtime_put_noidle(&intf->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
|
||||
|
@ -1715,8 +1707,6 @@ int usb_autopm_get_interface(struct usb_interface *intf)
|
|||
status = pm_runtime_get_sync(&intf->dev);
|
||||
if (status < 0)
|
||||
pm_runtime_put_sync(&intf->dev);
|
||||
else
|
||||
atomic_inc(&intf->pm_usage_cnt);
|
||||
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
|
||||
__func__, atomic_read(&intf->dev.power.usage_count),
|
||||
status);
|
||||
|
@ -1750,8 +1740,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
|
|||
status = pm_runtime_get(&intf->dev);
|
||||
if (status < 0 && status != -EINPROGRESS)
|
||||
pm_runtime_put_noidle(&intf->dev);
|
||||
else
|
||||
atomic_inc(&intf->pm_usage_cnt);
|
||||
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
|
||||
__func__, atomic_read(&intf->dev.power.usage_count),
|
||||
status);
|
||||
|
@ -1775,7 +1763,6 @@ void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
|
|||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
usb_mark_last_busy(udev);
|
||||
atomic_inc(&intf->pm_usage_cnt);
|
||||
pm_runtime_get_noresume(&intf->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
|
||||
|
|
|
@ -820,9 +820,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
|||
|
||||
if (dev->state == USB_STATE_SUSPENDED)
|
||||
return -EHOSTUNREACH;
|
||||
if (size <= 0 || !buf || !index)
|
||||
if (size <= 0 || !buf)
|
||||
return -EINVAL;
|
||||
buf[0] = 0;
|
||||
if (index <= 0 || index >= 256)
|
||||
return -EINVAL;
|
||||
tbuf = kmalloc(256, GFP_NOIO);
|
||||
if (!tbuf)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -979,8 +979,18 @@ static int dummy_udc_start(struct usb_gadget *g,
|
|||
struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g);
|
||||
struct dummy *dum = dum_hcd->dum;
|
||||
|
||||
if (driver->max_speed == USB_SPEED_UNKNOWN)
|
||||
switch (g->speed) {
|
||||
/* All the speeds we support */
|
||||
case USB_SPEED_LOW:
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_HIGH:
|
||||
case USB_SPEED_SUPER:
|
||||
break;
|
||||
default:
|
||||
dev_err(dummy_dev(dum_hcd), "Unsupported driver max speed %d\n",
|
||||
driver->max_speed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* SLAVE side init ... the layer above hardware, which
|
||||
|
@ -1784,9 +1794,10 @@ static void dummy_timer(struct timer_list *t)
|
|||
/* Bus speed is 500000 bytes/ms, so use a little less */
|
||||
total = 490000;
|
||||
break;
|
||||
default:
|
||||
default: /* Can't happen */
|
||||
dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
|
||||
return;
|
||||
total = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* FIXME if HZ != 1000 this will probably misbehave ... */
|
||||
|
@ -1828,7 +1839,7 @@ static void dummy_timer(struct timer_list *t)
|
|||
|
||||
/* Used up this frame's bandwidth? */
|
||||
if (total <= 0)
|
||||
break;
|
||||
continue;
|
||||
|
||||
/* find the gadget's ep for this request (if configured) */
|
||||
address = usb_pipeendpoint (urb->pipe);
|
||||
|
|
|
@ -314,6 +314,7 @@ static void yurex_disconnect(struct usb_interface *interface)
|
|||
usb_deregister_dev(interface, &yurex_class);
|
||||
|
||||
/* prevent more I/O from starting */
|
||||
usb_poison_urb(dev->urb);
|
||||
mutex_lock(&dev->io_mutex);
|
||||
dev->interface = NULL;
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
|
|
|
@ -763,18 +763,16 @@ static void rts51x_suspend_timer_fn(struct timer_list *t)
|
|||
break;
|
||||
case RTS51X_STAT_IDLE:
|
||||
case RTS51X_STAT_SS:
|
||||
usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n",
|
||||
atomic_read(&us->pusb_intf->pm_usage_cnt),
|
||||
usb_stor_dbg(us, "RTS51X_STAT_SS, power.usage:%d\n",
|
||||
atomic_read(&us->pusb_intf->dev.power.usage_count));
|
||||
|
||||
if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) {
|
||||
if (atomic_read(&us->pusb_intf->dev.power.usage_count) > 0) {
|
||||
usb_stor_dbg(us, "Ready to enter SS state\n");
|
||||
rts51x_set_stat(chip, RTS51X_STAT_SS);
|
||||
/* ignore mass storage interface's children */
|
||||
pm_suspend_ignore_children(&us->pusb_intf->dev, true);
|
||||
usb_autopm_put_interface_async(us->pusb_intf);
|
||||
usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n",
|
||||
atomic_read(&us->pusb_intf->pm_usage_cnt),
|
||||
usb_stor_dbg(us, "RTS51X_STAT_SS 01, power.usage:%d\n",
|
||||
atomic_read(&us->pusb_intf->dev.power.usage_count));
|
||||
}
|
||||
break;
|
||||
|
@ -807,11 +805,10 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
int ret;
|
||||
|
||||
if (working_scsi(srb)) {
|
||||
usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n",
|
||||
atomic_read(&us->pusb_intf->pm_usage_cnt),
|
||||
usb_stor_dbg(us, "working scsi, power.usage:%d\n",
|
||||
atomic_read(&us->pusb_intf->dev.power.usage_count));
|
||||
|
||||
if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) {
|
||||
if (atomic_read(&us->pusb_intf->dev.power.usage_count) <= 0) {
|
||||
ret = usb_autopm_get_interface(us->pusb_intf);
|
||||
usb_stor_dbg(us, "working scsi, ret=%d\n", ret);
|
||||
}
|
||||
|
|
|
@ -361,16 +361,10 @@ static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu)
|
|||
}
|
||||
|
||||
if (usb_endpoint_xfer_isoc(epd)) {
|
||||
/* validate packet size and number of packets */
|
||||
unsigned int maxp, packets, bytes;
|
||||
|
||||
maxp = usb_endpoint_maxp(epd);
|
||||
maxp *= usb_endpoint_maxp_mult(epd);
|
||||
bytes = pdu->u.cmd_submit.transfer_buffer_length;
|
||||
packets = DIV_ROUND_UP(bytes, maxp);
|
||||
|
||||
/* validate number of packets */
|
||||
if (pdu->u.cmd_submit.number_of_packets < 0 ||
|
||||
pdu->u.cmd_submit.number_of_packets > packets) {
|
||||
pdu->u.cmd_submit.number_of_packets >
|
||||
USBIP_MAX_ISO_PACKETS) {
|
||||
dev_err(&sdev->udev->dev,
|
||||
"CMD_SUBMIT: isoc invalid num packets %d\n",
|
||||
pdu->u.cmd_submit.number_of_packets);
|
||||
|
|
|
@ -121,6 +121,13 @@ extern struct device_attribute dev_attr_usbip_debug;
|
|||
#define USBIP_DIR_OUT 0x00
|
||||
#define USBIP_DIR_IN 0x01
|
||||
|
||||
/*
|
||||
* Arbitrary limit for the maximum number of isochronous packets in an URB,
|
||||
* compare for example the uhci_submit_isochronous function in
|
||||
* drivers/usb/host/uhci-q.c
|
||||
*/
|
||||
#define USBIP_MAX_ISO_PACKETS 1024
|
||||
|
||||
/**
|
||||
* struct usbip_header_basic - data pertinent to every request
|
||||
* @command: the usbip request type
|
||||
|
|
|
@ -1016,15 +1016,15 @@ static int ds_probe(struct usb_interface *intf,
|
|||
/* alternative 3, 1ms interrupt (greatly speeds search), 64 byte bulk */
|
||||
alt = 3;
|
||||
err = usb_set_interface(dev->udev,
|
||||
intf->altsetting[alt].desc.bInterfaceNumber, alt);
|
||||
intf->cur_altsetting->desc.bInterfaceNumber, alt);
|
||||
if (err) {
|
||||
dev_err(&dev->udev->dev, "Failed to set alternative setting %d "
|
||||
"for %d interface: err=%d.\n", alt,
|
||||
intf->altsetting[alt].desc.bInterfaceNumber, err);
|
||||
intf->cur_altsetting->desc.bInterfaceNumber, err);
|
||||
goto err_out_clear;
|
||||
}
|
||||
|
||||
iface_desc = &intf->altsetting[alt];
|
||||
iface_desc = intf->cur_altsetting;
|
||||
if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
|
||||
pr_info("Num endpoints=%d. It is not DS9490R.\n",
|
||||
iface_desc->desc.bNumEndpoints);
|
||||
|
|
|
@ -200,7 +200,6 @@ usb_find_last_int_out_endpoint(struct usb_host_interface *alt,
|
|||
* @dev: driver model's view of this device
|
||||
* @usb_dev: if an interface is bound to the USB major, this will point
|
||||
* to the sysfs representation for that device.
|
||||
* @pm_usage_cnt: PM usage counter for this interface
|
||||
* @reset_ws: Used for scheduling resets from atomic context.
|
||||
* @resetting_device: USB core reset the device, so use alt setting 0 as
|
||||
* current; needs bandwidth alloc after reset.
|
||||
|
@ -257,7 +256,6 @@ struct usb_interface {
|
|||
|
||||
struct device dev; /* interface specific device info */
|
||||
struct device *usb_dev;
|
||||
atomic_t pm_usage_cnt; /* usage counter for autosuspend */
|
||||
struct work_struct reset_ws; /* for resets in atomic context */
|
||||
};
|
||||
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
|
||||
|
|
Loading…
Reference in a new issue