xhci: Check endpoint state before stop

* As per the spec, the only exit from an endpoint in a halt
  state is to issue a restart command. (restart puts the endpoint
  into a stop state.. it's named poorly)

Change-Id: I4a1a556374ad7f564a562d995d1a2e29230a50c3
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3959
Reviewed-by: Alex von Gluck IV <kallisti5@unixzen.com>
This commit is contained in:
Alexander von Gluck IV 2021-05-21 12:30:14 -05:00 committed by Alex von Gluck IV
parent bd6434b663
commit 53d0323422
3 changed files with 34 additions and 13 deletions

View File

@ -968,8 +968,7 @@ XHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
// complete, one of the queued transfers posts a completion event, so in
// order to avoid a deadlock, we must unlock the endpoint.
endpointLocker.Unlock();
status_t status = StopEndpoint(false, endpoint->id + 1,
endpoint->device->slot);
status_t status = StopEndpoint(false, endpoint);
endpointLocker.Lock();
// Detach the head TD from the endpoint.
@ -1776,7 +1775,7 @@ XHCI::_RemoveEndpointForPipe(Pipe *pipe)
if (endpoint->id > 0) {
xhci_device *device = endpoint->device;
uint8 epNumber = endpoint->id + 1;
StopEndpoint(true, epNumber, device->slot);
StopEndpoint(true, endpoint);
mutex_lock(&endpoint->lock);
@ -2686,14 +2685,15 @@ XHCI::EvaluateContext(uint64 inputContext, uint8 slot)
status_t
XHCI::ResetEndpoint(bool preserve, uint8 endpoint, uint8 slot)
XHCI::ResetEndpoint(bool preserve, xhci_endpoint* endpoint)
{
TRACE("Reset Endpoint\n");
xhci_trb trb;
trb.address = 0;
trb.status = 0;
trb.flags = TRB_3_TYPE(TRB_TYPE_RESET_ENDPOINT)
| TRB_3_SLOT(slot) | TRB_3_ENDPOINT(endpoint);
| TRB_3_SLOT(endpoint->device->slot) | TRB_3_ENDPOINT(endpoint->id + 1);
if (preserve)
trb.flags |= TRB_3_PRSV_BIT;
@ -2702,14 +2702,29 @@ XHCI::ResetEndpoint(bool preserve, uint8 endpoint, uint8 slot)
status_t
XHCI::StopEndpoint(bool suspend, uint8 endpoint, uint8 slot)
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))) {
case ENDPOINT_STATE_HALTED:
TRACE("Detected XHCI endpoint in halted state. Calling reset.");
return ResetEndpoint(false, endpoint);
case ENDPOINT_STATE_STOPPED:
return B_OK;
default:
break;
}
xhci_trb trb;
trb.address = 0;
trb.status = 0;
trb.flags = TRB_3_TYPE(TRB_TYPE_STOP_ENDPOINT)
| TRB_3_SLOT(slot) | TRB_3_ENDPOINT(endpoint);
| TRB_3_SLOT(endpoint->device->slot) | TRB_3_ENDPOINT(endpoint->id + 1);
if (suspend)
trb.flags |= TRB_3_SUSPEND_ENDPOINT_BIT;

View File

@ -185,10 +185,8 @@ private:
bool deconfigure, uint8 slot);
status_t EvaluateContext(uint64 inputContext,
uint8 slot);
status_t ResetEndpoint(bool preserve, uint8 endpoint,
uint8 slot);
status_t StopEndpoint(bool suspend, uint8 endpoint,
uint8 slot);
status_t ResetEndpoint(bool preserve, xhci_endpoint* endpoint);
status_t StopEndpoint(bool suspend, xhci_endpoint* endpoint);
status_t SetTRDequeue(uint64 dequeue, uint16 stream,
uint8 endpoint, uint8 slot);
status_t ResetDevice(uint8 slot);

View File

@ -385,8 +385,8 @@ struct xhci_endpoint_ctx {
};
#define ENDPOINT_0_STATE(x) ((x) & 0x3)
#define ENDPOINT_0_STATE_GET(x) ((x) & 0x3)
#define ENDPOINT_0_STATE(x) ((x) & 0x7)
#define ENDPOINT_0_STATE_GET(x) ((x) & 0x7)
#define ENDPOINT_0_MULT(x) (((x) & 0x3) << 8)
#define ENDPOINT_0_MULT_GET(x) (((x) >> 8) & 0x3)
#define ENDPOINT_0_MAXPSTREAMS(x) (((x) & 0x1F) << 10)
@ -412,6 +412,14 @@ struct xhci_endpoint_ctx {
#define ENDPOINT_4_MAXESITPAYLOAD(x) (((x) & 0xFFFF) << 16)
#define ENDPOINT_4_MAXESITPAYLOAD_GET(x) (((x) >> 16) & 0xFFFF)
#define ENDPOINT_STATE_DISABLED 0
#define ENDPOINT_STATE_RUNNING 1
#define ENDPOINT_STATE_HALTED 2
#define ENDPOINT_STATE_STOPPED 3
#define ENDPOINT_STATE_ERROR 4
#define ENDPOINT_STATE_RESERVED_5 5
#define ENDPOINT_STATE_RESERVED_6 6
#define ENDPOINT_STATE_RESERVED_7 7
struct xhci_stream_ctx {
uint64 qwstream0;