From patchwork Tue Apr 21 14:08:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathias Nyman X-Patchwork-Id: 11501539 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7647D112C for ; Tue, 21 Apr 2020 14:06:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6894D206B9 for ; Tue, 21 Apr 2020 14:06:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728823AbgDUOGN (ORCPT ); Tue, 21 Apr 2020 10:06:13 -0400 Received: from mga03.intel.com ([134.134.136.65]:63242 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728786AbgDUOGK (ORCPT ); Tue, 21 Apr 2020 10:06:10 -0400 IronPort-SDR: OOB2buhqClYQ6qIMiAI9zPPvpwBb3Av57UVNiEH3ZlpkyNuFp6kmiT44YhU5iNJrz2cqPkfMGL oIT86dmqGsDg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2020 07:05:50 -0700 IronPort-SDR: VLvW7sE1BVjMMmJqiJseg+5kNRpLfKuB9W4kmus6Je6tgy/4nCYp4HmCSjUvYoH24MiabtXh49 cdJvEnpwf1aQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,410,1580803200"; d="scan'208";a="300618776" Received: from mattu-haswell.fi.intel.com ([10.237.72.170]) by FMSMGA003.fm.intel.com with ESMTP; 21 Apr 2020 07:05:49 -0700 From: Mathias Nyman To: Cc: , Mathias Nyman , stable@vger.kernel.org, Jeremy Compostella Subject: [PATCH 1/3] xhci: Fix handling halted endpoint even if endpoint ring appears empty Date: Tue, 21 Apr 2020 17:08:20 +0300 Message-Id: <20200421140822.28233-2-mathias.nyman@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200421140822.28233-1-mathias.nyman@linux.intel.com> References: <20200421140822.28233-1-mathias.nyman@linux.intel.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org If a class driver cancels its only URB then the endpoint ring buffer will appear empty to the xhci driver. xHC hardware may still process cached TRBs, and complete with a STALL, halting the endpoint. This halted endpoint was not handled correctly by xhci driver as events on empty rings were all assumed to be spurious events. xhci driver refused to restart the ring with EP_HALTED flag set, so class driver was never informed the endpoint halted even if it queued new URBs. The host side of the endpoint needs to be reset, and dequeue pointer should be moved in order to clear the cached TRBs and resetart the endpoint. Small adjustments in finding the new dequeue pointer are needed to support the case of stall on an empty ring and unknown current TD. Cc: cc: Jeremy Compostella Signed-off-by: Mathias Nyman --- drivers/usb/host/xhci-ring.c | 30 +++++++++++++++++++++++++++++- drivers/usb/host/xhci.c | 14 +++++++------- drivers/usb/host/xhci.h | 5 +++-- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a78787bb5133..a7f4cd35da55 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -547,6 +547,23 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, stream_id); return; } + /* + * A cancelled TD can complete with a stall if HW cached the trb. + * In this case driver can't find cur_td, but if the ring is empty we + * can move the dequeue pointer to the current enqueue position. + */ + if (!cur_td) { + if (list_empty(&ep_ring->td_list)) { + state->new_deq_seg = ep_ring->enq_seg; + state->new_deq_ptr = ep_ring->enqueue; + state->new_cycle_state = ep_ring->cycle_state; + goto done; + } else { + xhci_warn(xhci, "Can't find new dequeue state, missing cur_td\n"); + return; + } + } + /* Dig out the cycle state saved by the xHC during the stop ep cmd */ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Finding endpoint context"); @@ -592,6 +609,7 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, state->new_deq_seg = new_seg; state->new_deq_ptr = new_deq; +done: /* Don't update the ring cycle state for the producer (us). */ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Cycle state = 0x%x", state->new_cycle_state); @@ -1856,7 +1874,8 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, if (reset_type == EP_HARD_RESET) { ep->ep_state |= EP_HARD_CLEAR_TOGGLE; - xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td); + xhci_cleanup_stalled_ring(xhci, slot_id, ep_index, stream_id, + td); xhci_clear_hub_tt_buffer(xhci, td, ep); } xhci_ring_cmd_db(xhci); @@ -2539,6 +2558,15 @@ static int handle_tx_event(struct xhci_hcd *xhci, xhci_dbg(xhci, "td_list is empty while skip flag set. Clear skip flag for slot %u ep %u.\n", slot_id, ep_index); } + if (trb_comp_code == COMP_STALL_ERROR || + xhci_requires_manual_halt_cleanup(xhci, ep_ctx, + trb_comp_code)) { + xhci_cleanup_halted_endpoint(xhci, slot_id, + ep_index, + ep_ring->stream_id, + NULL, + EP_HARD_RESET); + } goto cleanup; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index fe38275363e0..bee5deccc83d 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3031,19 +3031,19 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, added_ctxs, added_ctxs); } -void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, - unsigned int stream_id, struct xhci_td *td) +void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int slot_id, + unsigned int ep_index, unsigned int stream_id, + struct xhci_td *td) { struct xhci_dequeue_state deq_state; - struct usb_device *udev = td->urb->dev; xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, "Cleaning up stalled endpoint ring"); /* We need to move the HW's dequeue pointer past this TD, * or it will attempt to resend it on the next doorbell ring. */ - xhci_find_new_dequeue_state(xhci, udev->slot_id, - ep_index, stream_id, td, &deq_state); + xhci_find_new_dequeue_state(xhci, slot_id, ep_index, stream_id, td, + &deq_state); if (!deq_state.new_deq_ptr || !deq_state.new_deq_seg) return; @@ -3054,7 +3054,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) { xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, "Queueing new dequeue state"); - xhci_queue_new_dequeue_state(xhci, udev->slot_id, + xhci_queue_new_dequeue_state(xhci, slot_id, ep_index, &deq_state); } else { /* Better hope no one uses the input context between now and the @@ -3065,7 +3065,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "Setting up input context for " "configure endpoint command"); - xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id, + xhci_setup_input_ctx_for_quirk(xhci, slot_id, ep_index, &deq_state); } } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3289bb516201..86cfefdd6632 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2116,8 +2116,9 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state); -void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, - unsigned int stream_id, struct xhci_td *td); +void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int slot_id, + unsigned int ep_index, unsigned int stream_id, + struct xhci_td *td); void xhci_stop_endpoint_command_watchdog(struct timer_list *t); void xhci_handle_command_timeout(struct work_struct *work); From patchwork Tue Apr 21 14:08:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathias Nyman X-Patchwork-Id: 11501535 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EF8DD913 for ; Tue, 21 Apr 2020 14:06:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D817A206B8 for ; Tue, 21 Apr 2020 14:06:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728825AbgDUOGN (ORCPT ); Tue, 21 Apr 2020 10:06:13 -0400 Received: from mga03.intel.com ([134.134.136.65]:63245 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726691AbgDUOGL (ORCPT ); Tue, 21 Apr 2020 10:06:11 -0400 IronPort-SDR: 7E9q1WQMLbPVGsU1WYyinM3EyW0H2cA02EdvIL0YTYJBxlXyH5wpKBZVYFWyQ98WznzXOtQwED z+YpygC5BeaA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2020 07:05:52 -0700 IronPort-SDR: S4nTtBZJn0OzWgKune4epgHbGhcfbMXbhOdYPGj9NoQdt+8d9nhnsJvMioeyIOzjrO/9t5Z4Jl dP6qcJj5sUHA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,410,1580803200"; d="scan'208";a="300618777" Received: from mattu-haswell.fi.intel.com ([10.237.72.170]) by FMSMGA003.fm.intel.com with ESMTP; 21 Apr 2020 07:05:51 -0700 From: Mathias Nyman To: Cc: , Mathias Nyman , stable@vger.kernel.org Subject: [PATCH 2/3] xhci: prevent bus suspend if a roothub port detected a over-current condition Date: Tue, 21 Apr 2020 17:08:21 +0300 Message-Id: <20200421140822.28233-3-mathias.nyman@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200421140822.28233-1-mathias.nyman@linux.intel.com> References: <20200421140822.28233-1-mathias.nyman@linux.intel.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Suspending the bus and host controller while a port is in a over-current condition may halt the host. Also keep the roothub running if over-current is active. Cc: Signed-off-by: Mathias Nyman --- drivers/usb/host/xhci-hub.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 9eca1fe81061..f37316d2c8fa 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1571,6 +1571,8 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) } if ((temp & PORT_RC)) reset_change = true; + if (temp & PORT_OC) + status = 1; } if (!status && !reset_change) { xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); @@ -1636,6 +1638,13 @@ int xhci_bus_suspend(struct usb_hcd *hcd) port_index); goto retry; } + /* bail out if port detected a over-current condition */ + if (t1 & PORT_OC) { + bus_state->bus_suspended = 0; + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "Bus suspend bailout, port over-current detected\n"); + return -EBUSY; + } /* suspend ports in U0, or bail out for new connect changes */ if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) { if ((t1 & PORT_CSC) && wake_enabled) { From patchwork Tue Apr 21 14:08:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathias Nyman X-Patchwork-Id: 11501537 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8B330112C for ; Tue, 21 Apr 2020 14:06:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7D6AD20679 for ; Tue, 21 Apr 2020 14:06:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728859AbgDUOGN (ORCPT ); Tue, 21 Apr 2020 10:06:13 -0400 Received: from mga03.intel.com ([134.134.136.65]:63242 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728803AbgDUOGN (ORCPT ); Tue, 21 Apr 2020 10:06:13 -0400 IronPort-SDR: n7qBGmWkrR6aw5d0TYAekxYeKUbTdmb5sN8Lzj/sc96bPevdkUJLSbM0xw+86AE8Mh+4/o/uvB kYjnVlw0onwg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2020 07:05:54 -0700 IronPort-SDR: 2kQ2yg96dEgzsaxwkEf8tr67qltQsX4naEa30Ps9z+gXmacLoLu1sKes1TxkS+q5XRLmmnss// QkLBa89Ck4Yw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,410,1580803200"; d="scan'208";a="300618779" Received: from mattu-haswell.fi.intel.com ([10.237.72.170]) by FMSMGA003.fm.intel.com with ESMTP; 21 Apr 2020 07:05:52 -0700 From: Mathias Nyman To: Cc: , Mathias Nyman , stable@vger.kernel.org Subject: [PATCH 3/3] xhci: Don't clear hub TT buffer on ep0 protocol stall Date: Tue, 21 Apr 2020 17:08:22 +0300 Message-Id: <20200421140822.28233-4-mathias.nyman@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200421140822.28233-1-mathias.nyman@linux.intel.com> References: <20200421140822.28233-1-mathias.nyman@linux.intel.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org The default control endpoint ep0 can return a STALL indicating the device does not support the control transfer requests. This is called a protocol stall and does not halt the endpoint. xHC behaves a bit different. Its internal endpoint state will always be halted on any stall, even if the device side of the endpiont is not halted. So we do need to issue the reset endpoint command to clear the xHC host intenal endpoint halt state, but should not request the HS hub to clear the TT buffer unless device side of endpoint is halted. Clearing the hub TT buffer at protocol stall caused ep0 to become unresponsive for some FS/LS devices behind HS hubs, and class drivers failed to set the interface due to timeout: usb 1-2.1: 1:1: usb_set_interface failed (-110) Fixes: ef513be0a905 ("usb: xhci: Add Clear_TT_Buffer") Cc: # v5.3 Signed-off-by: Mathias Nyman --- drivers/usb/host/xhci-ring.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a7f4cd35da55..0fda0c0f4d31 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1876,7 +1876,6 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, ep->ep_state |= EP_HARD_CLEAR_TOGGLE; xhci_cleanup_stalled_ring(xhci, slot_id, ep_index, stream_id, td); - xhci_clear_hub_tt_buffer(xhci, td, ep); } xhci_ring_cmd_db(xhci); } @@ -1997,11 +1996,18 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, if (trb_comp_code == COMP_STALL_ERROR || xhci_requires_manual_halt_cleanup(xhci, ep_ctx, trb_comp_code)) { - /* Issue a reset endpoint command to clear the host side - * halt, followed by a set dequeue command to move the - * dequeue pointer past the TD. - * The class driver clears the device side halt later. + /* + * xhci internal endpoint state will go to a "halt" state for + * any stall, including default control pipe protocol stall. + * To clear the host side halt we need to issue a reset endpoint + * command, followed by a set dequeue command to move past the + * TD. + * Class drivers clear the device side halt from a functional + * stall later. Hub TT buffer should only be cleared for FS/LS + * devices behind HS hubs for functional stalls. */ + if ((ep_index != 0) || (trb_comp_code != COMP_STALL_ERROR)) + xhci_clear_hub_tt_buffer(xhci, td, ep); xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, ep_ring->stream_id, td, EP_HARD_RESET); } else {