Skip to content

Commit

Permalink
Merge tag 'usb-4.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/gregkh/usb

I wrote:
  "USB fixes for 4.19-rc6

   Here are some small USB core and driver fixes for reported issues for
   4.19-rc6.

   The most visible is the oops fix for when the USB core is built into the
   kernel that is present in 4.18.  Turns out not many people actually do
   that so it went unnoticed for a while.  The rest is some tiny typec,
   musb, and other core fixes.

   All have been in linux-next with no reported issues."

* tag 'usb-4.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: typec: mux: Take care of driver module reference counting
  usb: core: safely deal with the dynamic quirk lists
  usb: roles: Take care of driver module reference counting
  USB: handle NULL config in usb_find_alt_setting()
  USB: fix error handling in usb_driver_claim_interface()
  USB: remove LPM management from usb_driver_claim_interface()
  USB: usbdevfs: restore warning for nonsensical flags
  USB: usbdevfs: sanitize flags more
  Revert "usb: cdc-wdm: Fix a sleep-in-atomic-context bug in service_outstanding_interrupt()"
  usb: musb: dsps: do not disable CPPI41 irq in driver teardown
  • Loading branch information
gregkh committed Sep 25, 2018
2 parents ccf791e + 3e3b819 commit bfb0e9b
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 37 deletions.
2 changes: 1 addition & 1 deletion drivers/usb/class/cdc-wdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ static int service_outstanding_interrupt(struct wdm_device *desc)

set_bit(WDM_RESPONDING, &desc->flags);
spin_unlock_irq(&desc->iuspin);
rv = usb_submit_urb(desc->response, GFP_ATOMIC);
rv = usb_submit_urb(desc->response, GFP_KERNEL);
spin_lock_irq(&desc->iuspin);
if (rv) {
dev_err(&desc->intf->dev,
Expand Down
15 changes: 12 additions & 3 deletions drivers/usb/common/roles.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,15 @@ static void *usb_role_switch_match(struct device_connection *con, int ep,
*/
struct usb_role_switch *usb_role_switch_get(struct device *dev)
{
return device_connection_find_match(dev, "usb-role-switch", NULL,
usb_role_switch_match);
struct usb_role_switch *sw;

sw = device_connection_find_match(dev, "usb-role-switch", NULL,
usb_role_switch_match);

if (!IS_ERR_OR_NULL(sw))
WARN_ON(!try_module_get(sw->dev.parent->driver->owner));

return sw;
}
EXPORT_SYMBOL_GPL(usb_role_switch_get);

Expand All @@ -122,8 +129,10 @@ EXPORT_SYMBOL_GPL(usb_role_switch_get);
*/
void usb_role_switch_put(struct usb_role_switch *sw)
{
if (!IS_ERR_OR_NULL(sw))
if (!IS_ERR_OR_NULL(sw)) {
put_device(&sw->dev);
module_put(sw->dev.parent->driver->owner);
}
}
EXPORT_SYMBOL_GPL(usb_role_switch_put);

Expand Down
24 changes: 21 additions & 3 deletions drivers/usb/core/devio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1434,10 +1434,13 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
struct async *as = NULL;
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int i, ret, is_in, num_sgs = 0, ifnum = -1;
int i, ret, num_sgs = 0, ifnum = -1;
int number_of_packets = 0;
unsigned int stream_id = 0;
void *buf;
bool is_in;
bool allow_short = false;
bool allow_zero = false;
unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK |
USBDEVFS_URB_BULK_CONTINUATION |
USBDEVFS_URB_NO_FSBR |
Expand Down Expand Up @@ -1471,6 +1474,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
u = 0;
switch (uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
if (is_in)
allow_short = true;
if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet */
Expand Down Expand Up @@ -1511,6 +1516,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
break;

case USBDEVFS_URB_TYPE_BULK:
if (!is_in)
allow_zero = true;
else
allow_short = true;
switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
Expand All @@ -1531,6 +1540,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
interrupt_urb:
if (!is_in)
allow_zero = true;
else
allow_short = true;
break;

case USBDEVFS_URB_TYPE_ISO:
Expand Down Expand Up @@ -1676,14 +1689,19 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
u |= URB_ISO_ASAP;
if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in)
if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
u |= URB_SHORT_NOT_OK;
if (uurb->flags & USBDEVFS_URB_ZERO_PACKET)
if (allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
u |= URB_ZERO_PACKET;
if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
u |= URB_NO_INTERRUPT;
as->urb->transfer_flags = u;

if (!allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_SHORT_NOT_OK.\n");
if (!allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_ZERO_PACKET.\n");

as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char *)dr;
dr = NULL;
Expand Down
28 changes: 14 additions & 14 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct device *dev;
struct usb_device *udev;
int retval = 0;
int lpm_disable_error = -ENODEV;

if (!iface)
return -ENODEV;
Expand All @@ -533,16 +532,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,

iface->condition = USB_INTERFACE_BOUND;

/* See the comment about disabling LPM in usb_probe_interface(). */
if (driver->disable_hub_initiated_lpm) {
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error) {
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n",
__func__, driver->name);
return -ENOMEM;
}
}

/* Claimed interfaces are initially inactive (suspended) and
* runtime-PM-enabled, but only if the driver has autosuspend
* support. Otherwise they are marked active, to prevent the
Expand All @@ -561,9 +550,20 @@ int usb_driver_claim_interface(struct usb_driver *driver,
if (device_is_registered(dev))
retval = device_bind_driver(dev);

/* Attempt to re-enable USB3 LPM, if the disable was successful. */
if (!lpm_disable_error)
usb_unlocked_enable_lpm(udev);
if (retval) {
dev->driver = NULL;
usb_set_intfdata(iface, NULL);
iface->needs_remote_wakeup = 0;
iface->condition = USB_INTERFACE_UNBOUND;

/*
* Unbound interfaces are always runtime-PM-disabled
* and runtime-PM-suspended
*/
if (driver->supports_autosuspend)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
}

return retval;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/core/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ static int quirks_param_set(const char *val, const struct kernel_param *kp)
quirk_list = kcalloc(quirk_count, sizeof(struct quirk_entry),
GFP_KERNEL);
if (!quirk_list) {
quirk_count = 0;
mutex_unlock(&quirk_mutex);
return -ENOMEM;
}
Expand Down Expand Up @@ -154,7 +155,7 @@ static struct kparam_string quirks_param_string = {
.string = quirks_param,
};

module_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0644);
device_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0644);
MODULE_PARM_DESC(quirks, "Add/modify USB quirks by specifying quirks=vendorID:productID:quirks");

/* Lists of quirky USB devices, split in device quirks and interface quirks.
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/core/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ struct usb_host_interface *usb_find_alt_setting(
struct usb_interface_cache *intf_cache = NULL;
int i;

if (!config)
return NULL;
for (i = 0; i < config->desc.bNumInterfaces; i++) {
if (config->intf_cache[i]->altsetting[0].desc.bInterfaceNumber
== iface_num) {
Expand Down
12 changes: 1 addition & 11 deletions drivers/usb/musb/musb_dsps.c
Original file line number Diff line number Diff line change
Expand Up @@ -658,16 +658,6 @@ dsps_dma_controller_create(struct musb *musb, void __iomem *base)
return controller;
}

static void dsps_dma_controller_destroy(struct dma_controller *c)
{
struct musb *musb = c->musb;
struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent);
void __iomem *usbss_base = glue->usbss_base;

musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP);
cppi41_dma_controller_destroy(c);
}

#ifdef CONFIG_PM_SLEEP
static void dsps_dma_controller_suspend(struct dsps_glue *glue)
{
Expand Down Expand Up @@ -697,7 +687,7 @@ static struct musb_platform_ops dsps_ops = {

#ifdef CONFIG_USB_TI_CPPI41_DMA
.dma_init = dsps_dma_controller_create,
.dma_exit = dsps_dma_controller_destroy,
.dma_exit = cppi41_dma_controller_destroy,
#endif
.enable = dsps_musb_enable,
.disable = dsps_musb_disable,
Expand Down
17 changes: 13 additions & 4 deletions drivers/usb/typec/mux.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <linux/device.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/usb/typec_mux.h>

Expand Down Expand Up @@ -49,8 +50,10 @@ struct typec_switch *typec_switch_get(struct device *dev)
mutex_lock(&switch_lock);
sw = device_connection_find_match(dev, "typec-switch", NULL,
typec_switch_match);
if (!IS_ERR_OR_NULL(sw))
if (!IS_ERR_OR_NULL(sw)) {
WARN_ON(!try_module_get(sw->dev->driver->owner));
get_device(sw->dev);
}
mutex_unlock(&switch_lock);

return sw;
Expand All @@ -65,8 +68,10 @@ EXPORT_SYMBOL_GPL(typec_switch_get);
*/
void typec_switch_put(struct typec_switch *sw)
{
if (!IS_ERR_OR_NULL(sw))
if (!IS_ERR_OR_NULL(sw)) {
module_put(sw->dev->driver->owner);
put_device(sw->dev);
}
}
EXPORT_SYMBOL_GPL(typec_switch_put);

Expand Down Expand Up @@ -136,8 +141,10 @@ struct typec_mux *typec_mux_get(struct device *dev, const char *name)

mutex_lock(&mux_lock);
mux = device_connection_find_match(dev, name, NULL, typec_mux_match);
if (!IS_ERR_OR_NULL(mux))
if (!IS_ERR_OR_NULL(mux)) {
WARN_ON(!try_module_get(mux->dev->driver->owner));
get_device(mux->dev);
}
mutex_unlock(&mux_lock);

return mux;
Expand All @@ -152,8 +159,10 @@ EXPORT_SYMBOL_GPL(typec_mux_get);
*/
void typec_mux_put(struct typec_mux *mux)
{
if (!IS_ERR_OR_NULL(mux))
if (!IS_ERR_OR_NULL(mux)) {
module_put(mux->dev->driver->owner);
put_device(mux->dev);
}
}
EXPORT_SYMBOL_GPL(typec_mux_put);

Expand Down

0 comments on commit bfb0e9b

Please sign in to comment.