hrev50454 adds 1 changeset to branch 'master'
old head: 1646f49791b360b46fb70125e6c4a9563298b668
new head: 8a12a74e81e7969b2b963f95bb27779b80dc9ad4
overview:
http://cgit.haiku-os.org/haiku/log/?qt=range&q=8a12a74e81e7+%5E1646f49791b3
----------------------------------------------------------------------------
8a12a74e81e7: XHCI: fix KDL for transfers using more than 1TD.
* TD chains were broken, any transfer above ~1MB would trigger a KDL.
* _LinkDescriptorForPipe() links the last TD of the chain instead of the
first.
* Still buggy: the transfer ring can still block and transfers then fail.
* Enable TRB_3_ISP_BIT where appropriate (Interrupt on Short Packet).
* Also fix WriteDescriptorChain() and ReadDescriptorChain() for multiple-TD
chains.
[ Jérôme Duval <jerome.duval@xxxxxxxxx> ]
----------------------------------------------------------------------------
Revision: hrev50454
Commit: 8a12a74e81e7969b2b963f95bb27779b80dc9ad4
URL: http://cgit.haiku-os.org/haiku/commit/?id=8a12a74e81e7
Author: Jérôme Duval <jerome.duval@xxxxxxxxx>
Date: Wed Jul 27 19:26:18 2016 UTC
----------------------------------------------------------------------------
2 files changed, 72 insertions(+), 36 deletions(-)
src/add-ons/kernel/busses/usb/xhci.cpp | 105 +++++++++++++++++++----------
src/add-ons/kernel/busses/usb/xhci.h | 3 +-
----------------------------------------------------------------------------
diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp
b/src/add-ons/kernel/busses/usb/xhci.cpp
index 764a6c7..7564ca1 100644
--- a/src/add-ons/kernel/busses/usb/xhci.cpp
+++ b/src/add-ons/kernel/busses/usb/xhci.cpp
@@ -614,7 +614,8 @@ XHCI::SubmitControlRequest(Transfer *transfer)
| TRB_2_BYTES(requestData->Length)
| TRB_2_TD_SIZE(transfer->VectorCount());
setupDescriptor->trbs[index].dwtrb3 =
TRB_3_TYPE(TRB_TYPE_DATA_STAGE)
- | (directionIn ? TRB_3_DIR_IN : 0) | TRB_3_CYCLE_BIT;
+ | (directionIn ? (TRB_3_DIR_IN | TRB_3_ISP_BIT) : 0)
+ | TRB_3_CYCLE_BIT;
// TODO copy data for out transfers
index++;
@@ -663,23 +664,44 @@ XHCI::SubmitNormalRequest(Transfer *transfer)
return B_BAD_VALUE;
bool directionIn = (pipe->Direction() == Pipe::In);
- xhci_td *descriptor = CreateDescriptorChain(transfer->DataLength());
+ int32 trbCount = 0;
+ xhci_td *descriptor = CreateDescriptorChain(transfer->DataLength(),
trbCount);
if (descriptor == NULL)
return B_NO_MEMORY;
- descriptor->trb_count = descriptor->buffer_count;
+
+ xhci_td *td_chain = descriptor;
+ xhci_td *last = descriptor;
+ int32 rest = trbCount - 1;
// set NormalStage
- uint8 index;
- for (index = 0; index < descriptor->buffer_count; index++) {
- descriptor->trbs[index].qwtrb0 = descriptor->buffer_phy[index];
- descriptor->trbs[index].dwtrb2 = TRB_2_IRQ(0)
- | TRB_2_BYTES(descriptor->buffer_size[index])
- | TRB_2_TD_SIZE(descriptor->trb_count);
- descriptor->trbs[index].dwtrb3 = TRB_3_TYPE(TRB_TYPE_NORMAL)
- | TRB_3_CYCLE_BIT;
+ 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];
+ td_chain->trbs[index].dwtrb2 = TRB_2_IRQ(0)
+ | TRB_2_BYTES(descriptor->buffer_size[index])
+ | TRB_2_TD_SIZE(rest);
+ td_chain->trbs[index].dwtrb3 =
TRB_3_TYPE(TRB_TYPE_NORMAL)
+ | TRB_3_CYCLE_BIT | TRB_3_CHAIN_BIT |
(directionIn ? TRB_3_ISP_BIT : 0);
+ rest--;
+ }
+ // link next td, if any
+ if (td_chain->next_chain != NULL) {
+ td_chain->trbs[td_chain->trb_count].qwtrb0 =
td_chain->next_chain->this_phy;
+ td_chain->trbs[td_chain->trb_count].dwtrb2 =
TRB_2_IRQ(0);
+ td_chain->trbs[td_chain->trb_count].dwtrb3 =
TRB_3_TYPE(TRB_TYPE_LINK)
+ | TRB_3_CYCLE_BIT | TRB_3_CHAIN_BIT;
+ }
+
+ last = td_chain;
+ td_chain = td_chain->next_chain;
+ }
+
+ if (last->trb_count > 0) {
+ last->trbs[last->trb_count - 1].dwtrb3 |= TRB_3_IOC_BIT;
+ last->trbs[last->trb_count - 1].dwtrb3 &= ~TRB_3_CHAIN_BIT;
}
- if (descriptor->trb_count > 0)
- descriptor->trbs[index - 1].dwtrb3 |= TRB_3_IOC_BIT;
if (!directionIn) {
TRACE("copying out iov count %ld\n", transfer->VectorCount());
@@ -826,10 +848,10 @@ XHCI::AddTo(Stack *stack)
xhci_td *
-XHCI::CreateDescriptorChain(size_t bufferSize)
+XHCI::CreateDescriptorChain(size_t bufferSize, int32 &trbCount)
{
size_t packetSize = B_PAGE_SIZE * 16;
- int32 trbCount = (bufferSize + packetSize - 1) / packetSize;
+ trbCount = (bufferSize + packetSize - 1) / packetSize;
// keep one trb for linking
int32 tdCount = (trbCount + XHCI_MAX_TRBS_PER_TD - 2)
/ (XHCI_MAX_TRBS_PER_TD - 1);
@@ -839,12 +861,13 @@ XHCI::CreateDescriptorChain(size_t bufferSize)
for (int32 i = 0; i < tdCount; i++) {
xhci_td *descriptor = CreateDescriptor(0);
if (!descriptor) {
- //FreeDescriptorChain(firstDescriptor);
+ if (first != NULL)
+ FreeDescriptor(first);
return NULL;
} else if (first == NULL)
first = descriptor;
- uint8 trbs = min_c(trbCount, XHCI_MAX_TRBS_PER_TD);
+ uint8 trbs = min_c(trbCount, 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],
@@ -888,6 +911,8 @@ XHCI::CreateDescriptor(size_t bufferSize)
result->buffer_size[0] = bufferSize;
result->trb_count = 0;
result->buffer_count = 1;
+ result->next = NULL;
+ result->next_chain = NULL;
if (bufferSize <= 0) {
result->buffer_log[0] = NULL;
result->buffer_phy[0] = 0;
@@ -902,6 +927,9 @@ XHCI::CreateDescriptor(size_t bufferSize)
return NULL;
}
+ TRACE("CreateDescriptor allocated buffer_size %ld %p\n",
+ result->buffer_size[0], result->buffer_log[0]);
+
return result;
}
@@ -909,20 +937,22 @@ XHCI::CreateDescriptor(size_t bufferSize)
void
XHCI::FreeDescriptor(xhci_td *descriptor)
{
- if (!descriptor)
- return;
+ while (descriptor != NULL) {
- for (int i = 0; i < descriptor->buffer_count; i++) {
- if (descriptor->buffer_size[i] == 0)
- continue;
- TRACE("FreeDescriptor buffer %d buffer_size %ld\n", i,
- descriptor->buffer_size[i]);
- fStack->FreeChunk(descriptor->buffer_log[i],
- descriptor->buffer_phy[i], descriptor->buffer_size[i]);
- }
+ for (int i = 0; i < descriptor->buffer_count; i++) {
+ if (descriptor->buffer_size[i] == 0)
+ continue;
+ TRACE("FreeDescriptor buffer %d buffer_size %ld %p\n",
i,
+ descriptor->buffer_size[i],
descriptor->buffer_log[i]);
+ fStack->FreeChunk(descriptor->buffer_log[i],
+ descriptor->buffer_phy[i],
descriptor->buffer_size[i]);
+ }
- fStack->FreeChunk(descriptor, descriptor->this_phy,
- sizeof(xhci_td));
+ xhci_td *next = descriptor->next_chain;
+ fStack->FreeChunk(descriptor, descriptor->this_phy,
+ sizeof(xhci_td));
+ descriptor = next;
+ }
}
@@ -966,9 +996,9 @@ XHCI::WriteDescriptorChain(xhci_td *descriptor, iovec
*vector,
}
if (bufferOffset >= current->buffer_size[trbIndex]) {
+ bufferOffset = 0;
if (++trbIndex >= current->buffer_count)
break;
- bufferOffset = 0;
}
}
@@ -1016,14 +1046,14 @@ XHCI::ReadDescriptorChain(xhci_td *descriptor, iovec
*vector,
actualLength);
return actualLength;
}
-
vectorOffset = 0;
+
}
if (bufferOffset >= current->buffer_size[trbIndex]) {
+ bufferOffset = 0;
if (++trbIndex >= current->buffer_count)
break;
- bufferOffset = 0;
}
}
@@ -1470,17 +1500,22 @@ XHCI::_LinkDescriptorForPipe(xhci_td *descriptor,
xhci_endpoint *endpoint)
TRACE("_LinkDescriptorForPipe current %d, next %d\n", current, next);
+ xhci_td *last = descriptor;
+ while (last->next_chain != NULL)
+ last = last->next_chain;
+
// compute next link
addr_t addr = endpoint->trb_addr + next * sizeof(struct xhci_trb);
- descriptor->trbs[descriptor->trb_count].qwtrb0 = addr;
- descriptor->trbs[descriptor->trb_count].dwtrb2 = TRB_2_IRQ(0);
- descriptor->trbs[descriptor->trb_count].dwtrb3 =
TRB_3_TYPE(TRB_TYPE_LINK)
+ last->trbs[last->trb_count].qwtrb0 = addr;
+ last->trbs[last->trb_count].dwtrb2 = TRB_2_IRQ(0);
+ last->trbs[last->trb_count].dwtrb3 = TRB_3_TYPE(TRB_TYPE_LINK)
| TRB_3_IOC_BIT | TRB_3_CYCLE_BIT;
endpoint->trbs[next].qwtrb0 = 0;
endpoint->trbs[next].dwtrb2 = 0;
endpoint->trbs[next].dwtrb3 = 0;
+ // link the descriptor
endpoint->trbs[current].qwtrb0 = descriptor->this_phy;
endpoint->trbs[current].dwtrb2 = TRB_2_IRQ(0);
endpoint->trbs[current].dwtrb3 = TRB_3_TYPE(TRB_TYPE_LINK)
diff --git a/src/add-ons/kernel/busses/usb/xhci.h
b/src/add-ons/kernel/busses/usb/xhci.h
index de84a82..1ad1e01 100644
--- a/src/add-ons/kernel/busses/usb/xhci.h
+++ b/src/add-ons/kernel/busses/usb/xhci.h
@@ -140,7 +140,8 @@ private:
// Descriptor
xhci_td * CreateDescriptor(size_t
bufferSize);
- xhci_td *
CreateDescriptorChain(size_t bufferSize);
+ xhci_td *
CreateDescriptorChain(size_t bufferSize,
+ int32
&trbCount);
void FreeDescriptor(xhci_td
*descriptor);
size_t
WriteDescriptorChain(xhci_td *descriptor,