Skip to content

Commit

Permalink
Merge tag 'usb-4.20-rc6' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
torvalds committed Dec 9, 2018
2 parents bc4caf1 + 3caad34 commit 50a5528
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 15 deletions.
11 changes: 9 additions & 2 deletions drivers/tty/tty_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,13 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
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;
int idx = tty->index;
Expand All @@ -1392,6 +1398,7 @@ static void tty_free_termios(struct tty_struct *tty)
}
*tp = tty->termios;
}
EXPORT_SYMBOL_GPL(tty_save_termios);

/**
* tty_flush_works - flush all works of a tty/pty pair
Expand Down Expand Up @@ -1491,7 +1498,7 @@ static void release_tty(struct tty_struct *tty, int idx)
WARN_ON(!mutex_is_locked(&tty_mutex));
if (tty->ops->shutdown)
tty->ops->shutdown(tty);
tty_free_termios(tty);
tty_save_termios(tty);
tty_driver_remove_tty(tty->driver, tty);
tty->port->itty = NULL;
if (tty->link)
Expand Down
5 changes: 3 additions & 2 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -2251,7 +2251,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
/* descriptor may appear anywhere in config */
err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
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))
return 0;

Expand Down Expand Up @@ -5163,7 +5163,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* Handle notifying userspace about hub over-current events */
static void port_over_current_notify(struct usb_port *port_dev)
{
static char *envp[] = { NULL, NULL, NULL };
char *envp[3];
struct device *hub_dev;
char *port_dev_path;

Expand All @@ -5187,6 +5187,7 @@ static void port_over_current_notify(struct usb_port *port_dev)
if (!envp[1])
goto exit;

envp[2] = NULL;
kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp);

kfree(envp[1]);
Expand Down
4 changes: 4 additions & 0 deletions drivers/usb/core/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Midiman M-Audio Keystation 88es */
{ 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 */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },

Expand Down
6 changes: 3 additions & 3 deletions drivers/usb/core/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -832,14 +832,14 @@ EXPORT_SYMBOL_GPL(usb_get_current_frame_number);
*/

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;

while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;

if (header->bLength < 2) {
if (header->bLength < 2 || header->bLength > size) {
printk(KERN_ERR
"%s: bogus descriptor, type %d length %d\n",
usbcore_name,
Expand All @@ -848,7 +848,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
return -1;
}

if (header->bDescriptorType == type) {
if (header->bDescriptorType == type && header->bLength >= minsize) {
*ptr = header;
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/hwa-hc.c
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ static int hwahc_security_create(struct hwahc *hwahc)
top = itr + itr_size;
result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
USB_DT_SECURITY, (void **) &secd);
USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
if (result == -1) {
dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
return 0;
Expand Down
4 changes: 4 additions & 0 deletions drivers/usb/host/xhci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
pdev->device == 0x43bb))
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)
xhci->quirks |= XHCI_TRUST_TX_LENGTH;

Expand Down
42 changes: 38 additions & 4 deletions drivers/usb/host/xhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
unsigned int delay = XHCI_MAX_HALT_USEC;
struct usb_hcd *hcd = xhci_to_hcd(xhci);
u32 command;
u32 res;

if (!hcd->state)
return 0;
Expand Down Expand Up @@ -1021,11 +1022,28 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
command = readl(&xhci->op_regs->command);
command |= CMD_CSS;
writel(command, &xhci->op_regs->command);
xhci->broken_suspend = 0;
if (xhci_handshake(&xhci->op_regs->status,
STS_SAVE, 0, 10 * 1000)) {
xhci_warn(xhci, "WARN: xHC save state timeout\n");
spin_unlock_irq(&xhci->lock);
return -ETIMEDOUT;
/*
* AMD SNPS xHC 3.0 occasionally does not clear the
* 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);

Expand Down Expand Up @@ -1078,7 +1096,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);

spin_lock_irq(&xhci->lock);
if (xhci->quirks & XHCI_RESET_ON_RESUME)
if ((xhci->quirks & XHCI_RESET_ON_RESUME) || xhci->broken_suspend)
hibernated = true;

if (!hibernated) {
Expand Down Expand Up @@ -4496,6 +4514,14 @@ static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci,
{
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)
timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc);
else
Expand Down Expand Up @@ -4552,6 +4578,14 @@ static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci,
{
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)
timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc);
else
Expand Down
3 changes: 3 additions & 0 deletions drivers/usb/host/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1850,6 +1850,7 @@ struct xhci_hcd {
#define XHCI_ZERO_64B_REGS BIT_ULL(32)
#define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
#define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
#define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)

unsigned int num_active_eps;
unsigned int limit_active_eps;
Expand Down Expand Up @@ -1879,6 +1880,8 @@ struct xhci_hcd {
void *dbc;
/* platform-specific data -- must come last */
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 */
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/misc/appledisplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ static const struct usb_device_id appledisplay_table[] = {
{ APPLEDISPLAY_DEVICE(0x921c) },
{ APPLEDISPLAY_DEVICE(0x921d) },
{ APPLEDISPLAY_DEVICE(0x9222) },
{ APPLEDISPLAY_DEVICE(0x9226) },
{ APPLEDISPLAY_DEVICE(0x9236) },

/* Terminating entry */
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/serial/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ static int usb_console_setup(struct console *co, char *options)
cflag |= PARENB;
break;
}
co->cflag = cflag;

/*
* no need to check the index here: if the index is wrong, console
Expand Down Expand Up @@ -164,6 +163,7 @@ static int usb_console_setup(struct console *co, char *options)
serial->type->set_termios(tty, port, &dummy);

tty_port_tty_set(&port->port, NULL);
tty_save_termios(tty);
tty_kref_put(tty);
}
tty_port_set_initialized(&port->port, 1);
Expand Down
1 change: 1 addition & 0 deletions include/linux/tty.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 int tty_release(struct inode *inode, struct file *filp);
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,
struct tty_struct *tty);

Expand Down
4 changes: 2 additions & 2 deletions include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,11 +407,11 @@ struct usb_host_bos {
};

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) \
__usb_get_extra_descriptor((ifpoint)->extra, \
(ifpoint)->extralen, \
type, (void **)ptr)
type, (void **)ptr, sizeof(**(ptr)))

/* ----------------------------------------------------------------------- */

Expand Down

0 comments on commit 50a5528

Please sign in to comment.