Commit 4cd73195 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-4.20-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are a number of small USB fixes for 4.20-rc4.

  There's the usual xhci and dwc2/3 fixes as well as a few minor other
  issues resolved for problems that have been reported. Full details are
  in the shortlog.

  All have been in linux-next for a while with no reported issues"

* tag 'usb-4.20-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: cdc-acm: add entry for Hiro (Conexant) modem
  usb: xhci: Prevent bus suspend if a port connect change or polling state is detected
  usb: core: Fix hub port connection events lost
  usb: dwc3: gadget: fix ISOC TRB type on unaligned transfers
  Revert "usb: gadget: ffs: Fix BUG when userland exits with submitted AIO transfers"
  usb: dwc2: pci: Fix an error code in probe
  usb: dwc3: Fix NULL pointer exception in dwc3_pci_remove()
  xhci: Add quirk to workaround the errata seen on Cavium Thunder-X2 Soc
  usb: xhci: fix timeout for transition from RExit to U0
  usb: xhci: fix uninitialized completion when USB3 port got wrong status
  xhci: Add check for invalid byte size error when UAS devices are connected.
  xhci: handle port status events for removed USB3 hcd
  xhci: Fix leaking USB3 shared_hcd at xhci removal
  USB: misc: appledisplay: add 20" Apple Cinema Display
  USB: quirks: Add no-lpm quirk for Raydium touchscreens
  usb: quirks: Add delay-init quirk for Corsair K70 LUX RGB
  USB: Wait for extra delay time after USB_PORT_FEAT_RESET for quirky hub
  usb: dwc3: gadget: Properly check last unaligned/zero chain TRB
  usb: dwc3: core: Clean up ULPI device
parents ef4d6f2c 63529eaa
...@@ -4713,6 +4713,8 @@ ...@@ -4713,6 +4713,8 @@
prevent spurious wakeup); prevent spurious wakeup);
n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a
pause after every control message); pause after every control message);
o = USB_QUIRK_HUB_SLOW_RESET (Hub needs extra
delay after resetting its port);
Example: quirks=0781:5580:bk,0a5c:5834:gij Example: quirks=0781:5580:bk,0a5c:5834:gij
usbhid.mousepoll= usbhid.mousepoll=
......
...@@ -1696,6 +1696,9 @@ static const struct usb_device_id acm_ids[] = { ...@@ -1696,6 +1696,9 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */ { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
}, },
{ USB_DEVICE(0x0572, 0x1349), /* Hiro (Conexant) USB MODEM H50228 */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
{ USB_DEVICE(0x20df, 0x0001), /* Simtec Electronics Entropy Key */ { USB_DEVICE(0x20df, 0x0001), /* Simtec Electronics Entropy Key */
.driver_info = QUIRK_CONTROL_LINE_STATE, }, .driver_info = QUIRK_CONTROL_LINE_STATE, },
{ USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */ { USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */
......
...@@ -2794,6 +2794,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, ...@@ -2794,6 +2794,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
int i, status; int i, status;
u16 portchange, portstatus; u16 portchange, portstatus;
struct usb_port *port_dev = hub->ports[port1 - 1]; struct usb_port *port_dev = hub->ports[port1 - 1];
int reset_recovery_time;
if (!hub_is_superspeed(hub->hdev)) { if (!hub_is_superspeed(hub->hdev)) {
if (warm) { if (warm) {
...@@ -2849,6 +2850,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, ...@@ -2849,6 +2850,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
USB_PORT_FEAT_C_BH_PORT_RESET); USB_PORT_FEAT_C_BH_PORT_RESET);
usb_clear_port_feature(hub->hdev, port1, usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_PORT_LINK_STATE); USB_PORT_FEAT_C_PORT_LINK_STATE);
if (udev)
usb_clear_port_feature(hub->hdev, port1, usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_CONNECTION); USB_PORT_FEAT_C_CONNECTION);
...@@ -2885,11 +2888,18 @@ static int hub_port_reset(struct usb_hub *hub, int port1, ...@@ -2885,11 +2888,18 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
done: done:
if (status == 0) { if (status == 0) {
/* TRSTRCY = 10 ms; plus some extra */
if (port_dev->quirks & USB_PORT_QUIRK_FAST_ENUM) if (port_dev->quirks & USB_PORT_QUIRK_FAST_ENUM)
usleep_range(10000, 12000); usleep_range(10000, 12000);
else else {
msleep(10 + 40); /* TRSTRCY = 10 ms; plus some extra */
reset_recovery_time = 10 + 40;
/* Hub needs extra delay after resetting its port. */
if (hub->hdev->quirks & USB_QUIRK_HUB_SLOW_RESET)
reset_recovery_time += 100;
msleep(reset_recovery_time);
}
if (udev) { if (udev) {
struct usb_hcd *hcd = bus_to_hcd(udev->bus); struct usb_hcd *hcd = bus_to_hcd(udev->bus);
......
...@@ -128,6 +128,9 @@ static int quirks_param_set(const char *val, const struct kernel_param *kp) ...@@ -128,6 +128,9 @@ static int quirks_param_set(const char *val, const struct kernel_param *kp)
case 'n': case 'n':
flags |= USB_QUIRK_DELAY_CTRL_MSG; flags |= USB_QUIRK_DELAY_CTRL_MSG;
break; break;
case 'o':
flags |= USB_QUIRK_HUB_SLOW_RESET;
break;
/* Ignore unrecognized flag characters */ /* Ignore unrecognized flag characters */
} }
} }
...@@ -380,6 +383,9 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -380,6 +383,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x1a0a, 0x0200), .driver_info = { USB_DEVICE(0x1a0a, 0x0200), .driver_info =
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
/* Terminus Technology Inc. Hub */
{ USB_DEVICE(0x1a40, 0x0101), .driver_info = USB_QUIRK_HUB_SLOW_RESET },
/* Corsair K70 RGB */ /* Corsair K70 RGB */
{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },
...@@ -391,6 +397,9 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -391,6 +397,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT | { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT |
USB_QUIRK_DELAY_CTRL_MSG }, USB_QUIRK_DELAY_CTRL_MSG },
/* Corsair K70 LUX RGB */
{ USB_DEVICE(0x1b1c, 0x1b33), .driver_info = USB_QUIRK_DELAY_INIT },
/* Corsair K70 LUX */ /* Corsair K70 LUX */
{ USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
...@@ -411,6 +420,11 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -411,6 +420,11 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x2040, 0x7200), .driver_info = { USB_DEVICE(0x2040, 0x7200), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS }, USB_QUIRK_CONFIG_INTF_STRINGS },
/* Raydium Touchscreen */
{ USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM },
{ USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM },
/* DJI CineSSD */ /* DJI CineSSD */
{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
......
...@@ -120,6 +120,7 @@ static int dwc2_pci_probe(struct pci_dev *pci, ...@@ -120,6 +120,7 @@ static int dwc2_pci_probe(struct pci_dev *pci,
dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO); dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO);
if (!dwc2) { if (!dwc2) {
dev_err(dev, "couldn't allocate dwc2 device\n"); dev_err(dev, "couldn't allocate dwc2 device\n");
ret = -ENOMEM;
goto err; goto err;
} }
......
...@@ -1499,6 +1499,7 @@ static int dwc3_probe(struct platform_device *pdev) ...@@ -1499,6 +1499,7 @@ static int dwc3_probe(struct platform_device *pdev)
err5: err5:
dwc3_event_buffers_cleanup(dwc); dwc3_event_buffers_cleanup(dwc);
dwc3_ulpi_exit(dwc);
err4: err4:
dwc3_free_scratch_buffers(dwc); dwc3_free_scratch_buffers(dwc);
......
...@@ -283,7 +283,9 @@ static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) ...@@ -283,7 +283,9 @@ static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
static void dwc3_pci_remove(struct pci_dev *pci) static void dwc3_pci_remove(struct pci_dev *pci)
{ {
struct dwc3_pci *dwc = pci_get_drvdata(pci); struct dwc3_pci *dwc = pci_get_drvdata(pci);
struct pci_dev *pdev = dwc->pci;
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT)
gpiod_remove_lookup_table(&platform_bytcr_gpios); gpiod_remove_lookup_table(&platform_bytcr_gpios);
#ifdef CONFIG_PM #ifdef CONFIG_PM
cancel_work_sync(&dwc->wakeup_work); cancel_work_sync(&dwc->wakeup_work);
......
...@@ -1081,7 +1081,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, ...@@ -1081,7 +1081,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
/* Now prepare one extra TRB to align transfer size */ /* Now prepare one extra TRB to align transfer size */
trb = &dep->trb_pool[dep->trb_enqueue]; trb = &dep->trb_pool[dep->trb_enqueue];
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr,
maxp - rem, false, 0, maxp - rem, false, 1,
req->request.stream_id, req->request.stream_id,
req->request.short_not_ok, req->request.short_not_ok,
req->request.no_interrupt); req->request.no_interrupt);
...@@ -1125,7 +1125,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, ...@@ -1125,7 +1125,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
/* Now prepare one extra TRB to align transfer size */ /* Now prepare one extra TRB to align transfer size */
trb = &dep->trb_pool[dep->trb_enqueue]; trb = &dep->trb_pool[dep->trb_enqueue];
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem, __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem,
false, 0, req->request.stream_id, false, 1, req->request.stream_id,
req->request.short_not_ok, req->request.short_not_ok,
req->request.no_interrupt); req->request.no_interrupt);
} else if (req->request.zero && req->request.length && } else if (req->request.zero && req->request.length &&
...@@ -1141,7 +1141,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, ...@@ -1141,7 +1141,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
/* Now prepare one extra TRB to handle ZLP */ /* Now prepare one extra TRB to handle ZLP */
trb = &dep->trb_pool[dep->trb_enqueue]; trb = &dep->trb_pool[dep->trb_enqueue];
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0, __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
false, 0, req->request.stream_id, false, 1, req->request.stream_id,
req->request.short_not_ok, req->request.short_not_ok,
req->request.no_interrupt); req->request.no_interrupt);
} else { } else {
...@@ -2259,7 +2259,7 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, ...@@ -2259,7 +2259,7 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep,
* with one TRB pending in the ring. We need to manually clear HWO bit * with one TRB pending in the ring. We need to manually clear HWO bit
* from that TRB. * from that TRB.
*/ */
if ((req->zero || req->unaligned) && (trb->ctrl & DWC3_TRB_CTRL_HWO)) { if ((req->zero || req->unaligned) && !(trb->ctrl & DWC3_TRB_CTRL_CHN)) {
trb->ctrl &= ~DWC3_TRB_CTRL_HWO; trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
return 1; return 1;
} }
......
...@@ -215,7 +215,6 @@ struct ffs_io_data { ...@@ -215,7 +215,6 @@ struct ffs_io_data {
struct mm_struct *mm; struct mm_struct *mm;
struct work_struct work; struct work_struct work;
struct work_struct cancellation_work;
struct usb_ep *ep; struct usb_ep *ep;
struct usb_request *req; struct usb_request *req;
...@@ -1073,31 +1072,22 @@ ffs_epfile_open(struct inode *inode, struct file *file) ...@@ -1073,31 +1072,22 @@ ffs_epfile_open(struct inode *inode, struct file *file)
return 0; return 0;
} }
static void ffs_aio_cancel_worker(struct work_struct *work)
{
struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
cancellation_work);
ENTER();
usb_ep_dequeue(io_data->ep, io_data->req);
}
static int ffs_aio_cancel(struct kiocb *kiocb) static int ffs_aio_cancel(struct kiocb *kiocb)
{ {
struct ffs_io_data *io_data = kiocb->private; struct ffs_io_data *io_data = kiocb->private;
struct ffs_data *ffs = io_data->ffs; struct ffs_epfile *epfile = kiocb->ki_filp->private_data;
int value; int value;
ENTER(); ENTER();
if (likely(io_data && io_data->ep && io_data->req)) { spin_lock_irq(&epfile->ffs->eps_lock);
INIT_WORK(&io_data->cancellation_work, ffs_aio_cancel_worker);
queue_work(ffs->io_completion_wq, &io_data->cancellation_work); if (likely(io_data && io_data->ep && io_data->req))
value = -EINPROGRESS; value = usb_ep_dequeue(io_data->ep, io_data->req);
} else { else
value = -EINVAL; value = -EINVAL;
}
spin_unlock_irq(&epfile->ffs->eps_lock);
return value; return value;
} }
......
...@@ -325,14 +325,16 @@ static int xhci_histb_remove(struct platform_device *dev) ...@@ -325,14 +325,16 @@ static int xhci_histb_remove(struct platform_device *dev)
struct xhci_hcd_histb *histb = platform_get_drvdata(dev); struct xhci_hcd_histb *histb = platform_get_drvdata(dev);
struct usb_hcd *hcd = histb->hcd; struct usb_hcd *hcd = histb->hcd;
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct usb_hcd *shared_hcd = xhci->shared_hcd;
xhci->xhc_state |= XHCI_STATE_REMOVING; xhci->xhc_state |= XHCI_STATE_REMOVING;
usb_remove_hcd(xhci->shared_hcd); usb_remove_hcd(shared_hcd);
xhci->shared_hcd = NULL;
device_wakeup_disable(&dev->dev); device_wakeup_disable(&dev->dev);
usb_remove_hcd(hcd); usb_remove_hcd(hcd);
usb_put_hcd(xhci->shared_hcd); usb_put_hcd(shared_hcd);
xhci_histb_host_disable(histb); xhci_histb_host_disable(histb);
usb_put_hcd(hcd); usb_put_hcd(hcd);
......
...@@ -876,7 +876,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, ...@@ -876,7 +876,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
status |= USB_PORT_STAT_SUSPEND; status |= USB_PORT_STAT_SUSPEND;
} }
if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME && if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
!DEV_SUPERSPEED_ANY(raw_port_status)) { !DEV_SUPERSPEED_ANY(raw_port_status) && hcd->speed < HCD_USB3) {
if ((raw_port_status & PORT_RESET) || if ((raw_port_status & PORT_RESET) ||
!(raw_port_status & PORT_PE)) !(raw_port_status & PORT_PE))
return 0xffffffff; return 0xffffffff;
...@@ -921,7 +921,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, ...@@ -921,7 +921,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
time_left = wait_for_completion_timeout( time_left = wait_for_completion_timeout(
&bus_state->rexit_done[wIndex], &bus_state->rexit_done[wIndex],
msecs_to_jiffies( msecs_to_jiffies(
XHCI_MAX_REXIT_TIMEOUT)); XHCI_MAX_REXIT_TIMEOUT_MS));
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
if (time_left) { if (time_left) {
...@@ -935,7 +935,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, ...@@ -935,7 +935,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
} else { } else {
int port_status = readl(port->addr); int port_status = readl(port->addr);
xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n", xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
XHCI_MAX_REXIT_TIMEOUT, XHCI_MAX_REXIT_TIMEOUT_MS,
port_status); port_status);
status |= USB_PORT_STAT_SUSPEND; status |= USB_PORT_STAT_SUSPEND;
clear_bit(wIndex, &bus_state->rexit_ports); clear_bit(wIndex, &bus_state->rexit_ports);
...@@ -1474,15 +1474,18 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -1474,15 +1474,18 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
unsigned long flags; unsigned long flags;
struct xhci_hub *rhub; struct xhci_hub *rhub;
struct xhci_port **ports; struct xhci_port **ports;
u32 portsc_buf[USB_MAXCHILDREN];
bool wake_enabled;
rhub = xhci_get_rhub(hcd); rhub = xhci_get_rhub(hcd);
ports = rhub->ports; ports = rhub->ports;
max_ports = rhub->num_ports; max_ports = rhub->num_ports;
bus_state = &xhci->bus_state[hcd_index(hcd)]; bus_state = &xhci->bus_state[hcd_index(hcd)];
wake_enabled = hcd->self.root_hub->do_remote_wakeup;
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
if (hcd->self.root_hub->do_remote_wakeup) { if (wake_enabled) {
if (bus_state->resuming_ports || /* USB2 */ if (bus_state->resuming_ports || /* USB2 */
bus_state->port_remote_wakeup) { /* USB3 */ bus_state->port_remote_wakeup) { /* USB3 */
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
...@@ -1490,26 +1493,36 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -1490,26 +1493,36 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
return -EBUSY; return -EBUSY;
} }
} }
/*
port_index = max_ports; * Prepare ports for suspend, but don't write anything before all ports
* are checked and we know bus suspend can proceed
*/
bus_state->bus_suspended = 0; bus_state->bus_suspended = 0;
port_index = max_ports;
while (port_index--) { while (port_index--) {
/* suspend the port if the port is not suspended */
u32 t1, t2; u32 t1, t2;
int slot_id;
t1 = readl(ports[port_index]->addr); t1 = readl(ports[port_index]->addr);
t2 = xhci_port_state_to_neutral(t1); t2 = xhci_port_state_to_neutral(t1);
portsc_buf[port_index] = 0;
if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { /* Bail out if a USB3 port has a new device in link training */
xhci_dbg(xhci, "port %d not suspended\n", port_index); if ((t1 & PORT_PLS_MASK) == XDEV_POLLING) {
slot_id = xhci_find_slot_id_by_port(hcd, xhci, bus_state->bus_suspended = 0;
port_index + 1);
if (slot_id) {
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
xhci_stop_device(xhci, slot_id, 1); xhci_dbg(xhci, "Bus suspend bailout, port in polling\n");
spin_lock_irqsave(&xhci->lock, flags); return -EBUSY;
} }
/* suspend ports in U0, or bail out for new connect changes */
if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) {
if ((t1 & PORT_CSC) && wake_enabled) {
bus_state->bus_suspended = 0;
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "Bus suspend bailout, port connect change\n");
return -EBUSY;
}
xhci_dbg(xhci, "port %d not suspended\n", port_index);
t2 &= ~PORT_PLS_MASK; t2 &= ~PORT_PLS_MASK;
t2 |= PORT_LINK_STROBE | XDEV_U3; t2 |= PORT_LINK_STROBE | XDEV_U3;
set_bit(port_index, &bus_state->bus_suspended); set_bit(port_index, &bus_state->bus_suspended);
...@@ -1518,7 +1531,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -1518,7 +1531,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
* including the USB 3.0 roothub, but only if CONFIG_PM * including the USB 3.0 roothub, but only if CONFIG_PM
* is enabled, so also enable remote wake here. * is enabled, so also enable remote wake here.
*/ */
if (hcd->self.root_hub->do_remote_wakeup) { if (wake_enabled) {
if (t1 & PORT_CONNECT) { if (t1 & PORT_CONNECT) {
t2 |= PORT_WKOC_E | PORT_WKDISC_E; t2 |= PORT_WKOC_E | PORT_WKDISC_E;
t2 &= ~PORT_WKCONN_E; t2 &= ~PORT_WKCONN_E;
...@@ -1538,7 +1551,26 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -1538,7 +1551,26 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
t1 = xhci_port_state_to_neutral(t1); t1 = xhci_port_state_to_neutral(t1);
if (t1 != t2) if (t1 != t2)
writel(t2, ports[port_index]->addr); portsc_buf[port_index] = t2;
}
/* write port settings, stopping and suspending ports if needed */
port_index = max_ports;
while (port_index--) {
if (!portsc_buf[port_index])
continue;
if (test_bit(port_index, &bus_state->bus_suspended)) {
int slot_id;
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
port_index + 1);
if (slot_id) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_stop_device(xhci, slot_id, 1);
spin_lock_irqsave(&xhci->lock, flags);
}
}
writel(portsc_buf[port_index], ports[port_index]->addr);
} }
hcd->state = HC_STATE_SUSPENDED; hcd->state = HC_STATE_SUSPENDED;
bus_state->next_statechange = jiffies + msecs_to_jiffies(10); bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
......
...@@ -590,12 +590,14 @@ static int xhci_mtk_remove(struct platform_device *dev) ...@@ -590,12 +590,14 @@ static int xhci_mtk_remove(struct platform_device *dev)
struct xhci_hcd_mtk *mtk = platform_get_drvdata(dev); struct xhci_hcd_mtk *mtk = platform_get_drvdata(dev);
struct usb_hcd *hcd = mtk->hcd; struct usb_hcd *hcd = mtk->hcd;
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct usb_hcd *shared_hcd = xhci->shared_hcd;
usb_remove_hcd(xhci->shared_hcd); usb_remove_hcd(shared_hcd);
xhci->shared_hcd = NULL;
device_init_wakeup(&dev->dev, false); device_init_wakeup(&dev->dev, false);
usb_remove_hcd(hcd); usb_remove_hcd(hcd);
usb_put_hcd(xhci->shared_hcd); usb_put_hcd(shared_hcd);
usb_put_hcd(hcd); usb_put_hcd(hcd);
xhci_mtk_sch_exit(mtk); xhci_mtk_sch_exit(mtk);
xhci_mtk_clks_disable(mtk); xhci_mtk_clks_disable(mtk);
......
...@@ -248,6 +248,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) ...@@ -248,6 +248,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241) if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241)
xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7; xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7;
if ((pdev->vendor == PCI_VENDOR_ID_BROADCOM ||
pdev->vendor == PCI_VENDOR_ID_CAVIUM) &&
pdev->device == 0x9026)
xhci->quirks |= XHCI_RESET_PLL_ON_DISCONNECT;
if (xhci->quirks & XHCI_RESET_ON_RESUME) if (xhci->quirks & XHCI_RESET_ON_RESUME)
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
"QUIRK: Resetting on resume"); "QUIRK: Resetting on resume");
...@@ -380,6 +385,7 @@ static void xhci_pci_remove(struct pci_dev *dev) ...@@ -380,6 +385,7 @@ static void xhci_pci_remove(struct pci_dev *dev)
if (xhci->shared_hcd) { if (xhci->shared_hcd) {
usb_remove_hcd(xhci->shared_hcd); usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd);
xhci->shared_hcd = NULL;
} }
/* Workaround for spurious wakeups at shutdown with HSW */ /* Workaround for spurious wakeups at shutdown with HSW */
......
...@@ -362,14 +362,16 @@ static int xhci_plat_remove(struct platform_device *dev) ...@@ -362,14 +362,16 @@ static int xhci_plat_remove(struct platform_device *dev)
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct clk *clk = xhci->clk; struct clk *clk = xhci->clk;
struct clk *reg_clk = xhci->reg_clk; struct clk *reg_clk = xhci->reg_clk;
struct usb_hcd *shared_hcd = xhci->shared_hcd;
xhci->xhc_state |= XHCI_STATE_REMOVING; xhci->xhc_state |= XHCI_STATE_REMOVING;
usb_remove_hcd(xhci->shared_hcd); usb_remove_hcd(shared_hcd);
xhci->shared_hcd = NULL;
usb_phy_shutdown(hcd->usb_phy); usb_phy_shutdown(hcd->usb_phy);
usb_remove_hcd(hcd); usb_remove_hcd(hcd);
usb_put_hcd(xhci->shared_hcd); usb_put_hcd(shared_hcd);
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
clk_disable_unprepare(reg_clk); clk_disable_unprepare(reg_clk);
......
...@@ -1521,6 +1521,35 @@ static void handle_device_notification(struct xhci_hcd *xhci, ...@@ -1521,6 +1521,35 @@ static void handle_device_notification(struct xhci_hcd *xhci,
usb_wakeup_notification(udev->parent, udev->portnum); usb_wakeup_notification(udev->parent, udev->portnum);
} }
/*
* Quirk hanlder for errata seen on Cavium ThunderX2 processor XHCI
* Controller.
* As per ThunderX2errata-129 USB 2 device may come up as USB 1
* If a connection to a USB 1 device is followed by another connection
* to a USB 2 device.
*
* Reset the PHY after the USB device is disconnected if device speed
* is less than HCD_USB3.
* Retry the reset sequence max of 4 times checking the PLL lock status.
*
*/
static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
{
struct usb_hcd *hcd = xhci_to_hcd(xhci);
u32 pll_lock_check;
u32 retry_count = 4;
do {
/* Assert PHY reset */
writel(0x6F, hcd->regs + 0x1048);
udelay(10);
/* De-assert the PHY reset */
writel(0x7F, hcd->regs + 0x1048);
udelay(200);
pll_lock_check = readl(hcd->regs + 0x1070);
} while (!(pll_lock_check & 0x1) && --retry_count);
}
static void handle_port_status(struct xhci_hcd *xhci, static void handle_port_status(struct xhci_hcd *xhci,
union xhci_trb *event) union xhci_trb *event)
{ {
...@@ -1556,6 +1585,13 @@ static void handle_port_status(struct xhci_hcd *xhci, ...@@ -1556,6 +1585,13 @@ static void handle_port_status(struct xhci_hcd *xhci,
goto cleanup; goto cleanup;
} }
/* We might get interrupts after shared_hcd is removed */
if (port->rhub == &xhci->usb3_rhub && xhci->shared_hcd == NULL) {
xhci_dbg(xhci, "ignore port event for removed USB3 hcd\n");
bogus_port_status = true;
goto cleanup;
}
hcd = port->rhub->hcd; hcd = port->rhub->hcd;
bus_state = &xhci->bus_state[hcd_index(hcd)]; bus_state = &xhci->bus_state[hcd_index(hcd)];
hcd_portnum = port->hcd_portnum; hcd_portnum = port->hcd_portnum;
...@@ -1639,7 +1675,7 @@ static void handle_port_status(struct xhci_hcd *xhci, ...@@ -1639,7 +1675,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
* RExit to a disconnect state). If so, let the the driver know it's * RExit to a disconnect state). If so, let the the driver know it's
* out of the RExit state. * out of the RExit state.
*/ */
if (!DEV_SUPERSPEED_ANY(portsc) && if (!DEV_SUPERSPEED_ANY(portsc) && hcd->speed < HCD_USB3 &&
test_and_clear_bit(hcd_portnum, test_and_clear_bit(hcd_portnum,
&bus_state->rexit_ports)) { &bus_state->rexit_ports)) {
complete(&bus_state->rexit_done[hcd_portnum]); complete(&bus_state->rexit_done[hcd_portnum]);
...@@ -1647,8 +1683,12 @@ static void handle_port_status(struct xhci_hcd *xhci, ...@@ -1647,8 +1683,12 @@ static void handle_port_status(struct xhci_hcd *xhci,
goto cleanup; goto cleanup;
} }
if (hcd->speed < HCD_USB3) if (hcd->speed < HCD_USB3) {
xhci_test_and_clear_bit(xhci, port, PORT_PLC); xhci_test_and_clear_bit(xhci, port, PORT_PLC);
if ((xhci->quirks & XHCI_RESET_PLL_ON_DISCONNECT) &&
(portsc & PORT_CSC) && !(portsc & PORT_CONNECT))
xhci_cavium_reset_phy_quirk(xhci);
}
cleanup: cleanup:
/* Update event ring dequeue pointer before dropping the lock */ /* Update event ring dequeue pointer before dropping the lock */
...@@ -2266,6 +2306,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -2266,6 +2306,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
goto cleanup; goto cleanup;
case COMP_RING_UNDERRUN: case COMP_RING_UNDERRUN:
case COMP_RING_OVERRUN: case COMP_RING_OVERRUN:
case COMP_STOPPED_LENGTH_INVALID:
goto cleanup; goto cleanup;
default: default:
xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n", xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n",
......
...@@ -1303,6 +1303,7 @@ static int tegra_xusb_remove(struct platform_device *pdev) ...@@ -1303,6 +1303,7 @@ static int tegra_xusb_remove(struct platform_device *pdev)
usb_remove_hcd(xhci->shared_hcd); usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd);
xhci->shared_hcd = NULL;
usb_remove_hcd(tegra->hcd); usb_remove_hcd(tegra->hcd);
usb_put_hcd(tegra->hcd); usb_put_hcd(tegra->hcd);
......
...@@ -719,8 +719,6 @@ static void xhci_stop(struct usb_hcd *hcd) ...@@ -719,8 +719,6 @@ static void xhci_stop(struct usb_hcd *hcd)
/* Only halt host and free memory after both hcds are removed */ /* Only halt host and free memory after both hcds are removed */
if (!usb_hcd_is_primary_hcd(hcd)) { if (!usb_hcd_is_primary_hcd(hcd)) {
/* usb core will free this hcd shortly, unset pointer */
xhci->shared_hcd = NULL;
mutex_unlock(&xhci->mutex); mutex_unlock(&xhci->mutex);
return; return;
} }
......
...@@ -1680,7 +1680,7 @@ struct xhci_bus_state { ...@@ -1680,7 +1680,7 @@ struct xhci_bus_state {
* It can take up to 20 ms to transition from RExit to U0 on the * It can take up to 20 ms to transition from RExit to U0 on the
* Intel Lynx Point LP xHCI host. * Intel Lynx Point LP xHCI host.
*/ */
#define XHCI_MAX_REXIT_TIMEOUT (20 * 1000) #define XHCI_MAX_REXIT_TIMEOUT_MS 20
static inline unsigned int hcd_index(struct usb_hcd *hcd) static inline unsigned int hcd_index(struct usb_hcd *hcd)
{ {
...@@ -1849,6 +1849,7 @@ struct xhci_hcd { ...@@ -1849,6 +1849,7 @@ struct xhci_hcd {
#define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31) #define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31)
#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)
unsigned int num_active_eps; unsigned int num_active_eps;
unsigned int limit_active_eps; unsigned int limit_active_eps;
......
...@@ -50,6 +50,7 @@ static const struct usb_device_id appledisplay_table[] = { ...@@ -50,6 +50,7 @@ static const struct usb_device_id appledisplay_table[] = {
{ APPLEDISPLAY_DEVICE(0x9219) }, { APPLEDISPLAY_DEVICE(0x9219) },
{ APPLEDISPLAY_DEVICE(0x921c) }, { APPLEDISPLAY_DEVICE(0x921c) },
{ APPLEDISPLAY_DEVICE(0x921d) }, { APPLEDISPLAY_DEVICE(0x921d) },
{ APPLEDISPLAY_DEVICE(0x9222) },
{ APPLEDISPLAY_DEVICE(0x9236) }, { APPLEDISPLAY_DEVICE(0x9236) },
/* Terminating entry */ /* Terminating entry */
......
...@@ -66,4 +66,7 @@ ...@@ -66,4 +66,7 @@
/* Device needs a pause after every control message. */ /* Device needs a pause after every control message. */
#define USB_QUIRK_DELAY_CTRL_MSG BIT(13) #define USB_QUIRK_DELAY_CTRL_MSG BIT(13)
/* Hub needs extra delay after resetting its port. */
#define USB_QUIRK_HUB_SLOW_RESET BIT(14)
#endif /* __LINUX_USB_QUIRKS_H */ #endif /* __LINUX_USB_QUIRKS_H */
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