From cffb9be80f8a6d51d025780864c781ba83541720 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 Aug 2014 16:41:51 +0300 Subject: [PATCH] xhci: Log extra info on "ERROR Transfer event TRB DMA ptr not part of current TD" Lately (with the use of uas / bulk-streams) we have been seeing several cases where this error triggers (which should never happen). Add some extra logging to make debugging these errors easier. Signed-off-by: Hans de Goede Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 4 +++- drivers/usb/host/xhci-ring.c | 26 +++++++++++++++++++++----- drivers/usb/host/xhci.h | 6 +++--- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8936211b161d..5cb3d7a10017 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1904,7 +1904,7 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci, start_dma = xhci_trb_virt_to_dma(input_seg, start_trb); end_dma = xhci_trb_virt_to_dma(input_seg, end_trb); - seg = trb_in_td(input_seg, start_trb, end_trb, input_dma); + seg = trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma, false); if (seg != result_seg) { xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n", test_name, test_number); @@ -1918,6 +1918,8 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci, end_trb, end_dma); xhci_warn(xhci, "Expected seg %p, got seg %p\n", result_seg, seg); + trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma, + true); return -1; } return 0; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 4e1c34f45b52..bc6fcbc16f61 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1660,10 +1660,12 @@ cleanup: * TRB in this TD, this function returns that TRB's segment. Otherwise it * returns 0. */ -struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, +struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, + struct xhci_segment *start_seg, union xhci_trb *start_trb, union xhci_trb *end_trb, - dma_addr_t suspect_dma) + dma_addr_t suspect_dma, + bool debug) { dma_addr_t start_dma; dma_addr_t end_seg_dma; @@ -1682,6 +1684,15 @@ struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, /* If the end TRB isn't in this segment, this is set to 0 */ end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb); + if (debug) + xhci_warn(xhci, + "Looking for event-dma %016llx trb-start %016llx trb-end %016llx seg-start %016llx seg-end %016llx\n", + (unsigned long long)suspect_dma, + (unsigned long long)start_dma, + (unsigned long long)end_trb_dma, + (unsigned long long)cur_seg->dma, + (unsigned long long)end_seg_dma); + if (end_trb_dma > 0) { /* The end TRB is in this segment, so suspect should be here */ if (start_dma <= end_trb_dma) { @@ -2414,8 +2425,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, td_num--; /* Is this a TRB in the currently executing TD? */ - event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, - td->last_trb, event_dma); + event_seg = trb_in_td(xhci, ep_ring->deq_seg, ep_ring->dequeue, + td->last_trb, event_dma, false); /* * Skip the Force Stopped Event. The event_trb(event_dma) of FSE @@ -2447,7 +2458,12 @@ static int handle_tx_event(struct xhci_hcd *xhci, /* HC is busted, give up! */ xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not " - "part of current TD\n"); + "part of current TD ep_index %d " + "comp_code %u\n", ep_index, + trb_comp_code); + trb_in_td(xhci, ep_ring->deq_seg, + ep_ring->dequeue, td->last_trb, + event_dma, true); return -ESHUTDOWN; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f4d12f6fcfe8..276fd8efd171 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1804,9 +1804,9 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); /* xHCI ring, segment, TRB, and TD functions */ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); -struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, - union xhci_trb *start_trb, union xhci_trb *end_trb, - dma_addr_t suspect_dma); +struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, + struct xhci_segment *start_seg, union xhci_trb *start_trb, + union xhci_trb *end_trb, dma_addr_t suspect_dma, bool debug); int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code); void xhci_ring_cmd_db(struct xhci_hcd *xhci); int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd, -- 2.20.1