Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/usb/host/xhci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_AVOID_DQ_ON_LINK;
xhci->quirks |= XHCI_VLI_TRB_CACHE_BUG;
xhci->quirks |= XHCI_VLI_SS_BULK_OUT_BUG;
xhci->quirks |= XHCI_VLI_HUB_TT_QUIRK;
}

if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
Expand Down
46 changes: 46 additions & 0 deletions drivers/usb/host/xhci-ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -3585,6 +3585,48 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
return 1;
}

static void xhci_vl805_hub_tt_quirk(struct xhci_hcd *xhci, struct urb *urb,
struct xhci_ring *ring)
{
struct list_head *tmp;
struct usb_device *udev = urb->dev;
unsigned int timeout = 0;
unsigned int single_td = 0;

/*
* Adding a TD to an Idle ring for a FS nonperiodic endpoint
* that is behind the internal hub's TT will run the risk of causing a
* downstream port babble if submitted late in uFrame 7.
* Wait until we've moved on into at least uFrame 0
* (MFINDEX references the next SOF to be transmitted).
*
* Rings for IN endpoints in the Running state also risk causing
* babble if the returned data is large, but there's not much we can do
* about it here.
*/
if (udev->route & 0xffff0 || udev->speed != USB_SPEED_FULL)
return;

list_for_each(tmp, &ring->td_list) {
single_td++;
if (single_td == 2) {
single_td = 0;
break;
}
}
if (single_td) {
while (timeout < 20 &&
(readl(&xhci->run_regs->microframe_index) & 0x7) == 0) {
udelay(10);
timeout++;
}
if (timeout >= 20)
xhci_warn(xhci, "MFINDEX didn't advance - %u.%u dodged\n",
readl(&xhci->run_regs->microframe_index) >> 3,
readl(&xhci->run_regs->microframe_index) & 7);
}
}

/* This is very similar to what ehci-q.c qtd_fill() does */
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
Expand Down Expand Up @@ -3753,6 +3795,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
}

check_trb_math(urb, enqd_len);
if (xhci->quirks & XHCI_VLI_HUB_TT_QUIRK)
xhci_vl805_hub_tt_quirk(xhci, urb, ring);
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
Expand Down Expand Up @@ -3888,6 +3932,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Event on completion */
field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);

if (xhci->quirks & XHCI_VLI_HUB_TT_QUIRK)
xhci_vl805_hub_tt_quirk(xhci, urb, ep_ring);
giveback_first_trb(xhci, slot_id, ep_index, 0,
start_cycle, start_trb);
return 0;
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/host/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,7 @@ struct xhci_hcd {
#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(45)
#define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(46)
#define XHCI_VLI_SS_BULK_OUT_BUG BIT_ULL(47)
#define XHCI_VLI_HUB_TT_QUIRK BIT_ULL(48)

unsigned int num_active_eps;
unsigned int limit_active_eps;
Expand Down