From 8a278a1bb7c57c701210c7ded6b5b8dca82e293f Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 24 Sep 2006 15:30:04 +0000 Subject: [PATCH] * Fixing my previous attempt at fixing cookie handling. Device addresses cannot be used, since there may be devices with the same address across different busses. A linked list of usb_driver_cookies is maintained now that relates devices and cookies. * Fixed endpoint halt clearing. The data toggle has to be reset when we clear a stall. * Now using up to B_PAGE_SIZE * 4 sized buffers in EHCI. They are split automatically by the host controller. This further pushes throughput. * Optimize memory allocator settings for the above case. Enlarging it's managed space to 1MB * Ignore the transaction error bit in EHCI. It is only of informational character as it also idicates errors that were recovered automatically. If an unrecoverable error occures, other bits will indicate this. * Fixed some more print formats in debug output. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18915 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/bus_managers/usb/Device.cpp | 32 +++++++++++----- src/add-ons/kernel/bus_managers/usb/Hub.cpp | 2 +- src/add-ons/kernel/bus_managers/usb/Pipe.cpp | 4 ++ src/add-ons/kernel/bus_managers/usb/Stack.cpp | 10 ++--- src/add-ons/kernel/bus_managers/usb/usb_p.h | 15 ++++++-- src/add-ons/kernel/busses/usb/ehci.cpp | 30 ++++++++------- src/add-ons/kernel/busses/usb/ehci.h | 4 +- src/add-ons/kernel/busses/usb/ehci_hardware.h | 2 +- src/add-ons/kernel/busses/usb/uhci.cpp | 37 +++++++++++-------- 9 files changed, 85 insertions(+), 51 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/usb/Device.cpp b/src/add-ons/kernel/bus_managers/usb/Device.cpp index 655cd8b044..5eedfdebe7 100644 --- a/src/add-ons/kernel/bus_managers/usb/Device.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Device.cpp @@ -350,12 +350,11 @@ Device::DeviceDescriptor() const status_t Device::ReportDevice(usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - void *cookies[], bool added) + usb_driver_cookie **cookies, bool added) { TRACE(("USB Device ReportDevice\n")); if ((added && hooks->device_added == NULL) - || (!added && hooks->device_removed == NULL) - || (!added && cookies[fDeviceAddress] == NULL)) + || (!added && hooks->device_removed == NULL)) return B_BAD_VALUE; bool supported = false; @@ -397,16 +396,31 @@ Device::ReportDevice(usb_support_descriptor *supportDescriptors, } if (supported) { + usb_id id = USBID(); if (added) { - status_t result = hooks->device_added(USBID(), &cookies[fDeviceAddress]); - if (result != B_OK) - cookies[fDeviceAddress] = NULL; + usb_driver_cookie *cookie = new(std::nothrow) usb_driver_cookie; + status_t result = hooks->device_added(id, &cookie->cookie); + cookie->device = id; + cookie->link = *cookies; + *cookies = cookie; return result; } - hooks->device_removed(cookies[fDeviceAddress]); - cookies[fDeviceAddress] = NULL; - return B_OK; + usb_driver_cookie **pointer = cookies; + usb_driver_cookie *cookie = *cookies; + while (cookie) { + if (cookie->device == id) + break; + pointer = &cookie->link; + cookie = cookie->link; + } + + if (cookie) { + hooks->device_removed(cookie->cookie); + *pointer = cookie->link; + delete cookie; + return B_OK; + } } return B_UNSUPPORTED; diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 6bb81f5f81..42950f2d66 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -256,7 +256,7 @@ Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID, status_t Hub::ReportDevice(usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - void *cookies[], bool added) + usb_driver_cookie **cookies, bool added) { TRACE(("USB Hub ReportDevice\n")); diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp index 0a57d5fa4a..15fdd3ef03 100644 --- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp @@ -62,6 +62,10 @@ Pipe::SetFeature(uint16 selector) status_t Pipe::ClearFeature(uint16 selector) { + // clearing a stalled condition resets the data toggle + if (selector == USB_FEATURE_ENDPOINT_HALT) + SetDataToggle(false); + return ((Device *)Parent())->DefaultPipe()->SendRequest( USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, USB_REQUEST_CLEAR_FEATURE, diff --git a/src/add-ons/kernel/bus_managers/usb/Stack.cpp b/src/add-ons/kernel/bus_managers/usb/Stack.cpp index 2bd351acb0..168ad5f638 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -32,7 +32,7 @@ Stack::Stack() memset(fObjectArray, 0, objectArraySize); fAllocator = new(std::nothrow) PhysicalMemoryAllocator("USB Stack Allocator", - 8, B_PAGE_SIZE * 4, 50); + 8, B_PAGE_SIZE * 4, 64); if (!fAllocator) { TRACE_ERROR(("usb stack: failed to allocate the allocator\n")); return; @@ -233,7 +233,7 @@ Stack::NotifyDeviceChange(Device *device, bool added) || (!added && element->notify_hooks.device_removed != NULL)) { status_t result = device->ReportDevice(element->support_descriptors, element->support_descriptor_count, - &element->notify_hooks, element->cookies, added); + &element->notify_hooks, &element->cookies, added); if (result == B_OK) { const char *name = element->driver_name; @@ -268,9 +268,9 @@ Stack::RegisterDriver(const char *driverName, memcpy(info->support_descriptors, descriptors, descriptorsSize); info->support_descriptor_count = descriptorCount; - memset(info->cookies, 0, sizeof(void *) * 128); info->notify_hooks.device_added = NULL; info->notify_hooks.device_removed = NULL; + info->cookies = NULL; info->link = NULL; if (!Lock()) { @@ -310,7 +310,7 @@ Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks) // Report device will recurse down the whole tree rootHub->ReportDevice(element->support_descriptors, element->support_descriptor_count, hooks, - element->cookies, true); + &element->cookies, true); } } @@ -342,7 +342,7 @@ Stack::UninstallNotify(const char *driverName) if (rootHub) rootHub->ReportDevice(element->support_descriptors, element->support_descriptor_count, - &element->notify_hooks, element->cookies, false); + &element->notify_hooks, &element->cookies, false); } element->notify_hooks.device_added = NULL; diff --git a/src/add-ons/kernel/bus_managers/usb/usb_p.h b/src/add-ons/kernel/bus_managers/usb/usb_p.h index fb568d34f4..7347d8f686 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_p.h @@ -42,13 +42,20 @@ struct host_controller_info { }; +struct usb_driver_cookie { + usb_id device; + void *cookie; + usb_driver_cookie *link; +}; + + struct usb_driver_info { const char *driver_name; usb_support_descriptor *support_descriptors; uint32 support_descriptor_count; const char *republish_driver_name; usb_notify_hooks notify_hooks; - void *cookies[128]; + usb_driver_cookie *cookies; usb_driver_info *link; }; @@ -385,7 +392,8 @@ virtual status_t ReportDevice( usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - void *cookies[], bool added); + usb_driver_cookie **cookies, + bool added); virtual status_t BuildDeviceName(char *string, uint32 *index, size_t bufferSize, Device *device); @@ -436,7 +444,8 @@ virtual status_t ReportDevice( usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - void *cookies[], bool added); + usb_driver_cookie **cookies, + bool added); virtual status_t BuildDeviceName(char *string, uint32 *index, size_t bufferSize, Device *device); diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index f52b67864e..c321860177 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -942,6 +942,12 @@ EHCI::FinishTransfers() if (acquire_sem(fFinishTransfersSem) < B_OK) continue; + // eat up sems that have been released by multiple interrupts + int32 semCount = 0; + get_sem_count(fFinishTransfersSem, &semCount); + if (semCount > 0) + acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); + if (!Lock()) continue; @@ -993,7 +999,7 @@ EHCI::FinishTransfers() TRACE(("usb_ehci: qtd (0x%08lx) done\n", descriptor->this_phy)); size_t actualLength = 0; - uint8 lastDataToggle = 0; + bool nextDataToggle = false; if (transfer->data_descriptor && transfer->incoming) { // data to read out iovec *vector = transfer->transfer->Vector(); @@ -1019,7 +1025,7 @@ EHCI::FinishTransfers() actualLength = ReadDescriptorChain( transfer->data_descriptor, vector, vectorCount, - &lastDataToggle); + &nextDataToggle); #ifndef HAIKU_TARGET_PLATFORM_HAIKU if (clonedArea >= B_OK) @@ -1029,11 +1035,11 @@ EHCI::FinishTransfers() // calculate transfered length actualLength = ReadActualLength( (ehci_qtd *)transfer->queue_head->element_log, - &lastDataToggle); + &nextDataToggle); } UnlinkQueueHead(transfer->queue_head, &freeListHead); - transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle); + transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle); transfer->transfer->Finished(B_USB_STATUS_SUCCESS, actualLength); transferDone = true; break; @@ -1324,7 +1330,7 @@ EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor, ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize, uint8 pid) { - size_t packetSize = pipe->MaxPacketSize(); + size_t packetSize = B_PAGE_SIZE * 4; int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; bool dataToggle = pipe->DataToggle(); @@ -1345,7 +1351,6 @@ EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor, if (lastDescriptor) LinkDescriptors(lastDescriptor, descriptor, strayDescriptor); - dataToggle = !dataToggle; bufferSize -= packetSize; lastDescriptor = descriptor; if (!firstDescriptor) @@ -1456,7 +1461,7 @@ EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, size_t EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, - size_t vectorCount, uint8 *lastDataToggle) + size_t vectorCount, bool *nextDataToggle) { uint32 dataToggle = 0; ehci_qtd *current = topDescriptor; @@ -1487,8 +1492,7 @@ EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, if (vectorOffset >= vector[vectorIndex].iov_len) { if (++vectorIndex >= vectorCount) { TRACE(("usb_ehci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength)); - if (lastDataToggle) - *lastDataToggle = dataToggle > 0 ? 1 : 0; + *nextDataToggle = dataToggle > 0 ? true : false; return actualLength; } @@ -1508,14 +1512,13 @@ EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, } TRACE(("usb_ehci: read descriptor chain (%ld bytes)\n", actualLength)); - if (lastDataToggle) - *lastDataToggle = dataToggle > 0 ? 1 : 0; + *nextDataToggle = dataToggle > 0 ? true : false; return actualLength; } size_t -EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle) +EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle) { size_t actualLength = 0; ehci_qtd *current = topDescriptor; @@ -1534,8 +1537,7 @@ EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle) } TRACE(("usb_ehci: read actual length (%ld bytes)\n", actualLength)); - if (lastDataToggle) - *lastDataToggle = dataToggle > 0 ? 1 : 0; + *nextDataToggle = dataToggle > 0 ? true : false; return actualLength; } diff --git a/src/add-ons/kernel/busses/usb/ehci.h b/src/add-ons/kernel/busses/usb/ehci.h index cf73ae7f95..bb9acabe21 100644 --- a/src/add-ons/kernel/busses/usb/ehci.h +++ b/src/add-ons/kernel/busses/usb/ehci.h @@ -107,9 +107,9 @@ static int32 FinishThread(void *data); iovec *vector, size_t vectorCount); size_t ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, size_t vectorCount, - uint8 *lastDataToggle); + bool *nextDataToggle); size_t ReadActualLength(ehci_qtd *topDescriptor, - uint8 *lastDataToggle); + bool *nextDataToggle); // Operational register functions inline void WriteOpReg(uint32 reg, uint32 value); diff --git a/src/add-ons/kernel/busses/usb/ehci_hardware.h b/src/add-ons/kernel/busses/usb/ehci_hardware.h index e40b0fafe7..3b2d0cb6b9 100644 --- a/src/add-ons/kernel/busses/usb/ehci_hardware.h +++ b/src/add-ons/kernel/busses/usb/ehci_hardware.h @@ -153,7 +153,7 @@ typedef struct { #define EHCI_QTD_PID_SETUP 0x02 #define EHCI_QTD_STATUS_SHIFT 0 #define EHCI_QTD_STATUS_MASK 0x7f -#define EHCI_QTD_STATUS_ERRMASK 0x78 +#define EHCI_QTD_STATUS_ERRMASK 0x70 #define EHCI_QTD_STATUS_ACTIVE (1 << 7) // Active #define EHCI_QTD_STATUS_HALTED (1 << 6) // Halted #define EHCI_QTD_STATUS_BUFFER (1 << 5) // Data Buffer Error diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 6b431016e3..dd0fdc74a8 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -67,7 +67,7 @@ void print_descriptor_chain(uhci_td *descriptor) { while (descriptor) { - dprintf("ph: 0x%08x; lp: 0x%08x; vf: %s; q: %s; t: %s; st: 0x%08x; to: 0x%08x\n", + dprintf("ph: 0x%08lx; lp: 0x%08lx; vf: %s; q: %s; t: %s; st: 0x%08lx; to: 0x%08lx\n", descriptor->this_phy & 0xffffffff, descriptor->link_phy & 0xfffffff0, descriptor->link_phy & 0x4 ? "y" : "n", descriptor->link_phy & 0x2 ? "qh" : "td", @@ -301,8 +301,8 @@ Queue::PrintToStream() { #ifdef TRACE_USB dprintf("USB UHCI Queue:\n"); - dprintf("link phy: 0x%08x; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no"); - dprintf("elem phy: 0x%08x; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no"); + dprintf("link phy: 0x%08lx; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no"); + dprintf("elem phy: 0x%08lx; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no"); dprintf("elements:\n"); print_descriptor_chain(fQueueTop); #endif @@ -476,7 +476,7 @@ UHCI::Start() bool running = false; for (int32 i = 0; i < 10; i++) { uint16 status = ReadReg16(UHCI_USBSTS); - TRACE(("usb_uhci: current loop %u, status 0x%04x\n", i, status)); + TRACE(("usb_uhci: current loop %ld, status 0x%04x\n", i, status)); if (status & UHCI_USBSTS_HCHALT) snooze(10000); @@ -515,12 +515,11 @@ UHCI::Start() status_t UHCI::SubmitTransfer(Transfer *transfer) { - TRACE(("usb_uhci: submit transfer called for device %d\n", transfer->TransferPipe()->DeviceAddress())); - // Short circuit the root hub if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) return fRootHub->ProcessTransfer(this, transfer); + TRACE(("usb_uhci: submit transfer called for device %d\n", transfer->TransferPipe()->DeviceAddress())); if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) return SubmitRequest(transfer); @@ -740,10 +739,16 @@ UHCI::FinishTransfers() if (acquire_sem(fFinishTransfersSem) < B_OK) continue; + // eat up sems that have been released by multiple interrupts + int32 semCount = 0; + get_sem_count(fFinishTransfersSem, &semCount); + if (semCount > 0) + acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); + if (!Lock()) continue; - TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08x; last transfer: 0x%08x)\n", fFirstTransfer, fLastTransfer)); + TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08lx; last transfer: 0x%08lx)\n", (uint32)fFirstTransfer, (uint32)fLastTransfer)); transfer_data *lastTransfer = NULL; transfer_data *transfer = fFirstTransfer; Unlock(); @@ -755,7 +760,7 @@ UHCI::FinishTransfers() while (descriptor) { uint32 status = descriptor->status; if (status & TD_STATUS_ACTIVE) { - TRACE(("usb_uhci: td (0x%08x) still active\n", descriptor->this_phy)); + TRACE(("usb_uhci: td (0x%08lx) still active\n", descriptor->this_phy)); // still in progress break; } @@ -789,7 +794,7 @@ UHCI::FinishTransfers() if (descriptor == transfer->last_descriptor || (descriptor->status & TD_STATUS_ACTLEN_MASK) < (descriptor->token >> TD_TOKEN_MAXLEN_SHIFT)) { - TRACE(("usb_uhci: td (0x%08x) ok\n", descriptor->this_phy)); + TRACE(("usb_uhci: td (0x%08lx) ok\n", descriptor->this_phy)); // we got through without errors so we are finished transfer->queue->RemoveDescriptorChain( transfer->first_descriptor, @@ -1317,7 +1322,7 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, size_t length = min_c(current->buffer_size - bufferOffset, vector[vectorIndex].iov_len - vectorOffset); - TRACE(("usb_uhci: copying %d bytes to bufferOffset %d from vectorOffset %d at index %d of %d\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount)); + TRACE(("usb_uhci: copying %ld bytes to bufferOffset %ld from vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount)); memcpy((uint8 *)current->buffer_log + bufferOffset, (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); @@ -1327,7 +1332,7 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, if (vectorOffset >= vector[vectorIndex].iov_len) { if (++vectorIndex >= vectorCount) { - TRACE(("usb_uhci: wrote descriptor chain (%d bytes, no more vectors)\n", actualLength)); + TRACE(("usb_uhci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength)); return actualLength; } @@ -1346,7 +1351,7 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, current = (uhci_td *)current->link_log; } - TRACE(("usb_uhci: wrote descriptor chain (%d bytes)\n", actualLength)); + TRACE(("usb_uhci: wrote descriptor chain (%ld bytes)\n", actualLength)); return actualLength; } @@ -1375,7 +1380,7 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, size_t length = min_c(bufferSize - bufferOffset, vector[vectorIndex].iov_len - vectorOffset); - TRACE(("usb_uhci: copying %d bytes to vectorOffset %d from bufferOffset %d at index %d of %d\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount)); + TRACE(("usb_uhci: copying %ld bytes to vectorOffset %ld from bufferOffset %ld at index %ld of %ld\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount)); memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, (uint8 *)current->buffer_log + bufferOffset, length); @@ -1385,7 +1390,7 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, if (vectorOffset >= vector[vectorIndex].iov_len) { if (++vectorIndex >= vectorCount) { - TRACE(("usb_uhci: read descriptor chain (%d bytes, no more vectors)\n", actualLength)); + TRACE(("usb_uhci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength)); if (lastDataToggle) *lastDataToggle = dataToggle; return actualLength; @@ -1409,7 +1414,7 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, if (lastDataToggle) *lastDataToggle = dataToggle; - TRACE(("usb_uhci: read descriptor chain (%d bytes)\n", actualLength)); + TRACE(("usb_uhci: read descriptor chain (%ld bytes)\n", actualLength)); return actualLength; } @@ -1438,7 +1443,7 @@ UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle) if (lastDataToggle) *lastDataToggle = dataToggle; - TRACE(("usb_uhci: read actual length (%d bytes)\n", actualLength)); + TRACE(("usb_uhci: read actual length (%ld bytes)\n", actualLength)); return actualLength; }