[haiku-commits] haiku: hrev50454 - src/add-ons/kernel/busses/usb

  • From: jerome.duval@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 27 Jul 2016 21:48:52 +0200 (CEST)

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,


Other related posts:

  • » [haiku-commits] haiku: hrev50454 - src/add-ons/kernel/busses/usb - jerome . duval