USB fixes for 4.20-rc4
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW/ZsOg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymPlACeO1ii05UG6Mb47AC0sZbgMk5diWwAnRK3A0Pe fSupZy5v6u1HBEormFco =5k0S -----END PGP SIGNATURE----- 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
This commit is contained in:
Коммит
4cd731953d
|
@ -4713,6 +4713,8 @@
|
|||
prevent spurious wakeup);
|
||||
n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a
|
||||
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
|
||||
|
||||
usbhid.mousepoll=
|
||||
|
|
|
@ -1696,6 +1696,9 @@ static const struct usb_device_id acm_ids[] = {
|
|||
{ USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
|
||||
.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 */
|
||||
.driver_info = QUIRK_CONTROL_LINE_STATE, },
|
||||
{ USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */
|
||||
|
|
|
@ -2794,6 +2794,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|||
int i, status;
|
||||
u16 portchange, portstatus;
|
||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
int reset_recovery_time;
|
||||
|
||||
if (!hub_is_superspeed(hub->hdev)) {
|
||||
if (warm) {
|
||||
|
@ -2849,7 +2850,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|||
USB_PORT_FEAT_C_BH_PORT_RESET);
|
||||
usb_clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_PORT_LINK_STATE);
|
||||
usb_clear_port_feature(hub->hdev, port1,
|
||||
|
||||
if (udev)
|
||||
usb_clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_CONNECTION);
|
||||
|
||||
/*
|
||||
|
@ -2885,11 +2888,18 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|||
|
||||
done:
|
||||
if (status == 0) {
|
||||
/* TRSTRCY = 10 ms; plus some extra */
|
||||
if (port_dev->quirks & USB_PORT_QUIRK_FAST_ENUM)
|
||||
usleep_range(10000, 12000);
|
||||
else
|
||||
msleep(10 + 40);
|
||||
else {
|
||||
/* 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) {
|
||||
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)
|
|||
case 'n':
|
||||
flags |= USB_QUIRK_DELAY_CTRL_MSG;
|
||||
break;
|
||||
case 'o':
|
||||
flags |= USB_QUIRK_HUB_SLOW_RESET;
|
||||
break;
|
||||
/* Ignore unrecognized flag characters */
|
||||
}
|
||||
}
|
||||
|
@ -380,6 +383,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
|
||||
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
|
||||
|
||||
/* Terminus Technology Inc. Hub */
|
||||
{ USB_DEVICE(0x1a40, 0x0101), .driver_info = USB_QUIRK_HUB_SLOW_RESET },
|
||||
|
||||
/* Corsair K70 RGB */
|
||||
{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
|
||||
|
@ -391,6 +397,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT |
|
||||
USB_QUIRK_DELAY_CTRL_MSG },
|
||||
|
||||
/* Corsair K70 LUX RGB */
|
||||
{ USB_DEVICE(0x1b1c, 0x1b33), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
|
||||
/* Corsair K70 LUX */
|
||||
{ USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
|
||||
|
@ -411,6 +420,11 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
{ USB_DEVICE(0x2040, 0x7200), .driver_info =
|
||||
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 */
|
||||
{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ static int dwc2_pci_probe(struct pci_dev *pci,
|
|||
dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO);
|
||||
if (!dwc2) {
|
||||
dev_err(dev, "couldn't allocate dwc2 device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1499,6 +1499,7 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
|
||||
err5:
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
dwc3_ulpi_exit(dwc);
|
||||
|
||||
err4:
|
||||
dwc3_free_scratch_buffers(dwc);
|
||||
|
|
|
@ -283,8 +283,10 @@ err:
|
|||
static void dwc3_pci_remove(struct pci_dev *pci)
|
||||
{
|
||||
struct dwc3_pci *dwc = pci_get_drvdata(pci);
|
||||
struct pci_dev *pdev = dwc->pci;
|
||||
|
||||
gpiod_remove_lookup_table(&platform_bytcr_gpios);
|
||||
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT)
|
||||
gpiod_remove_lookup_table(&platform_bytcr_gpios);
|
||||
#ifdef CONFIG_PM
|
||||
cancel_work_sync(&dwc->wakeup_work);
|
||||
#endif
|
||||
|
|
|
@ -1081,7 +1081,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
|
|||
/* Now prepare one extra TRB to align transfer size */
|
||||
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr,
|
||||
maxp - rem, false, 0,
|
||||
maxp - rem, false, 1,
|
||||
req->request.stream_id,
|
||||
req->request.short_not_ok,
|
||||
req->request.no_interrupt);
|
||||
|
@ -1125,7 +1125,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
|
|||
/* Now prepare one extra TRB to align transfer size */
|
||||
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||
__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.no_interrupt);
|
||||
} else if (req->request.zero && req->request.length &&
|
||||
|
@ -1141,7 +1141,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
|
|||
/* Now prepare one extra TRB to handle ZLP */
|
||||
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||
__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.no_interrupt);
|
||||
} else {
|
||||
|
@ -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
|
||||
* 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;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -215,7 +215,6 @@ struct ffs_io_data {
|
|||
|
||||
struct mm_struct *mm;
|
||||
struct work_struct work;
|
||||
struct work_struct cancellation_work;
|
||||
|
||||
struct usb_ep *ep;
|
||||
struct usb_request *req;
|
||||
|
@ -1073,31 +1072,22 @@ ffs_epfile_open(struct inode *inode, struct file *file)
|
|||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (likely(io_data && io_data->ep && io_data->req)) {
|
||||
INIT_WORK(&io_data->cancellation_work, ffs_aio_cancel_worker);
|
||||
queue_work(ffs->io_completion_wq, &io_data->cancellation_work);
|
||||
value = -EINPROGRESS;
|
||||
} else {
|
||||
spin_lock_irq(&epfile->ffs->eps_lock);
|
||||
|
||||
if (likely(io_data && io_data->ep && io_data->req))
|
||||
value = usb_ep_dequeue(io_data->ep, io_data->req);
|
||||
else
|
||||
value = -EINVAL;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -325,14 +325,16 @@ static int xhci_histb_remove(struct platform_device *dev)
|
|||
struct xhci_hcd_histb *histb = platform_get_drvdata(dev);
|
||||
struct usb_hcd *hcd = histb->hcd;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct usb_hcd *shared_hcd = xhci->shared_hcd;
|
||||
|
||||
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);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
usb_put_hcd(xhci->shared_hcd);
|
||||
usb_put_hcd(shared_hcd);
|
||||
|
||||
xhci_histb_host_disable(histb);
|
||||
usb_put_hcd(hcd);
|
||||
|
|
|
@ -876,7 +876,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
status |= USB_PORT_STAT_SUSPEND;
|
||||
}
|
||||
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) ||
|
||||
!(raw_port_status & PORT_PE))
|
||||
return 0xffffffff;
|
||||
|
@ -921,7 +921,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
time_left = wait_for_completion_timeout(
|
||||
&bus_state->rexit_done[wIndex],
|
||||
msecs_to_jiffies(
|
||||
XHCI_MAX_REXIT_TIMEOUT));
|
||||
XHCI_MAX_REXIT_TIMEOUT_MS));
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
if (time_left) {
|
||||
|
@ -935,7 +935,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
} else {
|
||||
int port_status = readl(port->addr);
|
||||
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);
|
||||
status |= USB_PORT_STAT_SUSPEND;
|
||||
clear_bit(wIndex, &bus_state->rexit_ports);
|
||||
|
@ -1474,15 +1474,18 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
unsigned long flags;
|
||||
struct xhci_hub *rhub;
|
||||
struct xhci_port **ports;
|
||||
u32 portsc_buf[USB_MAXCHILDREN];
|
||||
bool wake_enabled;
|
||||
|
||||
rhub = xhci_get_rhub(hcd);
|
||||
ports = rhub->ports;
|
||||
max_ports = rhub->num_ports;
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
wake_enabled = hcd->self.root_hub->do_remote_wakeup;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
if (hcd->self.root_hub->do_remote_wakeup) {
|
||||
if (wake_enabled) {
|
||||
if (bus_state->resuming_ports || /* USB2 */
|
||||
bus_state->port_remote_wakeup) { /* USB3 */
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
@ -1490,26 +1493,36 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
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;
|
||||
port_index = max_ports;
|
||||
while (port_index--) {
|
||||
/* suspend the port if the port is not suspended */
|
||||
u32 t1, t2;
|
||||
int slot_id;
|
||||
|
||||
t1 = readl(ports[port_index]->addr);
|
||||
t2 = xhci_port_state_to_neutral(t1);
|
||||
portsc_buf[port_index] = 0;
|
||||
|
||||
if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
|
||||
xhci_dbg(xhci, "port %d not suspended\n", port_index);
|
||||
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
||||
port_index + 1);
|
||||
if (slot_id) {
|
||||
/* Bail out if a USB3 port has a new device in link training */
|
||||
if ((t1 & PORT_PLS_MASK) == XDEV_POLLING) {
|
||||
bus_state->bus_suspended = 0;
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg(xhci, "Bus suspend bailout, port in polling\n");
|
||||
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_stop_device(xhci, slot_id, 1);
|
||||
spin_lock_irqsave(&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_LINK_STROBE | XDEV_U3;
|
||||
set_bit(port_index, &bus_state->bus_suspended);
|
||||
|
@ -1518,7 +1531,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
* including the USB 3.0 roothub, but only if CONFIG_PM
|
||||
* is enabled, so also enable remote wake here.
|
||||
*/
|
||||
if (hcd->self.root_hub->do_remote_wakeup) {
|
||||
if (wake_enabled) {
|
||||
if (t1 & PORT_CONNECT) {
|
||||
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
|
||||
t2 &= ~PORT_WKCONN_E;
|
||||
|
@ -1538,7 +1551,26 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
|
||||
t1 = xhci_port_state_to_neutral(t1);
|
||||
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;
|
||||
bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
|
||||
|
|
|
@ -590,12 +590,14 @@ static int xhci_mtk_remove(struct platform_device *dev)
|
|||
struct xhci_hcd_mtk *mtk = platform_get_drvdata(dev);
|
||||
struct usb_hcd *hcd = mtk->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);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
usb_put_hcd(xhci->shared_hcd);
|
||||
usb_put_hcd(shared_hcd);
|
||||
usb_put_hcd(hcd);
|
||||
xhci_mtk_sch_exit(mtk);
|
||||
xhci_mtk_clks_disable(mtk);
|
||||
|
|
|
@ -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)
|
||||
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)
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
|
||||
"QUIRK: Resetting on resume");
|
||||
|
@ -380,6 +385,7 @@ static void xhci_pci_remove(struct pci_dev *dev)
|
|||
if (xhci->shared_hcd) {
|
||||
usb_remove_hcd(xhci->shared_hcd);
|
||||
usb_put_hcd(xhci->shared_hcd);
|
||||
xhci->shared_hcd = NULL;
|
||||
}
|
||||
|
||||
/* Workaround for spurious wakeups at shutdown with HSW */
|
||||
|
|
|
@ -362,14 +362,16 @@ static int xhci_plat_remove(struct platform_device *dev)
|
|||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct clk *clk = xhci->clk;
|
||||
struct clk *reg_clk = xhci->reg_clk;
|
||||
struct usb_hcd *shared_hcd = xhci->shared_hcd;
|
||||
|
||||
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_remove_hcd(hcd);
|
||||
usb_put_hcd(xhci->shared_hcd);
|
||||
usb_put_hcd(shared_hcd);
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
clk_disable_unprepare(reg_clk);
|
||||
|
|
|
@ -1521,6 +1521,35 @@ static void handle_device_notification(struct xhci_hcd *xhci,
|
|||
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,
|
||||
union xhci_trb *event)
|
||||
{
|
||||
|
@ -1556,6 +1585,13 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
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;
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
hcd_portnum = port->hcd_portnum;
|
||||
|
@ -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
|
||||
* 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,
|
||||
&bus_state->rexit_ports)) {
|
||||
complete(&bus_state->rexit_done[hcd_portnum]);
|
||||
|
@ -1647,8 +1683,12 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (hcd->speed < HCD_USB3)
|
||||
if (hcd->speed < HCD_USB3) {
|
||||
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:
|
||||
/* Update event ring dequeue pointer before dropping the lock */
|
||||
|
@ -2266,6 +2306,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
goto cleanup;
|
||||
case COMP_RING_UNDERRUN:
|
||||
case COMP_RING_OVERRUN:
|
||||
case COMP_STOPPED_LENGTH_INVALID:
|
||||
goto cleanup;
|
||||
default:
|
||||
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)
|
|||
|
||||
usb_remove_hcd(xhci->shared_hcd);
|
||||
usb_put_hcd(xhci->shared_hcd);
|
||||
xhci->shared_hcd = NULL;
|
||||
usb_remove_hcd(tegra->hcd);
|
||||
usb_put_hcd(tegra->hcd);
|
||||
|
||||
|
|
|
@ -719,8 +719,6 @@ static void xhci_stop(struct usb_hcd *hcd)
|
|||
|
||||
/* Only halt host and free memory after both hcds are removed */
|
||||
if (!usb_hcd_is_primary_hcd(hcd)) {
|
||||
/* usb core will free this hcd shortly, unset pointer */
|
||||
xhci->shared_hcd = NULL;
|
||||
mutex_unlock(&xhci->mutex);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1680,7 +1680,7 @@ struct xhci_bus_state {
|
|||
* It can take up to 20 ms to transition from RExit to U0 on the
|
||||
* 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)
|
||||
{
|
||||
|
@ -1849,6 +1849,7 @@ struct xhci_hcd {
|
|||
#define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31)
|
||||
#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)
|
||||
|
||||
unsigned int num_active_eps;
|
||||
unsigned int limit_active_eps;
|
||||
|
|
|
@ -50,6 +50,7 @@ static const struct usb_device_id appledisplay_table[] = {
|
|||
{ APPLEDISPLAY_DEVICE(0x9219) },
|
||||
{ APPLEDISPLAY_DEVICE(0x921c) },
|
||||
{ APPLEDISPLAY_DEVICE(0x921d) },
|
||||
{ APPLEDISPLAY_DEVICE(0x9222) },
|
||||
{ APPLEDISPLAY_DEVICE(0x9236) },
|
||||
|
||||
/* Terminating entry */
|
||||
|
|
|
@ -66,4 +66,7 @@
|
|||
/* Device needs a pause after every control message. */
|
||||
#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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче