* 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:
@@ -123,6 +123,7 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||||||
fCleanupSem(-1),
|
fCleanupSem(-1),
|
||||||
fCleanupThread(-1),
|
fCleanupThread(-1),
|
||||||
fStopThreads(false),
|
fStopThreads(false),
|
||||||
|
fNextStartingFrame(-1),
|
||||||
fFrameBandwidth(NULL),
|
fFrameBandwidth(NULL),
|
||||||
fFirstIsochronousTransfer(NULL),
|
fFirstIsochronousTransfer(NULL),
|
||||||
fLastIsochronousTransfer(NULL),
|
fLastIsochronousTransfer(NULL),
|
||||||
@@ -221,6 +222,11 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||||||
TRACE("structural parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCSPARAMS));
|
TRACE("structural parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCSPARAMS));
|
||||||
TRACE("capability parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCCPARAMS));
|
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
|
// read port count from capability register
|
||||||
fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
|
fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
|
||||||
|
|
||||||
@@ -730,24 +736,26 @@ EHCI::SubmitIsochronous(Transfer *transfer)
|
|||||||
if (isochronousData->flags & USB_ISO_ASAP ||
|
if (isochronousData->flags & USB_ISO_ASAP ||
|
||||||
isochronousData->starting_frame_number == NULL) {
|
isochronousData->starting_frame_number == NULL) {
|
||||||
|
|
||||||
uint32 threshold = (ReadCapReg32(EHCI_HCCPARAMS)
|
if (fFirstIsochronousTransfer != NULL && fNextStartingFrame != -1)
|
||||||
>> EHCI_HCCPARAMS_IPT_SHIFT) & EHCI_HCCPARAMS_IPT_MASK;
|
currentFrame = fNextStartingFrame;
|
||||||
TRACE("threshold: %ld\n", threshold);
|
else {
|
||||||
|
uint32 threshold = fThreshold;
|
||||||
|
TRACE("threshold: %ld\n", threshold);
|
||||||
|
|
||||||
// find the first available frame with enough bandwidth.
|
// find the first available frame with enough bandwidth.
|
||||||
// This should always be the case, as defining the starting frame
|
// This should always be the case, as defining the starting frame
|
||||||
// number in the driver makes no sense for many reason, one of which
|
// number in the driver makes no sense for many reason, one of which
|
||||||
// is that frame numbers value are host controller specific, and the
|
// is that frame numbers value are host controller specific, and the
|
||||||
// driver does not know which host controller is running.
|
// driver does not know which host controller is running.
|
||||||
currentFrame = (ReadOpReg(EHCI_FRINDEX) / 8)
|
currentFrame = ((ReadOpReg(EHCI_FRINDEX) + threshold) / 8)
|
||||||
& (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
|
& (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure that:
|
// Make sure that:
|
||||||
// 1. We are at least 5ms ahead the controller
|
// 1. We are at least 5ms ahead the controller
|
||||||
// 2. We stay in the range 0-127
|
// 2. We stay in the range 0-127
|
||||||
// 3. There is enough bandwidth in the first entry
|
// 3. There is enough bandwidth in the first entry
|
||||||
currentFrame = (currentFrame + threshold)
|
currentFrame &= EHCI_VFRAMELIST_ENTRIES_COUNT - 1;
|
||||||
& (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
|
|
||||||
} else {
|
} else {
|
||||||
// Find out if the frame number specified has enough bandwidth,
|
// Find out if the frame number specified has enough bandwidth,
|
||||||
// otherwise find the first next available frame with enough bandwidth
|
// otherwise find the first next available frame with enough bandwidth
|
||||||
@@ -762,6 +770,7 @@ EHCI::SubmitIsochronous(Transfer *transfer)
|
|||||||
addr_t bufferPhy;
|
addr_t bufferPhy;
|
||||||
if (fStack->AllocateChunk(&bufferLog, (void**)&bufferPhy, dataLength) < B_OK) {
|
if (fStack->AllocateChunk(&bufferLog, (void**)&bufferPhy, dataLength) < B_OK) {
|
||||||
TRACE_ERROR("unable to allocate itd buffer\n");
|
TRACE_ERROR("unable to allocate itd buffer\n");
|
||||||
|
delete isoRequest;
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,6 +800,8 @@ EHCI::SubmitIsochronous(Transfer *transfer)
|
|||||||
itd->buffer_phy[pg + 1] = currentPhy & 0xfffff000;
|
itd->buffer_phy[pg + 1] = currentPhy & 0xfffff000;
|
||||||
pg++;
|
pg++;
|
||||||
}
|
}
|
||||||
|
if (dataLength <= 0)
|
||||||
|
itd->token[i] |= EHCI_ITD_IOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPhy += (offset & 0xfff) - (currentPhy & 0xfff);
|
currentPhy += (offset & 0xfff) - (currentPhy & 0xfff);
|
||||||
@@ -799,12 +810,17 @@ EHCI::SubmitIsochronous(Transfer *transfer)
|
|||||||
| (pipe->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT);
|
| (pipe->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT);
|
||||||
itd->buffer_phy[1] |= (pipe->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK)
|
itd->buffer_phy[1] |= (pipe->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK)
|
||||||
| (directionIn << EHCI_ITD_DIR_SHIFT);
|
| (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",
|
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]);
|
itd->buffer_phy[0], itd->buffer_phy[1], itd->buffer_phy[2]);
|
||||||
|
|
||||||
|
if (!LockIsochronous())
|
||||||
|
continue;
|
||||||
LinkITDescriptors(itd, &fItdEntries[currentFrame]);
|
LinkITDescriptors(itd, &fItdEntries[currentFrame]);
|
||||||
|
UnlockIsochronous();
|
||||||
fFrameBandwidth[currentFrame] -= bandwidth;
|
fFrameBandwidth[currentFrame] -= bandwidth;
|
||||||
currentFrame = (currentFrame + 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
|
currentFrame = (currentFrame + 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
|
||||||
frameCount++;
|
frameCount++;
|
||||||
@@ -818,11 +834,15 @@ EHCI::SubmitIsochronous(Transfer *transfer)
|
|||||||
transfer->DataLength());
|
transfer->DataLength());
|
||||||
if (result < B_OK) {
|
if (result < B_OK) {
|
||||||
TRACE_ERROR("failed to add pending isochronous transfer\n");
|
TRACE_ERROR("failed to add pending isochronous transfer\n");
|
||||||
|
for (uint32 i = 0; i < itdIndex; i++)
|
||||||
|
FreeDescriptor(isoRequest[i]);
|
||||||
|
delete isoRequest;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("appended isochronous transfer by starting at frame number %d\n",
|
TRACE("appended isochronous transfer by starting at frame number %d\n",
|
||||||
currentFrame);
|
currentFrame);
|
||||||
|
fNextStartingFrame = currentFrame + 1;
|
||||||
|
|
||||||
// Wake up the isochronous finisher thread
|
// Wake up the isochronous finisher thread
|
||||||
release_sem_etc(fFinishIsochronousTransfersSem, 1 /*frameCount*/, B_DO_NOT_RESCHEDULE);
|
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);
|
(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)
|
if (!descriptor)
|
||||||
return;
|
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)
|
if (!descriptor)
|
||||||
return;
|
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 (vectorOffset >= vector[vectorIndex].iov_len) {
|
||||||
if (++vectorIndex >= vectorCount) {
|
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;
|
*nextDataToggle = dataToggle > 0 ? true : false;
|
||||||
return actualLength;
|
return actualLength;
|
||||||
}
|
}
|
||||||
@@ -2437,7 +2461,6 @@ EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
|
|||||||
{
|
{
|
||||||
iovec *vector = transfer->transfer->Vector();
|
iovec *vector = transfer->transfer->Vector();
|
||||||
size_t vectorCount = transfer->transfer->VectorCount();
|
size_t vectorCount = transfer->transfer->VectorCount();
|
||||||
|
|
||||||
size_t vectorOffset = 0;
|
size_t vectorOffset = 0;
|
||||||
size_t vectorIndex = 0;
|
size_t vectorIndex = 0;
|
||||||
usb_isochronous_data *isochronousData
|
usb_isochronous_data *isochronousData
|
||||||
@@ -2456,6 +2479,10 @@ EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
|
|||||||
|
|
||||||
size_t bufferSize = (itd->token[j] >> EHCI_ITD_TLENGTH_SHIFT)
|
size_t bufferSize = (itd->token[j] >> EHCI_ITD_TLENGTH_SHIFT)
|
||||||
& EHCI_ITD_TLENGTH_MASK;
|
& 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 =
|
isochronousData->packet_descriptors[packet].actual_length =
|
||||||
bufferSize;
|
bufferSize;
|
||||||
|
|
||||||
@@ -2467,6 +2494,7 @@ EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
|
|||||||
totalLength += bufferSize;
|
totalLength += bufferSize;
|
||||||
|
|
||||||
size_t offset = bufferOffset;
|
size_t offset = bufferOffset;
|
||||||
|
size_t skipSize = packetSize - bufferSize;
|
||||||
while (bufferSize > 0) {
|
while (bufferSize > 0) {
|
||||||
size_t length = min_c(bufferSize,
|
size_t length = min_c(bufferSize,
|
||||||
vector[vectorIndex].iov_len - vectorOffset);
|
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;
|
bufferOffset += packetSize;
|
||||||
if (bufferOffset >= transfer->buffer_size)
|
if (bufferOffset >= transfer->buffer_size)
|
||||||
return totalLength;
|
return totalLength;
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ static pci_module_info * sPCIModule;
|
|||||||
pci_info * fPCIInfo;
|
pci_info * fPCIInfo;
|
||||||
Stack * fStack;
|
Stack * fStack;
|
||||||
uint32 fEnabledInterrupts;
|
uint32 fEnabledInterrupts;
|
||||||
|
uint32 fThreshold;
|
||||||
|
|
||||||
// Periodic transfer framelist and interrupt entries
|
// Periodic transfer framelist and interrupt entries
|
||||||
area_id fPeriodicFrameListArea;
|
area_id fPeriodicFrameListArea;
|
||||||
@@ -218,6 +219,7 @@ static pci_module_info * sPCIModule;
|
|||||||
sem_id fCleanupSem;
|
sem_id fCleanupSem;
|
||||||
thread_id fCleanupThread;
|
thread_id fCleanupThread;
|
||||||
bool fStopThreads;
|
bool fStopThreads;
|
||||||
|
int32 fNextStartingFrame;
|
||||||
|
|
||||||
// fFrameBandwidth[n] holds the available bandwidth
|
// fFrameBandwidth[n] holds the available bandwidth
|
||||||
// of the nth frame in microseconds
|
// of the nth frame in microseconds
|
||||||
|
|||||||
@@ -112,8 +112,8 @@
|
|||||||
#define EHCI_HCCPARAMS_PPCEC (1 << 18) // Per-Port Change Event
|
#define EHCI_HCCPARAMS_PPCEC (1 << 18) // Per-Port Change Event
|
||||||
#define EHCI_HCCPARAMS_LPM (1 << 17) // Link Power Management
|
#define EHCI_HCCPARAMS_LPM (1 << 17) // Link Power Management
|
||||||
#define EHCI_HCCPARAMS_HP (1 << 16) // Hardware Prefetch
|
#define EHCI_HCCPARAMS_HP (1 << 16) // Hardware Prefetch
|
||||||
#define EHCI_HCCPARAMS_IPT_SHIFT 4 // Isochronous Periodic Threshold
|
#define EHCI_HCCPARAMS_FRAME_CACHE(x) ((x >> 7) & 0x1) // Isochronous Periodic Threshold
|
||||||
#define EHCI_HCCPARAMS_IPT_MASK 0xf
|
#define EHCI_HCCPARAMS_IPT(x) ((x >> 4) & 0x7) // Isochronous Periodic Threshold
|
||||||
|
|
||||||
|
|
||||||
// Data Structures (EHCI Spec 3)
|
// Data Structures (EHCI Spec 3)
|
||||||
@@ -161,10 +161,12 @@ typedef struct ehci_itd {
|
|||||||
#define EHCI_ITD_ENDPOINT_MASK 0xf
|
#define EHCI_ITD_ENDPOINT_MASK 0xf
|
||||||
#define EHCI_ITD_DIR_SHIFT 11
|
#define EHCI_ITD_DIR_SHIFT 11
|
||||||
#define EHCI_ITD_MUL_SHIFT 0
|
#define EHCI_ITD_MUL_SHIFT 0
|
||||||
|
#define EHCI_ITD_MUL_MASK 0x3
|
||||||
#define EHCI_ITD_BUFFERPOINTER_SHIFT 12
|
#define EHCI_ITD_BUFFERPOINTER_SHIFT 12
|
||||||
#define EHCI_ITD_BUFFERPOINTER_MASK 0xfffff
|
#define EHCI_ITD_BUFFERPOINTER_MASK 0xfffff
|
||||||
#define EHCI_ITD_MAXPACKETSIZE_SHIFT 0
|
#define EHCI_ITD_MAXPACKETSIZE_SHIFT 0
|
||||||
#define EHCI_ITD_MAXPACKETSIZE_MASK 0x7ff
|
#define EHCI_ITD_MAXPACKETSIZE_MASK 0x7ff
|
||||||
|
#define EHCI_ITD_MAXPACKETSIZE_LENGTH 11
|
||||||
|
|
||||||
|
|
||||||
// Split Transaction Isochronous Transfer Descriptors (siTD, EHCI Spec 3.3)
|
// Split Transaction Isochronous Transfer Descriptors (siTD, EHCI Spec 3.3)
|
||||||
|
|||||||
Reference in New Issue
Block a user