Commit cffb9be8 authored by Hans de Goede's avatar Hans de Goede Committed by Greg Kroah-Hartman

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: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f85c9fb6
...@@ -1904,7 +1904,7 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci, ...@@ -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); start_dma = xhci_trb_virt_to_dma(input_seg, start_trb);
end_dma = xhci_trb_virt_to_dma(input_seg, end_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) { if (seg != result_seg) {
xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n", xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n",
test_name, test_number); test_name, test_number);
...@@ -1918,6 +1918,8 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci, ...@@ -1918,6 +1918,8 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
end_trb, end_dma); end_trb, end_dma);
xhci_warn(xhci, "Expected seg %p, got seg %p\n", xhci_warn(xhci, "Expected seg %p, got seg %p\n",
result_seg, seg); result_seg, seg);
trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma,
true);
return -1; return -1;
} }
return 0; return 0;
......
...@@ -1660,10 +1660,12 @@ static void handle_port_status(struct xhci_hcd *xhci, ...@@ -1660,10 +1660,12 @@ static void handle_port_status(struct xhci_hcd *xhci,
* TRB in this TD, this function returns that TRB's segment. Otherwise it * TRB in this TD, this function returns that TRB's segment. Otherwise it
* returns 0. * 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 *start_trb,
union xhci_trb *end_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 start_dma;
dma_addr_t end_seg_dma; dma_addr_t end_seg_dma;
...@@ -1682,6 +1684,15 @@ struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, ...@@ -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 */ /* 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); 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) { if (end_trb_dma > 0) {
/* The end TRB is in this segment, so suspect should be here */ /* The end TRB is in this segment, so suspect should be here */
if (start_dma <= end_trb_dma) { if (start_dma <= end_trb_dma) {
...@@ -2414,8 +2425,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -2414,8 +2425,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td_num--; td_num--;
/* Is this a TRB in the currently executing TD? */ /* Is this a TRB in the currently executing TD? */
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, event_seg = trb_in_td(xhci, ep_ring->deq_seg, ep_ring->dequeue,
td->last_trb, event_dma); td->last_trb, event_dma, false);
/* /*
* Skip the Force Stopped Event. The event_trb(event_dma) of FSE * 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, ...@@ -2447,7 +2458,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* HC is busted, give up! */ /* HC is busted, give up! */
xhci_err(xhci, xhci_err(xhci,
"ERROR Transfer event TRB DMA ptr not " "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; return -ESHUTDOWN;
} }
......
...@@ -1804,9 +1804,9 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); ...@@ -1804,9 +1804,9 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
/* xHCI ring, segment, TRB, and TD functions */ /* xHCI ring, segment, TRB, and TD functions */
dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); 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, struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
union xhci_trb *start_trb, union xhci_trb *end_trb, struct xhci_segment *start_seg, union xhci_trb *start_trb,
dma_addr_t suspect_dma); 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); int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
void xhci_ring_cmd_db(struct xhci_hcd *xhci); void xhci_ring_cmd_db(struct xhci_hcd *xhci);
int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd, int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd,
......
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