From patchwork Fri Apr 4 00:26:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wesley Cheng X-Patchwork-Id: 878588 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B21C51F3FD2; Fri, 4 Apr 2025 00:28:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743726490; cv=none; b=Hv+0hRANODKdqdp6aejewTwA1hhRD7p6CqBYf6COlIludIlq3w5HX2VSSofuCEJEqRuIsE3Q95F3vNtPmsIxl8rRpviwwU12Ag20PjYA+Wdr92Po1ghkfTFcLQqW56d2ANDd3/Q3TOYeZD+IuRpQHRRrXi5VLMbvmYfHvn/hwaI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743726490; c=relaxed/simple; bh=rwgxL+BHcw7P/J4RymdX9lTPTAqo2UpedZtzaYAyz90=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KU3ZSnvwbZ+1sPnRXWvsPxnN1Cr0Nj2i3W4XqADLb7xBdlMsUUcVraTAgTHxSlPatnR6MdTvaYryZoDRcdV0uAWKskKRsMkPAtfBBfWBjUB8654SOGxHo+B+g1QYxjITF9CptpXWzuRComKIYYi+oO+TkPl3E58WAqtgxsF0G6w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=RYx3JtuB; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="RYx3JtuB" Received: from pps.filterd (m0279871.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 533NY7ha024033; Fri, 4 Apr 2025 00:27:41 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= IOK2OitAwTGpm57npB7O35t+UR/IiygxmUmRF8Jrf/I=; b=RYx3JtuBaUS7MvlR l1hs6IjKq8Ia9Hxr0QD0/gJtQ4UKefDyUZyAP3jt0aKtvEw8dPfV74stMZjd33zV gLltJ3MDH7aQSXpy0d1cEOCS98xhxZHwikLiGeZJQJBpaCWtQylSuX2As0EQ6yAe lMD96E3vlBiKj+Z5UW5u8FIMuYGtzDQcIsRwSfNSBcX6IMqYQLLwLN+3sR3WtU9t ogZLfoalSZXXKefAoBLvSlIb59hV/5AMedy0U34iVkxtdMGN0LROlp/H7nRdniG4 AkuT/t8JAJlFSZ4cSlkj/G8PJOMn1BQ2m2YFyW+Z7iC0PswYJzfc6hhZj/axSL78 0xEclA== Received: from nalasppmta03.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 45t2dar8th-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 04 Apr 2025 00:27:41 +0000 (GMT) Received: from nalasex01b.na.qualcomm.com (nalasex01b.na.qualcomm.com [10.47.209.197]) by NALASPPMTA03.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 5340Rd5C013294 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 4 Apr 2025 00:27:39 GMT Received: from hu-wcheng-lv.qualcomm.com (10.49.16.6) by nalasex01b.na.qualcomm.com (10.47.209.197) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Thu, 3 Apr 2025 17:27:39 -0700 From: Wesley Cheng To: , , , , , , , , , , , , , CC: , , , , , , , Wesley Cheng , Puma Hsu , Daehwan Jung Subject: [PATCH v37 02/31] usb: host: xhci-mem: Cleanup pending secondary event ring events Date: Thu, 3 Apr 2025 17:26:59 -0700 Message-ID: <20250404002728.3590501-3-quic_wcheng@quicinc.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250404002728.3590501-1-quic_wcheng@quicinc.com> References: <20250404002728.3590501-1-quic_wcheng@quicinc.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: nalasex01c.na.qualcomm.com (10.47.97.35) To nalasex01b.na.qualcomm.com (10.47.209.197) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: xLdBgf_ELbCggXWtlaNPeWPwYygEH3OJ X-Authority-Analysis: v=2.4 cv=MqFS63ae c=1 sm=1 tr=0 ts=67ef277d cx=c_pps a=ouPCqIW2jiPt+lZRy3xVPw==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=3H110R4YSZwA:10 a=XR8D0OoHHMoA:10 a=1XWaLZrsAAAA:8 a=hD80L64hAAAA:8 a=COk6AnOGAAAA:8 a=oNwvUYI6z9JRYqJgw0cA:9 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-GUID: xLdBgf_ELbCggXWtlaNPeWPwYygEH3OJ X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1095,Hydra:6.0.680,FMLib:17.12.68.34 definitions=2025-04-03_11,2025-04-03_03,2024-11-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 malwarescore=0 mlxlogscore=802 clxscore=1011 mlxscore=0 adultscore=0 impostorscore=0 bulkscore=0 priorityscore=1501 spamscore=0 suspectscore=0 phishscore=0 classifier=spam authscore=0 authtc=n/a authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2502280000 definitions=main-2504040001 As part of xHCI bus suspend, the xHCI is halted. However, if there are pending events in the secondary event ring, it is observed that the xHCI controller stops responding to further commands upon host or device initiated bus resume. Iterate through all pending events and update the dequeue pointer to the beginning of the event ring. Tested-by: Puma Hsu Tested-by: Daehwan Jung Signed-off-by: Wesley Cheng --- drivers/usb/host/xhci-mem.c | 7 +++++- drivers/usb/host/xhci-ring.c | 47 ++++++++++++++++++++++++++++++------ drivers/usb/host/xhci.c | 2 +- drivers/usb/host/xhci.h | 7 ++++++ 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d698095fc88d..daea0f76e844 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1805,7 +1805,7 @@ xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) tmp &= ERST_SIZE_MASK; writel(tmp, &ir->ir_set->erst_size); - xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue); + xhci_update_erst_dequeue(xhci, ir, true); } } @@ -1848,6 +1848,11 @@ void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrup return; } + /* + * Cleanup secondary interrupter to ensure there are no pending events. + * This also updates event ring dequeue pointer back to the start. + */ + xhci_skip_sec_intr_events(xhci, ir->event_ring, ir); intr_num = ir->intr_num; xhci_remove_interrupter(xhci, ir); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 5d64c297721c..bfef765dd78c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3054,9 +3054,9 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter * - When all events have finished * - To avoid "Event Ring Full Error" condition */ -static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, - struct xhci_interrupter *ir, - bool clear_ehb) +void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + struct xhci_interrupter *ir, + bool clear_ehb) { u64 temp_64; dma_addr_t deq; @@ -3099,10 +3099,11 @@ static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir) * Handle all OS-owned events on an interrupter event ring. It may drop * and reaquire xhci->lock between event processing. */ -static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir) +static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir, + bool skip_events) { int event_loop = 0; - int err; + int err = 0; u64 temp; xhci_clear_interrupt_pending(ir); @@ -3125,7 +3126,8 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir /* Process all OS owned event TRBs on this event ring */ while (unhandled_event_trb(ir->event_ring)) { - err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue); + if (!skip_events) + err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue); /* * If half a segment of events have been handled in one go then @@ -3152,6 +3154,37 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir return 0; } +/* + * Move the event ring dequeue pointer to skip events kept in the secondary + * event ring. This is used to ensure that pending events in the ring are + * acknowledged, so the xHCI HCD can properly enter suspend/resume. The + * secondary ring is typically maintained by an external component. + */ +void xhci_skip_sec_intr_events(struct xhci_hcd *xhci, + struct xhci_ring *ring, struct xhci_interrupter *ir) +{ + union xhci_trb *current_trb; + u64 erdp_reg; + dma_addr_t deq; + + /* disable irq, ack pending interrupt and ack all pending events */ + xhci_disable_interrupter(ir); + + /* last acked event trb is in erdp reg */ + erdp_reg = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); + deq = (dma_addr_t)(erdp_reg & ERST_PTR_MASK); + if (!deq) { + xhci_err(xhci, "event ring handling not required\n"); + return; + } + + current_trb = ir->event_ring->dequeue; + /* read cycle state of the last acked trb to find out CCS */ + ring->cycle_state = le32_to_cpu(current_trb->event_cmd.flags) & TRB_CYCLE; + + xhci_handle_events(xhci, ir, true); +} + /* * xHCI spec says we can get an interrupt, and if the HC has an error condition, * we might get bad data out of the event ring. Section 4.10.2.7 has a list of @@ -3196,7 +3229,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) writel(status, &xhci->op_regs->status); /* This is the handler of the primary interrupter */ - xhci_handle_events(xhci, xhci->interrupters[0]); + xhci_handle_events(xhci, xhci->interrupters[0], false); out: spin_unlock(&xhci->lock); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 83a4adf57bae..61950a350432 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -335,7 +335,7 @@ static int xhci_enable_interrupter(struct xhci_interrupter *ir) return 0; } -static int xhci_disable_interrupter(struct xhci_interrupter *ir) +int xhci_disable_interrupter(struct xhci_interrupter *ir) { u32 iman; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 39db228f0b84..3fa8669e3b2d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1856,6 +1856,9 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, u32 imod_interval); void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir); +void xhci_skip_sec_intr_events(struct xhci_hcd *xhci, + struct xhci_ring *ring, + struct xhci_interrupter *ir); /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); @@ -1895,6 +1898,7 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci, struct usb_tt *tt, gfp_t mem_flags); int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, u32 imod_interval); +int xhci_disable_interrupter(struct xhci_interrupter *ir); /* xHCI ring, segment, TRB, and TD functions */ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); @@ -1939,6 +1943,9 @@ unsigned int count_trbs(u64 addr, u64 len); int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, int suspend, gfp_t gfp_flags); void xhci_process_cancelled_tds(struct xhci_virt_ep *ep); +void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + struct xhci_interrupter *ir, + bool clear_ehb); /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,