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 <hdegoede@redhat.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
f85c9fb62c
commit
cffb9be80f
@@ -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,
|
|||||||
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 @@ cleanup:
|
|||||||
* 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,
|
|||||||
/* 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,
|
|||||||
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,
|
|||||||
/* 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);
|
|||||||
|
|
||||||
/* 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,
|
||||||
|
|||||||
Reference in New Issue
Block a user