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 <kallisti5@unixzen.com>
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
Alexander von Gluck IV 2021-05-24 19:43:36 -05:00 committed by Adrien Destugues
parent a60e5cb46e
commit 37db8e9aed
2 changed files with 34 additions and 8 deletions

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 <jerome.duval@gmail.com>
* Akshay Jaggi <akshay1994.leo@gmail.com>
* Michael Lotz <mmlr@mlotz.ch>
* Alexander von Gluck <kallisti5@unixzen.com>
*/
@ -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;

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);