From patchwork Tue Jan 2 21:45:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wesley Cheng X-Patchwork-Id: 13509399 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.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 DBBE0171DE; Tue, 2 Jan 2024 21:46:42 +0000 (UTC) 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="f2RLNxYu" Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.24/8.17.1.24) with ESMTP id 402LLX2k018405; Tue, 2 Jan 2024 21:46:20 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type; s=qcppdkim1; bh=dvSeSujDsWAxoUgpDofY eTPsm6P/pMlRxfIJ/11lUYU=; b=f2RLNxYueYV4o2pMXQKUpL4KRWZZmtKc0WUK pc/JxTOxJsZWPwme/klqSMJJoYe5kO8M6pdRco2PKBngasS4uKDcqK3YCrbflQPs J9e5HACoxXfN4VR64lB0giZ5ITeTs9/xRIvz0+gqVTfNJamltsO/rc9/qVkvthd9 bhejiPmDsFk9yRGou7PJFpRNXJx19P8pSgFd0OovItGIu9zUJk4ESXd/hdEaeRb6 ptOgEmAKkFs+j6fY4XPLT8K5zaA/wt0q1cy/Fmz/loIW+3XKzAyjEflK7vDGtwLM wZURbOx6/u8SdTql9FcDGDMPzKaXccysScxPRau8xSt8mYcwtg== Received: from nalasppmta02.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3vcg419bat-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 02 Jan 2024 21:46:19 +0000 (GMT) Received: from nalasex01b.na.qualcomm.com (nalasex01b.na.qualcomm.com [10.47.209.197]) by NALASPPMTA02.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 402LkI7O011442 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 2 Jan 2024 21:46:18 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.1118.40; Tue, 2 Jan 2024 13:46:18 -0800 From: Wesley Cheng To: , , , , , , , , , , , , , , , CC: , , , , , , , Wesley Cheng Subject: [PATCH v12 04/41] usb: host: xhci-mem: Cleanup pending secondary event ring events Date: Tue, 2 Jan 2024 13:45:12 -0800 Message-ID: <20240102214549.22498-5-quic_wcheng@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240102214549.22498-1-quic_wcheng@quicinc.com> References: <20240102214549.22498-1-quic_wcheng@quicinc.com> Precedence: bulk X-Mailing-List: linux-sound@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-GUID: nGR2oXkUThsdwGRb_FdP30C5PMFCSnck X-Proofpoint-ORIG-GUID: nGR2oXkUThsdwGRb_FdP30C5PMFCSnck X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.997,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2023-12-09_01,2023-12-07_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 mlxscore=0 phishscore=0 spamscore=0 bulkscore=0 adultscore=0 priorityscore=1501 impostorscore=0 mlxlogscore=780 malwarescore=0 suspectscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2311290000 definitions=main-2401020161 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. Signed-off-by: Wesley Cheng --- drivers/usb/host/xhci-mem.c | 11 +++++---- drivers/usb/host/xhci-ring.c | 46 +++++++++++++++++++++++++++++++++++- drivers/usb/host/xhci.c | 2 +- drivers/usb/host/xhci.h | 7 ++++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 4460fa7e9fab..5bf74c37cbf6 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1827,7 +1827,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, ir->event_ring->first_seg->trbs, true); } } @@ -1865,11 +1865,12 @@ void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrup if (!ir || !ir->intr_num || ir->intr_num >= xhci->max_interrupters) xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n"); - /* fixme, should we check xhci->interrupter[intr_num] == ir */ - /* fixme locking */ - spin_lock_irq(&xhci->lock); - + /* + * 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 33806ae966f9..448417c5d5b1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2980,7 +2980,7 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir) * - When all events have finished * - To avoid "Event Ring Full Error" condition */ -static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, +void xhci_update_erst_dequeue(struct xhci_hcd *xhci, struct xhci_interrupter *ir, union xhci_trb *event_ring_deq, bool clear_ehb) @@ -3013,6 +3013,50 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue); } +/* + * 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 *erdp_trb, *current_trb; + u64 erdp_reg; + u32 iman_reg; + dma_addr_t deq; + + /* disable irq, ack pending interrupt and ack all pending events */ + xhci_disable_interrupter(ir); + iman_reg = readl_relaxed(&ir->ir_set->irq_pending); + if (iman_reg & IMAN_IP) + writel_relaxed(iman_reg, &ir->ir_set->irq_pending); + + /* 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; + } + + erdp_trb = 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; + + while (1) { + inc_deq(xhci, ir->event_ring); + erdp_trb = ir->event_ring->dequeue; + /* cycle state transition */ + if ((le32_to_cpu(erdp_trb->event_cmd.flags) & TRB_CYCLE) != + ring->cycle_state) + break; + } + + xhci_update_erst_dequeue(xhci, ir, current_trb, 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 diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 573ca5c4f31a..eb15c63e6775 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -333,7 +333,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 e98099b960e4..37887c2f0653 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2093,6 +2093,9 @@ struct xhci_interrupter * xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg); 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); +int xhci_disable_interrupter(struct xhci_interrupter *ir); /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); @@ -2180,6 +2183,10 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring); 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_update_erst_dequeue(struct xhci_hcd *xhci, + struct xhci_interrupter *ir, + union xhci_trb *event_ring_deq, + bool clear_ehb); /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,