hrev47481 adds 1 changeset to branch 'master' old head: 8674959175ead46ef143a0a60c59e34ce77294c0 new head: 17aa359b5df69f658b4b33e29546c9fb2f0cfce3 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=17aa359+%5E8674959 ---------------------------------------------------------------------------- 17aa359: XHCI USB: Fixes. * Add support for hubs in AllocateDevice(). * Prevent page fault in FinishTransfers(). * Set fCapabilityLength * Correct in BIOS ownership code * Fix context errors in _InsertEndpointForPipe(). * Update constants according to latest Specification (v1.1) * Fix SMI code (reference http://lkml.iu.edu/hypermail/linux/kernel/1204.2/02460.html). * Fix Memory/Device-Slot leaks. * Fix area allocation for TRBs. * Fix for Intel Lynx Point and Panther Point chipsets. Also move init of xhci before ehci, to switch USB 2.0 ports before the ehci module discovers them. Signed-off-by: Jérôme Duval <jerome.duval@xxxxxxxxx> [ Akshay Jaggi <akshay1994.leo@xxxxxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev47481 Commit: 17aa359b5df69f658b4b33e29546c9fb2f0cfce3 URL: http://cgit.haiku-os.org/haiku/commit/?id=17aa359 Author: Akshay Jaggi <akshay1994.leo@xxxxxxxxx> Date: Sat Jun 28 17:03:12 2014 UTC Committer: Jérôme Duval <jerome.duval@xxxxxxxxx> Commit-Date: Fri Jul 11 20:14:05 2014 UTC ---------------------------------------------------------------------------- 9 files changed, 334 insertions(+), 83 deletions(-) build/jam/packages/Haiku | 4 +- headers/posix/netinet/in.h | 1 + src/add-ons/kernel/bus_managers/usb/Hub.cpp | 4 +- src/add-ons/kernel/bus_managers/usb/Stack.cpp | 5 +- .../kernel/bus_managers/usb/usb_private.h | 3 +- src/add-ons/kernel/busses/usb/xhci.cpp | 283 ++++++++++++++----- src/add-ons/kernel/busses/usb/xhci.h | 2 + src/add-ons/kernel/busses/usb/xhci_hardware.h | 24 +- src/add-ons/kernel/network/protocols/udp/udp.cpp | 91 +++++- ---------------------------------------------------------------------------- diff --git a/build/jam/packages/Haiku b/build/jam/packages/Haiku index 72f52ab..c975bbb 100644 --- a/build/jam/packages/Haiku +++ b/build/jam/packages/Haiku @@ -38,7 +38,7 @@ if $(HAIKU_ATA_STACK) = 1 { AddFilesToPackage add-ons kernel busses random : virtio_rng ; AddFilesToPackage add-ons kernel busses scsi : ahci virtio_scsi ; -AddFilesToPackage add-ons kernel busses usb : <usb>uhci <usb>ohci <usb>ehci ; +AddFilesToPackage add-ons kernel busses usb : <usb>uhci <usb>ohci <usb>ehci <usb>xhci ; AddFilesToPackage add-ons kernel busses virtio : virtio_pci ; AddFilesToPackage add-ons kernel console : vga_text ; AddFilesToPackage add-ons kernel debugger @@ -206,7 +206,7 @@ AddBootModuleSymlinksToPackage openpic@ppc packagefs pci scsi scsi_cd scsi_disk scsi_periph silicon_image_3112 - usb usb_disk <usb>ehci <usb>ohci <usb>uhci + usb usb_disk <usb>ehci <usb>ohci <usb>uhci <usb>xhci virtio virtio_block virtio_pci virtio_scsi ; diff --git a/headers/posix/netinet/in.h b/headers/posix/netinet/in.h index ab891cb..73a6bfc 100644 --- a/headers/posix/netinet/in.h +++ b/headers/posix/netinet/in.h @@ -64,6 +64,7 @@ typedef uint32_t in_addr_t; #define IPPROTO_NONE 59 /* 59, IPv6 no next header */ #define IPPROTO_DSTOPTS 60 /* 60, IPv6 destination option */ #define IPPROTO_ETHERIP 97 /* 97, Ethernet in IPv4 */ +#define IPPROTO_UDPLITE 136 /* 136, UDPLite */ #define IPPROTO_RAW 255 /* 255 */ #define IPPROTO_MAX 256 diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index a1f2d6b..3190018 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -17,9 +17,9 @@ Hub::Hub(Object *parent, int8 hubAddress, uint8 hubPort, usb_device_descriptor &desc, int8 deviceAddress, usb_speed speed, - bool isRootHub) + bool isRootHub, void *controllerCookie) : Device(parent, hubAddress, hubPort, desc, deviceAddress, speed, - isRootHub), + isRootHub, controllerCookie), fInterruptPipe(NULL) { TRACE("creating hub\n"); diff --git a/src/add-ons/kernel/bus_managers/usb/Stack.cpp b/src/add-ons/kernel/bus_managers/usb/Stack.cpp index 04ad075..92cb858 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -60,11 +60,14 @@ Stack::Stack() // companion host controllers (per the EHCI specs) and it would therefore // be enumerated as the last item. As this does not apply to us we have to // ensure ordering using another method. + // Intel Lynx Point and Panther Point chipsets have ports shared between + // EHCI and XHCI, defaulting to EHCI. The XHCI module will switch USB 2.0 + // ports before the EHCI module discovers them. const char *moduleNames[] = { + "busses/usb/xhci", "busses/usb/uhci", "busses/usb/ohci", "busses/usb/ehci", - "busses/usb/xhci", NULL }; diff --git a/src/add-ons/kernel/bus_managers/usb/usb_private.h b/src/add-ons/kernel/bus_managers/usb/usb_private.h index 13c189b..8ca6b84 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_private.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_private.h @@ -579,7 +579,8 @@ public: uint8 hubPort, usb_device_descriptor &desc, int8 deviceAddress, - usb_speed speed, bool isRootHub); + usb_speed speed, bool isRootHub, + void *controllerCookie = NULL); virtual ~Hub(); virtual status_t Changed(change_item **changeList, diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index f53f721..50b11ef 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2012, Haiku Inc. All rights reserved. + * Copyright 2006-2014, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Some code borrowed from the Haiku EHCI driver @@ -8,6 +8,7 @@ * Michael Lotz <mmlr@xxxxxxxx> * Jian Chiang <j.jian.chiang@xxxxxxxxx> * Jérôme Duval <jerome.duval@xxxxxxxxx> + * Akshay Jaggi <akshay1994.leo@xxxxxxxxx> */ @@ -174,8 +175,9 @@ XHCI::XHCI(pci_info *info, Stack *stack) uint32 hciCapLength = ReadCapReg32(XHCI_HCI_CAPLENGTH); fCapabilityRegisters += offset; + fCapabilityLength = HCI_CAPLENGTH(hciCapLength); TRACE("mapped capability length: 0x%" B_PRIx32 "\n", fCapabilityLength); - fOperationalRegisters = fCapabilityRegisters + HCI_CAPLENGTH(hciCapLength); + fOperationalRegisters = fCapabilityRegisters + fCapabilityLength; fRuntimeRegisters = fCapabilityRegisters + ReadCapReg32(XHCI_RTSOFF); fDoorbellRegisters = fCapabilityRegisters + ReadCapReg32(XHCI_DBOFF); TRACE("mapped capability registers: 0x%p\n", fCapabilityRegisters); @@ -199,37 +201,69 @@ XHCI::XHCI(pci_info *info, Stack *stack) eec = ReadCapReg32(eecp); if (XECP_ID(eec) != XHCI_LEGSUP_CAPID) continue; - } - TRACE("eecp register: 0x%04" B_PRIx32 "\n", eecp); - if (eec & XHCI_LEGSUP_BIOSOWNED) { - TRACE_ALWAYS("the host controller is bios owned, claiming" - " ownership\n"); - WriteCapReg32(eecp, eec | XHCI_LEGSUP_OSOWNED); - - for (int32 i = 0; i < 20; i++) { - eec = ReadCapReg32(eecp); - - if ((eec & XHCI_LEGSUP_BIOSOWNED) == 0) - break; - - TRACE_ALWAYS("controller is still bios owned, waiting\n"); - snooze(50000); - } - + + TRACE("eecp register: 0x%08" B_PRIx32 "\n", eecp); if (eec & XHCI_LEGSUP_BIOSOWNED) { - TRACE_ERROR("bios won't give up control over the host " - "controller (ignoring)\n"); - } else if (eec & XHCI_LEGSUP_OSOWNED) { - TRACE_ALWAYS("successfully took ownership of the host " - "controller\n"); + TRACE_ALWAYS("the host controller is bios owned, claiming" + " ownership\n"); + WriteCapReg32(eecp, eec | XHCI_LEGSUP_OSOWNED); + + for (int32 i = 0; i < 20; i++) { + eec = ReadCapReg32(eecp); + + if ((eec & XHCI_LEGSUP_BIOSOWNED) == 0) + break; + + TRACE_ALWAYS("controller is still bios owned, waiting\n"); + snooze(50000); + } + + if (eec & XHCI_LEGSUP_BIOSOWNED) { + TRACE_ERROR("bios won't give up control over the host " + "controller (ignoring)\n"); + } else if (eec & XHCI_LEGSUP_OSOWNED) { + TRACE_ALWAYS("successfully took ownership of the host " + "controller\n"); + } + + // Force off the BIOS owned flag, and clear all SMIs. Some BIOSes + // do indicate a successful handover but do not remove their SMIs + // and then freeze the system when interrupts are generated. + WriteCapReg32(eecp, eec & ~XHCI_LEGSUP_BIOSOWNED); } - - // Force off the BIOS owned flag, and clear all SMIs. Some BIOSes - // do indicate a successful handover but do not remove their SMIs - // and then freeze the system when interrupts are generated. - WriteCapReg32(eecp, eec & ~XHCI_LEGSUP_BIOSOWNED); + break; + } + uint32 legctlsts = ReadCapReg32(eecp + XHCI_LEGCTLSTS); + legctlsts &= XHCI_LEGCTLSTS_DISABLE_SMI; + legctlsts |= XHCI_LEGCTLSTS_EVENTS_SMI; + WriteCapReg32(eecp + XHCI_LEGCTLSTS, legctlsts); + + // On Intel's Panther Point and Lynx Point Chipset taking ownership + // of EHCI owned ports, is what we do here. + if (fPCIInfo->vendor_id == PCI_VENDOR_INTEL + && (fPCIInfo->device_id == PCI_DEVICE_INTEL_PANTHER_POINT_XHCI + || fPCIInfo->device_id == PCI_DEVICE_INTEL_LYNX_POINT_XHCI + || fPCIInfo->device_id == PCI_DEVICE_INTEL_LYNX_POINT_LP_XHCI)) { + + TRACE("Intel xHC Controller\n"); + TRACE("Looking for EHCI owned ports\n"); + uint32 ports = sPCIModule->read_pci_config(fPCIInfo->bus, + fPCIInfo->device, fPCIInfo->function, XHCI_INTEL_USB3PRM, 4); + TRACE("Superspeed Ports: 0x%" B_PRIx32 "\n", ports); + sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, + fPCIInfo->function, XHCI_INTEL_USB3_PSSEN, 4, ports); + ports = sPCIModule->read_pci_config(fPCIInfo->bus, + fPCIInfo->device, fPCIInfo->function, XHCI_INTEL_USB3_PSSEN, 4); + TRACE("Superspeed ports now under XHCI : 0x%" B_PRIx32 "\n", ports); + ports = sPCIModule->read_pci_config(fPCIInfo->bus, + fPCIInfo->device, fPCIInfo->function, XHCI_INTEL_USB2PRM, 4); + TRACE("USB 2.0 Ports : 0x%" B_PRIx32 "\n", ports); + sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, + fPCIInfo->function, XHCI_INTEL_XUSB2PR, 4, ports); + ports = sPCIModule->read_pci_config(fPCIInfo->bus, + fPCIInfo->device, fPCIInfo->function, XHCI_INTEL_XUSB2PR, 4); + TRACE("USB 2.0 ports now under XHCI: 0x%" B_PRIx32 "\n", ports); } - WriteCapReg32(eecp + XHCI_LEGCTLSTS, XHCI_LEGCTLSTS_DISABLE_SMI); // halt the host controller if (ControllerHalt() < B_OK) { @@ -337,8 +371,7 @@ XHCI::Start() } // read port count from capability register - uint32 capabilities = ReadCapReg32(XHCI_HCSPARAMS1); - + uint32 capabilities = ReadCapReg32(XHCI_HCSPARAMS1); fPortCount = HCS_MAX_PORTS(capabilities); if (fPortCount == 0) { TRACE_ERROR("Invalid number of ports: %u\n", fPortCount); @@ -573,15 +606,25 @@ XHCI::SubmitControlRequest(Transfer *transfer) xhci_endpoint *endpoint = (xhci_endpoint *)pipe->ControllerCookie(); uint8 id = XHCI_ENDPOINT_ID(pipe); - if (id >= XHCI_MAX_ENDPOINTS) + if (id >= XHCI_MAX_ENDPOINTS) { + TRACE_ERROR("Invalid Endpoint"); return B_BAD_VALUE; + } setupDescriptor->transfer = transfer; + transfer->InitKernelAccess(); _LinkDescriptorForPipe(setupDescriptor, endpoint); TRACE("SubmitControlRequest() request linked\n"); + TRACE("Endpoint status 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx64 "\n", + endpoint->device->device_ctx->endpoints[id-1].dwendpoint0, + endpoint->device->device_ctx->endpoints[id-1].dwendpoint1, + endpoint->device->device_ctx->endpoints[id-1].qwendpoint2); Ring(endpoint->device->slot, id); - + TRACE("Endpoint status 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx64 "\n", + endpoint->device->device_ctx->endpoints[id-1].dwendpoint0, + endpoint->device->device_ctx->endpoints[id-1].dwendpoint1, + endpoint->device->device_ctx->endpoints[id-1].qwendpoint2); return B_OK; } @@ -625,11 +668,20 @@ XHCI::SubmitNormalRequest(Transfer *transfer) xhci_endpoint *endpoint = (xhci_endpoint *)pipe->ControllerCookie(); descriptor->transfer = transfer; + transfer->InitKernelAccess(); _LinkDescriptorForPipe(descriptor, endpoint); TRACE("SubmitNormalRequest() request linked\n"); + TRACE("Endpoint status 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx64 "\n", + endpoint->device->device_ctx->endpoints[id - 1].dwendpoint0, + endpoint->device->device_ctx->endpoints[id - 1].dwendpoint1, + endpoint->device->device_ctx->endpoints[id - 1].qwendpoint2); Ring(endpoint->device->slot, id); + TRACE("Endpoint status 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx64 "\n", + endpoint->device->device_ctx->endpoints[id - 1].dwendpoint0, + endpoint->device->device_ctx->endpoints[id - 1].dwendpoint1, + endpoint->device->device_ctx->endpoints[id - 1].qwendpoint2); return B_OK; } @@ -994,6 +1046,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, "XHCI input context"); if (device->input_ctx_area < B_OK) { TRACE_ERROR("unable to create a input context area\n"); + device->state = XHCI_STATE_DISABLED; return NULL; } @@ -1003,7 +1056,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, uint32 route = 0; uint8 routePort = hubPort; - uint8 rhPort = 0; + uint8 rhPort = hubPort; for (Device *hubDevice = parent; hubDevice != RootObject(); hubDevice = (Device *)hubDevice->Parent()) { @@ -1020,8 +1073,6 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, } device->input_ctx->slot.dwslot0 = SLOT_0_NUM_ENTRIES(1) | SLOT_0_ROUTE(route); - //device->input_ctx->slot.dwslot0 = - // SLOT_0_NUM_ENTRIES(XHCI_MAX_ENDPOINTS - 1) | SLOT_0_ROUTE(route); // add the speed switch (speed) { @@ -1059,15 +1110,18 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, "XHCI device context"); if (device->device_ctx_area < B_OK) { TRACE_ERROR("unable to create a device context area\n"); + device->state = XHCI_STATE_DISABLED; delete_area(device->input_ctx_area); return NULL; } memset(device->device_ctx, 0, sizeof(*device->device_ctx)); device->trb_area = fStack->AllocateArea((void **)&device->trbs, - &device->trb_addr, sizeof(*device->trbs), "XHCI endpoint trbs"); + &device->trb_addr, sizeof(*device->trbs) * (XHCI_MAX_ENDPOINTS - 1) + * XHCI_MAX_TRANSFERS, "XHCI endpoint trbs"); if (device->trb_area < B_OK) { TRACE_ERROR("unable to create a device trbs area\n"); + device->state = XHCI_STATE_DISABLED; delete_area(device->input_ctx_area); delete_area(device->device_ctx_area); return NULL; @@ -1102,6 +1156,10 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, if (ConfigureEndpoint(slot, 0, 4, device->trb_addr, 0, 1, 1, 0, maxPacketSize, maxPacketSize, speed) != B_OK) { TRACE_ERROR("unable to configure default control endpoint\n"); + device->state = XHCI_STATE_DISABLED; + delete_area(device->input_ctx_area); + delete_area(device->device_ctx_area); + delete_area(device->trb_area); return NULL; } @@ -1116,6 +1174,10 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, // device should get to addressed state (bsr = 0) if (SetAddress(device->input_ctx_addr, false, slot) != B_OK) { TRACE_ERROR("unable to set address\n"); + device->state = XHCI_STATE_DISABLED; + delete_area(device->input_ctx_area); + delete_area(device->device_ctx_area); + delete_area(device->trb_area); return NULL; } @@ -1154,6 +1216,10 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, if (actualLength != 8) { TRACE_ERROR("error while getting the device descriptor\n"); + device->state = XHCI_STATE_DISABLED; + delete_area(device->input_ctx_area); + delete_area(device->device_ctx_area); + delete_area(device->trb_area); return NULL; } @@ -1161,11 +1227,51 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, deviceDescriptor.device_class, deviceDescriptor.device_subclass, deviceDescriptor.device_protocol); - TRACE("creating new device\n"); - Device *deviceObject = new(std::nothrow) Device(parent, hubAddress, hubPort, - deviceDescriptor, device->address + 1, speed, false, device); - if (!deviceObject) { + Device *deviceObject = NULL; + if (deviceDescriptor.device_class == 0x09) { + TRACE("creating new Hub\n"); + TRACE("getting the hub descriptor\n"); + size_t actualLength = 0; + usb_hub_descriptor hubDescriptor; + pipe.SendRequest( + USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type + USB_REQUEST_GET_DESCRIPTOR, // request + USB_DESCRIPTOR_HUB << 8, // value + 0, // index + sizeof(usb_hub_descriptor), // length + (void *)&hubDescriptor, // buffer + sizeof(usb_hub_descriptor), // buffer length + &actualLength); + + if (actualLength != sizeof(usb_hub_descriptor)) { + TRACE_ERROR("error while getting the hub descriptor\n"); + device->state = XHCI_STATE_DISABLED; + delete_area(device->input_ctx_area); + delete_area(device->device_ctx_area); + delete_area(device->trb_area); + return NULL; + } + + device->input_ctx->slot.dwslot0 |= SLOT_0_HUB_BIT; + device->input_ctx->slot.dwslot1 |= SLOT_1_NUM_PORTS(hubDescriptor.num_ports); + if (speed == USB_SPEED_HIGHSPEED) { + device->input_ctx->slot.dwslot2 |= + SLOT_2_TT_TIME(HUB_TTT_GET(hubDescriptor.characteristics)); + } + + deviceObject = new(std::nothrow) Hub(parent, hubAddress, hubPort, + deviceDescriptor, device->address + 1, speed, false, device); + } else { + TRACE("creating new device\n"); + deviceObject = new(std::nothrow) Device(parent, hubAddress, hubPort, + deviceDescriptor, device->address + 1, speed, false, device); + } + if (deviceObject == NULL) { TRACE_ERROR("no memory to allocate device\n"); + device->state = XHCI_STATE_DISABLED; + delete_area(device->input_ctx_area); + delete_area(device->device_ctx_area); + delete_area(device->trb_area); return NULL; } fPortSlots[hubPort] = slot; @@ -1193,6 +1299,8 @@ XHCI::FreeDevice(Device *device) status_t XHCI::_InsertEndpointForPipe(Pipe *pipe) { + TRACE("_InsertEndpointForPipe endpoint address %" B_PRId8 "\n", + pipe->EndpointAddress()); if (pipe->ControllerCookie() != NULL || pipe->Parent()->Type() != USB_OBJECT_DEVICE) { // default pipe is already referenced @@ -1303,8 +1411,10 @@ XHCI::_LinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint) { TRACE("_LinkDescriptorForPipe\n"); MutexLocker endpointLocker(endpoint->lock); - if (endpoint->used >= XHCI_MAX_TRANSFERS) + if (endpoint->used >= XHCI_MAX_TRANSFERS) { + TRACE_ERROR("_LinkDescriptorForPipe max transfers count exceeded\n"); return B_BAD_VALUE; + } endpoint->used++; if (endpoint->td_head == NULL) @@ -1468,7 +1578,7 @@ XHCI::GetPortStatus(uint8 index, usb_port_status *status) status->status = status->change = 0; uint32 portStatus = ReadOpReg(XHCI_PORTSC(index)); - //TRACE("port status=0x%08lx\n", portStatus); + TRACE("port %" B_PRId8 " status=0x%08" B_PRIx32 "\n", index, portStatus); // build the status switch (PS_SPEED_GET(portStatus)) { @@ -1767,8 +1877,8 @@ XHCI::HandleTransferComplete(xhci_trb *trb) { TRACE("HandleTransferComplete trb %p\n", trb); addr_t source = trb->qwtrb0; - //uint8 completionCode = TRB_2_COMP_CODE_GET(trb->dwtrb2); - //uint32 remainder = TRB_2_REM_GET(trb->dwtrb2); + uint8 completionCode = TRB_2_COMP_CODE_GET(trb->dwtrb2); + uint32 remainder = TRB_2_REM_GET(trb->dwtrb2); uint8 endpointNumber = TRB_3_ENDPOINT_GET(trb->dwtrb3); uint8 slot = TRB_3_SLOT_GET(trb->dwtrb3); @@ -1785,7 +1895,8 @@ XHCI::HandleTransferComplete(xhci_trb *trb) offset); (void)offset; _UnlinkDescriptorForPipe(td, endpoint); - + td->trb_completion_code = completionCode; + td->trb_left = remainder; // add descriptor to finished list (to be processed and freed) Lock(); td->next = fFinishedHead; @@ -1838,6 +1949,7 @@ XHCI::DoCommand(xhci_trb *trb) status_t XHCI::Noop() { + TRACE("Noop\n"); xhci_trb trb; trb.qwtrb0 = 0; trb.dwtrb2 = 0; @@ -1850,6 +1962,7 @@ XHCI::Noop() status_t XHCI::EnableSlot(uint8 *slot) { + TRACE("Enable Slot\n"); xhci_trb trb; trb.qwtrb0 = 0; trb.dwtrb2 = 0; @@ -1867,6 +1980,7 @@ XHCI::EnableSlot(uint8 *slot) status_t XHCI::DisableSlot(uint8 slot) { + TRACE("Disable Slot\n"); xhci_trb trb; trb.qwtrb0 = 0; trb.dwtrb2 = 0; @@ -1879,6 +1993,7 @@ XHCI::DisableSlot(uint8 slot) status_t XHCI::SetAddress(uint64 inputContext, bool bsr, uint8 slot) { + TRACE("Set Address\n"); xhci_trb trb; trb.qwtrb0 = inputContext; trb.dwtrb2 = 0; @@ -1894,6 +2009,7 @@ XHCI::SetAddress(uint64 inputContext, bool bsr, uint8 slot) status_t XHCI::ConfigureEndpoint(uint64 inputContext, bool deconfigure, uint8 slot) { + TRACE("Configure Endpoint\n"); xhci_trb trb; trb.qwtrb0 = inputContext; trb.dwtrb2 = 0; @@ -1909,6 +2025,7 @@ XHCI::ConfigureEndpoint(uint64 inputContext, bool deconfigure, uint8 slot) status_t XHCI::EvaluateContext(uint64 inputContext, uint8 slot) { + TRACE("Evaluate Context\n"); xhci_trb trb; trb.qwtrb0 = inputContext; trb.dwtrb2 = 0; @@ -1921,6 +2038,7 @@ XHCI::EvaluateContext(uint64 inputContext, uint8 slot) status_t XHCI::ResetEndpoint(bool preserve, uint8 endpoint, uint8 slot) { + TRACE("Reset Endpoint\n"); xhci_trb trb; trb.qwtrb0 = 0; trb.dwtrb2 = 0; @@ -1936,6 +2054,7 @@ XHCI::ResetEndpoint(bool preserve, uint8 endpoint, uint8 slot) status_t XHCI::StopEndpoint(bool suspend, uint8 endpoint, uint8 slot) { + TRACE("Stop Endpoint\n"); xhci_trb trb; trb.qwtrb0 = 0; trb.dwtrb2 = 0; @@ -1951,6 +2070,7 @@ XHCI::StopEndpoint(bool suspend, uint8 endpoint, uint8 slot) status_t XHCI::SetTRDequeue(uint64 dequeue, uint16 stream, uint8 endpoint, uint8 slot) { + TRACE("Set TR Dequeue\n"); xhci_trb trb; trb.qwtrb0 = dequeue; trb.dwtrb2 = TRB_2_STREAM(stream); @@ -1964,6 +2084,7 @@ XHCI::SetTRDequeue(uint64 dequeue, uint16 stream, uint8 endpoint, uint8 slot) status_t XHCI::ResetDevice(uint8 slot) { + TRACE("Reset Device\n"); xhci_trb trb; trb.qwtrb0 = 0; trb.dwtrb2 = 0; @@ -2000,6 +2121,9 @@ XHCI::CompleteEvents() while (1) { uint32 temp = fEventRing[i].dwtrb3; + TRACE_ALWAYS("event[%u] = %u (0x%016" B_PRIx64 " 0x%08" B_PRIx32 " 0x%08" + B_PRIx32 ")\n", i, (uint8)TRB_3_TYPE_GET(temp), fEventRing[i].qwtrb0, + fEventRing[i].dwtrb2, fEventRing[i].dwtrb3); uint8 k = (temp & TRB_3_CYCLE_BIT) ? 1 : 0; if (j != k) break; @@ -2073,28 +2197,61 @@ XHCI::FinishTransfers() td->next = NULL; Unlock(); + TRACE("finishing transfer td %p\n", td); + Transfer* transfer = td->transfer; bool directionIn = (transfer->TransferPipe()->Direction() != Pipe::Out); usb_request_data *requestData = transfer->RequestData(); - - // TODO check event + status_t callbackStatus = B_OK; - size_t actualLength = requestData ? requestData->Length - : transfer->DataLength(); - TRACE("finishing transfer td %p\n", td); - if (directionIn && actualLength > 0) { - if (requestData) { - TRACE("copying in data %d bytes\n", requestData->Length); - memcpy((uint8 *)transfer->Vector()[0].iov_base, - td->buffer_log[0], requestData->Length); - } else { - TRACE("copying in iov count %ld\n", transfer->VectorCount()); - ReadDescriptorChain(td, transfer->Vector(), - transfer->VectorCount()); + switch (td->trb_completion_code) { + case COMP_SHORT_PACKET: + case COMP_SUCCESS: + callbackStatus = B_OK; + break; + case COMP_DATA_BUFFER: + callbackStatus = directionIn ? B_DEV_DATA_OVERRUN + : B_DEV_DATA_UNDERRUN; + break; + case COMP_BABBLE: + callbackStatus = directionIn ? B_DEV_FIFO_OVERRUN + : B_DEV_FIFO_UNDERRUN; + break; + case COMP_USB_TRANSACTION: + callbackStatus = B_DEV_CRC_ERROR; + break; + case COMP_STALL: + callbackStatus = B_DEV_STALLED; + break; + default: + callbackStatus = B_DEV_STALLED; + break; + } + + size_t actualLength = 0; + if (callbackStatus == B_OK) { + actualLength = requestData ? requestData->Length + : transfer->DataLength(); + + if (td->trb_completion_code == COMP_SHORT_PACKET) + actualLength -= td->trb_left; + + if (directionIn && actualLength > 0) { + if (requestData) { + TRACE("copying in data %d bytes\n", requestData->Length); + transfer->PrepareKernelAccess(); + memcpy((uint8 *)transfer->Vector()[0].iov_base, + td->buffer_log[0], requestData->Length); + } else { + TRACE("copying in iov count %ld\n", transfer->VectorCount()); + transfer->PrepareKernelAccess(); + ReadDescriptorChain(td, transfer->Vector(), + transfer->VectorCount()); + } } } - transfer->Finished(callbackStatus, actualLength); - + transfer->Finished(callbackStatus, actualLength); + delete transfer; FreeDescriptor(td); Lock(); } diff --git a/src/add-ons/kernel/busses/usb/xhci.h b/src/add-ons/kernel/busses/usb/xhci.h index df4a597..0b130f0 100644 --- a/src/add-ons/kernel/busses/usb/xhci.h +++ b/src/add-ons/kernel/busses/usb/xhci.h @@ -45,6 +45,8 @@ typedef struct xhci_td { struct xhci_td *next; Transfer *transfer; uint8 trb_count; + uint8 trb_completion_code; + uint32 trb_left; } xhci_td __attribute__((__aligned__(16))); diff --git a/src/add-ons/kernel/busses/usb/xhci_hardware.h b/src/add-ons/kernel/busses/usb/xhci_hardware.h index ebd3d43..05904d8 100644 --- a/src/add-ons/kernel/busses/usb/xhci_hardware.h +++ b/src/add-ons/kernel/busses/usb/xhci_hardware.h @@ -5,10 +5,22 @@ * Authors: * Jian Chiang <j.jian.chiang@xxxxxxxxx> * Jérôme Duval <jerome.duval@xxxxxxxxx> + * Akshay Jaggi <akshay1994.leo@xxxxxxxxx> */ #ifndef XHCI_HARDWARE_H #define XHCI_HARDWARE_H +// PCI IDs +#define PCI_VENDOR_INTEL 0x8086 +#define PCI_DEVICE_INTEL_PANTHER_POINT_XHCI 0x1e31 +#define PCI_DEVICE_INTEL_LYNX_POINT_XHCI 0x8c31 +#define PCI_DEVICE_INTEL_LYNX_POINT_LP_XHCI 0x9c31 + +// Intel quirks registers in PCI config +#define XHCI_INTEL_USB3PRM 0xdc // USB 3.0 Port Routing Mask +#define XHCI_INTEL_USB3_PSSEN 0xd8 // USB 3.0 Port SuperSpeed Enable +#define XHCI_INTEL_USB2PRM 0xd4 // USB 2.0 Port Routing Mask +#define XHCI_INTEL_XUSB2PR 0xd0 // USB 2.0 Port Routing // Host Controller Capability Registers #define XHCI_HCI_CAPLENGTH 0x00 // HCI Capability Register Length @@ -17,12 +29,12 @@ #define XHCI_HCSPARAMS1 0x04 // Structural Parameters 1 // HCSPARAMS1 #define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff) -#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f) +#define HCS_MAX_PORTS(p) (((p) >> 24) & 0xff) #define XHCI_HCSPARAMS2 0x08 // Structural Parameters 2 #define HCS_IST(p) (((p) >> 0) & 0xf) #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) #define HCS_SPR(p) (((p) >> 26) & 0x1) -#define HCS_MAX_SC_BUFFERS(p) (((p) >> 27) & 0x1f) +#define HCS_MAX_SC_BUFFERS(p) (((((p) >> 21) & 0x1f)<<5)|(((p) >> 27) & 0x1f)) #define XHCI_HCSPARAMS3 0x0C // Structural Parameters 3 #define HCS_U1_DEVICE_LATENCY(p) (((p) >> 0) & 0xff) #define HCS_U2_DEVICE_LATENCY(p) (((p) >> 16) & 0xffff) @@ -98,7 +110,8 @@ #define XHCI_LEGSUP_BIOSOWNED (1 << 16) // BIOS Owned Semaphore #define XHCI_LEGCTLSTS 0x04 -#define XHCI_LEGCTLSTS_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17)) +#define XHCI_LEGCTLSTS_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17)) +#define XHCI_LEGCTLSTS_EVENTS_SMI (0x7 << 29) #define XHCI_SUPPORTED_PROTOCOLS_CAPID 0x02 #define XHCI_SUPPORTED_PROTOCOLS_0_MINOR(x) (((x) >> 16) & 0xff) @@ -336,14 +349,15 @@ struct xhci_slot_ctx { #define SLOT_2_PORT_NUM_GET(x) (((x) >> 8) & 0xFF) #define SLOT_2_TT_TIME(x) (((x) & 0x3) << 16) #define SLOT_2_TT_TIME_GET(x) (((x) >> 16) & 0x3) -#define SLOT_2_IRQ_TARGET(x) (((x) & 0x1F) << 27) -#define SLOT_2_IRQ_TARGET_GET(x) (((x) >> 27) & 0x1f) +#define SLOT_2_IRQ_TARGET(x) (((x) & 0x7F) << 22) +#define SLOT_2_IRQ_TARGET_GET(x) (((x) >> 22) & 0x7F) #define SLOT_3_DEVICE_ADDRESS(x) ((x) & 0xFF) #define SLOT_3_DEVICE_ADDRESS_GET(x) ((x) & 0xFF) #define SLOT_3_SLOT_STATE(x) (((x) & 0x1F) << 27) #define SLOT_3_SLOT_STATE_GET(x) (((x) >> 27) & 0x1F) +#define HUB_TTT_GET(x) (((x) >> 5) & 0x3) struct xhci_endpoint_ctx { uint32 dwendpoint0; diff --git a/src/add-ons/kernel/network/protocols/udp/udp.cpp b/src/add-ons/kernel/network/protocols/udp/udp.cpp index 97926b1..d19474e 100644 --- a/src/add-ons/kernel/network/protocols/udp/udp.cpp +++ b/src/add-ons/kernel/network/protocols/udp/udp.cpp @@ -223,10 +223,12 @@ public: status_t InitCheck() const; - status_t ReceiveData(net_buffer* buffer); + status_t ReceiveData(net_buffer* buffer, + bool isUDPLite = false); status_t ReceiveError(status_t error, net_buffer* buffer); - status_t Deframe(net_buffer* buffer); + status_t Deframe(net_buffer* buffer, + bool isUDPLite = false); UdpDomainSupport* OpenEndpoint(UdpEndpoint* endpoint); status_t FreeEndpoint(UdpDomainSupport* domain); @@ -692,7 +694,7 @@ UdpEndpointManager::DumpEndpoints(int argc, char *argv[]) status_t -UdpEndpointManager::ReceiveData(net_buffer *buffer) +UdpEndpointManager::ReceiveData(net_buffer *buffer, bool isUDPLite) { TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); @@ -703,7 +705,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer) return B_ERROR; } - status_t status = Deframe(buffer); + status_t status = Deframe(buffer, isUDPLite); if (status != B_OK) return status; @@ -759,7 +761,7 @@ UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer) status_t -UdpEndpointManager::Deframe(net_buffer* buffer) +UdpEndpointManager::Deframe(net_buffer* buffer, bool isUDPLite) { TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); @@ -786,26 +788,33 @@ UdpEndpointManager::Deframe(net_buffer* buffer) TRACE_EPM(" Deframe(): data from %s to %s", source.AsString(true).Data(), destination.AsString(true).Data()); + bool liteCheck = isUDPLite; uint16 udpLength = ntohs(header.udp_length); + if (isUDPLite && udpLength == 0) { + udpLength = buffer->size; + liteCheck = false; + } if (udpLength > buffer->size) { TRACE_EPM(" Deframe(): buffer is too short, expected %hu.", udpLength); return B_MISMATCHED_VALUES; } - if (buffer->size > udpLength) + if (!isUDPLite && buffer->size > udpLength) gBufferModule->trim(buffer, udpLength); if (header.udp_checksum != 0) { // check UDP-checksum (simulating a so-called "pseudo-header"): uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule, - buffer, IPPROTO_UDP); + buffer, isUDPLite ? IPPROTO_UDPLITE : IPPROTO_UDP); if (sum != 0) { TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum); return B_BAD_VALUE; } } + // TODO check for udpLength < configured min length + bufferHeader.Remove(); // remove UDP-header from buffer before passing it on @@ -991,7 +1000,7 @@ UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route) if (buffer->size > (0xffff - sizeof(udp_header))) return EMSGSIZE; - buffer->protocol = IPPROTO_UDP; + buffer->protocol = Socket()->protocol; // add and fill UDP-specific header: NetBufferPrepend<udp_header> header(buffer); @@ -1071,7 +1080,7 @@ UdpEndpoint::DeliverData(net_buffer *_buffer) if (buffer == NULL) return B_NO_MEMORY; - status_t status = sUdpEndpointManager->Deframe(buffer); + status_t status = sUdpEndpointManager->Deframe(buffer, Socket()->protocol); if (status < B_OK) { gBufferModule->free(buffer); return status; @@ -1111,6 +1120,21 @@ udp_init_protocol(net_socket *socket) } +net_protocol * +udplite_init_protocol(net_socket *socket) +{ + UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket); + if (endpoint == NULL || endpoint->InitCheck() < B_OK) { + delete endpoint; + return NULL; + } + + socket->protocol = IPPROTO_UDPLITE; + + return endpoint; +} + + status_t udp_uninit_protocol(net_protocol *protocol) { @@ -1268,6 +1292,13 @@ udp_receive_data(net_buffer *buffer) status_t +udplite_receive_data(net_buffer *buffer) +{ + return sUdpEndpointManager->ReceiveData(buffer, true); +} + + +status_t udp_deliver_data(net_protocol *protocol, net_buffer *buffer) { return ((UdpEndpoint *)protocol)->DeliverData(buffer); @@ -1465,6 +1496,48 @@ net_protocol_module_info sUDPModule = { NULL // read_data_no_buffer() }; + +net_protocol_module_info sUDPLiteModule = { + { + "network/protocols/udplite/v1", + 0, + NULL + }, + NET_PROTOCOL_ATOMIC_MESSAGES, + + udplite_init_protocol, + udp_uninit_protocol, + udp_open, + udp_close, + udp_free, + udp_connect, + udp_accept, + udp_control, + udp_getsockopt, + udp_setsockopt, + udp_bind, + udp_unbind, + udp_listen, + udp_shutdown, + udp_send_data, + udp_send_routed_data, + udp_send_avail, + udp_read_data, + udp_read_avail, + udp_get_domain, + udp_get_mtu, + udplite_receive_data, + udp_deliver_data, + udp_error_received, + udp_error_reply, + NULL, // add_ancillary_data() + NULL, // process_ancillary_data() + udp_process_ancillary_data_no_container, + NULL, // send_data_no_buffer() + NULL // read_data_no_buffer() +}; + + module_dependency module_dependencies[] = { {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},