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:
Adrien Destugues
2020-07-19 08:07:48 +00:00
committed by Adrien Destugues
parent bd514095bb
commit 25f1ddecf7
+47
View File
@@ -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.