XHCI: add some docs after a chat with waddlesplash.
Better than nothing, but quite likely very incomplete. Change-Id: I9c0399d9da3851689bdddce98647a43e8d1e4ccf Reviewed-on: https://review.haiku-os.org/c/haiku/+/1540 Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
bd514095bb
commit
25f1ddecf7
@@ -0,0 +1,47 @@
|
|||||||
|
anyway, here's the summary of XHCI stuff:
|
||||||
|
- XHCI operates in units of "TRBs", which consist of a pointer and two 32-bit
|
||||||
|
fields holding varying types of data based on the TRB type. A "normal" type
|
||||||
|
TRB usually has a pointer to a physical buffer and then in one of the fields,
|
||||||
|
an indicator of how many bytes are stored there
|
||||||
|
- XHCI concept of "rings" is not, as you might expect, circular buffers.
|
||||||
|
Instead, it uses "Link TRBs", that is, a TRB in which the pointer field
|
||||||
|
points to the next place the hardware should read TRBs from, and it will do
|
||||||
|
so until hitting another Link TRB, etc. So it is in fact more like a linked
|
||||||
|
list. This allows easier management of the event queue, there is no need for
|
||||||
|
a fixed size ring, managing edge cases when the buffer wraps around, etc.
|
||||||
|
|
||||||
|
The way we handle transfers in the XHCI driver is:
|
||||||
|
- We allocate a "ring" of a small fixed amount for each endpoint (currently,
|
||||||
|
defined as XHCI_MAX_TRANSFERS*2+1, because we need 2 TRBs on the "ring" for
|
||||||
|
each transfer, and 1 at the end for the link to go back to the beginning)
|
||||||
|
- When the stack calls SubmitTransfer(), we allocate a new run of TRBs to
|
||||||
|
handle this transfer, and populate them with all the data. Then we insert one
|
||||||
|
Link TRB on the endpoint ring pointing to the first in the "transfer ring" we
|
||||||
|
just made, a link TRB at the end of the "transfer ring" pointing back to the
|
||||||
|
"endpoint ring", and then an "Event Status" TRB on the "endpoint ring" which
|
||||||
|
tells the XHCI to send an event back to us to tell us the transfer is done
|
||||||
|
- For easier tracking, the driver also keeps a TD (transfer descriptor), which
|
||||||
|
is a sideband structure not sent to the hardware, but used to keep track of
|
||||||
|
the TRBs in a given endpoint ring.
|
||||||
|
|
||||||
|
So under normal circumstances (i.e. all transfers submitted are successful), we
|
||||||
|
will get back only "Event" TRBs generated by the "Event Data" TRBs from the
|
||||||
|
"endpoint ring"s, and these will tell us what transfer they correspond to, we
|
||||||
|
will notify it as successful, and all is well.
|
||||||
|
|
||||||
|
If a transfer fails, then XHCI will generate an event that does *not*
|
||||||
|
correspond to an Event Status TRB (src/add-ons/kernel/busses/usb/xhci.cpp#L2372).
|
||||||
|
The pointer field in this TRB will point to the TRB that caused XHCI to
|
||||||
|
generate the event (i.e. the failed TRB), and so we look through the transfers
|
||||||
|
in progress on this endpoint and try to find which one corresponds to that TRB.
|
||||||
|
|
||||||
|
However, it seems in your case we are failing to find it, and so we get a
|
||||||
|
"TRB xxxx was not found in the endpoint!"
|
||||||
|
Most likely this TRB is on the "endpoint ring" itself. However as noted before,
|
||||||
|
only 2 TRBs for each transfer are actually on the endpoint ring: the Link TRB
|
||||||
|
going to the "transfer ring", and the Event Data TRB telling XHCI to fire an
|
||||||
|
interrupt.
|
||||||
|
|
||||||
|
Valid Link TRBs should never fail to execute; and to my knowledge Event Data
|
||||||
|
TRBs should not either.
|
||||||
|
|
||||||
Reference in New Issue
Block a user