mirror of https://gitee.com/openkylin/linux.git
USB fixes for 4.20-rc6
Here are some small USB fixes for 4.20-rc6 The "largest" here are some xhci fixes for reported issues. Also here is a USB core fix, some quirk additions, and a usb-serial fix which required the export of one of the tty layer's functions to prevent code duplication. The tty maintainer agreed with this change. All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXAz3WA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yl+mwCgox0WZiO3qfnpQsIrJ5gJFCTrcmMAoMBC5jDf e81bwzu507PcqvEXh+rg =giw6 -----END PGP SIGNATURE----- Merge tag 'usb-4.20-rc6' 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 4.20-rc6 The "largest" here are some xhci fixes for reported issues. Also here is a USB core fix, some quirk additions, and a usb-serial fix which required the export of one of the tty layer's functions to prevent code duplication. The tty maintainer agreed with this change. All of these have been in linux-next with no reported issues" * tag 'usb-4.20-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: xhci: Prevent U1/U2 link pm states if exit latency is too long xhci: workaround CSS timeout on AMD SNPS 3.0 xHC USB: check usb_get_extra_descriptor for proper size USB: serial: console: fix reported terminal settings usb: quirk: add no-LPM quirk on SanDisk Ultra Flair device USB: Fix invalid-free bug in port_over_current_notify() usb: appledisplay: Add 27" Apple Cinema Display
This commit is contained in:
commit
50a5528a4b
|
@ -1373,7 +1373,13 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
|
||||||
return ERR_PTR(retval);
|
return ERR_PTR(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tty_free_termios(struct tty_struct *tty)
|
/**
|
||||||
|
* tty_save_termios() - save tty termios data in driver table
|
||||||
|
* @tty: tty whose termios data to save
|
||||||
|
*
|
||||||
|
* Locking: Caller guarantees serialisation with tty_init_termios().
|
||||||
|
*/
|
||||||
|
void tty_save_termios(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct ktermios *tp;
|
struct ktermios *tp;
|
||||||
int idx = tty->index;
|
int idx = tty->index;
|
||||||
|
@ -1392,6 +1398,7 @@ static void tty_free_termios(struct tty_struct *tty)
|
||||||
}
|
}
|
||||||
*tp = tty->termios;
|
*tp = tty->termios;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tty_save_termios);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_flush_works - flush all works of a tty/pty pair
|
* tty_flush_works - flush all works of a tty/pty pair
|
||||||
|
@ -1491,7 +1498,7 @@ static void release_tty(struct tty_struct *tty, int idx)
|
||||||
WARN_ON(!mutex_is_locked(&tty_mutex));
|
WARN_ON(!mutex_is_locked(&tty_mutex));
|
||||||
if (tty->ops->shutdown)
|
if (tty->ops->shutdown)
|
||||||
tty->ops->shutdown(tty);
|
tty->ops->shutdown(tty);
|
||||||
tty_free_termios(tty);
|
tty_save_termios(tty);
|
||||||
tty_driver_remove_tty(tty->driver, tty);
|
tty_driver_remove_tty(tty->driver, tty);
|
||||||
tty->port->itty = NULL;
|
tty->port->itty = NULL;
|
||||||
if (tty->link)
|
if (tty->link)
|
||||||
|
|
|
@ -2251,7 +2251,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
|
||||||
/* descriptor may appear anywhere in config */
|
/* descriptor may appear anywhere in config */
|
||||||
err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
|
err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
|
||||||
le16_to_cpu(udev->config[0].desc.wTotalLength),
|
le16_to_cpu(udev->config[0].desc.wTotalLength),
|
||||||
USB_DT_OTG, (void **) &desc);
|
USB_DT_OTG, (void **) &desc, sizeof(*desc));
|
||||||
if (err || !(desc->bmAttributes & USB_OTG_HNP))
|
if (err || !(desc->bmAttributes & USB_OTG_HNP))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -5163,7 +5163,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||||
/* Handle notifying userspace about hub over-current events */
|
/* Handle notifying userspace about hub over-current events */
|
||||||
static void port_over_current_notify(struct usb_port *port_dev)
|
static void port_over_current_notify(struct usb_port *port_dev)
|
||||||
{
|
{
|
||||||
static char *envp[] = { NULL, NULL, NULL };
|
char *envp[3];
|
||||||
struct device *hub_dev;
|
struct device *hub_dev;
|
||||||
char *port_dev_path;
|
char *port_dev_path;
|
||||||
|
|
||||||
|
@ -5187,6 +5187,7 @@ static void port_over_current_notify(struct usb_port *port_dev)
|
||||||
if (!envp[1])
|
if (!envp[1])
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
envp[2] = NULL;
|
||||||
kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp);
|
kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp);
|
||||||
|
|
||||||
kfree(envp[1]);
|
kfree(envp[1]);
|
||||||
|
|
|
@ -333,6 +333,10 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||||
/* Midiman M-Audio Keystation 88es */
|
/* Midiman M-Audio Keystation 88es */
|
||||||
{ USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
|
{ USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||||
|
|
||||||
|
/* SanDisk Ultra Fit and Ultra Flair */
|
||||||
|
{ USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM },
|
||||||
|
{ USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM },
|
||||||
|
|
||||||
/* M-Systems Flash Disk Pioneers */
|
/* M-Systems Flash Disk Pioneers */
|
||||||
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
|
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||||
|
|
||||||
|
|
|
@ -832,14 +832,14 @@ EXPORT_SYMBOL_GPL(usb_get_current_frame_number);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int __usb_get_extra_descriptor(char *buffer, unsigned size,
|
int __usb_get_extra_descriptor(char *buffer, unsigned size,
|
||||||
unsigned char type, void **ptr)
|
unsigned char type, void **ptr, size_t minsize)
|
||||||
{
|
{
|
||||||
struct usb_descriptor_header *header;
|
struct usb_descriptor_header *header;
|
||||||
|
|
||||||
while (size >= sizeof(struct usb_descriptor_header)) {
|
while (size >= sizeof(struct usb_descriptor_header)) {
|
||||||
header = (struct usb_descriptor_header *)buffer;
|
header = (struct usb_descriptor_header *)buffer;
|
||||||
|
|
||||||
if (header->bLength < 2) {
|
if (header->bLength < 2 || header->bLength > size) {
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"%s: bogus descriptor, type %d length %d\n",
|
"%s: bogus descriptor, type %d length %d\n",
|
||||||
usbcore_name,
|
usbcore_name,
|
||||||
|
@ -848,7 +848,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header->bDescriptorType == type) {
|
if (header->bDescriptorType == type && header->bLength >= minsize) {
|
||||||
*ptr = header;
|
*ptr = header;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -640,7 +640,7 @@ static int hwahc_security_create(struct hwahc *hwahc)
|
||||||
top = itr + itr_size;
|
top = itr + itr_size;
|
||||||
result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
|
result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
|
||||||
le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
|
le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
|
||||||
USB_DT_SECURITY, (void **) &secd);
|
USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
|
dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -139,6 +139,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||||
pdev->device == 0x43bb))
|
pdev->device == 0x43bb))
|
||||||
xhci->quirks |= XHCI_SUSPEND_DELAY;
|
xhci->quirks |= XHCI_SUSPEND_DELAY;
|
||||||
|
|
||||||
|
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
|
||||||
|
(pdev->device == 0x15e0 || pdev->device == 0x15e1))
|
||||||
|
xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND;
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_AMD)
|
if (pdev->vendor == PCI_VENDOR_ID_AMD)
|
||||||
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
||||||
|
|
||||||
|
|
|
@ -968,6 +968,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
|
||||||
unsigned int delay = XHCI_MAX_HALT_USEC;
|
unsigned int delay = XHCI_MAX_HALT_USEC;
|
||||||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||||||
u32 command;
|
u32 command;
|
||||||
|
u32 res;
|
||||||
|
|
||||||
if (!hcd->state)
|
if (!hcd->state)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1021,11 +1022,28 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
|
||||||
command = readl(&xhci->op_regs->command);
|
command = readl(&xhci->op_regs->command);
|
||||||
command |= CMD_CSS;
|
command |= CMD_CSS;
|
||||||
writel(command, &xhci->op_regs->command);
|
writel(command, &xhci->op_regs->command);
|
||||||
|
xhci->broken_suspend = 0;
|
||||||
if (xhci_handshake(&xhci->op_regs->status,
|
if (xhci_handshake(&xhci->op_regs->status,
|
||||||
STS_SAVE, 0, 10 * 1000)) {
|
STS_SAVE, 0, 10 * 1000)) {
|
||||||
xhci_warn(xhci, "WARN: xHC save state timeout\n");
|
/*
|
||||||
spin_unlock_irq(&xhci->lock);
|
* AMD SNPS xHC 3.0 occasionally does not clear the
|
||||||
return -ETIMEDOUT;
|
* SSS bit of USBSTS and when driver tries to poll
|
||||||
|
* to see if the xHC clears BIT(8) which never happens
|
||||||
|
* and driver assumes that controller is not responding
|
||||||
|
* and times out. To workaround this, its good to check
|
||||||
|
* if SRE and HCE bits are not set (as per xhci
|
||||||
|
* Section 5.4.2) and bypass the timeout.
|
||||||
|
*/
|
||||||
|
res = readl(&xhci->op_regs->status);
|
||||||
|
if ((xhci->quirks & XHCI_SNPS_BROKEN_SUSPEND) &&
|
||||||
|
(((res & STS_SRE) == 0) &&
|
||||||
|
((res & STS_HCE) == 0))) {
|
||||||
|
xhci->broken_suspend = 1;
|
||||||
|
} else {
|
||||||
|
xhci_warn(xhci, "WARN: xHC save state timeout\n");
|
||||||
|
spin_unlock_irq(&xhci->lock);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&xhci->lock);
|
spin_unlock_irq(&xhci->lock);
|
||||||
|
|
||||||
|
@ -1078,7 +1096,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
||||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
|
set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
|
||||||
|
|
||||||
spin_lock_irq(&xhci->lock);
|
spin_lock_irq(&xhci->lock);
|
||||||
if (xhci->quirks & XHCI_RESET_ON_RESUME)
|
if ((xhci->quirks & XHCI_RESET_ON_RESUME) || xhci->broken_suspend)
|
||||||
hibernated = true;
|
hibernated = true;
|
||||||
|
|
||||||
if (!hibernated) {
|
if (!hibernated) {
|
||||||
|
@ -4496,6 +4514,14 @@ static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci,
|
||||||
{
|
{
|
||||||
unsigned long long timeout_ns;
|
unsigned long long timeout_ns;
|
||||||
|
|
||||||
|
/* Prevent U1 if service interval is shorter than U1 exit latency */
|
||||||
|
if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) {
|
||||||
|
if (xhci_service_interval_to_ns(desc) <= udev->u1_params.mel) {
|
||||||
|
dev_dbg(&udev->dev, "Disable U1, ESIT shorter than exit latency\n");
|
||||||
|
return USB3_LPM_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (xhci->quirks & XHCI_INTEL_HOST)
|
if (xhci->quirks & XHCI_INTEL_HOST)
|
||||||
timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc);
|
timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc);
|
||||||
else
|
else
|
||||||
|
@ -4552,6 +4578,14 @@ static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci,
|
||||||
{
|
{
|
||||||
unsigned long long timeout_ns;
|
unsigned long long timeout_ns;
|
||||||
|
|
||||||
|
/* Prevent U2 if service interval is shorter than U2 exit latency */
|
||||||
|
if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) {
|
||||||
|
if (xhci_service_interval_to_ns(desc) <= udev->u2_params.mel) {
|
||||||
|
dev_dbg(&udev->dev, "Disable U2, ESIT shorter than exit latency\n");
|
||||||
|
return USB3_LPM_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (xhci->quirks & XHCI_INTEL_HOST)
|
if (xhci->quirks & XHCI_INTEL_HOST)
|
||||||
timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc);
|
timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc);
|
||||||
else
|
else
|
||||||
|
|
|
@ -1850,6 +1850,7 @@ struct xhci_hcd {
|
||||||
#define XHCI_ZERO_64B_REGS BIT_ULL(32)
|
#define XHCI_ZERO_64B_REGS BIT_ULL(32)
|
||||||
#define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
|
#define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
|
||||||
#define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
|
#define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
|
||||||
|
#define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
|
||||||
|
|
||||||
unsigned int num_active_eps;
|
unsigned int num_active_eps;
|
||||||
unsigned int limit_active_eps;
|
unsigned int limit_active_eps;
|
||||||
|
@ -1879,6 +1880,8 @@ struct xhci_hcd {
|
||||||
void *dbc;
|
void *dbc;
|
||||||
/* platform-specific data -- must come last */
|
/* platform-specific data -- must come last */
|
||||||
unsigned long priv[0] __aligned(sizeof(s64));
|
unsigned long priv[0] __aligned(sizeof(s64));
|
||||||
|
/* Broken Suspend flag for SNPS Suspend resume issue */
|
||||||
|
u8 broken_suspend;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Platform specific overrides to generic XHCI hc_driver ops */
|
/* Platform specific overrides to generic XHCI hc_driver ops */
|
||||||
|
|
|
@ -51,6 +51,7 @@ static const struct usb_device_id appledisplay_table[] = {
|
||||||
{ APPLEDISPLAY_DEVICE(0x921c) },
|
{ APPLEDISPLAY_DEVICE(0x921c) },
|
||||||
{ APPLEDISPLAY_DEVICE(0x921d) },
|
{ APPLEDISPLAY_DEVICE(0x921d) },
|
||||||
{ APPLEDISPLAY_DEVICE(0x9222) },
|
{ APPLEDISPLAY_DEVICE(0x9222) },
|
||||||
|
{ APPLEDISPLAY_DEVICE(0x9226) },
|
||||||
{ APPLEDISPLAY_DEVICE(0x9236) },
|
{ APPLEDISPLAY_DEVICE(0x9236) },
|
||||||
|
|
||||||
/* Terminating entry */
|
/* Terminating entry */
|
||||||
|
|
|
@ -101,7 +101,6 @@ static int usb_console_setup(struct console *co, char *options)
|
||||||
cflag |= PARENB;
|
cflag |= PARENB;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
co->cflag = cflag;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* no need to check the index here: if the index is wrong, console
|
* no need to check the index here: if the index is wrong, console
|
||||||
|
@ -164,6 +163,7 @@ static int usb_console_setup(struct console *co, char *options)
|
||||||
serial->type->set_termios(tty, port, &dummy);
|
serial->type->set_termios(tty, port, &dummy);
|
||||||
|
|
||||||
tty_port_tty_set(&port->port, NULL);
|
tty_port_tty_set(&port->port, NULL);
|
||||||
|
tty_save_termios(tty);
|
||||||
tty_kref_put(tty);
|
tty_kref_put(tty);
|
||||||
}
|
}
|
||||||
tty_port_set_initialized(&port->port, 1);
|
tty_port_set_initialized(&port->port, 1);
|
||||||
|
|
|
@ -556,6 +556,7 @@ extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx);
|
||||||
extern void tty_release_struct(struct tty_struct *tty, int idx);
|
extern void tty_release_struct(struct tty_struct *tty, int idx);
|
||||||
extern int tty_release(struct inode *inode, struct file *filp);
|
extern int tty_release(struct inode *inode, struct file *filp);
|
||||||
extern void tty_init_termios(struct tty_struct *tty);
|
extern void tty_init_termios(struct tty_struct *tty);
|
||||||
|
extern void tty_save_termios(struct tty_struct *tty);
|
||||||
extern int tty_standard_install(struct tty_driver *driver,
|
extern int tty_standard_install(struct tty_driver *driver,
|
||||||
struct tty_struct *tty);
|
struct tty_struct *tty);
|
||||||
|
|
||||||
|
|
|
@ -407,11 +407,11 @@ struct usb_host_bos {
|
||||||
};
|
};
|
||||||
|
|
||||||
int __usb_get_extra_descriptor(char *buffer, unsigned size,
|
int __usb_get_extra_descriptor(char *buffer, unsigned size,
|
||||||
unsigned char type, void **ptr);
|
unsigned char type, void **ptr, size_t min);
|
||||||
#define usb_get_extra_descriptor(ifpoint, type, ptr) \
|
#define usb_get_extra_descriptor(ifpoint, type, ptr) \
|
||||||
__usb_get_extra_descriptor((ifpoint)->extra, \
|
__usb_get_extra_descriptor((ifpoint)->extra, \
|
||||||
(ifpoint)->extralen, \
|
(ifpoint)->extralen, \
|
||||||
type, (void **)ptr)
|
type, (void **)ptr, sizeof(**(ptr)))
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue