xhci: Enhance endpoint state handling

* Expands on previous change to no enter a stopped
  state on an endpoint teardown.
* Doorbells could re-awaken the port in a stopped state

Change-Id: Ib5d9c89c4b721ea36ca22aaaf3ff92760a3ec2ff
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3996
Reviewed-by: Alex von Gluck IV <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Alexander von Gluck IV
2021-06-04 07:39:12 +00:00
committed by Adrien Destugues
parent a60e5cb46e
commit 37db8e9aed
2 changed files with 34 additions and 8 deletions
+32 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2019, Haiku, Inc. All rights reserved.
* Copyright 2011-2021, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -8,6 +8,7 @@
* Jérôme Duval <[email protected]>
* Akshay Jaggi <[email protected]>
* Michael Lotz <[email protected]>
* Alexander von Gluck <[email protected]>
*/
@@ -969,6 +970,12 @@ XHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
// order to avoid a deadlock, we must unlock the endpoint.
endpointLocker.Unlock();
status_t status = StopEndpoint(false, endpoint);
if (status == B_NOT_ALLOWED) {
// XHCI 1.2, 4.8.3 Endpoint State Diagram
// Only exit from a HALTED state is a reset
TRACE_ERROR("cancel queued transfers: halted endpoint. reset!");
status = ResetEndpoint(false, endpoint);
}
endpointLocker.Lock();
// Detach the head TD from the endpoint.
@@ -1665,6 +1672,16 @@ XHCI::FreeDevice(Device *device)
}
uint8
XHCI::_GetEndpointState(xhci_endpoint* endpoint)
{
struct xhci_device_ctx* device_ctx = endpoint->device->device_ctx;
return ENDPOINT_0_STATE_GET(
_ReadContext(&device_ctx->endpoints[endpoint->id].dwendpoint0));
}
status_t
XHCI::_InsertEndpointForPipe(Pipe *pipe)
{
@@ -2689,6 +2706,16 @@ XHCI::ResetEndpoint(bool preserve, xhci_endpoint* endpoint)
{
TRACE("Reset Endpoint\n");
switch (_GetEndpointState(endpoint)) {
case ENDPOINT_STATE_STOPPED:
TRACE("Reset Endpoint: already stopped");
return B_OK;
case ENDPOINT_STATE_HALTED:
TRACE("Reset Endpoint: warning, weird state!");
default:
break;
}
xhci_trb trb;
trb.address = 0;
trb.status = 0;
@@ -2705,16 +2732,13 @@ status_t
XHCI::StopEndpoint(bool suspend, xhci_endpoint* endpoint)
{
TRACE("Stop Endpoint\n");
struct xhci_device_ctx* device_ctx = endpoint->device->device_ctx;
// XHCI 1.2, 4.8.3 Endpoint State Diagram
// Only exit from a HALTED state is a reset which will also stop the ep
switch (ENDPOINT_0_STATE_GET(_ReadContext(
&device_ctx->endpoints[endpoint->id].dwendpoint0))) {
switch (_GetEndpointState(endpoint)) {
case ENDPOINT_STATE_HALTED:
TRACE("Detected XHCI endpoint in halted state. Calling reset.");
return ResetEndpoint(false, endpoint);
TRACE("Stop Endpoint: error, halted");
return B_NOT_ALLOWED;
case ENDPOINT_STATE_STOPPED:
TRACE("Stop Endpoint: already stopped");
return B_OK;
default:
break;
+2
View File
@@ -138,6 +138,8 @@ private:
uint16 interval, uint16 maxPacketSize,
usb_speed speed, uint8 maxBurst,
uint16 bytesPerInterval);
uint8 _GetEndpointState(xhci_endpoint* ep);
status_t _InsertEndpointForPipe(Pipe *pipe);
status_t _RemoveEndpointForPipe(Pipe *pipe);