From 37db8e9aed7556b26c04f89a16c83b9110e841d7 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Mon, 24 May 2021 19:43:36 -0500 Subject: [PATCH] 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 Reviewed-by: Adrien Destugues Tested-by: Commit checker robot --- src/add-ons/kernel/busses/usb/xhci.cpp | 40 ++++++++++++++++++++------ src/add-ons/kernel/busses/usb/xhci.h | 2 ++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index cc49b2f2b5..13cb0cc5c9 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -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 * Akshay Jaggi * Michael Lotz + * Alexander von Gluck */ @@ -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; diff --git a/src/add-ons/kernel/busses/usb/xhci.h b/src/add-ons/kernel/busses/usb/xhci.h index 57d0c14819..c7e108e9ff 100644 --- a/src/add-ons/kernel/busses/usb/xhci.h +++ b/src/add-ons/kernel/busses/usb/xhci.h @@ -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);