Re: some question about xhci skip_isoc_td

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 06/24/2014 05:01 PM, vichy wrote:
> hi Mathias:
> 2014-06-24 16:38 GMT+08:00 Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>:
>> On 06/23/2014 03:44 PM, David Laight wrote:
>>> From: vichy
>>>> hi all:
>>>> when i trace xhci source, I found in skip_isoc_td, there is a
>>>> possibility to increase de-queue pointer twice.
>>>>
>>>> in skip_isoc_td:
>>>>       /* Update ring dequeue pointer */
>>>>         while (ep_ring->dequeue != td->last_trb)
>>>>                 inc_deq(xhci, ep_ring);
>>>>         inc_deq(xhci, ep_ring);
>>>>
>>>> why (ep_ring->dequeue != td->last_trb) we have to increase the dequeue pointer?
>>>> I try to find any description in spec about this but in vain.
>>>> is there any special reason to do so?
>>>
>>> An isoc transfer can consist of a lot of TRB.
>>> The code wants to skip all of them.
>>> I suspect there are faster ways to achieve the same effect!
>>>
>>
>> As David says, the inc_dec() in the while loop will move the dequeue pointer to the last TRB of that TD.
>> The additional inc_deq() then moves it to the next TD, (or to enqueue if no more TDs are on the endpoint ring)
>>
>> section 4.10.1 in xhci specification has some info on this:
>>
>> "If a Missed Service Error occurs on
> did "Missed Service Error occurs" you mean is when we cannot find
> match ep_dequeue_seg which contain event_buffer?
> like the below code in handle_tx_event:
> if (!event_seg) {
> .......................

I took a look at how we handle missed service errors.
I don't now where the fault is yet, but this is how it should work;

Basically when we get a missed service error (case MISSED_INT) we mark that endpoint to later skip
all its queued TDs the next time the endpoint gets a transfer event. 

case COMP_MISSED_INT:
  ep->skip = true;
  goto cleanup; 
  ...  // nothing interesing   
  return;

At the EP's next transfer event the ep->skip flag is true, so we count the number of TDs that EP has queued,
and start cleaning them out. Once we're done with them all we set the ep->skip to false, and goto cleanup, and return.

For the error message you are seeing to trigger the dequeue pointer trb can't be a part
of the TD picked from ep_ring->td_list, and the skip flag is cleared, (or ep is not an isoc) 

if (!event_seg) {
  if (!ep->skip || !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
    xhci_err(..)

But if we're in the process of skipping TDs then the error codepath can't be reached for isoc endpoints because
after ep->skip flag is cleared we goto cleanup and return.

Could you add some debugging to show each time we touch ep->skip in handle_tx_event().
Such as in case COMP_MISSED_INT, and later in the do{}while loop
This way we can se if it's related to skipping TDs at all.

It might also be that its the ring expansion somehow races with the transfer events and messes up pointers.

Did you update to a newer kernel version than 3.8 you first triggered this with?

-Mathias


 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux