Fixing bug #1284.
* 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:
@@ -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(),
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user