* 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
+68 -82
View File
@@ -180,9 +180,9 @@ Queue::TerminateByStrayDescriptor()
fStrayDescriptor->status = 0; fStrayDescriptor->status = 0;
fStrayDescriptor->this_phy = (addr_t)physicalAddress; fStrayDescriptor->this_phy = (addr_t)physicalAddress;
fStrayDescriptor->link_phy = TD_TERMINATE; fStrayDescriptor->link_phy = TD_TERMINATE;
fStrayDescriptor->link_log = 0; fStrayDescriptor->link_log = NULL;
fStrayDescriptor->buffer_phy = 0; fStrayDescriptor->buffer_phy = 0;
fStrayDescriptor->buffer_log = 0; fStrayDescriptor->buffer_log = NULL;
fStrayDescriptor->buffer_size = 0; fStrayDescriptor->buffer_size = 0;
fStrayDescriptor->token = TD_TOKEN_NULL_DATA fStrayDescriptor->token = TD_TOKEN_NULL_DATA
| (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN; | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN;
@@ -304,8 +304,6 @@ UHCI::UHCI(pci_info *info, Stack *stack)
fStopFinishThread(false), fStopFinishThread(false),
fFirstIsochronousTransfer(NULL), fFirstIsochronousTransfer(NULL),
fLastIsochronousTransfer(NULL), fLastIsochronousTransfer(NULL),
fFinishIsochronousThread(-1),
fStopFinishIsochronousThread(false),
fRootHub(NULL), fRootHub(NULL),
fRootHubAddress(0), fRootHubAddress(0),
fPortResetChange(0) fPortResetChange(0)
@@ -426,12 +424,6 @@ UHCI::UHCI(pci_info *info, Stack *stack)
return; 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 // Install the interrupt handler
TRACE(("usb_uhci: installing interrupt handler\n")); TRACE(("usb_uhci: installing interrupt handler\n"));
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
@@ -450,10 +442,8 @@ UHCI::~UHCI()
{ {
int32 result = 0; int32 result = 0;
fStopFinishThread = true; fStopFinishThread = true;
fStopFinishIsochronousThread = true;
delete_sem(fFinishTransfersSem); delete_sem(fFinishTransfersSem);
wait_for_thread(fFinishThread, &result); wait_for_thread(fFinishThread, &result);
wait_for_thread(fFinishIsochronousThread, &result);
LockIsochronous(); LockIsochronous();
isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer; 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 // Set the active bit off on every descriptor in order to prevent
// the controller from processing them. Then set off the is_active // the controller from processing them. Then set off the is_active
// field of the transfer in order to make the finisher thread skip // 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++) for (int32 i = 0; i < packetCount; i++)
current->descriptors[i]->status &= ~TD_STATUS_ACTIVE; current->descriptors[i]->status &= ~TD_STATUS_ACTIVE;
current->is_active = false; current->is_active = false;
@@ -999,6 +989,9 @@ UHCI::FinishTransfers()
if (semCount > 0) if (semCount > 0)
acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
// give the isochronous transfers a chance
FinishIsochronousTransfers();
if (!Lock()) if (!Lock())
continue; continue;
@@ -1160,89 +1153,82 @@ UHCI::FinishTransfers()
} }
int32
UHCI::FinishIsochronousThread(void *data)
{
((UHCI *)data)->FinishIsochronousTransfers();
return B_OK;
}
void void
UHCI::FinishIsochronousTransfers() UHCI::FinishIsochronousTransfers()
{ {
/* This thread stays one position behind the controller and processes every if (!LockIsochronous())
* isochronous descriptor. Once it finds the last isochronous descriptor return;
* of a transfer, it processes the entire transfer.
*/
uint16 currentFrame = ReadReg16(UHCI_FRNUM);
while (!fStopFinishIsochronousThread) { for (uint16 frame = 0; frame < NUMBER_OF_FRAMES; frame++) {
// wait 1ms in order to be sure to be one position behind uhci_td *current = fFirstIsochronousDescriptor[frame];
// the controller
if (currentFrame == ReadReg16(UHCI_FRNUM))
snooze(1000);
// Process the frame till it has isochronous descriptors in it. while (current) {
while (!(fFrameList[currentFrame] & FRAMELIST_NEXT_IS_QH)) { if (current->status & TD_STATUS_ACTIVE) {
uhci_td *current = fFirstIsochronousDescriptor[currentFrame]; // The transfer descriptor is still active
UnlinkIsochronousDescriptor(current, currentFrame); 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 // Process the transfer if we found the last descriptor
if (current->status & TD_CONTROL_IOC) { isochronous_transfer_data *transfer
isochronous_transfer_data *transfer = FindIsochronousTransfer(current);
= FindIsochronousTransfer(current);
// The following should NEVER happen // The following should NEVER happen
if (!transfer) if (!transfer) {
TRACE_ERROR(("usb_uhci: Isochronous transfer not found in" TRACE_ERROR(("usb_uhci: Isochronous transfer not found in"
" the finisher thread!\n")); " 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 // Remove the transfer
// to an INPUT transfer. If the transfer is not active, it if (transfer == fFirstIsochronousTransfer) {
// means the request has been removed, so simply remove the fFirstIsochronousTransfer = transfer->link;
// descriptors. } else {
else if (transfer->is_active && (current->status & TD_TOKEN_IN)) { isochronous_transfer_data *temp
iovec *vector = transfer->transfer->Vector(); = fFirstIsochronousTransfer;
transfer->transfer->PrepareKernelAccess(); while (transfer != temp->link)
ReadIsochronousDescriptorChain(transfer, vector); temp = temp->link;
// Remove the transfer if (transfer == fLastIsochronousTransfer)
if (LockIsochronous()) { fLastIsochronousTransfer = temp;
if (transfer == fFirstIsochronousTransfer) temp->link = temp->link->link;
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);
} }
uint32 packetCount = transfer->transfer->Finished(B_OK, 0);
transfer->transfer->IsochronousData()->packet_count; } else if (!transfer->is_active)
for (uint32 i = 0; i < packetCount; i++) transfer->transfer->Finished(B_CANCELED, 0);
FreeDescriptor(transfer->descriptors[i]);
delete [] transfer->descriptors; uint32 packetCount =
delete transfer->transfer; transfer->transfer->IsochronousData()->packet_count;
delete transfer; 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->status |= TD_CONTROL_IOC;
lastDescriptor->link_phy = TD_TERMINATE; lastDescriptor->link_phy = TD_TERMINATE;
lastDescriptor->link_log = 0; lastDescriptor->link_log = NULL;
if (!directionIn) { if (!directionIn) {
WriteDescriptorChain(firstDescriptor, transfer->Vector(), WriteDescriptorChain(firstDescriptor, transfer->Vector(),
-3
View File
@@ -133,7 +133,6 @@ static int32 FinishThread(void *data);
uhci_qh **_transferQueue); uhci_qh **_transferQueue);
// Isochronous transfer functions // Isochronous transfer functions
static int32 FinishIsochronousThread(void *data);
void FinishIsochronousTransfers(); void FinishIsochronousTransfers();
isochronous_transfer_data *FindIsochronousTransfer(uhci_td *descriptor); isochronous_transfer_data *FindIsochronousTransfer(uhci_td *descriptor);
@@ -220,9 +219,7 @@ static pci_module_info *sPCIModule;
// Maintain a linked list of isochronous transfers // Maintain a linked list of isochronous transfers
isochronous_transfer_data *fFirstIsochronousTransfer; isochronous_transfer_data *fFirstIsochronousTransfer;
isochronous_transfer_data *fLastIsochronousTransfer; isochronous_transfer_data *fLastIsochronousTransfer;
thread_id fFinishIsochronousThread;
benaphore fIsochronousLock; benaphore fIsochronousLock;
bool fStopFinishIsochronousThread;
// Root hub // Root hub
UHCIRootHub *fRootHub; UHCIRootHub *fRootHub;