From dc9a81f0d403e7b4ae195e6af76c8e4ede03aa21 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 4 Mar 2019 17:37:01 -0500 Subject: [PATCH] XHCI: Partially fix TD size computation. Previously we were sending the hardware completely garbage values, as CreateDescriptorChain clobbered the trbCount value it had set by using it to determine how many more TRBs it needed to allocate, and so it usually returned with the value set to 0. Then SubmitNormalRequest() would immediately subtract 1, causing it to become negative, and the loop would continue doing this, which also violated the spec's notice that the field should be 31 if its "true value" was >= 31, and of course 0 for the last TRB in the transfer. The spec also says this should be the number of packets remaining, not the number of TRBs remaining, which we also do not obey; but that will be a problem for another time, so just add a TODO. --- src/add-ons/kernel/busses/usb/xhci.cpp | 31 ++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index 715d1985e5..bcf3196fc1 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -790,7 +790,7 @@ XHCI::SubmitNormalRequest(Transfer *transfer) int32 trbCount = 0; xhci_td *descriptor = CreateDescriptorChain(transfer->DataLength(), - trbCount); + &trbCount); if (descriptor == NULL) return B_NO_MEMORY; @@ -798,15 +798,17 @@ XHCI::SubmitNormalRequest(Transfer *transfer) xhci_td *last = descriptor; int32 rest = trbCount - 1; - // set NormalStage + // Normal Stage while (td_chain != NULL) { td_chain->trb_count = td_chain->buffer_count; uint8 index; for (index = 0; index < td_chain->buffer_count; index++) { td_chain->trbs[index].qwtrb0 = descriptor->buffer_phy[index]; + // TODO: TD Size is actually supposed to be number of packets + // remaining, *not* number of TRBs remaining as it is presently. td_chain->trbs[index].dwtrb2 = TRB_2_IRQ(0) | TRB_2_BYTES(descriptor->buffer_size[index]) - | TRB_2_TD_SIZE(rest); + | TRB_2_TD_SIZE(rest > 31 ? 31 : rest); td_chain->trbs[index].dwtrb3 = B_HOST_TO_LENDIAN_INT32( TRB_3_TYPE(TRB_TYPE_NORMAL) | TRB_3_CYCLE_BIT | TRB_3_CHAIN_BIT | (directionIn ? TRB_3_ISP_BIT : 0)); @@ -935,29 +937,30 @@ XHCI::CreateDescriptor(size_t bufferSize) xhci_td * -XHCI::CreateDescriptorChain(size_t bufferSize, int32 &trbCount) +XHCI::CreateDescriptorChain(size_t bufferSize, int32 *trbCount) { size_t packetSize = B_PAGE_SIZE * 16; - trbCount = (bufferSize + packetSize - 1) / packetSize; - if (trbCount == 0) - trbCount = 1; + int32 trbsTotal = (bufferSize + packetSize - 1) / packetSize; + if (trbsTotal == 0) + trbsTotal = 1; + *trbCount = trbsTotal; // keep one trb for linking - int32 tdCount = (trbCount + XHCI_MAX_TRBS_PER_TD - 2) + int32 tdCount = (trbsTotal + XHCI_MAX_TRBS_PER_TD - 2) / (XHCI_MAX_TRBS_PER_TD - 1); xhci_td *first = NULL; xhci_td *last = NULL; for (int32 i = 0; i < tdCount; i++) { xhci_td *descriptor = CreateDescriptor(0); - if (!descriptor) { - if (first != NULL) - FreeDescriptor(first); + if (descriptor == NULL) { + FreeDescriptor(first); return NULL; - } else if (first == NULL) + } + if (first == NULL) first = descriptor; - uint8 trbs = min_c(trbCount, XHCI_MAX_TRBS_PER_TD - 1); + uint8 trbs = min_c(trbsTotal, XHCI_MAX_TRBS_PER_TD - 1); TRACE("CreateDescriptorChain trbs %d for td %" B_PRId32 "\n", trbs, i); for (int j = 0; j < trbs; j++) { if (fStack->AllocateChunk(&descriptor->buffer_log[j], @@ -975,7 +978,7 @@ XHCI::CreateDescriptorChain(size_t bufferSize, int32 &trbCount) } descriptor->buffer_count = trbs; - trbCount -= trbs; + trbsTotal -= trbs; if (last != NULL) last->next_chain = descriptor; last = descriptor;