hrev53137 adds 1 changeset to branch 'master'
old head: c8836afc0a2bebbfb34b7d71448cc372bdeea972
new head: 086528f66af8e1f420be92d2af971605554e5264
overview:
https://git.haiku-os.org/haiku/log/?qt=range&q=086528f66af8+%5Ec8836afc0a2b
----------------------------------------------------------------------------
086528f66af8: USB & XHCI: Refactor endpoint initialization to support
SuperSpeed better.
SuperSpeed (USB3) devices have a "companion descriptor" along with the
endpoint descriptors that describes certain other attributes they have,
which are important for the controller to schedule transfers properly.
Previously we were just using USB2 values; now we are properly using USB3
ones.
Tested on an Intel Lynx Point controller. As far as I can tell, no
regressions, but #15000 is not fixed anyway.
[ Augustin Cavalier <waddlesplash@xxxxxxxxx> ]
----------------------------------------------------------------------------
Revision: hrev53137
Commit: 086528f66af8e1f420be92d2af971605554e5264
URL: https://git.haiku-os.org/haiku/commit/?id=086528f66af8
Author: Augustin Cavalier <waddlesplash@xxxxxxxxx>
Date: Fri May 17 00:31:11 2019 UTC
Ticket: https://dev.haiku-os.org/ticket/15000
----------------------------------------------------------------------------
7 files changed, 102 insertions(+), 31 deletions(-)
src/add-ons/kernel/bus_managers/usb/Device.cpp | 43 ++++++++++++++++++++
src/add-ons/kernel/bus_managers/usb/Pipe.cpp | 11 +++++
.../kernel/bus_managers/usb/usb_private.h | 10 +++++
.../kernel/bus_managers/usb/usbspec_private.h | 11 +++++
src/add-ons/kernel/busses/usb/xhci.cpp | 42 ++++++++++---------
src/add-ons/kernel/busses/usb/xhci.h | 3 +-
src/add-ons/kernel/busses/usb/xhci_rh.cpp | 13 +-----
----------------------------------------------------------------------------
diff --git a/src/add-ons/kernel/bus_managers/usb/Device.cpp
b/src/add-ons/kernel/bus_managers/usb/Device.cpp
index f15b52216d..83e8adb509 100644
--- a/src/add-ons/kernel/bus_managers/usb/Device.cpp
+++ b/src/add-ons/kernel/bus_managers/usb/Device.cpp
@@ -254,6 +254,22 @@ Device::Device(Object* parent, int8 hubAddress, uint8
hubPort,
break;
}
+ case USB_DESCRIPTOR_ENDPOINT_COMPANION: {
+ usb_endpoint_descriptor* desc =
currentInterface
+
->endpoint[currentInterface->endpoint_count - 1].descr;
+ if ((uint8*)desc !=
(&configData[descriptorStart
+ - desc->length])) {
+ TRACE_ERROR("found endpoint
companion descriptor not immediately "
+ "following endpoint
descriptor, ignoring!\n");
+ break;
+ }
+ // TODO: It'd be nicer if we could
store the endpoint companion
+ // descriptor along with the endpoint
descriptor, but as the
+ // interface struct is public API, that
would be an ABI break.
+
+ // fall through
+ }
+
default:
TRACE("got generic descriptor\n");
usb_generic_descriptor*
genericDescriptor
@@ -472,6 +488,29 @@ Device::InitEndpoints(int32 interfaceIndex)
usb_endpoint_info* endpoint =
&interfaceInfo->endpoint[i];
Pipe* pipe = NULL;
+ usb_endpoint_companion_descriptor* comp_descr = NULL;
+ if (fSpeed == USB_SPEED_SUPER) {
+ // We should have a companion descriptor for
this device.
+ // Let's find it: it'll be the "i"th one.
+ size_t k = 0;
+ for (size_t j = 0; j <
interfaceInfo->generic_count; j++) {
+ usb_descriptor* desc =
interfaceInfo->generic[j];
+ if (desc->endpoint.descriptor_type
+ !=
USB_DESCRIPTOR_ENDPOINT_COMPANION) {
+ continue;
+ }
+ if (k == i) {
+ comp_descr =
(usb_endpoint_companion_descriptor*)desc;
+ break;
+ }
+ k++;
+ }
+ if (comp_descr == NULL) {
+ TRACE_ERROR("SuperSpeed device without
an endpoint companion "
+ "descriptor!");
+ }
+ }
+
Pipe::pipeDirection direction = Pipe::Out;
if ((endpoint->descr->endpoint_address & 0x80) != 0)
direction = Pipe::In;
@@ -505,6 +544,10 @@ Device::InitEndpoints(int32 interfaceIndex)
endpoint->descr->endpoint_address & 0x0f,
fSpeed, direction,
endpoint->descr->max_packet_size,
endpoint->descr->interval, fHubAddress,
fHubPort);
+ if (comp_descr != NULL) {
+ pipe->InitSuperSpeed(comp_descr->max_burst,
+ comp_descr->bytes_per_interval);
+ }
endpoint->handle = pipe->USBID();
}
}
diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp
b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp
index 96525ac359..6d976639c8 100644
--- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp
+++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp
@@ -40,10 +40,21 @@ Pipe::InitCommon(int8 deviceAddress, uint8 endpointAddress,
usb_speed speed,
fHubAddress = hubAddress;
fHubPort = hubPort;
+ fMaxBurst = 0;
+ fBytesPerInterval = 0;
+
GetBusManager()->NotifyPipeChange(this, USB_CHANGE_CREATED);
}
+void
+Pipe::InitSuperSpeed(uint8 maxBurst, uint16 bytesPerInterval)
+{
+ fMaxBurst = maxBurst;
+ fBytesPerInterval = bytesPerInterval;
+}
+
+
void
Pipe::SetHubInfo(int8 address, uint8 port)
{
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 93279c0865..2862f2c7c9 100644
--- a/src/add-ons/kernel/bus_managers/usb/usb_private.h
+++ b/src/add-ons/kernel/bus_managers/usb/usb_private.h
@@ -297,6 +297,8 @@ virtual void
InitCommon(int8 deviceAddress,
size_t maxPacketSize,
uint8 interval,
int8 hubAddress, uint8 hubPort);
+virtual void
InitSuperSpeed(uint8 maxBurst,
+
uint16 bytesPerInterval);
virtual uint32 Type()
const { return USB_OBJECT_PIPE; }
virtual const char * TypeName()
const { return "pipe"; }
@@ -311,6 +313,12 @@ virtual const char *
TypeName() const { return "pipe"; }
{ return fMaxPacketSize; }
uint8
Interval() const { return fInterval; }
+ // SuperSpeed-only parameters
+ uint8
MaxBurst() const
+
{ return fMaxBurst; }
+ uint16
BytesPerInterval() const
+
{ return fBytesPerInterval; }
+
// Hub port being the one-based logical port number on the hub
void
SetHubInfo(int8 address, uint8 port);
int8
HubAddress() const
@@ -342,6 +350,8 @@ private:
usb_speed fSpeed;
size_t
fMaxPacketSize;
uint8
fInterval;
+ uint8
fMaxBurst;
+ uint16
fBytesPerInterval;
int8
fHubAddress;
uint8
fHubPort;
bool
fDataToggle;
diff --git a/src/add-ons/kernel/bus_managers/usb/usbspec_private.h
b/src/add-ons/kernel/bus_managers/usb/usbspec_private.h
index dc8d068419..0a2899a5ae 100644
--- a/src/add-ons/kernel/bus_managers/usb/usbspec_private.h
+++ b/src/add-ons/kernel/bus_managers/usb/usbspec_private.h
@@ -71,6 +71,17 @@ struct usb_hub_descriptor {
#define USB_DESCRIPTOR_HUB 0x29
+struct usb_endpoint_companion_descriptor {
+ uint8 length;
+ uint8 descriptor_type;
+ uint8 max_burst;
+ uint8 attributes;
+ uint16 bytes_per_interval;
+} _PACKED;
+
+#define USB_DESCRIPTOR_ENDPOINT_COMPANION 0x30
+
+
// USB Spec 1.1 page 273
struct usb_port_status
{
diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp
b/src/add-ons/kernel/busses/usb/xhci.cpp
index 89d075f501..7508fca44a 100644
--- a/src/add-ons/kernel/busses/usb/xhci.cpp
+++ b/src/add-ons/kernel/busses/usb/xhci.cpp
@@ -1395,7 +1395,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8
hubPort,
// configure the Control endpoint 0
if (ConfigureEndpoint(slot, 0, USB_OBJECT_CONTROL_PIPE, false,
- device->trb_addr, 0, maxPacketSize, speed) != B_OK) {
+ device->trb_addr, 0, maxPacketSize, speed, 0, 0) !=
B_OK) {
TRACE_ERROR("unable to configure default control endpoint\n");
delete_area(device->input_ctx_area);
delete_area(device->device_ctx_area);
@@ -1645,7 +1645,8 @@ XHCI::_InsertEndpointForPipe(Pipe *pipe)
status_t status = ConfigureEndpoint(device->slot, id,
pipe->Type(),
pipe->Direction() == Pipe::In,
device->endpoints[id].trb_addr,
- pipe->Interval(), pipe->MaxPacketSize(),
usbDevice->Speed());
+ pipe->Interval(), pipe->MaxPacketSize(),
usbDevice->Speed(),
+ pipe->MaxBurst(), pipe->BytesPerInterval());
if (status != B_OK) {
TRACE_ERROR("unable to configure endpoint\n");
return status;
@@ -1844,7 +1845,8 @@ XHCI::_UnlinkDescriptorForPipe(xhci_td *descriptor,
xhci_endpoint *endpoint)
status_t
XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, bool directionIn,
- uint64 ringAddr, uint16 interval, uint16 maxPacketSize, usb_speed speed)
+ uint64 ringAddr, uint16 interval, uint16 maxPacketSize, usb_speed speed,
+ uint8 maxBurst, uint16 bytesPerInterval)
{
struct xhci_device* device = &fDevices[slot];
@@ -1903,21 +1905,18 @@ XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8
type, bool directionIn,
// For non-isochronous endpoints, we want the controller to retry failed
// transfers, if possible. (XHCI 1.1 § 4.10.2.3 p189.)
- if (!(type & USB_OBJECT_ISO_PIPE))
+ if ((type & USB_OBJECT_ISO_PIPE) == 0)
dwendpoint1 |= ENDPOINT_1_CERR(3);
- // Assign maximum burst size.
- // TODO: While computing the maximum burst this way is correct for USB2
- // devices, it is merely acceptable for USB3 devices, which have a more
- // correct value stored in the Companion Descriptor. (Further, this
value
- // in the USB3 Companion Descriptor is to be used for *all* endpoints,
not
- // just Interrupt and Isoch ones.)
- uint8 maxBurst = (maxPacketSize & 0x1800) >> 11;
- if (speed >= USB_SPEED_HIGHSPEED
- && (((type & USB_OBJECT_INTERRUPT_PIPE) != 0)
- || (type & USB_OBJECT_ISO_PIPE) != 0)) {
- dwendpoint1 |= ENDPOINT_1_MAXBURST(maxBurst);
+ // Assign maximum burst size. For USB3 devices this is passed in; for
+ // all other devices we compute it. (XHCI 1.1 § 4.8.2 p154.)
+ if (speed == USB_SPEED_HIGHSPEED && (type & (USB_OBJECT_INTERRUPT_PIPE
+ | USB_OBJECT_ISO_PIPE)) != 0) {
+ maxBurst = (maxPacketSize & 0x1800) >> 11;
+ } else if (speed != USB_SPEED_SUPER) {
+ maxBurst = 0;
}
+ dwendpoint1 |= ENDPOINT_1_MAXBURST(maxBurst);
// Assign maximum packet size, set the ring address, and set the
// "Dequeue Cycle State" bit. (XHCI 1.1 § 6.2.3 Table 6-10 p430.)
@@ -1934,10 +1933,15 @@ XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8
type, bool directionIn,
}
// Assign maximum ESIT payload. (XHCI 1.1 § 4.14.2 p250.)
- // TODO: This computation is *only* correct for USB2 devices.
- if (((type & USB_OBJECT_INTERRUPT_PIPE) != 0)
- || ((type & USB_OBJECT_ISO_PIPE) != 0)) {
- dwendpoint4 |= ENDPOINT_4_MAXESITPAYLOAD((maxBurst + 1) *
maxPacketSize);
+ if ((type & (USB_OBJECT_INTERRUPT_PIPE | USB_OBJECT_ISO_PIPE)) != 0) {
+ // TODO: For SuperSpeedPlus endpoints, there is yet another
descriptor
+ // for isochronous endpoints that specifies the maximum ESIT
payload.
+ // We don't fetch this yet, so just fall back to the USB2
computation
+ // method if bytesPerInterval is 0.
+ if (speed == USB_SPEED_SUPER && bytesPerInterval != 0)
+ dwendpoint4 |=
ENDPOINT_4_MAXESITPAYLOAD(bytesPerInterval);
+ else if (speed >= USB_SPEED_HIGHSPEED)
+ dwendpoint4 |= ENDPOINT_4_MAXESITPAYLOAD((maxBurst + 1)
* maxPacketSize);
}
_WriteContext(&device->input_ctx->endpoints[number].dwendpoint0,
diff --git a/src/add-ons/kernel/busses/usb/xhci.h
b/src/add-ons/kernel/busses/usb/xhci.h
index 674c421a3d..f5d5a07b9a 100644
--- a/src/add-ons/kernel/busses/usb/xhci.h
+++ b/src/add-ons/kernel/busses/usb/xhci.h
@@ -137,7 +137,8 @@ private:
status_t ConfigureEndpoint(uint8
slot, uint8 number,
uint8
type, bool directionIn, uint64 ringAddr,
uint16
interval, uint16 maxPacketSize,
-
usb_speed speed);
+
usb_speed speed, uint8 maxBurst,
+ uint16
bytesPerInterval);
status_t
_InsertEndpointForPipe(Pipe *pipe);
status_t
_RemoveEndpointForPipe(Pipe *pipe);
diff --git a/src/add-ons/kernel/busses/usb/xhci_rh.cpp
b/src/add-ons/kernel/busses/usb/xhci_rh.cpp
index 5556c8c08c..e313b136ed 100644
--- a/src/add-ons/kernel/busses/usb/xhci_rh.cpp
+++ b/src/add-ons/kernel/busses/usb/xhci_rh.cpp
@@ -31,20 +31,11 @@ static usb_device_descriptor sXHCIRootHubDevice =
};
-struct usb_endpoint_ss_comp_descriptor {
- uint8 length;
- uint8 descriptor_type;
- uint16 burst;
- uint8 attributes;
- uint16 internal;
-} _PACKED;
-
-
struct xhci_root_hub_configuration_s {
usb_configuration_descriptor configuration;
usb_interface_descriptor interface;
usb_endpoint_descriptor endpoint;
- usb_endpoint_ss_comp_descriptor endpc;
+ usb_endpoint_companion_descriptor endpc;
usb_hub_descriptor hub;
} _PACKED;
@@ -86,7 +77,7 @@ static xhci_root_hub_configuration_s sXHCIRootHubConfig =
{ // endpoint companion descriptor
7,
- 0x30,
+ USB_DESCRIPTOR_ENDPOINT_COMPANION,
0,
0,
0