* 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:
parent
886b38122b
commit
77660b03e8
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue