From patchwork Mon Mar 21 08:59:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jung Daehwan X-Patchwork-Id: 12787001 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E9C86C4332F for ; Mon, 21 Mar 2022 09:02:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345632AbiCUJDn (ORCPT ); Mon, 21 Mar 2022 05:03:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41180 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345600AbiCUJDl (ORCPT ); Mon, 21 Mar 2022 05:03:41 -0400 Received: from mailout4.samsung.com (mailout4.samsung.com [203.254.224.34]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A82B992855 for ; Mon, 21 Mar 2022 02:02:13 -0700 (PDT) Received: from epcas2p2.samsung.com (unknown [182.195.41.54]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20220321090211epoutp04e33141b9c25c5c1f827dde8460832589~eWd-b2S9i2431824318epoutp049 for ; Mon, 21 Mar 2022 09:02:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20220321090211epoutp04e33141b9c25c5c1f827dde8460832589~eWd-b2S9i2431824318epoutp049 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1647853331; bh=0ZBKOal9o0RAwuPgYl39qViuPY1EiXnhyFe1NQOXlrU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=r9xgPm4haxpIr9G3S3mWcvLBthYFnFwk/1wiKQwPw7k8ic1CdS3pcYpd0ki4/k136 gvTozL+DhxQJ3DudHJMFNRWMNFSg3Nn5uz6+uS6iIftS+U94Cncvz7z6CrfrGsMmSO giT2tAuM+j68Y6HzabLjTPcx8CEI7PzSrK2YMiMM= Received: from epsnrtp3.localdomain (unknown [182.195.42.164]) by epcas2p4.samsung.com (KnoxPortal) with ESMTP id 20220321090211epcas2p4237f28cb622e695e90f57ea0db78a089~eWd_6hJZW0252402524epcas2p4v; Mon, 21 Mar 2022 09:02:11 +0000 (GMT) Received: from epsmges2p3.samsung.com (unknown [182.195.36.88]) by epsnrtp3.localdomain (Postfix) with ESMTP id 4KMTC31YDTz4x9QH; Mon, 21 Mar 2022 09:02:07 +0000 (GMT) Received: from epcas2p3.samsung.com ( [182.195.41.55]) by epsmges2p3.samsung.com (Symantec Messaging Gateway) with SMTP id CE.16.25540.C0F38326; Mon, 21 Mar 2022 18:02:04 +0900 (KST) Received: from epsmtrp1.samsung.com (unknown [182.195.40.13]) by epcas2p3.samsung.com (KnoxPortal) with ESMTPA id 20220321090204epcas2p31e39a4b8b6fc803ceecac5d19e6e39e9~eWd4hNu8u1861518615epcas2p3I; Mon, 21 Mar 2022 09:02:04 +0000 (GMT) Received: from epsmgms1p2.samsung.com (unknown [182.195.42.42]) by epsmtrp1.samsung.com (KnoxPortal) with ESMTP id 20220321090204epsmtrp1577d4b73b077bdb91a42d68d917e800e~eWd4fpugv2591125911epsmtrp1a; Mon, 21 Mar 2022 09:02:04 +0000 (GMT) X-AuditID: b6c32a47-81bff700000063c4-70-62383f0cb425 Received: from epsmtip2.samsung.com ( [182.195.34.31]) by epsmgms1p2.samsung.com (Symantec Messaging Gateway) with SMTP id C1.F7.03370.C0F38326; Mon, 21 Mar 2022 18:02:04 +0900 (KST) Received: from ubuntu.dsn.sec.samsung.com (unknown [12.36.155.120]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20220321090203epsmtip264c16ceaf60044cce02b0cdada3b8f9c~eWd4PxAtW1528315283epsmtip26; Mon, 21 Mar 2022 09:02:03 +0000 (GMT) From: Daehwan Jung To: Mathias Nyman , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org (open list:USB XHCI DRIVER), linux-kernel@vger.kernel.org (open list), Howard Yen , Jack Pham , Puma Hsu , "J . Avila" , Daehwan Jung , sc.suh@samsung.com Subject: [PATCH v3 1/4] usb: host: export symbols for xhci hooks usage Date: Mon, 21 Mar 2022 17:59:51 +0900 Message-Id: <1647853194-62147-2-git-send-email-dh10.jung@samsung.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1647853194-62147-1-git-send-email-dh10.jung@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrLKsWRmVeSWpSXmKPExsWy7bCmuS6PvUWSwfI9JhZ3FkxjsnhyZBG7 RfPi9WwW1/+8Z7Rof36BzeLyrjlsFouWtTJbNG+awmoxc62yRdfdG4wOXB6X+3qZPBZsKvVY vOclk8f+uWvYPfq2rGL0+LxJLoAtKtsmIzUxJbVIITUvOT8lMy/dVsk7ON453tTMwFDX0NLC XEkhLzE31VbJxSdA1y0zB+gwJYWyxJxSoFBAYnGxkr6dTVF+aUmqQkZ+cYmtUmpBSk6BeYFe cWJucWleul5eaomVoYGBkSlQYUJ2xo7nE9kKfphX7Pz+hb2BcYpeFyMnh4SAiUTX+ScsXYxc HEICOxglfh16yQ7hfGKUONjTB5X5zCgx9d98oAwHWMvzByUQ8V2MEoe+n2eCcH4wSlza+Z4V pIhNQEvi+0JGkBUiAnESSzsvgdUwC6xmknj/8SIbSEJYwE2if+dbZhCbRUBVon3/BbAGXgFX iYYFvxkh7pOTuHmuE6yGE6h+7c1GsIskBF6ySyw5/Q3qIheJb9vTIOqFJV4d38IOYUtJvOxv g7KLJXZ9amWC6G1glGh8cIIZImEsMetZOyPIHGYBTYn1u/QhRipLHLnFAlLBLMAn0XH4L9Qm XomONiGIRmWJ6ZcnsELYkhIHX5+DGughseRuBzRIZjJK7Ju1lXUCo9wshAULGBlXMYqlFhTn pqcWGxUYwyMsOT93EyM43Wm572Cc8faD3iFGJg7GQ4wSHMxKIryLP5gnCfGmJFZWpRblxxeV 5qQWH2I0BYbdRGYp0eR8YMLNK4k3NLE0MDEzMzQ3MjUwVxLn9UrZkCgkkJ5YkpqdmlqQWgTT x8TBKdXAxPH8QvMdo33cGk/aHkbMkXSc8Sd8N+/dl9zpUas7l+tU7FjBuGol99Pp3MtM+Fyn 2uy9urR42ylR30tqd45tEVjJOpHP/sKdjUff+KqWCi96azZFvrh+0Yn0AyylOve5gx15xRhC e81C9y27dvbRX9H/bCZv1OayBT2e8PJf5JW6Q1u47m7jebtWepfCNOHOBwWx9zMOPTvT4Vgb oKdq8ykz1dLX9cjBc8ulD9+eZmmgpxsnoZ3f5vu87fuDaUo+L+7uZ9vpJdad1c3l0nvQeEld 60eH9nUfdzq9PSKjc33HpKQuiatBPiXTrt3+FZPJyWQa2bfH7Ib+ubkLT7d9W/BqQlFA7dno 3qp9H3V9/iuxFGckGmoxFxUnAgDnotB2AAQAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrBLMWRmVeSWpSXmKPExsWy7bCSvC6PvUWSwZI7zBZ3FkxjsnhyZBG7 RfPi9WwW1/+8Z7Rof36BzeLyrjlsFouWtTJbNG+awmoxc62yRdfdG4wOXB6X+3qZPBZsKvVY vOclk8f+uWvYPfq2rGL0+LxJLoAtissmJTUnsyy1SN8ugStjx/OJbAU/zCt2fv/C3sA4Ra+L kYNDQsBE4vmDki5GLg4hgR2MEtv/P2TpYuQEiktKLJ17gx3CFpa433KEFaLoG6PEnnsXWEGa 2QS0JL4vZASpERGIk1hxeQ8LSA2zwEYmiUkPLoENEhZwk+jf+ZYZxGYRUJVo338BrIFXwFWi YcFvRogFchI3z3WC1XAC1a+92QjWKwRUs3XSDNYJjHwLGBlWMUqmFhTnpucWGxYY5aWW6xUn 5haX5qXrJefnbmIEB6aW1g7GPas+6B1iZOJgPMQowcGsJMK7+IN5khBvSmJlVWpRfnxRaU5q 8SFGaQ4WJXHeC10n44UE0hNLUrNTUwtSi2CyTBycUg1MKQ7XVh5PfaS+6E//8Y8ysyfNsrgs Vy5zc0tV3oeU+ZtnWteeNzuyv77oCL/po+0CxyW5Tk/LnzFx9+GF/Q9XbXltdVbiK8fk088W c3R7S3Jx3Woo/rS3/aBa/JfwkP95l21rfv5auOPuSsEHLrUcan+EEvjsPr2Oz/SeuH8Pa2tu ww5Bv2lW6dNvHy7bYR5W2fpVfQFDaMw9QZ4TAXJza1aXfU30iCmRvXC/LeyXPNvGF4ubJWff fL5qx+ePq3Qu7axbsHf7GdfHmV/bGW7cc9Oad/fH9L1/3z72ee99eMskvsexl42nBUzf/ulb 7+opez+tb3Rw7hXanP2N3T3keW307UUGvZLeU2w3mquGNTsosRRnJBpqMRcVJwIAJzsT2LsC AAA= X-CMS-MailID: 20220321090204epcas2p31e39a4b8b6fc803ceecac5d19e6e39e9 X-Msg-Generator: CA X-Sendblock-Type: AUTO_CONFIDENTIAL CMS-TYPE: 102P DLP-Filter: Pass X-CFilter-Loop: Reflected X-CMS-RootMailID: 20220321090204epcas2p31e39a4b8b6fc803ceecac5d19e6e39e9 References: <1647853194-62147-1-git-send-email-dh10.jung@samsung.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Export symbols for xhci hooks usage: xhci_get_slot_ctx xhci_get_endpoint_address - Allow xhci hook to get ep_ctx from the xhci_container_ctx for getting the ep_ctx information to know which ep is offloading and comparing the context in remote subsystem memory if needed. xhci_ring_alloc - Allow xhci hook to allocate vendor specific ring. xhci_trb_virt_to_dma - Used to retrieve the DMA address of vendor specific ring. xhci_segment_free xhci_link_segments - Allow xhci hook to handle vendor specific segment. xhci_initialize_ring_info - Allow xhci hook to initialize vendor specific ring. xhci_check_trb_in_td_math - Allow xhci hook to Check TRB math for validation. xhci_address_device - Allow override to give configuration info to Co-processor. xhci_bus_suspend xhci_bus_resume - Allow override of suspend and resume for power scenario. xhci_remove_stream_mapping - Allow xhci hook to remove stream mapping. Signed-off-by: Daehwan Jung Signed-off-by: Jack Pham Signed-off-by: Howard Yen Reported-by: kernel test robot --- drivers/usb/host/xhci-hub.c | 2 ++ drivers/usb/host/xhci-mem.c | 19 +++++++++++++------ drivers/usb/host/xhci-ring.c | 1 + drivers/usb/host/xhci.c | 4 +++- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 1e7dc130c39a..56546aaa93c7 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1812,6 +1812,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) return 0; } +EXPORT_SYMBOL_GPL(xhci_bus_suspend); /* * Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3. @@ -1956,6 +1957,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) spin_unlock_irqrestore(&xhci->lock, flags); return 0; } +EXPORT_SYMBOL_GPL(xhci_bus_resume); unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index bbb27ee2c6a3..82b9f90c0f27 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -65,7 +65,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, return seg; } -static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) +void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) { if (seg->trbs) { dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma); @@ -74,6 +74,7 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) kfree(seg->bounce_buf); kfree(seg); } +EXPORT_SYMBOL_GPL(xhci_segment_free); static void xhci_free_segments_for_ring(struct xhci_hcd *xhci, struct xhci_segment *first) @@ -96,9 +97,9 @@ static void xhci_free_segments_for_ring(struct xhci_hcd *xhci, * DMA address of the next segment. The caller needs to set any Link TRB * related flags, such as End TRB, Toggle Cycle, and no snoop. */ -static void xhci_link_segments(struct xhci_segment *prev, - struct xhci_segment *next, - enum xhci_ring_type type, bool chain_links) +void xhci_link_segments(struct xhci_segment *prev, + struct xhci_segment *next, + enum xhci_ring_type type, bool chain_links) { u32 val; @@ -118,6 +119,7 @@ static void xhci_link_segments(struct xhci_segment *prev, prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); } } +EXPORT_SYMBOL_GPL(xhci_link_segments); /* * Link the ring to the new segments. @@ -256,7 +258,7 @@ static int xhci_update_stream_segment_mapping( return ret; } -static void xhci_remove_stream_mapping(struct xhci_ring *ring) +void xhci_remove_stream_mapping(struct xhci_ring *ring) { struct xhci_segment *seg; @@ -269,6 +271,7 @@ static void xhci_remove_stream_mapping(struct xhci_ring *ring) seg = seg->next; } while (seg != ring->first_seg); } +EXPORT_SYMBOL_GPL(xhci_remove_stream_mapping); static int xhci_update_stream_mapping(struct xhci_ring *ring, gfp_t mem_flags) { @@ -316,6 +319,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring, */ ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; } +EXPORT_SYMBOL_GPL(xhci_initialize_ring_info); /* Allocate segments and link them for a ring */ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, @@ -407,6 +411,7 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, kfree(ring); return NULL; } +EXPORT_SYMBOL_GPL(xhci_ring_alloc); void xhci_free_endpoint_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, @@ -518,6 +523,7 @@ struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, return (struct xhci_slot_ctx *) (ctx->bytes + CTX_SIZE(xhci->hcc_params)); } +EXPORT_SYMBOL_GPL(xhci_get_slot_ctx); struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, @@ -1965,7 +1971,7 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci, } /* TRB math checks for xhci_trb_in_td(), using the command and event rings. */ -static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci) +int xhci_check_trb_in_td_math(struct xhci_hcd *xhci) { struct { dma_addr_t input_dma; @@ -2085,6 +2091,7 @@ static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci) xhci_dbg(xhci, "TRB math tests passed.\n"); return 0; } +EXPORT_SYMBOL_GPL(xhci_check_trb_in_td_math); static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d0b6806275e0..c6896bdab763 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -79,6 +79,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, return 0; return seg->dma + (segment_offset * sizeof(*trb)); } +EXPORT_SYMBOL_GPL(xhci_trb_virt_to_dma); static bool trb_is_noop(union xhci_trb *trb) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 642610c78f58..8f53672dcd97 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1457,6 +1457,7 @@ unsigned int xhci_get_endpoint_address(unsigned int ep_index) unsigned int direction = ep_index % 2 ? USB_DIR_OUT : USB_DIR_IN; return direction | number; } +EXPORT_SYMBOL_GPL(xhci_get_endpoint_address); /* Find the flag for this endpoint (for use in the control context). Use the * endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is @@ -4313,10 +4314,11 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, return ret; } -static int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) { return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS); } +EXPORT_SYMBOL_GPL(xhci_address_device); static int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev) { From patchwork Mon Mar 21 08:59:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jung Daehwan X-Patchwork-Id: 12787003 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0CF51C433F5 for ; Mon, 21 Mar 2022 09:02:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345640AbiCUJDq (ORCPT ); Mon, 21 Mar 2022 05:03:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345612AbiCUJDm (ORCPT ); Mon, 21 Mar 2022 05:03:42 -0400 Received: from mailout4.samsung.com (mailout4.samsung.com [203.254.224.34]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A81909156F for ; Mon, 21 Mar 2022 02:02:12 -0700 (PDT) Received: from epcas2p4.samsung.com (unknown [182.195.41.56]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20220321090209epoutp04377dddba093069315143bd06e2091ba4~eWd9F6tJR2431824318epoutp045 for ; Mon, 21 Mar 2022 09:02:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20220321090209epoutp04377dddba093069315143bd06e2091ba4~eWd9F6tJR2431824318epoutp045 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1647853329; bh=uRnFLQg5/8hmbZcP6DXKCztRA1dIuNN9qRZ4XIDEJrs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nTasvr8Uxhl0rf0lCVEJbIsvtKROzTaaaGJ+7CgBcvIcTheOqSqsRzfum0S3LSB0o q6ba7qlFa+GliVHIOZdOg4iSOMpfUhGlFRF5X6JjiWAecyVfCwYx0q9OHxgPuqMSQu ePfjBHisqkHL+F/lNrEFrssqBHytowpbN8qeeOM8= Received: from epsnrtp4.localdomain (unknown [182.195.42.165]) by epcas2p1.samsung.com (KnoxPortal) with ESMTP id 20220321090208epcas2p157de555b8e5edb0e35ce053593f8eefc~eWd8ns66I1490814908epcas2p1I; Mon, 21 Mar 2022 09:02:08 +0000 (GMT) Received: from epsmges2p1.samsung.com (unknown [182.195.36.69]) by epsnrtp4.localdomain (Postfix) with ESMTP id 4KMTC16f3dz4x9Q8; Mon, 21 Mar 2022 09:02:05 +0000 (GMT) Received: from epcas2p2.samsung.com ( [182.195.41.54]) by epsmges2p1.samsung.com (Symantec Messaging Gateway) with SMTP id BA.5A.10444.D0F38326; Mon, 21 Mar 2022 18:02:05 +0900 (KST) Received: from epsmtrp1.samsung.com (unknown [182.195.40.13]) by epcas2p3.samsung.com (KnoxPortal) with ESMTPA id 20220321090204epcas2p3b2be5c6b131240e408d12d40c517395c~eWd5EuZGk3112631126epcas2p3E; Mon, 21 Mar 2022 09:02:04 +0000 (GMT) Received: from epsmgms1p1new.samsung.com (unknown [182.195.42.41]) by epsmtrp1.samsung.com (KnoxPortal) with ESMTP id 20220321090204epsmtrp1ab7b85b35f5cb943a66db8ca2b1e0b45~eWd5D8nux2589125891epsmtrp1k; Mon, 21 Mar 2022 09:02:04 +0000 (GMT) X-AuditID: b6c32a45-4fdff700000228cc-55-62383f0d2bab Received: from epsmtip2.samsung.com ( [182.195.34.31]) by epsmgms1p1new.samsung.com (Symantec Messaging Gateway) with SMTP id 85.3E.29871.C0F38326; Mon, 21 Mar 2022 18:02:04 +0900 (KST) Received: from ubuntu.dsn.sec.samsung.com (unknown [12.36.155.120]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20220321090204epsmtip209d2f68655623b26b74d774866d6ae53~eWd4xv5TX1773717737epsmtip2D; Mon, 21 Mar 2022 09:02:04 +0000 (GMT) From: Daehwan Jung To: Mathias Nyman , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org (open list:USB XHCI DRIVER), linux-kernel@vger.kernel.org (open list), Howard Yen , Jack Pham , Puma Hsu , "J . Avila" , Daehwan Jung , sc.suh@samsung.com Subject: [PATCH v3 2/4] usb: host: add xhci hooks for USB offload Date: Mon, 21 Mar 2022 17:59:52 +0900 Message-Id: <1647853194-62147-3-git-send-email-dh10.jung@samsung.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1647853194-62147-1-git-send-email-dh10.jung@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrAKsWRmVeSWpSXmKPExsWy7bCmmS6vvUWSwam93BZ3FkxjsnhyZBG7 RfPi9WwW1/+8Z7Rof36BzeLyrjlsFouWtTJbNG+awmoxc62yRdfdG4wOXB6X+3qZPBZsKvVY vOclk8f+uWvYPfq2rGL0+LxJLoAtKtsmIzUxJbVIITUvOT8lMy/dVsk7ON453tTMwFDX0NLC XEkhLzE31VbJxSdA1y0zB+gwJYWyxJxSoFBAYnGxkr6dTVF+aUmqQkZ+cYmtUmpBSk6BeYFe cWJucWleul5eaomVoYGBkSlQYUJ2xuy17gVN8xkr1jX1MTUwzmth7GLk5JAQMJHY0bmNqYuR i0NIYAejRP/HQ8wQzidGids7bjNCON8YJd48nsMK07J6ZisbRGIvo8TMdY9ZIZwfjBIfp7wB auHgYBPQkvi+EGyHiECcxNLOS2A7mAVWM0m8/3iRDSQhLOAosWT/A3YQm0VAVeLnsq9gcV4B V4nNN9cxQ2yTk7h5rhPM5hRwk1h7s5EFZJCEwCN2iT2TvrFBFLlInJ24HcoWlnh1fAs7hC0l 8bK/Dcoultj1qZUJormBUaLxwQmoDcYSs561g13NLKApsX6XPogpIaAsceQWC0gFswCfRMfh v+wQYV6JjjYhiEZliemXJ0ADRVLi4OtzUAM9JFqv7oUG0ExGickbpzNOYJSbhbBgASPjKkax 1ILi3PTUYqMCQ3icJefnbmIEJz0t1x2Mk99+0DvEyMTBeIhRgoNZSYR38QfzJCHelMTKqtSi /Pii0pzU4kOMpsDAm8gsJZqcD0y7eSXxhiaWBiZmZobmRqYG5krivF4pGxKFBNITS1KzU1ML Uotg+pg4OKUamJSOBXYGTX9q4dv3gf+Ox886aeeP8Q1LBJanO1+8e3O91Pvt0yPM+gS7wz2v 2qxJW+fotKNZP27K1Z7jCW1h9XvYH8/1OPMtQkzyhccd+73RYpfyb11bJRZ4uzor6M9ctz/z 840+l9Ro79l74YmBJzN35FX9d3eOzvbSvXuEz/GgyKuX6gIblvad/fz1/yx5d5OUB3mLwzcv 3NTd+Gx39lbTf9l1xnd9/iX0rrJeudDld6Fy5PtlDZcK+l6dXP2/Z9Zn0Ws23Ee/8S/VmR68 a0nB3i1ujP0b127lrqxZUjDder+12BP21H2ruOZVO8zgSGzJvZ8zcd9NUXuWn3OLndz+b3gw 8bLzv8htKo8eXtRXYinOSDTUYi4qTgQA/NmKUQMEAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrFLMWRmVeSWpSXmKPExsWy7bCSvC6PvUWSwbmDmhZ3FkxjsnhyZBG7 RfPi9WwW1/+8Z7Rof36BzeLyrjlsFouWtTJbNG+awmoxc62yRdfdG4wOXB6X+3qZPBZsKvVY vOclk8f+uWvYPfq2rGL0+LxJLoAtissmJTUnsyy1SN8ugStj9lr3gqb5jBXrmvqYGhjntTB2 MXJySAiYSKye2crWxcjFISSwm1Hi/O0uqISkxNK5N9ghbGGJ+y1HWCGKvjFKvDi8G6iDg4NN QEvi+0KwehGBOIkVl/ewgNQwC2xkkpj04BILSEJYwFFiyf4HYINYBFQlfi77ygZi8wq4Smy+ uY4ZYoGcxM1znWA2p4CbxNqbjWC9QkA1WyfNYJ3AyLeAkWEVo2RqQXFuem6xYYFhXmq5XnFi bnFpXrpecn7uJkZwcGpp7mDcvuqD3iFGJg7GQ4wSHMxKIryLP5gnCfGmJFZWpRblxxeV5qQW H2KU5mBREue90HUyXkggPbEkNTs1tSC1CCbLxMEp1cAU31FeM0Vjq9mromsrvLz+aC5qK5uf +2cHV+SizLz5GhvWuHQt4/v2Nm7Cw2+TIwXWhok4z7q+4BA3q3Qem0udwLYAxy9Oajvs7ESe 7XJb5zZVxdLhx5Xc6wEB35hS89kn911i6pgz++hhIW7Rq2/Xxf8vTHlwt6GOPd095cxj1rKo zFSvcK0nir8OzPl97+ATieNODxf9E1v5L2T2ceaAqxzOny6f8lgrf/T7zwvejL0pBpvvmhd9 OjCzcw9/BedX/tJdhbGWpsv3rKibfkTc7bKXfIzc1+j4Xb/X8Nc05V+PW794zbwP81eHdWka iZ20ldVecmLbGo+sNFejpYffWOd82iPLnfXaQHeFd7qiEktxRqKhFnNRcSIAv3serb0CAAA= X-CMS-MailID: 20220321090204epcas2p3b2be5c6b131240e408d12d40c517395c X-Msg-Generator: CA X-Sendblock-Type: AUTO_CONFIDENTIAL CMS-TYPE: 102P DLP-Filter: Pass X-CFilter-Loop: Reflected X-CMS-RootMailID: 20220321090204epcas2p3b2be5c6b131240e408d12d40c517395c References: <1647853194-62147-1-git-send-email-dh10.jung@samsung.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org To enable supporting for USB offload, define "offload" in usb controller node of device tree. "offload" value can be used to determine which type of offload was been enabled in the SoC. For example: &usbdrd_dwc3 { ... /* support usb offloading, 0: disabled, 1: audio */ offload = <1>; ... }; There are several vendor_ops introduced by this patch: struct xhci_vendor_ops - function callbacks for vendor specific operations { @vendor_init: - called for vendor init process during xhci-plat-hcd probe. @vendor_cleanup: - called for vendor cleanup process during xhci-plat-hcd remove. @is_usb_offload_enabled: - called to check if usb offload enabled. @alloc_dcbaa: - called when allocating vendor specific dcbaa during memory initializtion. @free_dcbaa: - called to free vendor specific dcbaa when cleanup the memory. @alloc_transfer_ring: - called when vendor specific transfer ring allocation is required @free_transfer_ring: - called to free vendor specific transfer ring @sync_dev_ctx: - called when synchronization for device context is required } The xhci hooks with prefix "xhci_vendor_" on the ops in xhci_vendor_ops. For example, vendor_init ops will be invoked by xhci_vendor_init() hook, is_usb_offload_enabled ops will be invoked by xhci_vendor_is_usb_offload_enabled(), and so on. Signed-off-by: Daehwan Jung Signed-off-by: J. Avila Signed-off-by: Puma Hsu Signed-off-by: Howard Yen --- drivers/usb/host/xhci-hub.c | 5 ++ drivers/usb/host/xhci-mem.c | 131 +++++++++++++++++++++++++++++++---- drivers/usb/host/xhci-plat.c | 43 +++++++++++- drivers/usb/host/xhci-plat.h | 7 ++ drivers/usb/host/xhci.c | 80 ++++++++++++++++++++- drivers/usb/host/xhci.h | 46 ++++++++++++ 6 files changed, 295 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 56546aaa93c7..aea72ffce820 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -535,8 +535,13 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) cmd->status == COMP_COMMAND_RING_STOPPED) { xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n"); ret = -ETIME; + goto cmd_cleanup; } + ret = xhci_vendor_sync_dev_ctx(xhci, slot_id); + if (ret) + xhci_warn(xhci, "Sync device context failed, ret=%d\n", ret); + cmd_cleanup: xhci_free_command(xhci, cmd); return ret; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 82b9f90c0f27..5ee0ffb676d3 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -365,6 +365,54 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, return 0; } +static void xhci_vendor_free_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->free_container_ctx) + ops->free_container_ctx(xhci, ctx); +} + +static void xhci_vendor_alloc_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, + int type, gfp_t flags) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->alloc_container_ctx) + ops->alloc_container_ctx(xhci, ctx, type, flags); +} + +static struct xhci_ring *xhci_vendor_alloc_transfer_ring(struct xhci_hcd *xhci, + u32 endpoint_type, enum xhci_ring_type ring_type, + unsigned int max_packet, gfp_t mem_flags) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->alloc_transfer_ring) + return ops->alloc_transfer_ring(xhci, endpoint_type, ring_type, + max_packet, mem_flags); + return 0; +} + +void xhci_vendor_free_transfer_ring(struct xhci_hcd *xhci, + struct xhci_ring *ring, unsigned int ep_index) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->free_transfer_ring) + ops->free_transfer_ring(xhci, ring, ep_index); +} + +bool xhci_vendor_is_usb_offload_enabled(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, unsigned int ep_index) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->is_usb_offload_enabled) + return ops->is_usb_offload_enabled(xhci, virt_dev, ep_index); + return false; +} + /* * Create a new ring with zero or more segments. * @@ -417,7 +465,11 @@ void xhci_free_endpoint_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, unsigned int ep_index) { - xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); + if (xhci_vendor_is_usb_offload_enabled(xhci, virt_dev, ep_index)) + xhci_vendor_free_transfer_ring(xhci, virt_dev->eps[ep_index].ring, ep_index); + else + xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); + virt_dev->eps[ep_index].ring = NULL; } @@ -475,6 +527,7 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, { struct xhci_container_ctx *ctx; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); if ((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT)) return NULL; @@ -488,7 +541,12 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, if (type == XHCI_CTX_TYPE_INPUT) ctx->size += CTX_SIZE(xhci->hcc_params); - ctx->bytes = dma_pool_zalloc(xhci->device_pool, flags, &ctx->dma); + if (xhci_vendor_is_usb_offload_enabled(xhci, NULL, 0) && + (ops && ops->alloc_container_ctx)) + xhci_vendor_alloc_container_ctx(xhci, ctx, type, flags); + else + ctx->bytes = dma_pool_zalloc(xhci->device_pool, flags, &ctx->dma); + if (!ctx->bytes) { kfree(ctx); return NULL; @@ -499,9 +557,16 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, void xhci_free_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) { + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + if (!ctx) return; - dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma); + if (xhci_vendor_is_usb_offload_enabled(xhci, NULL, 0) && + (ops && ops->free_container_ctx)) + xhci_vendor_free_container_ctx(xhci, ctx); + else + dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma); + kfree(ctx); } @@ -894,7 +959,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) for (i = 0; i < 31; i++) { if (dev->eps[i].ring) - xhci_ring_free(xhci, dev->eps[i].ring); + xhci_free_endpoint_ring(xhci, dev, i); if (dev->eps[i].stream_info) xhci_free_stream_info(xhci, dev->eps[i].stream_info); @@ -1492,8 +1557,16 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, mult = 0; /* Set up the endpoint ring */ - virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags); + if (xhci_vendor_is_usb_offload_enabled(xhci, virt_dev, ep_index) && + usb_endpoint_xfer_isoc(&ep->desc)) { + virt_dev->eps[ep_index].new_ring = + xhci_vendor_alloc_transfer_ring(xhci, endpoint_type, ring_type, + max_packet, mem_flags); + } else { + virt_dev->eps[ep_index].new_ring = + xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags); + } + if (!virt_dev->eps[ep_index].new_ring) return -ENOMEM; @@ -1837,6 +1910,24 @@ void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) erst->entries = NULL; } +static struct xhci_device_context_array *xhci_vendor_alloc_dcbaa( + struct xhci_hcd *xhci, gfp_t flags) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->alloc_dcbaa) + return ops->alloc_dcbaa(xhci, flags); + return 0; +} + +static void xhci_vendor_free_dcbaa(struct xhci_hcd *xhci) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->free_dcbaa) + ops->free_dcbaa(xhci); +} + void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; @@ -1888,9 +1979,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed medium stream array pool"); - if (xhci->dcbaa) - dma_free_coherent(dev, sizeof(*xhci->dcbaa), - xhci->dcbaa, xhci->dcbaa->dma); + if (xhci_vendor_is_usb_offload_enabled(xhci, NULL, 0)) { + xhci_vendor_free_dcbaa(xhci); + } else { + if (xhci->dcbaa) + dma_free_coherent(dev, sizeof(*xhci->dcbaa), + xhci->dcbaa, xhci->dcbaa->dma); + } xhci->dcbaa = NULL; scratchpad_free(xhci); @@ -2427,15 +2522,21 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * xHCI section 5.4.6 - Device Context array must be * "physically contiguous and 64-byte (cache line) aligned". */ - xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma, - flags); - if (!xhci->dcbaa) - goto fail; - xhci->dcbaa->dma = dma; + if (xhci_vendor_is_usb_offload_enabled(xhci, NULL, 0)) { + xhci->dcbaa = xhci_vendor_alloc_dcbaa(xhci, flags); + if (!xhci->dcbaa) + goto fail; + } else { + xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma, + flags); + if (!xhci->dcbaa) + goto fail; + xhci->dcbaa->dma = dma; + } xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Device context base array address = 0x%llx (DMA), %p (virt)", (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); - xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); + xhci_write_64(xhci, xhci->dcbaa->dma, &xhci->op_regs->dcbaa_ptr); /* * Initialize the ring segment pool. The ring must be a contiguous diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 649ffd861b44..3d2fe4d77f38 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -173,6 +173,41 @@ static const struct of_device_id usb_xhci_of_match[] = { MODULE_DEVICE_TABLE(of, usb_xhci_of_match); #endif +static struct xhci_plat_priv_overwrite xhci_plat_vendor_overwrite; + +int xhci_plat_register_vendor_ops(struct xhci_vendor_ops *vendor_ops) +{ + if (vendor_ops == NULL) + return -EINVAL; + + xhci_plat_vendor_overwrite.vendor_ops = vendor_ops; + + return 0; +} +EXPORT_SYMBOL_GPL(xhci_plat_register_vendor_ops); + +static int xhci_vendor_init(struct xhci_hcd *xhci) +{ + struct xhci_vendor_ops *ops = NULL; + + if (xhci_plat_vendor_overwrite.vendor_ops) + ops = xhci->vendor_ops = xhci_plat_vendor_overwrite.vendor_ops; + + if (ops && ops->vendor_init) + return ops->vendor_init(xhci); + return 0; +} + +static void xhci_vendor_cleanup(struct xhci_hcd *xhci) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->vendor_cleanup) + ops->vendor_cleanup(xhci); + + xhci->vendor_ops = NULL; +} + static int xhci_plat_probe(struct platform_device *pdev) { const struct xhci_plat_priv *priv_match; @@ -321,6 +356,10 @@ static int xhci_plat_probe(struct platform_device *pdev) goto put_usb3_hcd; } + ret = xhci_vendor_init(xhci); + if (ret) + goto disable_usb_phy; + hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); xhci->shared_hcd->tpl_support = hcd->tpl_support; if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)) @@ -393,8 +432,10 @@ static int xhci_plat_remove(struct platform_device *dev) usb_phy_shutdown(hcd->usb_phy); usb_remove_hcd(hcd); - usb_put_hcd(shared_hcd); + xhci_vendor_cleanup(xhci); + + usb_put_hcd(shared_hcd); clk_disable_unprepare(clk); clk_disable_unprepare(reg_clk); usb_put_hcd(hcd); diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index 1fb149d1fbce..18b349883eea 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -21,4 +21,11 @@ struct xhci_plat_priv { #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv) #define xhci_to_priv(x) ((struct xhci_plat_priv *)(x)->priv) + +struct xhci_plat_priv_overwrite { + struct xhci_vendor_ops *vendor_ops; +}; + +int xhci_plat_register_vendor_ops(struct xhci_vendor_ops *vendor_ops); + #endif /* _XHCI_PLAT_H */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8f53672dcd97..4e4fcf97ba42 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2975,6 +2975,14 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, xhci_finish_resource_reservation(xhci, ctrl_ctx); spin_unlock_irqrestore(&xhci->lock, flags); } + if (ret) + goto failed; + + ret = xhci_vendor_sync_dev_ctx(xhci, udev->slot_id); + if (ret) + xhci_warn(xhci, "sync device context failed, ret=%d", ret); + +failed: return ret; } @@ -3118,7 +3126,11 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) for (i = 0; i < 31; i++) { if (virt_dev->eps[i].new_ring) { xhci_debugfs_remove_endpoint(xhci, virt_dev, i); - xhci_ring_free(xhci, virt_dev->eps[i].new_ring); + if (xhci_vendor_is_usb_offload_enabled(xhci, virt_dev, i)) + xhci_vendor_free_transfer_ring(xhci, virt_dev->eps[i].new_ring, i); + else + xhci_ring_free(xhci, virt_dev->eps[i].new_ring); + virt_dev->eps[i].new_ring = NULL; } } @@ -3279,6 +3291,13 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, wait_for_completion(stop_cmd->completion); + err = xhci_vendor_sync_dev_ctx(xhci, udev->slot_id); + if (err) { + xhci_warn(xhci, "%s: Failed to sync device context failed, err=%d", + __func__, err); + goto cleanup; + } + spin_lock_irqsave(&xhci->lock, flags); /* config ep command clears toggle if add and drop ep flags are set */ @@ -3310,6 +3329,11 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, wait_for_completion(cfg_cmd->completion); + err = xhci_vendor_sync_dev_ctx(xhci, udev->slot_id); + if (err) + xhci_warn(xhci, "%s: Failed to sync device context failed, err=%d", + __func__, err); + xhci_free_command(xhci, cfg_cmd); cleanup: xhci_free_command(xhci, stop_cmd); @@ -3855,6 +3879,13 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, /* Wait for the Reset Device command to finish */ wait_for_completion(reset_device_cmd->completion); + ret = xhci_vendor_sync_dev_ctx(xhci, slot_id); + if (ret) { + xhci_warn(xhci, "%s: Failed to sync device context failed, err=%d", + __func__, ret); + goto command_cleanup; + } + /* The Reset Device command can't fail, according to the 0.95/0.96 spec, * unless we tried to reset a slot ID that wasn't enabled, * or the device wasn't in the addressed or configured state. @@ -4100,6 +4131,14 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n"); goto disable_slot; } + + ret = xhci_vendor_sync_dev_ctx(xhci, slot_id); + if (ret) { + xhci_warn(xhci, "%s: Failed to sync device context failed, err=%d", + __func__, ret); + goto disable_slot; + } + vdev = xhci->devs[slot_id]; slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx); trace_xhci_alloc_dev(slot_ctx); @@ -4230,6 +4269,13 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */ wait_for_completion(command->completion); + ret = xhci_vendor_sync_dev_ctx(xhci, udev->slot_id); + if (ret) { + xhci_warn(xhci, "%s: Failed to sync device context failed, err=%d", + __func__, ret); + goto out; + } + /* FIXME: From section 4.3.4: "Software shall be responsible for timing * the SetAddress() "recovery interval" required by USB and aborting the * command on a timeout. @@ -4382,6 +4428,14 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, return -ENOMEM; } + ret = xhci_vendor_sync_dev_ctx(xhci, udev->slot_id); + if (ret) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_warn(xhci, "%s: Failed to sync device context failed, err=%d", + __func__, ret); + return ret; + } + xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx); spin_unlock_irqrestore(&xhci->lock, flags); @@ -4409,6 +4463,21 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, return ret; } +struct xhci_vendor_ops *xhci_vendor_get_ops(struct xhci_hcd *xhci) +{ + return xhci->vendor_ops; +} +EXPORT_SYMBOL_GPL(xhci_vendor_get_ops); + +int xhci_vendor_sync_dev_ctx(struct xhci_hcd *xhci, unsigned int slot_id) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->sync_dev_ctx) + return ops->sync_dev_ctx(xhci, slot_id); + return 0; +} + #ifdef CONFIG_PM /* BESL to HIRD Encoding array for USB2 LPM */ @@ -5133,6 +5202,15 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, return -ENOMEM; } + ret = xhci_vendor_sync_dev_ctx(xhci, hdev->slot_id); + if (ret) { + xhci_warn(xhci, "%s: Failed to sync device context failed, err=%d", + __func__, ret); + xhci_free_command(xhci, config_cmd); + spin_unlock_irqrestore(&xhci->lock, flags); + return ret; + } + xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx); ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 473a33ce299e..f690a5dc9eb3 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1929,6 +1929,9 @@ struct xhci_hcd { struct list_head regset_list; void *dbc; + + struct xhci_vendor_ops *vendor_ops; + /* platform-specific data -- must come last */ unsigned long priv[] __aligned(sizeof(s64)); }; @@ -2207,6 +2210,49 @@ static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, urb->stream_id); } +/** + * struct xhci_vendor_ops - function callbacks for vendor specific operations + * @vendor_init: called for vendor init process + * @vendor_cleanup: called for vendor cleanup process + * @is_usb_offload_enabled: called to check if usb offload enabled + * @alloc_dcbaa: called when allocating vendor specific dcbaa + * @free_dcbaa: called to free vendor specific dcbaa + * @alloc_transfer_ring: called when remote transfer ring allocation is required + * @free_transfer_ring: called to free vendor specific transfer ring + * @sync_dev_ctx: called when synchronization for device context is required + * @alloc_container_ctx: called when allocating vendor specific container context + * @free_container_ctx: called to free vendor specific container context + */ +struct xhci_vendor_ops { + int (*vendor_init)(struct xhci_hcd *xhci); + void (*vendor_cleanup)(struct xhci_hcd *xhci); + bool (*is_usb_offload_enabled)(struct xhci_hcd *xhci, + struct xhci_virt_device *vdev, + unsigned int ep_index); + + struct xhci_device_context_array *(*alloc_dcbaa)(struct xhci_hcd *xhci, + gfp_t flags); + void (*free_dcbaa)(struct xhci_hcd *xhci); + + struct xhci_ring *(*alloc_transfer_ring)(struct xhci_hcd *xhci, + u32 endpoint_type, enum xhci_ring_type ring_type, + unsigned int max_packet, gfp_t mem_flags); + void (*free_transfer_ring)(struct xhci_hcd *xhci, + struct xhci_ring *ring, unsigned int ep_index); + int (*sync_dev_ctx)(struct xhci_hcd *xhci, unsigned int slot_id); + void (*alloc_container_ctx)(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, + int type, gfp_t flags); + void (*free_container_ctx)(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); +}; + +struct xhci_vendor_ops *xhci_vendor_get_ops(struct xhci_hcd *xhci); + +int xhci_vendor_sync_dev_ctx(struct xhci_hcd *xhci, unsigned int slot_id); +void xhci_vendor_free_transfer_ring(struct xhci_hcd *xhci, + struct xhci_ring *ring, unsigned int ep_index); +bool xhci_vendor_is_usb_offload_enabled(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, unsigned int ep_index); + /* * TODO: As per spec Isochronous IDT transmissions are supported. We bypass * them anyways as we where unable to find a device that matches the From patchwork Mon Mar 21 08:59:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jung Daehwan X-Patchwork-Id: 12787002 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4FEA4C43217 for ; Mon, 21 Mar 2022 09:02:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345633AbiCUJDp (ORCPT ); Mon, 21 Mar 2022 05:03:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345603AbiCUJDm (ORCPT ); Mon, 21 Mar 2022 05:03:42 -0400 Received: from mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A5F9090263 for ; Mon, 21 Mar 2022 02:02:12 -0700 (PDT) Received: from epcas2p2.samsung.com (unknown [182.195.41.54]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20220321090208epoutp0399f432cddbab6f42a572d7677cd70d91~eWd8jviMY0694306943epoutp03a for ; Mon, 21 Mar 2022 09:02:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20220321090208epoutp0399f432cddbab6f42a572d7677cd70d91~eWd8jviMY0694306943epoutp03a DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1647853328; bh=jkqJCU4+aVDJS7yOCCdF4ZZs3P9ETXU7EF57rPAUAM4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=erkwhH2lf4GzwhlMB0Gtrcwg0wgVbju1o01DzIkPXsn0lGf0nsjbKKdfeAKBcUGqg rt5SP3b/8qRgSfIv3mYTd5eHRkEjGKNgeevCvva3DckMQH2xPRO1FQRv6kj1mdUGLc OSGvO89SsGdm95hBabVLwvaK3m0ZtLfQ4WcIvLyY= Received: from epsnrtp4.localdomain (unknown [182.195.42.165]) by epcas2p2.samsung.com (KnoxPortal) with ESMTP id 20220321090208epcas2p2d2768e0c3a1c1447ad04eb4161ac8f60~eWd8GCMv83058430584epcas2p2c; Mon, 21 Mar 2022 09:02:08 +0000 (GMT) Received: from epsmges2p4.samsung.com (unknown [182.195.36.99]) by epsnrtp4.localdomain (Postfix) with ESMTP id 4KMTC15rCrz4x9QM; Mon, 21 Mar 2022 09:02:05 +0000 (GMT) Received: from epcas2p3.samsung.com ( [182.195.41.55]) by epsmges2p4.samsung.com (Symantec Messaging Gateway) with SMTP id 93.C7.33036.D0F38326; Mon, 21 Mar 2022 18:02:05 +0900 (KST) Received: from epsmtrp1.samsung.com (unknown [182.195.40.13]) by epcas2p4.samsung.com (KnoxPortal) with ESMTPA id 20220321090205epcas2p4f3698a0aa49d251c0a8f008e85d968ba~eWd5i-KTd0252402524epcas2p4b; Mon, 21 Mar 2022 09:02:05 +0000 (GMT) Received: from epsmgms1p1new.samsung.com (unknown [182.195.42.41]) by epsmtrp1.samsung.com (KnoxPortal) with ESMTP id 20220321090205epsmtrp1324d4e15cd89a97cdac910ade2dd33a2~eWd5hy0uF2591125911epsmtrp1b; Mon, 21 Mar 2022 09:02:05 +0000 (GMT) X-AuditID: b6c32a48-4fbff7000000810c-95-62383f0dff75 Received: from epsmtip2.samsung.com ( [182.195.34.31]) by epsmgms1p1new.samsung.com (Symantec Messaging Gateway) with SMTP id 56.3E.29871.D0F38326; Mon, 21 Mar 2022 18:02:05 +0900 (KST) Received: from ubuntu.dsn.sec.samsung.com (unknown [12.36.155.120]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20220321090205epsmtip2b9eb2f9c109f6f1fe94ed3429fac1de3~eWd5SjMw81528315283epsmtip27; Mon, 21 Mar 2022 09:02:05 +0000 (GMT) From: Daehwan Jung To: Mathias Nyman , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org (open list:USB XHCI DRIVER), linux-kernel@vger.kernel.org (open list), Howard Yen , Jack Pham , Puma Hsu , "J . Avila" , Daehwan Jung , sc.suh@samsung.com Subject: [PATCH v3 3/4] usb: host: add some to xhci overrides for USB offload Date: Mon, 21 Mar 2022 17:59:53 +0900 Message-Id: <1647853194-62147-4-git-send-email-dh10.jung@samsung.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1647853194-62147-1-git-send-email-dh10.jung@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrLKsWRmVeSWpSXmKPExsWy7bCmuS6vvUWSwexWLYs7C6YxWTw5sojd onnxejaL63/eM1q0P7/AZnF51xw2i0XLWpktmjdNYbWYuVbZouvuDUYHLo/Lfb1MHgs2lXos 3vOSyWP/3DXsHn1bVjF6fN4kF8AWlW2TkZqYklqkkJqXnJ+SmZduq+QdHO8cb2pmYKhraGlh rqSQl5ibaqvk4hOg65aZA3SYkkJZYk4pUCggsbhYSd/Opii/tCRVISO/uMRWKbUgJafAvECv ODG3uDQvXS8vtcTK0MDAyBSoMCE743vTY/aCu4IVzV83Mjcw/ufrYuTkkBAwkVh47RhzFyMX h5DADkaJ3VsOMUE4nxgljk8/yALhfGOUaJ74mr2LkQOsZedaNoj4XkaJs4eWQrX/YJTY0Hae GaSITUBL4vtCRpAVIgJxEks7L4FNZRZYzSTx/uNFNpCEsIC/xMlzV8CKWARUJbb/2cAMYvMK uEq0zf/OCHGfnMTNc51gcU4BN4m1NxvBLpIQeMQusXvKejaIIheJtvv7WSBsYYlXx7ewQ9hS Ei/726DsYoldn1qZIJobGCUaH5xghkgYS8x61s4IcjWzgKbE+l36EF8qSxy5BTaSWYBPouPw X6jneSU62oQgGpUlpl+ewAphS0ocfH2OGaLEQ2L7A2i4zWSUODD5LPsERrlZCPMXMDKuYhRL LSjOTU8tNiowgUdYcn7uJkZwutPy2ME4++0HvUOMTByMhxglOJiVRHgXfzBPEuJNSaysSi3K jy8qzUktPsRoCgy7icxSosn5wISbVxJvaGJpYGJmZmhuZGpgriTO65WyIVFIID2xJDU7NbUg tQimj4mDU6qBKXCfpJSr+6uX9UtbA/6cYnPZqh0QfTFz4XpNtglr/a67tAlucj/45WNp0qP6 rg8uSreKdGvnPnP9cuKR/OX4HF+VdYcmXI85uXyG0YFW9bbvHxcfWzk/O+3Oi3+nb/5+Xyyt PlU+McSycMm5D26+jP+3Lf30Os3h26mdVw673LO6Xfrw99PaeZL+/G7H7my9euh4gug5A7OP seZG01WUQ+84n10SLjNBtV/r+QzZlJzlz4LE9xzd5qYhc1vwzrnemVuMm3w5p3B+szmtu1/i Zcxzxg0xi4O2yGXct5l/4L245PaPm1X/rLK71JhQfJll8w7fV1GWjxMmVnxZFHZi8gO2loul to/tXr2KOqApsfCREktxRqKhFnNRcSIAehl6SwAEAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrBLMWRmVeSWpSXmKPExsWy7bCSvC6vvUWSwa2DXBZ3FkxjsnhyZBG7 RfPi9WwW1/+8Z7Rof36BzeLyrjlsFouWtTJbNG+awmoxc62yRdfdG4wOXB6X+3qZPBZsKvVY vOclk8f+uWvYPfq2rGL0+LxJLoAtissmJTUnsyy1SN8ugSvje9Nj9oK7ghXNXzcyNzD+5+ti 5OCQEDCR2LmWrYuRi0NIYDejxIf7Txi7GDmB4pISS+feYIewhSXutxxhhSj6xijROLGXEaSZ TUBL4vtCsHoRgTiJFZf3sIDUMAtsZJKY9OASC0hCWMBX4t3vPUwgNouAqsT2PxuYQWxeAVeJ tvnfoZbJSdw81wkW5xRwk1h7sxGsVwioZuukGawTGPkWMDKsYpRMLSjOTc8tNiwwzEst1ytO zC0uzUvXS87P3cQIDkwtzR2M21d90DvEyMTBeIhRgoNZSYR38QfzJCHelMTKqtSi/Pii0pzU 4kOM0hwsSuK8F7pOxgsJpCeWpGanphakFsFkmTg4pRqYeFySL+TUKf3rf7+WOe8j/zT9JjnG uAvfJ8w3k30pf3/79k8NIdsbUv8vmPM99PCCnd/9Ul1WTJ+24nDkGqnCHw82fy6yzz3beHbb vIgsy0cZ7+/+2N3pcFGj9UbNrire3TILPj9e9mDqE9clfl9vV/7ZKOE7M2yJc/bZkIvbY3Ji 3Kp4DXM4tgquq60SOfUoWDBhW+ciRp1LYTWavBdWsbAdD312WLx8oZ2dLpfe7MySf1tMH2Vs 1XojaW73jvtf92uW6B/n+S+K+eixvfgR0VFS55ZwOv2py+krB570z0xlNLip+nnJzq0NWUVe eaIL9nuXzxet/VOakrYuRdO69IGAjydzAws3y+Vl9v+/KLEUZyQaajEXFScCAMHWax27AgAA X-CMS-MailID: 20220321090205epcas2p4f3698a0aa49d251c0a8f008e85d968ba X-Msg-Generator: CA X-Sendblock-Type: AUTO_CONFIDENTIAL CMS-TYPE: 102P DLP-Filter: Pass X-CFilter-Loop: Reflected X-CMS-RootMailID: 20220321090205epcas2p4f3698a0aa49d251c0a8f008e85d968ba References: <1647853194-62147-1-git-send-email-dh10.jung@samsung.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Co-processor needs some information about connected usb device. It's proper to pass information after usb device gets address when getting "Set Address" command. It supports vendors to implement it using xhci overrides. There're several power scenarios depending on vendors. It gives vendors flexibilty to meet their power requirement. They can override suspend and resume of root hub. Signed-off-by: Daehwan Jung --- drivers/usb/host/xhci.c | 6 ++++++ drivers/usb/host/xhci.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 4e4fcf97ba42..d3c3d57c89f9 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -5544,6 +5544,12 @@ void xhci_init_driver(struct hc_driver *drv, drv->check_bandwidth = over->check_bandwidth; if (over->reset_bandwidth) drv->reset_bandwidth = over->reset_bandwidth; + if (over->address_device) + drv->address_device = over->address_device; + if (over->bus_suspend) + drv->bus_suspend = over->bus_suspend; + if (over->bus_resume) + drv->bus_resume = over->bus_resume; } } EXPORT_SYMBOL_GPL(xhci_init_driver); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f690a5dc9eb3..de37d72847f2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1947,6 +1947,9 @@ struct xhci_driver_overrides { struct usb_host_endpoint *ep); int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); + int (*address_device)(struct usb_hcd *hcd, struct usb_device *udev); + int (*bus_suspend)(struct usb_hcd *hcd); + int (*bus_resume)(struct usb_hcd *hcd); }; #define XHCI_CFC_DELAY 10 @@ -2103,6 +2106,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); +int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); int xhci_ext_cap_init(struct xhci_hcd *xhci); From patchwork Mon Mar 21 08:59:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jung Daehwan X-Patchwork-Id: 12787004 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F6E9C433EF for ; Mon, 21 Mar 2022 09:02:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345644AbiCUJDs (ORCPT ); Mon, 21 Mar 2022 05:03:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41180 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345610AbiCUJDm (ORCPT ); Mon, 21 Mar 2022 05:03:42 -0400 Received: from mailout1.samsung.com (mailout1.samsung.com [203.254.224.24]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A7ED591558 for ; Mon, 21 Mar 2022 02:02:12 -0700 (PDT) Received: from epcas2p1.samsung.com (unknown [182.195.41.53]) by mailout1.samsung.com (KnoxPortal) with ESMTP id 20220321090211epoutp01bec642d20c7782344a8e252b65383340~eWd_2O2us3085530855epoutp01g for ; Mon, 21 Mar 2022 09:02:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.samsung.com 20220321090211epoutp01bec642d20c7782344a8e252b65383340~eWd_2O2us3085530855epoutp01g DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1647853331; bh=Y12NnJmI0Qq6xZu4BblXFh/Tz0cs/jb2DFHh+5RbQhc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CeJd9wSbA0NCM25JQEQdzAFkm1FRVhb/g9a/VvVjfpfXY50An/nKCszX/W0bx4AJt w6PnR7b9nAwfN38EMFxEkF/sqFGTXave7FClQzjAozJdLkvjAjiPNrusv18UubZqv8 DJ1O57tjrzX32KDQ9RBM24d2lQZ4cfMy7L/OansM= Received: from epsnrtp3.localdomain (unknown [182.195.42.164]) by epcas2p4.samsung.com (KnoxPortal) with ESMTP id 20220321090210epcas2p48b9b43c3b23d86f55a5395be28938eb3~eWd_S9T3c0733307333epcas2p4N; Mon, 21 Mar 2022 09:02:10 +0000 (GMT) Received: from epsmges2p4.samsung.com (unknown [182.195.36.92]) by epsnrtp3.localdomain (Postfix) with ESMTP id 4KMTC36xrsz4x9QQ; Mon, 21 Mar 2022 09:02:07 +0000 (GMT) Received: from epcas2p1.samsung.com ( [182.195.41.53]) by epsmges2p4.samsung.com (Symantec Messaging Gateway) with SMTP id 2A.C7.33036.E0F38326; Mon, 21 Mar 2022 18:02:06 +0900 (KST) Received: from epsmtrp2.samsung.com (unknown [182.195.40.14]) by epcas2p1.samsung.com (KnoxPortal) with ESMTPA id 20220321090205epcas2p15ac16f281554b663062e0e31666defab~eWd6FyyYH1490814908epcas2p1D; Mon, 21 Mar 2022 09:02:05 +0000 (GMT) Received: from epsmgms1p2.samsung.com (unknown [182.195.42.42]) by epsmtrp2.samsung.com (KnoxPortal) with ESMTP id 20220321090205epsmtrp21d0988bcbabfe2f6ddc6818dd428839c~eWd6FAQXA0169601696epsmtrp2E; Mon, 21 Mar 2022 09:02:05 +0000 (GMT) X-AuditID: b6c32a48-4fbff7000000810c-99-62383f0e6694 Received: from epsmtip2.samsung.com ( [182.195.34.31]) by epsmgms1p2.samsung.com (Symantec Messaging Gateway) with SMTP id 53.F7.03370.D0F38326; Mon, 21 Mar 2022 18:02:05 +0900 (KST) Received: from ubuntu.dsn.sec.samsung.com (unknown [12.36.155.120]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20220321090205epsmtip289ba9c556ae55711b90ca4862350e8a0~eWd525YP61528315283epsmtip28; Mon, 21 Mar 2022 09:02:05 +0000 (GMT) From: Daehwan Jung To: Mathias Nyman , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org (open list:USB XHCI DRIVER), linux-kernel@vger.kernel.org (open list), Howard Yen , Jack Pham , Puma Hsu , "J . Avila" , Daehwan Jung , sc.suh@samsung.com Subject: [PATCH v3 4/4] usb: host: add xhci-exynos driver Date: Mon, 21 Mar 2022 17:59:54 +0900 Message-Id: <1647853194-62147-5-git-send-email-dh10.jung@samsung.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1647853194-62147-1-git-send-email-dh10.jung@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrLKsWRmVeSWpSXmKPExsWy7bCmqS6fvUWSwfMmEYs7C6YxWTw5sojd onnxejaL63/eM1q0P7/AZnF51xw2i0XLWpktmjdNYbWYuVbZouvuDUYHLo/Lfb1MHgs2lXos 3vOSyWP/3DXsHn1bVjF6fN4kF8AWlW2TkZqYklqkkJqXnJ+SmZduq+QdHO8cb2pmYKhraGlh rqSQl5ibaqvk4hOg65aZA3SYkkJZYk4pUCggsbhYSd/Opii/tCRVISO/uMRWKbUgJafAvECv ODG3uDQvXS8vtcTK0MDAyBSoMCE74/vD1cwFK94yVmz6fZ25gXHXUcYuRk4OCQETif//W9i7 GLk4hAR2MEp0frzOAuF8YpS4sbQdKvOZUeLk242sMC3bjj1jB7GFBHYxStw5IAxh/2CU2Pkx rIuRg4NNQEvi+0KwDSICcRJLOy8xgcxhFljNJPH+40U2kISwgKXExZ9dLCD1LAKqEi2bPUDC vAKuEkeXbGOCWCUncfNcJzOIzSngJrH2ZiPYcRICL9klWvfeYIcocpFY9O0w1G3CEq+Ob4GK S0l8freXDcIultj1qZUJormBUaLxwQlmiISxxKxn7YwgRzALaEqs36UPYkoIKEscucUCUsEs wCfRcfgvO0SYV6KjTQiiUVli+uUJUFslJQ6+Pgc10ENi+rfjLJAQmckoceak6QRGuVkI8xcw Mq5iFEstKM5NTy02KjCBR1hyfu4mRnC60/LYwTj77Qe9Q4xMHIyHGCU4mJVEeBd/ME8S4k1J rKxKLcqPLyrNSS0+xGgKDLqJzFKiyfnAhJtXEm9oYmlgYmZmaG5kamCuJM7rlbIhUUggPbEk NTs1tSC1CKaPiYNTqoGJi1sxQ1rTTeznf/EF+ev69pqcWee7Iq7n7sItrE1sYnFS93bHutuk PTsbMENbPaOxv+q+6LkFC+PfaS/RXvJpo4yOkJP/B60bu+unb5tZsH5yZmGpoOtDwbjMiT7l HG62Hw6L89Vfkdc0zlnfzKHNXPW3W1LA/877uTb7VEznOx83uJaS2tBXfeCPFtcG1dj9S1eJ +m2r5NrCHbrY/MnD2bJ7T3x3n678xoLZ1aag2cnwo86RHH7h5VdeTeDimuJrebLCcUVRbNIc 6dyqefv23+OQ3P1Rxuwey3v15M23peyq+5gPt1lx/9aNidvl4br9ddIrQ6a9CZI+fHuFNN3u 1e74w/ZtKs+z/Gcs4UosxRmJhlrMRcWJANkkg1gABAAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrBLMWRmVeSWpSXmKPExsWy7bCSvC6vvUWSwfNWI4s7C6YxWTw5sojd onnxejaL63/eM1q0P7/AZnF51xw2i0XLWpktmjdNYbWYuVbZouvuDUYHLo/Lfb1MHgs2lXos 3vOSyWP/3DXsHn1bVjF6fN4kF8AWxWWTkpqTWZZapG+XwJXx/eFq5oIVbxkrNv2+ztzAuOso YxcjJ4eEgInEtmPP2EFsIYEdjBJndkpAxCUlls69wQ5hC0vcbznCClHzjVHi9QSfLkYODjYB LYnvC8HGiAjESay4vIeli5GLg1lgI5PEpAeXWEASwgKWEhd/drGA1LMIqEq0bPYACfMKuEoc XbKNCWK8nMTNc53MIDangJvE2puNLBCrXCW2TprBOoGRbwEjwypGydSC4tz03GLDAqO81HK9 4sTc4tK8dL3k/NxNjODA1NLawbhn1Qe9Q4xMHIyHGCU4mJVEeBd/ME8S4k1JrKxKLcqPLyrN SS0+xCjNwaIkznuh62S8kEB6YklqdmpqQWoRTJaJg1OqgUkj3yToda7y9QU3LsQ5z+E6OedN rprGla6of1aerZ/Y9T+b3evYUfV87sPgK1re0kcnTpoeO/PKtelv2h+tTLt0sTni+h6jW9as 34WTo7oZmthPZp9l52jY0v5yVeQ96YSGukmNnccqq1OYGW98vT5ls2DJ3WPxZk5HfUMU125s y3p5NjC6jSdIu0/0l/67+Y8exXxUnuyie3n1Gvkb617dUvDYkZLyUffVnz1Rhk+k7S8sn8A/ /a/dhcrjopHzWfyU1j5rPbOygJtt91F+e0v5v9yha+RDl7y89e3W7zvqmz5PnPK+e98ticVb umWTLbbULpomN1GeO+N20lkN98tdFfuuzn0nuO3CtR23eTM/K7EUZyQaajEXFScCAMJxHBm7 AgAA X-CMS-MailID: 20220321090205epcas2p15ac16f281554b663062e0e31666defab X-Msg-Generator: CA X-Sendblock-Type: AUTO_CONFIDENTIAL CMS-TYPE: 102P DLP-Filter: Pass X-CFilter-Loop: Reflected X-CMS-RootMailID: 20220321090205epcas2p15ac16f281554b663062e0e31666defab References: <1647853194-62147-1-git-send-email-dh10.jung@samsung.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This driver supports USB Audio offload with Co-processor. It only cares DCBAA, Device Context, Transfer Ring, Event Ring, and ERST. They are allocated on specific address with xhci hooks. Co-processor could use them directly without xhci driver after then. Signed-off-by: Daehwan Jung Reported-by: kernel test robot Reported-by: kernel test robot --- drivers/usb/host/Kconfig | 9 + drivers/usb/host/Makefile | 1 + drivers/usb/host/xhci-exynos.c | 982 +++++++++++++++++++++++++++++++++ drivers/usb/host/xhci-exynos.h | 63 +++ 4 files changed, 1055 insertions(+) create mode 100644 drivers/usb/host/xhci-exynos.c create mode 100644 drivers/usb/host/xhci-exynos.h diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 57ca5f97a3dc..850e6b71fac5 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -783,3 +783,12 @@ config USB_XEN_HCD by the Xen host (usually Dom0). Only needed if the kernel is running in a Xen guest and generic access to a USB device is needed. + +config USB_XHCI_EXYNOS + tristate "XHCI support for Samsung Exynos SoC Series" + depends on ARCH_EXYNOS || COMPILE_TEST + help + Enable support for the Samsung Exynos SOC's on-chip XHCI + controller. + + If unsure, say N. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 2948983618fb..300f22b6eb1b 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -86,3 +86,4 @@ obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o obj-$(CONFIG_USB_XEN_HCD) += xen-hcd.o +obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos.o diff --git a/drivers/usb/host/xhci-exynos.c b/drivers/usb/host/xhci-exynos.c new file mode 100644 index 000000000000..19ee21f1d024 --- /dev/null +++ b/drivers/usb/host/xhci-exynos.c @@ -0,0 +1,982 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * xhci-exynos.c - xHCI host controller driver platform Bus Glue for Exynos. + * + * Copyright (C) 2022 Samsung Electronics Incorporated - http://www.samsung.com + * Author: Daehwan Jung + * + * A lot of code borrowed from the Linux xHCI driver. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xhci.h" +#include "xhci-plat.h" +#include "xhci-mvebu.h" +#include "xhci-rcar.h" + +#include "xhci-exynos.h" + +static struct hc_driver __read_mostly xhci_exynos_hc_driver; + +static void xhci_exynos_free_event_ring(struct xhci_hcd *xhci); +static struct xhci_ring *xhci_ring_alloc_uram(struct xhci_hcd *xhci, + unsigned int num_segs, unsigned int cycle_state, + enum xhci_ring_type type, unsigned int max_packet, gfp_t flags, + u32 endpoint_type); +static void xhci_exynos_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); + +static struct xhci_plat_priv_overwrite xhci_plat_vendor_overwrite; + +static int xhci_exynos_setup(struct usb_hcd *hcd); +static int xhci_exynos_start(struct usb_hcd *hcd); + +static void xhci_priv_exynos_start(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (priv->plat_start) + priv->plat_start(hcd); +} + +static int xhci_priv_exynos_setup(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (!priv->plat_setup) + return 0; + + return priv->plat_setup(hcd); +} + + +static int xhci_exynos_register_vendor_ops(struct xhci_vendor_ops *vendor_ops) +{ + if (vendor_ops == NULL) + return -EINVAL; + + xhci_plat_vendor_overwrite.vendor_ops = vendor_ops; + + return 0; +} + +static int xhci_exynos_vendor_init(struct xhci_hcd *xhci) +{ + /* TODO */ + return 0; +} + +static void xhci_exynos_vendor_cleanup(struct xhci_hcd *xhci) +{ + xhci_exynos_free_event_ring(xhci); +} + +static bool xhci_exynos_is_usb_offload_enabled(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, unsigned int ep_index) +{ + /* TODO */ + return true; +} + +static struct xhci_device_context_array *xhci_exynos_alloc_dcbaa( + struct xhci_hcd *xhci, gfp_t flags) +{ + int i; + + xhci->dcbaa = ioremap(EXYNOS_URAM_DCBAA_ADDR, + sizeof(*xhci->dcbaa)); + if (!xhci->dcbaa) + return NULL; + /* Clear DCBAA */ + for (i = 0; i < MAX_HC_SLOTS; i++) + xhci->dcbaa->dev_context_ptrs[i] = 0x0; + + xhci->dcbaa->dma = EXYNOS_URAM_DCBAA_ADDR; + + return xhci->dcbaa; +} + +static void xhci_exynos_free_dcbaa(struct xhci_hcd *xhci) +{ + iounmap(xhci->dcbaa); + xhci->dcbaa = NULL; +} + +static struct xhci_ring *xhci_exynos_alloc_transfer_ring(struct xhci_hcd *xhci, u32 endpoint_type, + enum xhci_ring_type ring_type, unsigned int max_packet, gfp_t mem_flags) +{ + return xhci_ring_alloc_uram(xhci, 1, 1, ring_type, max_packet, mem_flags, endpoint_type); +} + +static void xhci_exynos_free_transfer_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, + unsigned int ep_index) +{ + xhci_exynos_ring_free(xhci, ring); +} + +static void xhci_exynos_alloc_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, + int type, gfp_t flags) +{ + /* Only first Device Context uses URAM */ + int i; + + ctx->bytes = ioremap(EXYNOS_URAM_DEVICE_CTX_ADDR, EXYNOS_URAM_CTX_SIZE); + if (!ctx->bytes) + return; + + for (i = 0; i < EXYNOS_URAM_CTX_SIZE; i++) + ctx->bytes[i] = 0; + + ctx->dma = EXYNOS_URAM_DEVICE_CTX_ADDR; +} + +static void xhci_exynos_free_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) +{ + /* Ignore dma_pool_free if it is allocated from URAM */ + if (ctx->dma != EXYNOS_URAM_DEVICE_CTX_ADDR) + dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma); +} + +static int xhci_exynos_sync_dev_ctx(struct xhci_hcd *xhci, unsigned int slot_id) +{ + struct xhci_exynos_priv *priv = xhci_to_exynos_priv(xhci); + struct xhci_hcd_exynos *xhci_exynos = priv->xhci_exynos; + struct xhci_virt_device *virt_dev; + struct xhci_slot_ctx *slot_ctx; + + int i; + int last_ep; + int last_ep_ctx = 31; + + virt_dev = xhci->devs[slot_id]; + slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); + + last_ep = LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info)); + + if (last_ep < 31) + last_ep_ctx = last_ep + 1; + + for (i = 0; i < last_ep_ctx; ++i) { + unsigned int epaddr = xhci_get_endpoint_address(i); + struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->out_ctx, i); + + if (epaddr == xhci_exynos->in_ep) + xhci_exynos->in_deq = ep_ctx->deq; + else if (epaddr == xhci_exynos->out_ep) + xhci_exynos->out_deq = ep_ctx->deq; + } + + return 0; +} +static struct xhci_vendor_ops ops = { + .vendor_init = xhci_exynos_vendor_init, + .vendor_cleanup = xhci_exynos_vendor_cleanup, + .is_usb_offload_enabled = xhci_exynos_is_usb_offload_enabled, + .alloc_dcbaa = xhci_exynos_alloc_dcbaa, + .free_dcbaa = xhci_exynos_free_dcbaa, + .alloc_transfer_ring = xhci_exynos_alloc_transfer_ring, + .free_transfer_ring = xhci_exynos_free_transfer_ring, + .alloc_container_ctx = xhci_exynos_alloc_container_ctx, + .free_container_ctx = xhci_exynos_free_container_ctx, + .sync_dev_ctx = xhci_exynos_sync_dev_ctx, +}; + +static int xhci_exynos_wake_lock(struct xhci_hcd_exynos *xhci_exynos, + int is_main_hcd, int is_lock) +{ + struct usb_hcd *hcd = xhci_exynos->hcd; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct wakeup_source *main_wakelock, *shared_wakelock; + + main_wakelock = xhci_exynos->main_wakelock; + shared_wakelock = xhci_exynos->shared_wakelock; + + if (xhci->xhc_state & XHCI_STATE_REMOVING) + return -ESHUTDOWN; + + if (is_lock) { + if (is_main_hcd) + __pm_stay_awake(main_wakelock); + else + __pm_stay_awake(shared_wakelock); + } else { + if (is_main_hcd) + __pm_relax(main_wakelock); + else + __pm_relax(shared_wakelock); + } + + return 0; +} + +static int xhci_exynos_bus_suspend(struct usb_hcd *hcd) +{ + struct xhci_exynos_priv *priv = hcd_to_xhci_exynos_priv(hcd); + struct xhci_hcd_exynos *xhci_exynos = priv->xhci_exynos; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + int ret, main_hcd; + + if (hcd == xhci->main_hcd) + main_hcd = 1; + else + main_hcd = 0; + + ret = xhci_bus_suspend(hcd); + xhci_exynos_wake_lock(xhci_exynos, main_hcd, 0); + + return ret; +} + +static int xhci_exynos_bus_resume(struct usb_hcd *hcd) +{ + struct xhci_exynos_priv *priv = hcd_to_xhci_exynos_priv(hcd); + struct xhci_hcd_exynos *xhci_exynos = priv->xhci_exynos; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret, main_hcd; + + if (hcd == xhci->main_hcd) + main_hcd = 1; + else + main_hcd = 0; + + ret = xhci_bus_resume(hcd); + xhci_exynos_wake_lock(xhci_exynos, main_hcd, 1); + + return ret; +} + +static int xhci_exynos_address_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct xhci_hcd *xhci; + int ret; + + ret = xhci_address_device(hcd, udev); + xhci = hcd_to_xhci(hcd); + + return ret; +} + +static void xhci_exynos_parse_endpoint(struct xhci_hcd *xhci, struct usb_device *udev, + struct usb_endpoint_descriptor *desc, struct xhci_container_ctx *ctx) +{ + struct xhci_exynos_priv *priv = xhci_to_exynos_priv(xhci); + struct xhci_hcd_exynos *xhci_exynos = priv->xhci_exynos; + struct usb_endpoint_descriptor *d = desc; + unsigned int ep_index; + struct xhci_ep_ctx *ep_ctx; + + ep_index = xhci_get_endpoint_index(d); + ep_ctx = xhci_get_ep_ctx(xhci, ctx, ep_index); + + if ((d->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC) { + if (d->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + xhci_exynos->in_ep = d->bEndpointAddress; + else + xhci_exynos->out_ep = d->bEndpointAddress; + } +} + +static int xhci_exynos_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + int ret; + struct xhci_hcd *xhci; + struct xhci_virt_device *virt_dev; + + ret = xhci_add_endpoint(hcd, udev, ep); + + if (!ret && udev->slot_id) { + xhci = hcd_to_xhci(hcd); + virt_dev = xhci->devs[udev->slot_id]; + xhci_exynos_parse_endpoint(xhci, udev, &ep->desc, virt_dev->out_ctx); + } + + return ret; +} +static const struct xhci_driver_overrides xhci_exynos_overrides __initconst = { + .extra_priv_size = sizeof(struct xhci_plat_priv), + .reset = xhci_exynos_setup, + .start = xhci_exynos_start, + .add_endpoint = xhci_exynos_add_endpoint, + .address_device = xhci_exynos_address_device, + .bus_suspend = xhci_exynos_bus_suspend, + .bus_resume = xhci_exynos_bus_resume, +}; + + +static void xhci_exynos_segment_free_skip(struct xhci_hcd *xhci, struct xhci_segment *seg) +{ + kfree(seg->bounce_buf); + kfree(seg); +} + +static void xhci_exynos_free_segments_for_ring(struct xhci_hcd *xhci, + struct xhci_segment *first) +{ + struct xhci_segment *seg; + + seg = first->next; + + while (seg != first) { + struct xhci_segment *next = seg->next; + + xhci_exynos_segment_free_skip(xhci, seg); + seg = next; + } + xhci_exynos_segment_free_skip(xhci, first); +} + +static void xhci_exynos_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) +{ + if (!ring) + return; + + //trace_xhci_ring_free(ring); + + if (ring->first_seg) { + if (ring->type == TYPE_STREAM) + xhci_remove_stream_mapping(ring); + + xhci_exynos_free_segments_for_ring(xhci, ring->first_seg); + } + + kfree(ring); +} + +static void xhci_exynos_free_event_ring(struct xhci_hcd *xhci) +{ + struct xhci_exynos_priv *priv = xhci_to_exynos_priv(xhci); + struct xhci_hcd_exynos *xhci_exynos = priv->xhci_exynos; + + xhci_exynos_ring_free(xhci, xhci_exynos->event_ring_audio); +} + +static void xhci_exynos_set_hc_event_deq_audio(struct xhci_hcd *xhci) +{ + struct xhci_exynos_priv *priv = xhci_to_exynos_priv(xhci); + struct xhci_hcd_exynos *xhci_exynos = priv->xhci_exynos; + + dma_addr_t deq; + + deq = xhci_trb_virt_to_dma(xhci_exynos->event_ring_audio->deq_seg, + xhci_exynos->event_ring_audio->dequeue); +} + + + +static int xhci_exynos_alloc_event_ring(struct xhci_hcd *xhci, gfp_t flags) +{ + struct xhci_exynos_priv *priv = xhci_to_exynos_priv(xhci); + struct xhci_hcd_exynos *xhci_exynos = priv->xhci_exynos; + + if (xhci_check_trb_in_td_math(xhci) < 0) + goto fail; + + xhci_exynos->event_ring_audio = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, + TYPE_EVENT, 0, flags); + /* Set the event ring dequeue address */ + xhci_exynos_set_hc_event_deq_audio(xhci); + + return 0; +fail: + return -1; +} + +static int xhci_alloc_segments_for_ring_uram(struct xhci_hcd *xhci, + struct xhci_segment **first, struct xhci_segment **last, + unsigned int num_segs, unsigned int cycle_state, + enum xhci_ring_type type, unsigned int max_packet, gfp_t flags, + u32 endpoint_type) +{ + struct xhci_segment *prev; + bool chain_links = false; + + while (num_segs > 0) { + struct xhci_segment *next = NULL; + + if (!next) { + prev = *first; + while (prev) { + next = prev->next; + xhci_segment_free(xhci, prev); + prev = next; + } + return -ENOMEM; + } + xhci_link_segments(prev, next, type, chain_links); + + prev = next; + num_segs--; + } + xhci_link_segments(prev, *first, type, chain_links); + *last = prev; + + return 0; +} + +static struct xhci_ring *xhci_ring_alloc_uram(struct xhci_hcd *xhci, + unsigned int num_segs, unsigned int cycle_state, + enum xhci_ring_type type, unsigned int max_packet, gfp_t flags, + u32 endpoint_type) +{ + struct xhci_ring *ring; + int ret; + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + + ring = kzalloc_node(sizeof(*ring), flags, dev_to_node(dev)); + if (!ring) + return NULL; + + ring->num_segs = num_segs; + ring->bounce_buf_len = max_packet; + INIT_LIST_HEAD(&ring->td_list); + ring->type = type; + if (num_segs == 0) + return ring; + + ret = xhci_alloc_segments_for_ring_uram(xhci, &ring->first_seg, + &ring->last_seg, num_segs, cycle_state, type, + max_packet, flags, endpoint_type); + if (ret) + goto fail; + + /* Only event ring does not use link TRB */ + if (type != TYPE_EVENT) { + /* See section 4.9.2.1 and 6.4.4.1 */ + ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= + cpu_to_le32(LINK_TOGGLE); + } + xhci_initialize_ring_info(ring, cycle_state); + //trace_xhci_ring_alloc(ring); + return ring; + +fail: + kfree(ring); + return NULL; +} + +static void xhci_exynos_usb_offload_enable_event_ring(struct xhci_hcd *xhci) +{ + struct xhci_exynos_priv *priv = xhci_to_exynos_priv(xhci); + struct xhci_hcd_exynos *xhci_exynos = priv->xhci_exynos; + + u32 temp; + u64 temp_64; + + temp_64 = xhci_read_64(xhci, &xhci_exynos->ir_set_audio->erst_dequeue); + temp_64 &= ~ERST_PTR_MASK; + xhci_info(xhci, "ERST2 deq = 64'h%0lx", (unsigned long) temp_64); + + xhci_info(xhci, "// [USB Audio] Set the interrupt modulation register"); + temp = readl(&xhci_exynos->ir_set_audio->irq_control); + temp &= ~ER_IRQ_INTERVAL_MASK; + /* + * the increment interval is 8 times as much as that defined + * in xHCI spec on MTK's controller + */ + temp |= (u32) ((xhci->quirks & XHCI_MTK_HOST) ? 20 : 160); + writel(temp, &xhci_exynos->ir_set_audio->irq_control); + + temp = readl(&xhci_exynos->ir_set_audio->irq_pending); + xhci_info(xhci, "// [USB Audio] Enabling event ring interrupter %p by writing 0x%x to irq_pending", + xhci_exynos->ir_set_audio, (unsigned int) ER_IRQ_ENABLE(temp)); + writel(ER_IRQ_ENABLE(temp), &xhci_exynos->ir_set_audio->irq_pending); +} + +static int xhci_priv_init_quirk(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (!priv->init_quirk) + return 0; + + return priv->init_quirk(hcd); +} + +static int xhci_priv_suspend_quirk(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (!priv->suspend_quirk) + return 0; + + return priv->suspend_quirk(hcd); +} + +static int xhci_priv_resume_quirk(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (!priv->resume_quirk) + return 0; + + return priv->resume_quirk(hcd); +} + +static void xhci_exynos_quirks(struct device *dev, struct xhci_hcd *xhci) +{ + struct xhci_plat_priv *priv = xhci_to_priv(xhci); + + /* + * As of now platform drivers don't provide MSI support so we ensure + * here that the generic code does not try to make a pci_dev from our + * dev struct in order to setup MSI + */ + xhci->quirks |= XHCI_PLAT | priv->quirks; +} + +/* called during probe() after chip reset completes */ +static int xhci_exynos_setup(struct usb_hcd *hcd) +{ + int ret; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + ret = xhci_priv_init_quirk(hcd); + if (ret) + return ret; + + ret = xhci_gen_setup(hcd, xhci_exynos_quirks); + xhci_exynos_alloc_event_ring(xhci, GFP_KERNEL); + + return ret; +} + +static int xhci_exynos_start(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci; + int ret; + + xhci_priv_exynos_start(hcd); + + ret = xhci_run(hcd); + + xhci = hcd_to_xhci(hcd); + xhci_exynos_usb_offload_enable_event_ring(xhci); + + return ret; +} + +#ifdef CONFIG_OF +static const struct xhci_plat_priv xhci_plat_marvell_armada = { + .init_quirk = xhci_mvebu_mbus_init_quirk, +}; + +static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { + .plat_setup = xhci_mvebu_a3700_plat_setup, + .init_quirk = xhci_mvebu_a3700_init_quirk, +}; + +static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = { + SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V1) +}; + +static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { + SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V3) +}; + +static const struct xhci_plat_priv xhci_plat_brcm = { + .quirks = XHCI_RESET_ON_RESUME, +}; + +static const struct of_device_id usb_xhci_of_match[] = { + { + .compatible = "generic-xhci", + }, { + .compatible = "xhci-platform", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, usb_xhci_of_match); +#endif + +static int xhci_vendor_init(struct xhci_hcd *xhci) +{ + struct xhci_vendor_ops *ops = NULL; + + if (xhci_plat_vendor_overwrite.vendor_ops) + ops = xhci->vendor_ops = xhci_plat_vendor_overwrite.vendor_ops; + + if (ops && ops->vendor_init) + return ops->vendor_init(xhci); + return 0; +} + +static void xhci_vendor_cleanup(struct xhci_hcd *xhci) +{ + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); + + if (ops && ops->vendor_cleanup) + ops->vendor_cleanup(xhci); + + xhci->vendor_ops = NULL; +} + +static int xhci_exynos_probe(struct platform_device *pdev) +{ + const struct xhci_plat_priv *priv_match; + const struct hc_driver *driver; + struct device *sysdev, *tmpdev; + struct xhci_hcd *xhci; + struct resource *res; + struct usb_hcd *hcd; + int ret; + int irq; + struct xhci_plat_priv *priv = NULL; + + + xhci_exynos_register_vendor_ops(&ops); + + if (usb_disabled()) + return -ENODEV; + + driver = &xhci_exynos_hc_driver; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + /* + * sysdev must point to a device that is known to the system firmware + * or PCI hardware. We handle these three cases here: + * 1. xhci_plat comes from firmware + * 2. xhci_plat is child of a device from firmware (dwc3-plat) + * 3. xhci_plat is grandchild of a pci device (dwc3-pci) + */ + for (sysdev = &pdev->dev; sysdev; sysdev = sysdev->parent) { + if (is_of_node(sysdev->fwnode) || + is_acpi_device_node(sysdev->fwnode)) + break; +#ifdef CONFIG_PCI + else if (sysdev->bus == &pci_bus_type) + break; +#endif + } + + if (!sysdev) + sysdev = &pdev->dev; + + /* Try to set 64-bit DMA first */ + if (WARN_ON(!sysdev->dma_mask)) + /* Platform did not initialize dma_mask */ + ret = dma_coerce_mask_and_coherent(sysdev, + DMA_BIT_MASK(64)); + else + ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64)); + + /* If seting 64-bit DMA mask fails, fall back to 32-bit DMA mask */ + if (ret) { + ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + + hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, + dev_name(&pdev->dev), NULL); + if (!hcd) { + ret = -ENOMEM; + goto disable_runtime; + } + + hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); + goto put_hcd; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + xhci = hcd_to_xhci(hcd); + + /* + * Not all platforms have clks so it is not an error if the + * clock do not exist. + */ + xhci->reg_clk = devm_clk_get_optional(&pdev->dev, "reg"); + if (IS_ERR(xhci->reg_clk)) { + ret = PTR_ERR(xhci->reg_clk); + goto put_hcd; + } + + ret = clk_prepare_enable(xhci->reg_clk); + if (ret) + goto put_hcd; + + xhci->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(xhci->clk)) { + ret = PTR_ERR(xhci->clk); + goto disable_reg_clk; + } + + ret = clk_prepare_enable(xhci->clk); + if (ret) + goto disable_reg_clk; + + if (pdev->dev.of_node) + priv_match = of_device_get_match_data(&pdev->dev); + else + priv_match = dev_get_platdata(&pdev->dev); + + if (priv_match) { + priv = hcd_to_xhci_priv(hcd); + /* Just copy data for now */ + *priv = *priv_match; + } + + device_set_wakeup_capable(&pdev->dev, true); + + xhci->main_hcd = hcd; + xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, + dev_name(&pdev->dev), hcd); + if (!xhci->shared_hcd) { + ret = -ENOMEM; + goto disable_clk; + } + + /* imod_interval is the interrupt moderation value in nanoseconds. */ + xhci->imod_interval = 40000; + + /* Iterate over all parent nodes for finding quirks */ + for (tmpdev = &pdev->dev; tmpdev; tmpdev = tmpdev->parent) { + + if (device_property_read_bool(tmpdev, "usb2-lpm-disable")) + xhci->quirks |= XHCI_HW_LPM_DISABLE; + + if (device_property_read_bool(tmpdev, "usb3-lpm-capable")) + xhci->quirks |= XHCI_LPM_SUPPORT; + + if (device_property_read_bool(tmpdev, "quirk-broken-port-ped")) + xhci->quirks |= XHCI_BROKEN_PORT_PED; + + device_property_read_u32(tmpdev, "imod-interval-ns", + &xhci->imod_interval); + } + + hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0); + if (IS_ERR(hcd->usb_phy)) { + ret = PTR_ERR(hcd->usb_phy); + if (ret == -EPROBE_DEFER) + goto put_usb3_hcd; + hcd->usb_phy = NULL; + } else { + ret = usb_phy_init(hcd->usb_phy); + if (ret) + goto put_usb3_hcd; + } + + ret = xhci_vendor_init(xhci); + if (ret) + goto disable_usb_phy; + + hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); + xhci->shared_hcd->tpl_support = hcd->tpl_support; + + if (priv) { + ret = xhci_priv_exynos_setup(hcd); + if (ret) + goto disable_usb_phy; + } + + if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))) + hcd->skip_phy_initialization = 1; + + if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK)) + xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK; + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) + goto disable_usb_phy; + + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + xhci->shared_hcd->can_do_streams = 1; + + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + if (ret) + goto dealloc_usb2_hcd; + + device_enable_async_suspend(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + /* + * Prevent runtime pm from being on as default, users should enable + * runtime pm using power/control in sysfs. + */ + pm_runtime_forbid(&pdev->dev); + + return 0; + + +dealloc_usb2_hcd: + usb_remove_hcd(hcd); + +disable_usb_phy: + usb_phy_shutdown(hcd->usb_phy); + +put_usb3_hcd: + usb_put_hcd(xhci->shared_hcd); + +disable_clk: + clk_disable_unprepare(xhci->clk); + +disable_reg_clk: + clk_disable_unprepare(xhci->reg_clk); + +put_hcd: + usb_put_hcd(hcd); + +disable_runtime: + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int xhci_exynos_remove(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct clk *clk = xhci->clk; + struct clk *reg_clk = xhci->reg_clk; + struct usb_hcd *shared_hcd = xhci->shared_hcd; + + pm_runtime_get_sync(&dev->dev); + xhci->xhc_state |= XHCI_STATE_REMOVING; + + usb_remove_hcd(shared_hcd); + xhci->shared_hcd = NULL; + usb_phy_shutdown(hcd->usb_phy); + + usb_remove_hcd(hcd); + + xhci_vendor_cleanup(xhci); + + usb_put_hcd(shared_hcd); + clk_disable_unprepare(clk); + clk_disable_unprepare(reg_clk); + usb_put_hcd(hcd); + + pm_runtime_disable(&dev->dev); + pm_runtime_put_noidle(&dev->dev); + pm_runtime_set_suspended(&dev->dev); + + return 0; +} + +static int __maybe_unused xhci_exynos_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + + ret = xhci_priv_suspend_quirk(hcd); + if (ret) + return ret; + /* + * xhci_suspend() needs `do_wakeup` to know whether host is allowed + * to do wakeup during suspend. + */ + return xhci_suspend(xhci, device_may_wakeup(dev)); +} + +static int __maybe_unused xhci_exynos_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + + ret = xhci_priv_resume_quirk(hcd); + if (ret) + return ret; + + ret = xhci_resume(xhci, 0); + if (ret) + return ret; + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static int __maybe_unused xhci_exynos_runtime_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + + ret = xhci_priv_suspend_quirk(hcd); + if (ret) + return ret; + + return xhci_suspend(xhci, true); +} + +static int __maybe_unused xhci_exynos_runtime_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return xhci_resume(xhci, 0); +} + +static const struct dev_pm_ops xhci_exynos_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xhci_exynos_suspend, xhci_exynos_resume) + + SET_RUNTIME_PM_OPS(xhci_exynos_runtime_suspend, + xhci_exynos_runtime_resume, + NULL) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id usb_xhci_acpi_match[] = { + /* XHCI-compliant USB Controller */ + { "PNP0D10", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); +#endif + +static struct platform_driver usb_xhci_driver = { + .probe = xhci_exynos_probe, + .remove = xhci_exynos_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "xhci-exynos", + .pm = &xhci_exynos_pm_ops, + .of_match_table = of_match_ptr(usb_xhci_of_match), + .acpi_match_table = ACPI_PTR(usb_xhci_acpi_match), + }, +}; +MODULE_ALIAS("platform:xhci-exynos"); + +static int __init xhci_exynos_init(void) +{ + xhci_init_driver(&xhci_exynos_hc_driver, &xhci_exynos_overrides); + return platform_driver_register(&usb_xhci_driver); +} +module_init(xhci_exynos_init); + +static void __exit xhci_exynos_exit(void) +{ + platform_driver_unregister(&usb_xhci_driver); +} +module_exit(xhci_exynos_exit); + +MODULE_DESCRIPTION("xHCI Exynos Host Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/xhci-exynos.h b/drivers/usb/host/xhci-exynos.h new file mode 100644 index 000000000000..91860a3a1c7d --- /dev/null +++ b/drivers/usb/host/xhci-exynos.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * xhci-exynos.h - xHCI host controller driver platform Bus Glue for Exynos. + * + * Copyright (C) 2022 Samsung Electronics Incorporated - http://www.samsung.com + * Author: Daehwan Jung + * + * A lot of code borrowed from the Linux xHCI driver. + */ + +#include "xhci.h" + +/* EXYNOS uram memory map */ +#define EXYNOS_URAM_ABOX_EVT_RING_ADDR 0x02a00000 +#define EXYNOS_URAM_ISOC_OUT_RING_ADDR 0x02a01000 +#define EXYNOS_URAM_ISOC_IN_RING_ADDR 0x02a02000 +#define EXYNOS_URAM_DEVICE_CTX_ADDR 0x02a03000 +#define EXYNOS_URAM_DCBAA_ADDR 0x02a03880 +#define EXYNOS_URAM_ABOX_ERST_SEG_ADDR 0x02a03C80 +#define EXYNOS_URAM_CTX_SIZE 2112 + +struct xhci_hcd_exynos { + struct xhci_intr_reg __iomem *ir_set_audio; + + struct xhci_ring *event_ring_audio; + struct xhci_erst erst_audio; + + struct device *dev; + struct usb_hcd *hcd; + struct usb_hcd *shared_hcd; + + struct wakeup_source *main_wakelock; /* Wakelock for HS HCD */ + struct wakeup_source *shared_wakelock; /* Wakelock for SS HCD */ + + u32 in_ep; + u32 out_ep; + u32 in_deq; + u32 out_deq; +}; + +struct xhci_exynos_priv { + const char *firmware_name; + unsigned long long quirks; + struct xhci_vendor_data *vendor_data; + int (*plat_setup)(struct usb_hcd *); + void (*plat_start)(struct usb_hcd *); + int (*init_quirk)(struct usb_hcd *); + int (*suspend_quirk)(struct usb_hcd *); + int (*resume_quirk)(struct usb_hcd *); + struct xhci_hcd_exynos *xhci_exynos; +}; + +#define hcd_to_xhci_exynos_priv(h) ((struct xhci_exynos_priv *)hcd_to_xhci(h)->priv) +#define xhci_to_exynos_priv(x) ((struct xhci_exynos_priv *)(x)->priv) + +int xhci_check_trb_in_td_math(struct xhci_hcd *xhci); +void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg); +void xhci_link_segments(struct xhci_segment *prev, + struct xhci_segment *next, + enum xhci_ring_type type, bool chain_links); +void xhci_initialize_ring_info(struct xhci_ring *ring, + unsigned int cycle_state); +void xhci_remove_stream_mapping(struct xhci_ring *ring);