Commit bfb0e9b4 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'usb-4.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel/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
parents ccf791e5 3e3b8196
...@@ -460,7 +460,7 @@ static int service_outstanding_interrupt(struct wdm_device *desc) ...@@ -460,7 +460,7 @@ static int service_outstanding_interrupt(struct wdm_device *desc)
set_bit(WDM_RESPONDING, &desc->flags); set_bit(WDM_RESPONDING, &desc->flags);
spin_unlock_irq(&desc->iuspin); 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); spin_lock_irq(&desc->iuspin);
if (rv) { if (rv) {
dev_err(&desc->intf->dev, dev_err(&desc->intf->dev,
......
...@@ -109,8 +109,15 @@ static void *usb_role_switch_match(struct device_connection *con, int ep, ...@@ -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) struct usb_role_switch *usb_role_switch_get(struct device *dev)
{ {
return device_connection_find_match(dev, "usb-role-switch", NULL, struct usb_role_switch *sw;
usb_role_switch_match);
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); EXPORT_SYMBOL_GPL(usb_role_switch_get);
...@@ -122,8 +129,10 @@ EXPORT_SYMBOL_GPL(usb_role_switch_get); ...@@ -122,8 +129,10 @@ EXPORT_SYMBOL_GPL(usb_role_switch_get);
*/ */
void usb_role_switch_put(struct usb_role_switch *sw) 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); put_device(&sw->dev);
module_put(sw->dev.parent->driver->owner);
}
} }
EXPORT_SYMBOL_GPL(usb_role_switch_put); EXPORT_SYMBOL_GPL(usb_role_switch_put);
......
...@@ -1434,10 +1434,13 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb ...@@ -1434,10 +1434,13 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
struct async *as = NULL; struct async *as = NULL;
struct usb_ctrlrequest *dr = NULL; struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen; 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; int number_of_packets = 0;
unsigned int stream_id = 0; unsigned int stream_id = 0;
void *buf; void *buf;
bool is_in;
bool allow_short = false;
bool allow_zero = false;
unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK | unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK |
USBDEVFS_URB_BULK_CONTINUATION | USBDEVFS_URB_BULK_CONTINUATION |
USBDEVFS_URB_NO_FSBR | USBDEVFS_URB_NO_FSBR |
...@@ -1471,6 +1474,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb ...@@ -1471,6 +1474,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
u = 0; u = 0;
switch (uurb->type) { switch (uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL: case USBDEVFS_URB_TYPE_CONTROL:
if (is_in)
allow_short = true;
if (!usb_endpoint_xfer_control(&ep->desc)) if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL; return -EINVAL;
/* min 8 byte setup packet */ /* min 8 byte setup packet */
...@@ -1511,6 +1516,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb ...@@ -1511,6 +1516,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
break; break;
case USBDEVFS_URB_TYPE_BULK: case USBDEVFS_URB_TYPE_BULK:
if (!is_in)
allow_zero = true;
else
allow_short = true;
switch (usb_endpoint_type(&ep->desc)) { switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_ISOC:
...@@ -1531,6 +1540,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb ...@@ -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)) if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL; return -EINVAL;
interrupt_urb: interrupt_urb:
if (!is_in)
allow_zero = true;
else
allow_short = true;
break; break;
case USBDEVFS_URB_TYPE_ISO: case USBDEVFS_URB_TYPE_ISO:
...@@ -1676,14 +1689,19 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb ...@@ -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); u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
if (uurb->flags & USBDEVFS_URB_ISO_ASAP) if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
u |= 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; 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; u |= URB_ZERO_PACKET;
if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT) if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
u |= URB_NO_INTERRUPT; u |= URB_NO_INTERRUPT;
as->urb->transfer_flags = u; 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->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char *)dr; as->urb->setup_packet = (unsigned char *)dr;
dr = NULL; dr = NULL;
......
...@@ -512,7 +512,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, ...@@ -512,7 +512,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct device *dev; struct device *dev;
struct usb_device *udev; struct usb_device *udev;
int retval = 0; int retval = 0;
int lpm_disable_error = -ENODEV;
if (!iface) if (!iface)
return -ENODEV; return -ENODEV;
...@@ -533,16 +532,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, ...@@ -533,16 +532,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
iface->condition = USB_INTERFACE_BOUND; 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 /* Claimed interfaces are initially inactive (suspended) and
* runtime-PM-enabled, but only if the driver has autosuspend * runtime-PM-enabled, but only if the driver has autosuspend
* support. Otherwise they are marked active, to prevent the * support. Otherwise they are marked active, to prevent the
...@@ -561,9 +550,20 @@ int usb_driver_claim_interface(struct usb_driver *driver, ...@@ -561,9 +550,20 @@ int usb_driver_claim_interface(struct usb_driver *driver,
if (device_is_registered(dev)) if (device_is_registered(dev))
retval = device_bind_driver(dev); retval = device_bind_driver(dev);
/* Attempt to re-enable USB3 LPM, if the disable was successful. */ if (retval) {
if (!lpm_disable_error) dev->driver = NULL;
usb_unlocked_enable_lpm(udev); 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; return retval;
} }
......
...@@ -58,6 +58,7 @@ static int quirks_param_set(const char *val, const struct kernel_param *kp) ...@@ -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), quirk_list = kcalloc(quirk_count, sizeof(struct quirk_entry),
GFP_KERNEL); GFP_KERNEL);
if (!quirk_list) { if (!quirk_list) {
quirk_count = 0;
mutex_unlock(&quirk_mutex); mutex_unlock(&quirk_mutex);
return -ENOMEM; return -ENOMEM;
} }
...@@ -154,7 +155,7 @@ static struct kparam_string quirks_param_string = { ...@@ -154,7 +155,7 @@ static struct kparam_string quirks_param_string = {
.string = quirks_param, .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"); 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. /* Lists of quirky USB devices, split in device quirks and interface quirks.
......
...@@ -228,6 +228,8 @@ struct usb_host_interface *usb_find_alt_setting( ...@@ -228,6 +228,8 @@ struct usb_host_interface *usb_find_alt_setting(
struct usb_interface_cache *intf_cache = NULL; struct usb_interface_cache *intf_cache = NULL;
int i; int i;
if (!config)
return NULL;
for (i = 0; i < config->desc.bNumInterfaces; i++) { for (i = 0; i < config->desc.bNumInterfaces; i++) {
if (config->intf_cache[i]->altsetting[0].desc.bInterfaceNumber if (config->intf_cache[i]->altsetting[0].desc.bInterfaceNumber
== iface_num) { == iface_num) {
......
...@@ -658,16 +658,6 @@ dsps_dma_controller_create(struct musb *musb, void __iomem *base) ...@@ -658,16 +658,6 @@ dsps_dma_controller_create(struct musb *musb, void __iomem *base)
return controller; 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 #ifdef CONFIG_PM_SLEEP
static void dsps_dma_controller_suspend(struct dsps_glue *glue) static void dsps_dma_controller_suspend(struct dsps_glue *glue)
{ {
...@@ -697,7 +687,7 @@ static struct musb_platform_ops dsps_ops = { ...@@ -697,7 +687,7 @@ static struct musb_platform_ops dsps_ops = {
#ifdef CONFIG_USB_TI_CPPI41_DMA #ifdef CONFIG_USB_TI_CPPI41_DMA
.dma_init = dsps_dma_controller_create, .dma_init = dsps_dma_controller_create,
.dma_exit = dsps_dma_controller_destroy, .dma_exit = cppi41_dma_controller_destroy,
#endif #endif
.enable = dsps_musb_enable, .enable = dsps_musb_enable,
.disable = dsps_musb_disable, .disable = dsps_musb_disable,
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/usb/typec_mux.h> #include <linux/usb/typec_mux.h>
...@@ -49,8 +50,10 @@ struct typec_switch *typec_switch_get(struct device *dev) ...@@ -49,8 +50,10 @@ struct typec_switch *typec_switch_get(struct device *dev)
mutex_lock(&switch_lock); mutex_lock(&switch_lock);
sw = device_connection_find_match(dev, "typec-switch", NULL, sw = device_connection_find_match(dev, "typec-switch", NULL,
typec_switch_match); 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); get_device(sw->dev);
}
mutex_unlock(&switch_lock); mutex_unlock(&switch_lock);
return sw; return sw;
...@@ -65,8 +68,10 @@ EXPORT_SYMBOL_GPL(typec_switch_get); ...@@ -65,8 +68,10 @@ EXPORT_SYMBOL_GPL(typec_switch_get);
*/ */
void typec_switch_put(struct typec_switch *sw) 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); put_device(sw->dev);
}
} }
EXPORT_SYMBOL_GPL(typec_switch_put); EXPORT_SYMBOL_GPL(typec_switch_put);
...@@ -136,8 +141,10 @@ struct typec_mux *typec_mux_get(struct device *dev, const char *name) ...@@ -136,8 +141,10 @@ struct typec_mux *typec_mux_get(struct device *dev, const char *name)
mutex_lock(&mux_lock); mutex_lock(&mux_lock);
mux = device_connection_find_match(dev, name, NULL, typec_mux_match); 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); get_device(mux->dev);
}
mutex_unlock(&mux_lock); mutex_unlock(&mux_lock);
return mux; return mux;
...@@ -152,8 +159,10 @@ EXPORT_SYMBOL_GPL(typec_mux_get); ...@@ -152,8 +159,10 @@ EXPORT_SYMBOL_GPL(typec_mux_get);
*/ */
void typec_mux_put(struct typec_mux *mux) 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); put_device(mux->dev);
}
} }
EXPORT_SYMBOL_GPL(typec_mux_put); EXPORT_SYMBOL_GPL(typec_mux_put);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment