* Rearranged isochronous finishing to happen from within the finisher thread
* Removed the separate isochronous finishing thread

Since the finisher thread blocks when no transfers are complete this should bring down CPU load.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21516 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2007-06-27 21:40:54 +00:00
parent da0f338e87
commit 2172794336
2 changed files with 68 additions and 85 deletions

View File

@ -180,9 +180,9 @@ Queue::TerminateByStrayDescriptor()
fStrayDescriptor->status = 0;
fStrayDescriptor->this_phy = (addr_t)physicalAddress;
fStrayDescriptor->link_phy = TD_TERMINATE;
fStrayDescriptor->link_log = 0;
fStrayDescriptor->link_log = NULL;
fStrayDescriptor->buffer_phy = 0;
fStrayDescriptor->buffer_log = 0;
fStrayDescriptor->buffer_log = NULL;
fStrayDescriptor->buffer_size = 0;
fStrayDescriptor->token = TD_TOKEN_NULL_DATA
| (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN;
@ -304,8 +304,6 @@ UHCI::UHCI(pci_info *info, Stack *stack)
fStopFinishThread(false),
fFirstIsochronousTransfer(NULL),
fLastIsochronousTransfer(NULL),
fFinishIsochronousThread(-1),
fStopFinishIsochronousThread(false),
fRootHub(NULL),
fRootHubAddress(0),
fPortResetChange(0)
@ -426,12 +424,6 @@ UHCI::UHCI(pci_info *info, Stack *stack)
return;
}
// Create the isochronous finisher service thread
fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread,
"uhci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY,
(void *)this);
resume_thread(fFinishIsochronousThread);
// Install the interrupt handler
TRACE(("usb_uhci: installing interrupt handler\n"));
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
@ -450,10 +442,8 @@ UHCI::~UHCI()
{
int32 result = 0;
fStopFinishThread = true;
fStopFinishIsochronousThread = true;
delete_sem(fFinishTransfersSem);
wait_for_thread(fFinishThread, &result);
wait_for_thread(fFinishIsochronousThread, &result);
LockIsochronous();
isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
@ -635,7 +625,7 @@ UHCI::CancelQueuedIsochronousTransfers(Pipe *pipe)
// Set the active bit off on every descriptor in order to prevent
// the controller from processing them. Then set off the is_active
// field of the transfer in order to make the finisher thread skip
// the transfer. The FinishIsochronousThread will do the rest.
// the transfer. FinishIsochronousTransfers will do the rest.
for (int32 i = 0; i < packetCount; i++)
current->descriptors[i]->status &= ~TD_STATUS_ACTIVE;
current->is_active = false;
@ -999,6 +989,9 @@ UHCI::FinishTransfers()
if (semCount > 0)
acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
// give the isochronous transfers a chance
FinishIsochronousTransfers();
if (!Lock())
continue;
@ -1160,89 +1153,82 @@ UHCI::FinishTransfers()
}
int32
UHCI::FinishIsochronousThread(void *data)
{
((UHCI *)data)->FinishIsochronousTransfers();
return B_OK;
}
void
UHCI::FinishIsochronousTransfers()
{
/* This thread stays one position behind the controller and processes every
* isochronous descriptor. Once it finds the last isochronous descriptor
* of a transfer, it processes the entire transfer.
*/
uint16 currentFrame = ReadReg16(UHCI_FRNUM);
if (!LockIsochronous())
return;
while (!fStopFinishIsochronousThread) {
// wait 1ms in order to be sure to be one position behind
// the controller
if (currentFrame == ReadReg16(UHCI_FRNUM))
snooze(1000);
for (uint16 frame = 0; frame < NUMBER_OF_FRAMES; frame++) {
uhci_td *current = fFirstIsochronousDescriptor[frame];
// Process the frame till it has isochronous descriptors in it.
while (!(fFrameList[currentFrame] & FRAMELIST_NEXT_IS_QH)) {
uhci_td *current = fFirstIsochronousDescriptor[currentFrame];
UnlinkIsochronousDescriptor(current, currentFrame);
while (current) {
if (current->status & TD_STATUS_ACTIVE) {
// The transfer descriptor is still active
current = (uhci_td *)current->link_log;
continue;
}
UnlinkIsochronousDescriptor(current, frame);
if (!(current->status & TD_CONTROL_IOC)) {
current = (uhci_td *)current->link_log;
continue;
}
// Process the transfer if we found the last descriptor
if (current->status & TD_CONTROL_IOC) {
isochronous_transfer_data *transfer
= FindIsochronousTransfer(current);
isochronous_transfer_data *transfer
= FindIsochronousTransfer(current);
// The following should NEVER happen
if (!transfer)
TRACE_ERROR(("usb_uhci: Isochronous transfer not found in"
" the finisher thread!\n"));
// The following should NEVER happen
if (!transfer) {
TRACE_ERROR(("usb_uhci: Isochronous transfer not found in"
" the finisher thread!\n"));
return;
} else if (transfer->is_active
&& (current->status & TD_TOKEN_IN)) {
// Process the descriptors only if it is still active and
// belongs to an inbound transfer. If the transfer is not
// active, it means the request has been removed, so simply
// remove the descriptors.
iovec *vector = transfer->transfer->Vector();
transfer->transfer->PrepareKernelAccess();
ReadIsochronousDescriptorChain(transfer, vector);
// Process the transfer only if it is still active and belongs
// to an INPUT transfer. If the transfer is not active, it
// means the request has been removed, so simply remove the
// descriptors.
else if (transfer->is_active && (current->status & TD_TOKEN_IN)) {
iovec *vector = transfer->transfer->Vector();
transfer->transfer->PrepareKernelAccess();
ReadIsochronousDescriptorChain(transfer, vector);
// Remove the transfer
if (transfer == fFirstIsochronousTransfer) {
fFirstIsochronousTransfer = transfer->link;
} else {
isochronous_transfer_data *temp
= fFirstIsochronousTransfer;
while (transfer != temp->link)
temp = temp->link;
// Remove the transfer
if (LockIsochronous()) {
if (transfer == fFirstIsochronousTransfer)
fFirstIsochronousTransfer = transfer->link;
else {
isochronous_transfer_data *temp
= fFirstIsochronousTransfer;
while (transfer != temp->link)
temp = temp->link;
if (transfer == fLastIsochronousTransfer)
fLastIsochronousTransfer = temp;
temp->link = temp->link->link;
}
UnlockIsochronous();
}
transfer->transfer->Finished(B_OK, 0);
if (transfer == fLastIsochronousTransfer)
fLastIsochronousTransfer = temp;
temp->link = temp->link->link;
}
uint32 packetCount =
transfer->transfer->IsochronousData()->packet_count;
for (uint32 i = 0; i < packetCount; i++)
FreeDescriptor(transfer->descriptors[i]);
transfer->transfer->Finished(B_OK, 0);
} else if (!transfer->is_active)
transfer->transfer->Finished(B_CANCELED, 0);
delete [] transfer->descriptors;
delete transfer->transfer;
delete transfer;
}
uint32 packetCount =
transfer->transfer->IsochronousData()->packet_count;
for (uint32 i = 0; i < packetCount; i++)
FreeDescriptor(transfer->descriptors[i]);
uint16 bandwidth = transfer->transfer->Bandwidth() / packetCount;
fFrameBandwidth[frame] += bandwidth;
delete [] transfer->descriptors;
delete transfer->transfer;
delete transfer;
current = (uhci_td *)current->link_log;
}
// Make sure to reset the frame bandwidth
fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
}
UnlockIsochronous();
}
@ -1578,7 +1564,7 @@ UHCI::CreateFilledTransfer(Transfer *transfer, uhci_td **_firstDescriptor,
lastDescriptor->status |= TD_CONTROL_IOC;
lastDescriptor->link_phy = TD_TERMINATE;
lastDescriptor->link_log = 0;
lastDescriptor->link_log = NULL;
if (!directionIn) {
WriteDescriptorChain(firstDescriptor, transfer->Vector(),

View File

@ -133,7 +133,6 @@ static int32 FinishThread(void *data);
uhci_qh **_transferQueue);
// Isochronous transfer functions
static int32 FinishIsochronousThread(void *data);
void FinishIsochronousTransfers();
isochronous_transfer_data *FindIsochronousTransfer(uhci_td *descriptor);
@ -220,9 +219,7 @@ static pci_module_info *sPCIModule;
// Maintain a linked list of isochronous transfers
isochronous_transfer_data *fFirstIsochronousTransfer;
isochronous_transfer_data *fLastIsochronousTransfer;
thread_id fFinishIsochronousThread;
benaphore fIsochronousLock;
bool fStopFinishIsochronousThread;
// Root hub
UHCIRootHub *fRootHub;