* threshold higher bit means a full frame. Also use the threshold for micro frames instead of frames.

* introduces fNextStartingFrame to keep track of the next frame to use on next submit.
* set the IOC bit for the last ITD
* computes multiply field of the ITD based on the packed size (1, 2 or 3).
* use locking around linking of ITD
* free descriptors on errors
* on finishing, whenever a non success status is found, set actual length to zero
* on finishing, when copying data to the Transfer object, copy starting on packet boundaries (skipping unused bytes).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42679 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2011-08-23 18:36:57 +00:00
parent 886b38122b
commit 77660b03e8
3 changed files with 69 additions and 20 deletions

View File

@ -123,6 +123,7 @@ EHCI::EHCI(pci_info *info, Stack *stack)
fCleanupSem(-1),
fCleanupThread(-1),
fStopThreads(false),
fNextStartingFrame(-1),
fFrameBandwidth(NULL),
fFirstIsochronousTransfer(NULL),
fLastIsochronousTransfer(NULL),
@ -221,6 +222,11 @@ EHCI::EHCI(pci_info *info, Stack *stack)
TRACE("structural parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCSPARAMS));
TRACE("capability parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCCPARAMS));
if (EHCI_HCCPARAMS_FRAME_CACHE(ReadCapReg32(EHCI_HCCPARAMS)))
fThreshold = 2 + 8;
else
fThreshold = 2 + EHCI_HCCPARAMS_IPT(ReadCapReg32(EHCI_HCCPARAMS));
// read port count from capability register
fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
@ -730,24 +736,26 @@ EHCI::SubmitIsochronous(Transfer *transfer)
if (isochronousData->flags & USB_ISO_ASAP ||
isochronousData->starting_frame_number == NULL) {
uint32 threshold = (ReadCapReg32(EHCI_HCCPARAMS)
>> EHCI_HCCPARAMS_IPT_SHIFT) & EHCI_HCCPARAMS_IPT_MASK;
TRACE("threshold: %ld\n", threshold);
if (fFirstIsochronousTransfer != NULL && fNextStartingFrame != -1)
currentFrame = fNextStartingFrame;
else {
uint32 threshold = fThreshold;
TRACE("threshold: %ld\n", threshold);
// find the first available frame with enough bandwidth.
// This should always be the case, as defining the starting frame
// number in the driver makes no sense for many reason, one of which
// is that frame numbers value are host controller specific, and the
// driver does not know which host controller is running.
currentFrame = (ReadOpReg(EHCI_FRINDEX) / 8)
& (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
// find the first available frame with enough bandwidth.
// This should always be the case, as defining the starting frame
// number in the driver makes no sense for many reason, one of which
// is that frame numbers value are host controller specific, and the
// driver does not know which host controller is running.
currentFrame = ((ReadOpReg(EHCI_FRINDEX) + threshold) / 8)
& (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
}
// Make sure that:
// 1. We are at least 5ms ahead the controller
// 2. We stay in the range 0-127
// 3. There is enough bandwidth in the first entry
currentFrame = (currentFrame + threshold)
& (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
currentFrame &= EHCI_VFRAMELIST_ENTRIES_COUNT - 1;
} else {
// Find out if the frame number specified has enough bandwidth,
// otherwise find the first next available frame with enough bandwidth
@ -762,6 +770,7 @@ EHCI::SubmitIsochronous(Transfer *transfer)
addr_t bufferPhy;
if (fStack->AllocateChunk(&bufferLog, (void**)&bufferPhy, dataLength) < B_OK) {
TRACE_ERROR("unable to allocate itd buffer\n");
delete isoRequest;
return B_NO_MEMORY;
}
@ -791,6 +800,8 @@ EHCI::SubmitIsochronous(Transfer *transfer)
itd->buffer_phy[pg + 1] = currentPhy & 0xfffff000;
pg++;
}
if (dataLength <= 0)
itd->token[i] |= EHCI_ITD_IOC;
}
currentPhy += (offset & 0xfff) - (currentPhy & 0xfff);
@ -799,12 +810,17 @@ EHCI::SubmitIsochronous(Transfer *transfer)
| (pipe->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT);
itd->buffer_phy[1] |= (pipe->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK)
| (directionIn << EHCI_ITD_DIR_SHIFT);
itd->buffer_phy[2] |= (1 << EHCI_ITD_MUL_SHIFT);
itd->buffer_phy[2] |=
((((pipe->MaxPacketSize() >> EHCI_ITD_MAXPACKETSIZE_LENGTH) + 1)
& EHCI_ITD_MUL_MASK) << EHCI_ITD_MUL_SHIFT);
TRACE("isochronous filled itd buffer_phy[0,1,2] 0x%lx, 0x%lx 0x%lx\n",
itd->buffer_phy[0], itd->buffer_phy[1], itd->buffer_phy[2]);
if (!LockIsochronous())
continue;
LinkITDescriptors(itd, &fItdEntries[currentFrame]);
UnlockIsochronous();
fFrameBandwidth[currentFrame] -= bandwidth;
currentFrame = (currentFrame + 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
frameCount++;
@ -818,11 +834,15 @@ EHCI::SubmitIsochronous(Transfer *transfer)
transfer->DataLength());
if (result < B_OK) {
TRACE_ERROR("failed to add pending isochronous transfer\n");
for (uint32 i = 0; i < itdIndex; i++)
FreeDescriptor(isoRequest[i]);
delete isoRequest;
return result;
}
TRACE("appended isochronous transfer by starting at frame number %d\n",
currentFrame);
fNextStartingFrame = currentFrame + 1;
// Wake up the isochronous finisher thread
release_sem_etc(fFinishIsochronousTransfersSem, 1 /*frameCount*/, B_DO_NOT_RESCHEDULE);
@ -2146,7 +2166,8 @@ EHCI::FreeDescriptor(ehci_qtd *descriptor)
(void *)descriptor->buffer_phy[0], descriptor->buffer_size);
}
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_qtd));
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy,
sizeof(ehci_qtd));
}
@ -2208,7 +2229,8 @@ EHCI::FreeDescriptor(ehci_itd *descriptor)
if (!descriptor)
return;
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_itd));
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy,
sizeof(ehci_itd));
}
@ -2218,7 +2240,8 @@ EHCI::FreeDescriptor(ehci_sitd *descriptor)
if (!descriptor)
return;
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_sitd));
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy,
sizeof(ehci_sitd));
}
@ -2372,7 +2395,8 @@ EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
if (vectorOffset >= vector[vectorIndex].iov_len) {
if (++vectorIndex >= vectorCount) {
TRACE("read descriptor chain (%ld bytes, no more vectors)\n", actualLength);
TRACE("read descriptor chain (%ld bytes, no more vectors)"
"\n", actualLength);
*nextDataToggle = dataToggle > 0 ? true : false;
return actualLength;
}
@ -2437,7 +2461,6 @@ EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
{
iovec *vector = transfer->transfer->Vector();
size_t vectorCount = transfer->transfer->VectorCount();
size_t vectorOffset = 0;
size_t vectorIndex = 0;
usb_isochronous_data *isochronousData
@ -2456,6 +2479,10 @@ EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
size_t bufferSize = (itd->token[j] >> EHCI_ITD_TLENGTH_SHIFT)
& EHCI_ITD_TLENGTH_MASK;
if (((itd->token[j] >> EHCI_ITD_STATUS_SHIFT)
& EHCI_ITD_STATUS_MASK) != 0) {
bufferSize = 0;
}
isochronousData->packet_descriptors[packet].actual_length =
bufferSize;
@ -2467,6 +2494,7 @@ EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
totalLength += bufferSize;
size_t offset = bufferOffset;
size_t skipSize = packetSize - bufferSize;
while (bufferSize > 0) {
size_t length = min_c(bufferSize,
vector[vectorIndex].iov_len - vectorOffset);
@ -2487,6 +2515,23 @@ EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
}
}
// skip to next packet offset
while (skipSize > 0) {
size_t length = min_c(skipSize,
vector[vectorIndex].iov_len - vectorOffset);
vectorOffset += length;
skipSize -= length;
if (vectorOffset >= vector[vectorIndex].iov_len) {
if (++vectorIndex >= vectorCount) {
TRACE("read isodescriptor chain (%ld bytes, no more "
"vectors)\n", totalLength);
return totalLength;
}
vectorOffset = 0;
}
}
bufferOffset += packetSize;
if (bufferOffset >= transfer->buffer_size)
return totalLength;

View File

@ -195,6 +195,7 @@ static pci_module_info * sPCIModule;
pci_info * fPCIInfo;
Stack * fStack;
uint32 fEnabledInterrupts;
uint32 fThreshold;
// Periodic transfer framelist and interrupt entries
area_id fPeriodicFrameListArea;
@ -218,6 +219,7 @@ static pci_module_info * sPCIModule;
sem_id fCleanupSem;
thread_id fCleanupThread;
bool fStopThreads;
int32 fNextStartingFrame;
// fFrameBandwidth[n] holds the available bandwidth
// of the nth frame in microseconds

View File

@ -112,8 +112,8 @@
#define EHCI_HCCPARAMS_PPCEC (1 << 18) // Per-Port Change Event
#define EHCI_HCCPARAMS_LPM (1 << 17) // Link Power Management
#define EHCI_HCCPARAMS_HP (1 << 16) // Hardware Prefetch
#define EHCI_HCCPARAMS_IPT_SHIFT 4 // Isochronous Periodic Threshold
#define EHCI_HCCPARAMS_IPT_MASK 0xf
#define EHCI_HCCPARAMS_FRAME_CACHE(x) ((x >> 7) & 0x1) // Isochronous Periodic Threshold
#define EHCI_HCCPARAMS_IPT(x) ((x >> 4) & 0x7) // Isochronous Periodic Threshold
// Data Structures (EHCI Spec 3)
@ -161,10 +161,12 @@ typedef struct ehci_itd {
#define EHCI_ITD_ENDPOINT_MASK 0xf
#define EHCI_ITD_DIR_SHIFT 11
#define EHCI_ITD_MUL_SHIFT 0
#define EHCI_ITD_MUL_MASK 0x3
#define EHCI_ITD_BUFFERPOINTER_SHIFT 12
#define EHCI_ITD_BUFFERPOINTER_MASK 0xfffff
#define EHCI_ITD_MAXPACKETSIZE_SHIFT 0
#define EHCI_ITD_MAXPACKETSIZE_MASK 0x7ff
#define EHCI_ITD_MAXPACKETSIZE_LENGTH 11
// Split Transaction Isochronous Transfer Descriptors (siTD, EHCI Spec 3.3)