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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW6pEcA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yk4bQCgqMMue1AXeRX710L4jcTjt0czJBgAoJp6SSA2 zNvnmLBVVKKEY+DtzJ78 =oqoU -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
bfb0e9b490
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 |
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue