From patchwork Thu Oct 27 00:40:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Albert Wang X-Patchwork-Id: 11508 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp562166wru; Wed, 26 Oct 2022 17:41:43 -0700 (PDT) X-Google-Smtp-Source: AMsMyM44baHlCfzKEmGRCqttcbgeXbFBXcLmOVHMqkxBa1OEDTt97fh65S3Q6tXRqAq01QGLBVTd X-Received: by 2002:a63:d0:0:b0:45b:b321:46d2 with SMTP id 199-20020a6300d0000000b0045bb32146d2mr40380401pga.250.1666831303070; Wed, 26 Oct 2022 17:41:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1666831303; cv=none; d=google.com; s=arc-20160816; b=LlKge1edj+RLPYlY2MngL9w1t1D1v/urAKtMgL2wXkZZWytVZCIb3spnrblxdb/mji 31h9GIZ7ZOLcD4lWWuSWpTzrd70oMdYwy5M5p0WusjyGlHTS9eo6M6CXC5kFLsNCAIUH 4hbzL50n0e8JU0p/vmsI9prem2F/YrEuQUNlc7NGTKFBiVYXrZhiHzasTyX2S+kDSja5 BbUdOpCxreyihQGUhSgu6lSPd3ty2udyIUNeuRHEcgJbwv0ZWG1/KPG7kyMYDbjO5Pqs U5w9hV7tCNbMtaEbw2a4IOvLMJ9kQWJqdYTCD+kHl4buJenV6rog/C05TwCFj4uvOU+l YfSA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:dkim-signature; bh=xF/nz0PjSe1bRrievHFP0p30tg5DgJ194I3faa5Li1Y=; b=YGgNef+oI100XK9EBwH/yUDypP7PNGpsqb/X9Zw+gWQgCO+NCnLLNpYgtaquZfaIiC zf9PdS3kuP3Xe6BNxBY89G51fjlh/gj1SSbVplU7tNfDnKBcdVBRNmDIwS2AxbP5LXMi 0HINZNGUTywtpfG+iMZPoz+pndFjF5roLooQPJwB60MiBQgfuuLQps0twVCHo/1iydy9 Jf6PKmfya4kPWe/WP3NIdRHPZ/FhJSTkQRyXazIq0/4bYZdfKpcH4+9HMAPPnHM1fi03 v6mtw40z/fcEyomGbSXZsK+CbMDVGTZbQSpuSZZU5YMKGniEZkw8u5NJ/12CM8qhM3u/ XIYQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=XnKtBFDC; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id n18-20020a170903111200b0017669d005casi9565917plh.595.2022.10.26.17.41.29; Wed, 26 Oct 2022 17:41:43 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=XnKtBFDC; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234065AbiJ0AlP (ORCPT + 99 others); Wed, 26 Oct 2022 20:41:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38748 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229565AbiJ0AlN (ORCPT ); Wed, 26 Oct 2022 20:41:13 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 98FC06A52E for ; Wed, 26 Oct 2022 17:41:12 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id oo18-20020a17090b1c9200b0020bdba475afso2517386pjb.4 for ; Wed, 26 Oct 2022 17:41:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=xF/nz0PjSe1bRrievHFP0p30tg5DgJ194I3faa5Li1Y=; b=XnKtBFDC5bQ0hteNM/KIxDI0pzi0X+3/rF8+qWQLjfln+1CyyXczR46PKPSt81Ja3w Wb/avi3PMF75+Fx20mC6EAj1J18Uw4GXyWunzbWO+7Mmhfdkseo8J6PBGVOlxTRubhXJ /Ms6gjAa6E/9BFs5XAoTUf4G8mfmjOMoMdK9kSV6pYpYB8GXo2Vj3AlpDzifBylPluUn kWuRiESkA6EYZQSyqXcM7OPJEOTnQ8H0AHf7NkGk68isfCB4GrXlGrUYVe1cPyQJdnFs XYv+rtXzHF6uKieNO2jS3Ah9qTJJUHFsY0q+sQMg5dAbTl4v7oyxAEVy+Ew3fYlSYxRW ADfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=xF/nz0PjSe1bRrievHFP0p30tg5DgJ194I3faa5Li1Y=; b=RWtKpm+WRckH5W0KmFj9+24kK7Nmg+Gq0416TYBXX9hefMY31tsdxbpy5i5HQOcuXk KjZLj6NwAafO0L/8yUUBExK1juAyAQVEF82HpL1BvCl8Fpf862ashbUn4PjbTRrmtJ7a fcJGyr05htr6OQyUOmCg4TvMfmOLfrYwY30t0F2BQaaXG7c4yrIpNxfbfQM/VRoAvpvp 9O5nkbvod8Aq/4XdJs8HUq4P9JisifSfWlTGaH9sMVqdocJqMh/U0bZjhJEi49GFCON3 3N15u4XVhhUdqPjoG+/3DeUW7/4Z8IHbffsT2cv9xJwxJgSZyps57s8Prgco2MwUNZZf w6sw== X-Gm-Message-State: ACrzQf1ebBlq0CCpGgj+c3UuQhveIZct1v/GU3jxOo7mgFnn+6vpyZA1 a5uivkaqDFqq4PWq1GGKoNGioIeJC4xAfEIvN20= X-Received: from albertccwang.ntc.corp.google.com ([2401:fa00:fc:202:57bd:c29a:f9b1:f09c]) (user=albertccwang job=sendgmr) by 2002:a17:90b:4c07:b0:213:44f5:6073 with SMTP id na7-20020a17090b4c0700b0021344f56073mr7086526pjb.184.1666831272214; Wed, 26 Oct 2022 17:41:12 -0700 (PDT) Date: Thu, 27 Oct 2022 08:40:48 +0800 In-Reply-To: <20221027004050.4192111-1-albertccwang@google.com> Message-Id: <20221027004050.4192111-2-albertccwang@google.com> Mime-Version: 1.0 References: <20221027004050.4192111-1-albertccwang@google.com> X-Mailer: git-send-email 2.38.0.135.g90850a2211-goog Subject: [PATCH 1/3] usb: host: add xhci hooks for USB offload From: Albert Wang To: mathias.nyman@intel.com, gregkh@linuxfoundation.org Cc: badhri@google.com, howardyen@google.com, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, Greg Kroah-Harktman X-Spam-Status: No, score=-8.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,HK_RANDOM_FROM, RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1747799300500107039?= X-GMAIL-MSGID: =?utf-8?q?1747799300500107039?= From: Howard Yen This change is to provide USB offload function which allows to offload some xHCI operations on co-processor. This is especially designed for USB audio usecase. The co-processor is able to manipulate some USB structures in his own memory, like SRAM. There are several offload_ops introduced by this patch: struct xhci_offload_ops - function callbacks for offlad specific operations { @offload_init: - called for vendor init process during xhci-plat-hcd probe. @offload_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 @usb_offload_skip_urb: - called to check if need to skip urb enqueue } The xhci hooks with prefix "xhci_vendor_" on the ops in xhci_offload_ops. For example, offload_init ops will be invoked by xhci_vendor_offload_init() hook,is_usb_offload_enabled ops will be invoked by xhci_vendor_is_usb_offload_enabled(), and so on. Signed-off-by: Howard Yen Link: https://lore.kernel.org/r/20210119101044.1637023-1-howardyen@google.com Signed-off-by: Greg Kroah-Harktman --- drivers/usb/host/xhci-mem.c | 97 +++++++++++++++++++++++++++++++----- drivers/usb/host/xhci-plat.c | 23 +++++++++ drivers/usb/host/xhci-plat.h | 1 + drivers/usb/host/xhci.c | 21 ++++++++ drivers/usb/host/xhci.h | 31 ++++++++++++ 5 files changed, 160 insertions(+), 13 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 9e56aa28efcd..0449109a973d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -361,6 +361,38 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, return 0; } +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_offload_ops *ops = xhci_offload_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; +} + +static void xhci_vendor_free_transfer_ring(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, unsigned int ep_index) +{ + struct xhci_offload_ops *ops = xhci_offload_get_ops(xhci); + + if (ops && ops->free_transfer_ring) + ops->free_transfer_ring(xhci, virt_dev, ep_index); +} + +static bool xhci_vendor_is_offload_enabled(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, unsigned int ep_index) +{ + struct xhci_offload_ops *ops = xhci_offload_get_ops(xhci); + + if (ops && ops->is_offload_enabled) + return ops->is_offload_enabled(xhci, virt_dev, ep_index); + + return false; +} + /* * Create a new ring with zero or more segments. * @@ -412,7 +444,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_offload_enabled(xhci, virt_dev, ep_index)) + xhci_vendor_free_transfer_ring(xhci, virt_dev, ep_index); + else + xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); + virt_dev->eps[ep_index].ring = NULL; } @@ -885,7 +921,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); @@ -1483,8 +1519,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_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; @@ -1828,6 +1872,23 @@ void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) erst->entries = NULL; } +static void xhci_vendor_alloc_dcbaa( + struct xhci_hcd *xhci, gfp_t flags) +{ + struct xhci_offload_ops *ops = xhci_offload_get_ops(xhci); + + if (ops && ops->alloc_dcbaa) + return ops->alloc_dcbaa(xhci, flags); +} + +static void xhci_vendor_free_dcbaa(struct xhci_hcd *xhci) +{ + struct xhci_offload_ops *ops = xhci_offload_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; @@ -1879,9 +1940,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_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); @@ -2418,15 +2483,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_offload_enabled(xhci, NULL, 0)) { + 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 5fb55bf19493..2f04acb42fa6 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -173,6 +173,23 @@ static const struct of_device_id usb_xhci_of_match[] = { MODULE_DEVICE_TABLE(of, usb_xhci_of_match); #endif +static int xhci_vendor_init(struct xhci_hcd *xhci) +{ + struct xhci_offload_ops *ops = xhci_offload_get_ops(xhci); + + if (ops && ops->offload_init) + return ops->offload_init(xhci); + return 0; +} + +static void xhci_vendor_cleanup(struct xhci_hcd *xhci) +{ + struct xhci_offload_ops *ops = xhci_offload_get_ops(xhci); + + if (ops && ops->offload_cleanup) + ops->offload_cleanup(xhci); +} + static int xhci_plat_probe(struct platform_device *pdev) { const struct xhci_plat_priv *priv_match; @@ -317,6 +334,10 @@ static int xhci_plat_probe(struct platform_device *pdev) goto disable_clk; } + ret = xhci_vendor_init(xhci); + if (ret) + goto disable_usb_phy; + hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)) @@ -410,6 +431,8 @@ static int xhci_plat_remove(struct platform_device *dev) if (shared_hcd) usb_put_hcd(shared_hcd); + xhci_vendor_cleanup(xhci); + 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..5aa0d38fa01a 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -13,6 +13,7 @@ struct xhci_plat_priv { const char *firmware_name; unsigned long long quirks; + struct xhci_offload_ops *offload_ops; void (*plat_start)(struct usb_hcd *); int (*init_quirk)(struct usb_hcd *); int (*suspend_quirk)(struct usb_hcd *); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5176765c4013..aa3a44733bbe 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -22,6 +22,7 @@ #include "xhci-trace.h" #include "xhci-debugfs.h" #include "xhci-dbgcap.h" +#include "xhci-plat.h" #define DRIVER_AUTHOR "Sarah Sharp" #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" @@ -1663,6 +1664,11 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag return -ENODEV; } + if (xhci_vendor_usb_offload_skip_urb(xhci, urb)) { + xhci_dbg(xhci, "skip urb for usb offload\n"); + return -EOPNOTSUPP; + } + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) num_tds = urb->number_of_packets; else if (usb_endpoint_is_bulk_out(&urb->ep->desc) && @@ -4435,6 +4441,21 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, return ret; } +struct xhci_offload_ops *xhci_offload_get_ops(struct xhci_hcd *xhci) +{ + return xhci_to_priv(xhci)->offload_ops; +} +EXPORT_SYMBOL_GPL(xhci_offload_get_ops); + +bool xhci_vendor_usb_offload_skip_urb(struct xhci_hcd *xhci, struct urb *urb) +{ + struct xhci_offload_ops *ops = xhci_offload_get_ops(xhci); + + if (ops && ops->usb_offload_skip_urb) + return ops->usb_offload_skip_urb(xhci, urb); + return false; +} + #ifdef CONFIG_PM /* BESL to HIRD Encoding array for USB2 LPM */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c0964fe8ac12..5368c66f5cec 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2228,6 +2228,37 @@ static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, urb->stream_id); } +/** + * struct xhci_offload_ops - function callbacks for offload specific operations + * @offload_init: called for offload init process + * @offload_cleanup: called for offload cleanup process + * @is_usb_offload_enabled: called to check if xhci offload enabled + * @alloc_dcbaa: called when allocating specific dcbaa for offload + * @free_dcbaa: called to free specific dcbaa for offload + * @alloc_transfer_ring: called when remote transfer ring allocation is required + * @free_transfer_ring: called to free specific transfer ring for offload + * @usb_offload_skip_urb: called to check if need to skip urb + */ +struct xhci_offload_ops { + int (*offload_init)(struct xhci_hcd *xhci); + void (*offload_cleanup)(struct xhci_hcd *xhci); + bool (*is_offload_enabled)(struct xhci_hcd *xhci, + struct xhci_virt_device *vdev, + unsigned int ep_index); + void (*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_virt_device *virt_dev, unsigned int ep_index); + bool (*usb_offload_skip_urb)(struct xhci_hcd *xhci, struct urb *urb); +}; + +struct xhci_offload_ops *xhci_offload_get_ops(struct xhci_hcd *xhci); +bool xhci_vendor_usb_offload_skip_urb(struct xhci_hcd *xhci, struct urb *urb); + /* * 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 Thu Oct 27 00:40:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Albert Wang X-Patchwork-Id: 11509 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp564422wru; Wed, 26 Oct 2022 17:48:49 -0700 (PDT) X-Google-Smtp-Source: AMsMyM65gnFk1ANRHqo923HhBOYIQc62Mo8yOBK7UvL3ezEOa38ukYx5Tjz6PHyTa7LhkTlqEQ4t X-Received: by 2002:a17:907:7f8e:b0:7aa:7598:126d with SMTP id qk14-20020a1709077f8e00b007aa7598126dmr14440116ejc.289.1666831729481; Wed, 26 Oct 2022 17:48:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1666831729; cv=none; d=google.com; s=arc-20160816; b=N0yTOiWdt8oIkMAd2YJVkbgGHPhSTk15tAijWVa5u9jnidz2nigyOmptmYVFZXORKe ICAHYf24Uv2I6zLYPmOTPD4TCzYDZDCWA+HNkpIDiSNv0fB2PwnhzZgSnZlFUVl1Roxr Q/7C6d+12F7EHXpjE6WWjlrUxv2huZRL7vBSDUBbenEU58UOV4DSNoEoTXBorbvlxSmX X4wHwIQ8B4CktycbWmCRTTwSlXAvgnWoFgY5GfkPcXiCio6j2subMKYyOuc6tVXDuHB6 gasE1KMbox74x0iufKjCDvrUra2r1WeAha4kInGL2c7ROfdHgjm/GxEHeRyY0AUC7/1n qelQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:dkim-signature; bh=p0nqHJsa5c2NZf9cWkPRuZHGIcCuYzYIiGgo8niECgY=; b=OHklY52fI7k+DY08cKNHGNQIa1j/zicIeMYR00j7A9nL20J3yhHcxtaHwqStQeyy0R Cz6MF10KhKBVVIj7m0Eo/bnClbZ0hXi0gu56n4wZbdZfunCiLN93XXBtR4AbdzBjW3ud GQ5dFgwIXuz+gmfzrN8+TX2uzlnlTVRXnhX4fP8PGf9lcNI5KOEjLlxdPHNmq7uUYaTJ 8SRecpxlrN0s9Uvt/KIAuYPPbeqaHSmCz6qeZ4Pmzt3jbSs2uMsu0OBort75r8SjxbUS p7oGuzZDNdEil+ijSQIjmsHyIPgEzuHzfRq5f1sKG3jToTfD2JcP+rZIkW9/PfjjaC4f pSWQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=L6g50xPD; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ho7-20020a1709070e8700b0078dbd939dacsi8276559ejc.545.2022.10.26.17.48.15; Wed, 26 Oct 2022 17:48:49 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=L6g50xPD; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234132AbiJ0Al1 (ORCPT + 99 others); Wed, 26 Oct 2022 20:41:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38988 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229565AbiJ0AlY (ORCPT ); Wed, 26 Oct 2022 20:41:24 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E9C9C7C1E8 for ; Wed, 26 Oct 2022 17:41:22 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-360b9418f64so161363347b3.7 for ; Wed, 26 Oct 2022 17:41:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=p0nqHJsa5c2NZf9cWkPRuZHGIcCuYzYIiGgo8niECgY=; b=L6g50xPDwU5qrKT9t4j2jcX1wFPSNRjsww6qLigzmWsalQKWYMXkB63Fmq6W70BSQY 2HVOeJPveyUuic0uYIkQk3Bxgrvk78X9EorcqupfiQu71HilngoaD2HDzY/XHjyfVsx5 bOJTzlQC9/WINE1FtvTOt+afYW5HZb8OOxIUYsJE0qC0GhgR+MddoA0dovENQBDn8C8M PnWgYlb2rQc8jlK+lks+UWsCrpKlLy2LPjap7gBoFqodNzt3p8D422TLCFxRP1WmCgAR YtnR4sdL3f01LdTPUYgV2PEPpBOQ/vnAHyp11sGi+1KPYKnlN2sVvSYYK5afHjC1QPUO gE7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=p0nqHJsa5c2NZf9cWkPRuZHGIcCuYzYIiGgo8niECgY=; b=44UuqHPSwZRbpLCQcjsO78lnxdB+bNYXOBjRV4DjwuCi5W5rRScjNvsH2Irn80zS2V tZvZMxh6sMQFQYWmTCodXJuceF2TcTIl2ymw+5npn21lJYD4qYKHu/EtPcGKOnDosxRm ErEuV7FnjiXgpkOvqJnPQ095bZFtf7SoZI2GOFWT111AgmepI4+5Ro2uUtk6JmZ+I+RL S8/nwwQoN4+jjnLxZfKkS6Fx7o65/qcggMhuZCL9h3sCTMumcijYV0/y+owaTWu7KHyW RCdpoRpqRi8kHNM0rLakAuukIK+DJihQxSrAEV7xSGDPUMb0Mz0sC1FGcWyRBEi/AcPN OQ+Q== X-Gm-Message-State: ACrzQf2Mky+vBxxI4VB+jpLZHL/QQjKwbT+Ld6iXrrI3g7o7myf7dncc ztkdxID1RSIib+UXfAdaybrUJsG6vnkli7bTkFE= X-Received: from albertccwang.ntc.corp.google.com ([2401:fa00:fc:202:57bd:c29a:f9b1:f09c]) (user=albertccwang job=sendgmr) by 2002:a25:e68c:0:b0:6cb:7596:8bdb with SMTP id d134-20020a25e68c000000b006cb75968bdbmr9752524ybh.145.1666831282254; Wed, 26 Oct 2022 17:41:22 -0700 (PDT) Date: Thu, 27 Oct 2022 08:40:49 +0800 In-Reply-To: <20221027004050.4192111-1-albertccwang@google.com> Message-Id: <20221027004050.4192111-3-albertccwang@google.com> Mime-Version: 1.0 References: <20221027004050.4192111-1-albertccwang@google.com> X-Mailer: git-send-email 2.38.0.135.g90850a2211-goog Subject: [PATCH 2/3] usb: xhci-plat: add xhci_plat_priv_overwrite From: Albert Wang To: mathias.nyman@intel.com, gregkh@linuxfoundation.org Cc: badhri@google.com, howardyen@google.com, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, Greg Kroah-Hartman X-Spam-Status: No, score=-8.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,HK_RANDOM_FROM, RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1747799747534750788?= X-GMAIL-MSGID: =?utf-8?q?1747799747534750788?= From: Howard Yen Add an overwrite to platform specific callback for setting up the xhci_offload_ops, allow vendor to store the xhci_offload_ops and overwrite them when xhci_plat_probe invoked. Signed-off-by: Howard Yen Link: https://lore.kernel.org/r/20210119101044.1637023-1-howardyen@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 20 ++++++++++++++++++++ drivers/usb/host/xhci-plat.h | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 2f04acb42fa6..11ff89f722b7 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -173,9 +173,26 @@ 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_offload_ops(struct xhci_offload_ops *offload_ops) +{ + if (offload_ops == NULL) + return -EINVAL; + + xhci_plat_vendor_overwrite.offload_ops = offload_ops; + + return 0; +} +EXPORT_SYMBOL_GPL(xhci_plat_register_offload_ops); + static int xhci_vendor_init(struct xhci_hcd *xhci) { struct xhci_offload_ops *ops = xhci_offload_get_ops(xhci); + struct xhci_plat_priv *priv = xhci_to_priv(xhci); + + if (xhci_plat_vendor_overwrite.offload_ops) + ops = priv->offload_ops = xhci_plat_vendor_overwrite.offload_ops; if (ops && ops->offload_init) return ops->offload_init(xhci); @@ -185,9 +202,12 @@ static int xhci_vendor_init(struct xhci_hcd *xhci) static void xhci_vendor_cleanup(struct xhci_hcd *xhci) { struct xhci_offload_ops *ops = xhci_offload_get_ops(xhci); + struct xhci_plat_priv *priv = xhci_to_priv(xhci); if (ops && ops->offload_cleanup) ops->offload_cleanup(xhci); + + priv->offload_ops = NULL; } static int xhci_plat_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index 5aa0d38fa01a..0656d6daa194 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -22,4 +22,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_offload_ops *offload_ops; +}; + +int xhci_plat_register_offload_ops(struct xhci_offload_ops *offload_ops); + #endif /* _XHCI_PLAT_H */ From patchwork Thu Oct 27 00:40:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Albert Wang X-Patchwork-Id: 11510 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp564448wru; Wed, 26 Oct 2022 17:48:53 -0700 (PDT) X-Google-Smtp-Source: AMsMyM71bqDGdGJpX/260JQUWuGfZWbp/tFUlnhJn4JWRnkx91vEFwSs+txmeI2WBFtVeo+Pk2m8 X-Received: by 2002:a17:907:86a2:b0:791:910e:cce4 with SMTP id qa34-20020a17090786a200b00791910ecce4mr40469821ejc.36.1666831733516; Wed, 26 Oct 2022 17:48:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1666831733; cv=none; d=google.com; s=arc-20160816; b=kJV8wTYxa+WHAoOsa2zcZmXhOT7HHlC2yhb55KxAOqPpyprfvqjgzixs6RmIsUiiMY ojkhACg4wjhTiM14sfQSydF3fGC05ixnbGiBkK50QRgkiw7WDe/NswDhJTLCB0rPwj28 s7/sQbX5YYlkVdILqhEn/Ld9kbxzFvLhbumsVvQfVJ8LCZrq6sqCLQDwGQRhBBk65J2k ErJtNPlremAwbevD3x7R1ePRG04Nbp3B7HXznvJGfhhLSEzWHFxcikqh0b/R9E03FU4w /bqXUknQ8q20zw9dy3I1LYwgeJFy3BQ/MnFXqAfd6fXvra17mK233HDAy8AlPnA0sn8d ZSjQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:dkim-signature; bh=kyyM0qteYt+Lf7RLYSvZS5KQjtZIwVjRvQ4LhjUtVoc=; b=RDhDYeX9xvd2mVM7gb74ZC730Ke0qkMBzbIPTkSnuT1C+nqYqsl+z9Q8V3y6SIHl4C EAE8KNc9lZuLjCQ1M86DLdH0nJx7+wrM9YyyBp9r/+DCzpTBPaBHrByMJVBoih8W2ysP NJzM9UVCtsTazrpykAsKUFpkiuAkS3Y4a70gfopmkE8HjciAB5ITTeonzR/Axx7GPvZ+ Mz8iJgDwnm9rNAifDtJpMvSQ8TwKh/JWTvgFq/TG5jh2w9bF00gLtoKgkOpP/Cmmo4lY xeuT6makXtycCuDYCVvlkscAknJQH0v6r2Vxc85f0k4hJInVIJVBu5Lm2DQ4YohdkKvx ITvQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=HC8wBeC2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id jg22-20020a170907971600b00797a5ba1347si7004827ejc.594.2022.10.26.17.48.29; Wed, 26 Oct 2022 17:48:53 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=HC8wBeC2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234182AbiJ0Alf (ORCPT + 99 others); Wed, 26 Oct 2022 20:41:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39140 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234071AbiJ0Ala (ORCPT ); Wed, 26 Oct 2022 20:41:30 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0EEE7FE6C for ; Wed, 26 Oct 2022 17:41:28 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id t6-20020a25b706000000b006b38040b6f7so16242459ybj.6 for ; Wed, 26 Oct 2022 17:41:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=kyyM0qteYt+Lf7RLYSvZS5KQjtZIwVjRvQ4LhjUtVoc=; b=HC8wBeC2AYBwwdXqL5VqkplN9DO6Xs+YkaC3n+d3233pHZfY0HTclXPiQ1Qx9/m/SV 9khL60AxGyfnQ24Qy62EpRraGQdG2GNP8qM5vFhcBkpgtlc9q0o05TYvGrWvqEiXXsc1 XBs0Ha0aVaNsn1IO4zYk3NUEuU1vEaxafVP0GYPw2rg7zG+uZXPxY2VZZiWlP7Z1+y2y +3m2gRSVP+0TktWeKCuf9DLv1ntDlK8gmWeB5AKaIDPlAZ4DVCpjvGfY9x6W7CWXlBtb LbNMf4kAu3FH99kqH+fNbrsQp4O6j+94Bcgs+LKvtskodKPxmO0mOZLuYRTzAwhwhq2K GQNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=kyyM0qteYt+Lf7RLYSvZS5KQjtZIwVjRvQ4LhjUtVoc=; b=Yrg6ercm5mjJ/Ql9ieR9wYXI+C7sIe6AiLMOB6Fa8dEq+Z+nRJBcPPzXkmSIKoGAWa XIHTKIjANf+5F8gGhjvsYWvRukS7pK4Lld9W832eRh0nz61kEF4h5HeZcPGiChPjT+Sc Idx+ow/CqSPAHyVBfSaSq8K4sve30AOp4wKLhL2DA3iljiMHXfiozsT/WxI4Qbw5ro2s DQ0Fc7poondw5nNgfEZKDLLdy1adYLfS9Sb1hTQ8V1vth93C7GeSWPoap9oqD2rH+VjO unm1mPC7o5lNVaBPoi6cDtWDNttJrWzGFcDpEdQwDX4f+BQ1SR1sx5LDK5KYdXHz01CT BgsQ== X-Gm-Message-State: ACrzQf23kye1rfy5nWRCxjS9Ik/0ZSRaxkFTz/cl8BAisEKdTACwyfm8 X/L2CZDu1528Qj8su3ogljCiU6AauKLXJb1M37w= X-Received: from albertccwang.ntc.corp.google.com ([2401:fa00:fc:202:57bd:c29a:f9b1:f09c]) (user=albertccwang job=sendgmr) by 2002:a25:d0d1:0:b0:6cb:3ae4:7de2 with SMTP id h200-20020a25d0d1000000b006cb3ae47de2mr14726395ybg.505.1666831288153; Wed, 26 Oct 2022 17:41:28 -0700 (PDT) Date: Thu, 27 Oct 2022 08:40:50 +0800 In-Reply-To: <20221027004050.4192111-1-albertccwang@google.com> Message-Id: <20221027004050.4192111-4-albertccwang@google.com> Mime-Version: 1.0 References: <20221027004050.4192111-1-albertccwang@google.com> X-Mailer: git-send-email 2.38.0.135.g90850a2211-goog Subject: [PATCH 3/3] usb: host: add the xhci offload hooks implementations From: Albert Wang To: mathias.nyman@intel.com, gregkh@linuxfoundation.org Cc: badhri@google.com, howardyen@google.com, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, Albert Wang X-Spam-Status: No, score=-8.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,HK_RANDOM_FROM, RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1747799752032315783?= X-GMAIL-MSGID: =?utf-8?q?1747799752032315783?= Add the offload hooks implementations and call to co-processor for offload operations. Signed-off-by: Albert Wang --- drivers/usb/host/xhci-offload-impl.c | 492 +++++++++++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 drivers/usb/host/xhci-offload-impl.c diff --git a/drivers/usb/host/xhci-offload-impl.c b/drivers/usb/host/xhci-offload-impl.c new file mode 100644 index 000000000000..90e546d63fbe --- /dev/null +++ b/drivers/usb/host/xhci-offload-impl.c @@ -0,0 +1,492 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Google Corp. + * + * Author: + * Howard.Yen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xhci.h" +#include "xhci-plat.h" + +enum usb_offload_op_mode { + USB_OFFLOAD_STOP, + USB_OFFLOAD_DRAM +}; + +enum usb_state { + USB_DISCONNECTED, + USB_CONNECTED +}; + +enum usb_offload_msg { + SET_DCBAA_PTR, + SETUP_DONE, + SET_ISOC_TR_INFO, + SYNC_CONN_STAT, + SET_OFFLOAD_STATE +}; + +struct conn_stat_args { + u16 bus_id; + u16 dev_num; + u16 slot_id; + u32 conn_stat; +}; + +struct get_isoc_tr_info_args { + u16 ep_id; + u16 dir; + u32 type; + u32 num_segs; + u32 seg_ptr; + u32 max_packet; + u32 deq_ptr; + u32 enq_ptr; + u32 cycle_state; + u32 num_trbs_free; +}; + +struct xhci_offload_data { + struct xhci_hcd *xhci; + + bool usb_accessory_enabled; + bool usb_audio_offload; + bool dt_direct_usb_access; + bool offload_state; + + enum usb_offload_op_mode op_mode; +}; + +static struct xhci_offload_data *offload_data; +struct xhci_offload_data *xhci_get_offload_data(void) +{ + return offload_data; +} + +/* + * Determine if an USB device is a compatible devices: + * True: Devices are audio class and they contain ISOC endpoint + * False: Devices are not audio class or they're audio class but no ISOC endpoint or + * they have at least one interface is video class + */ +static bool is_compatible_with_usb_audio_offload(struct usb_device *udev) +{ + struct usb_endpoint_descriptor *epd; + struct usb_host_config *config; + struct usb_host_interface *alt; + struct usb_interface_cache *intfc; + int i, j, k; + bool is_audio = false; + + config = udev->config; + for (i = 0; i < config->desc.bNumInterfaces; i++) { + intfc = config->intf_cache[i]; + for (j = 0; j < intfc->num_altsetting; j++) { + alt = &intfc->altsetting[j]; + + if (alt->desc.bInterfaceClass == USB_CLASS_VIDEO) { + is_audio = false; + goto out; + } + + if (alt->desc.bInterfaceClass == USB_CLASS_AUDIO) { + for (k = 0; k < alt->desc.bNumEndpoints; k++) { + epd = &alt->endpoint[k].desc; + if (usb_endpoint_xfer_isoc(epd)) { + is_audio = true; + break; + } + } + } + } + } + +out: + return is_audio; +} + +/* + * check the usb device including the video class: + * True: Devices contain video class + * False: Device doesn't contain video class + */ +static bool is_usb_video_device(struct usb_device *udev) +{ + struct usb_host_config *config; + struct usb_host_interface *alt; + struct usb_interface_cache *intfc; + int i, j; + bool is_video = false; + + if (!udev || !udev->config) + return is_video; + + config = udev->config; + + for (i = 0; i < config->desc.bNumInterfaces; i++) { + intfc = config->intf_cache[i]; + for (j = 0; j < intfc->num_altsetting; j++) { + alt = &intfc->altsetting[j]; + + if (alt->desc.bInterfaceClass == USB_CLASS_VIDEO) { + is_video = true; + goto out; + } + } + } + +out: + return is_video; +} + +/* + * This is the driver call to co-processor for offload operations. + */ +int offload_driver_call(enum usb_offload_msg msg, void *ptr) +{ + enum usb_offload_msg offload_msg; + void *argptr; + + offload_msg = msg; + argptr = ptr; + + return 0; +} + +static int xhci_sync_conn_stat(unsigned int bus_id, unsigned int dev_num, unsigned int slot_id, + unsigned int conn_stat) +{ + struct conn_stat_args conn_args; + + conn_args.bus_id = bus_id; + conn_args.dev_num = dev_num; + conn_args.slot_id = slot_id; + conn_args.conn_stat = conn_stat; + + return offload_driver_call(SYNC_CONN_STAT, &conn_args); +} + +static int usb_host_mode_state_notify(enum usb_state usb_state) +{ + return xhci_sync_conn_stat(0, 0, 0, usb_state); +} + +static int xhci_udev_notify(struct notifier_block *self, unsigned long action, + void *dev) +{ + struct usb_device *udev = dev; + struct xhci_offload_data *offload_data = xhci_get_offload_data(); + + switch (action) { + case USB_DEVICE_ADD: + if (is_compatible_with_usb_audio_offload(udev)) { + dev_dbg(&udev->dev, "Compatible with usb audio offload\n"); + if (offload_data->op_mode == USB_OFFLOAD_DRAM) { + xhci_sync_conn_stat(udev->bus->busnum, udev->devnum, udev->slot_id, + USB_CONNECTED); + } + } + offload_data->usb_accessory_enabled = false; + break; + case USB_DEVICE_REMOVE: + if (is_compatible_with_usb_audio_offload(udev) && + (offload_data->op_mode == USB_OFFLOAD_DRAM)) { + xhci_sync_conn_stat(udev->bus->busnum, udev->devnum, udev->slot_id, + USB_DISCONNECTED); + } + offload_data->usb_accessory_enabled = false; + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block xhci_udev_nb = { + .notifier_call = xhci_udev_notify, +}; + +static int usb_audio_offload_init(struct xhci_hcd *xhci) +{ + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + struct xhci_offload_data *offload_data = xhci_get_offload_data(); + int ret; + u32 out_val; + + offload_data = kzalloc(sizeof(struct xhci_offload_data), GFP_KERNEL); + if (!offload_data) + return -ENOMEM; + + if (!of_property_read_u32(dev->of_node, "offload", &out_val)) + offload_data->usb_audio_offload = (out_val == 1) ? true : false; + + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_err(dev, "Could not get reserved memory\n"); + kfree(offload_data); + return ret; + } + + offload_data->dt_direct_usb_access = + of_property_read_bool(dev->of_node, "direct-usb-access") ? true : false; + if (!offload_data->dt_direct_usb_access) + dev_warn(dev, "Direct USB access is not supported\n"); + + offload_data->offload_state = true; + + usb_register_notify(&xhci_udev_nb); + offload_data->op_mode = USB_OFFLOAD_DRAM; + offload_data->xhci = xhci; + + return 0; +} + +static void usb_audio_offload_cleanup(struct xhci_hcd *xhci) +{ + struct xhci_offload_data *offload_data = xhci_get_offload_data(); + + offload_data->usb_audio_offload = false; + offload_data->op_mode = USB_OFFLOAD_STOP; + offload_data->xhci = NULL; + + usb_unregister_notify(&xhci_udev_nb); + + /* Notification for xhci driver removing */ + usb_host_mode_state_notify(USB_DISCONNECTED); + + kfree(offload_data); + offload_data = NULL; +} + +static bool is_offload_enabled(struct xhci_hcd *xhci, + struct xhci_virt_device *vdev, unsigned int ep_index) +{ + struct usb_device *udev; + struct xhci_offload_data *offload_data = xhci_get_offload_data(); + bool global_enabled = offload_data->op_mode != USB_OFFLOAD_STOP; + struct xhci_ring *ep_ring; + + if (vdev == NULL || vdev->eps[ep_index].ring == NULL) + return global_enabled; + + udev = vdev->udev; + + if (global_enabled) { + ep_ring = vdev->eps[ep_index].ring; + if (offload_data->op_mode == USB_OFFLOAD_DRAM) { + if (is_usb_video_device(udev)) + return false; + else if (ep_ring->type == TYPE_ISOC) + return offload_data->offload_state; + } + } + + return false; +} + +static bool is_usb_bulk_transfer_enabled(struct xhci_hcd *xhci, struct urb *urb) +{ + struct xhci_offload_data *offload_data = xhci_get_offload_data(); + struct usb_endpoint_descriptor *desc = &urb->ep->desc; + int ep_type = usb_endpoint_type(desc); + struct usb_ctrlrequest *cmd; + bool skip_bulk = false; + + cmd = (struct usb_ctrlrequest *) urb->setup_packet; + + if (ep_type == USB_ENDPOINT_XFER_CONTROL) { + if (!usb_endpoint_dir_in(desc) && cmd->bRequest == 0x35) + offload_data->usb_accessory_enabled = true; + else + offload_data->usb_accessory_enabled = false; + } + + if (ep_type == USB_ENDPOINT_XFER_BULK && !usb_endpoint_dir_in(desc)) + skip_bulk = offload_data->usb_accessory_enabled; + + return skip_bulk; +} + +static int xhci_set_dcbaa_ptr(u64 dcbaa_ptr) +{ + return offload_driver_call(SET_DCBAA_PTR, &dcbaa_ptr); +} + +static int xhci_setup_done(void) +{ + return offload_driver_call(SETUP_DONE, NULL); +} + +static void alloc_dcbaa(struct xhci_hcd *xhci, gfp_t flags) +{ + dma_addr_t dma; + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + struct xhci_offload_data *offload_data = xhci_get_offload_data(); + + if (offload_data->op_mode == USB_OFFLOAD_DRAM) { + xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), + &dma, flags); + if (!xhci->dcbaa) + return; + + xhci->dcbaa->dma = dma; + if (xhci_set_dcbaa_ptr(xhci->dcbaa->dma) != 0) { + xhci_err(xhci, "Set DCBAA pointer failed\n"); + xhci->dcbaa = NULL; + return; + } + xhci_setup_done(); + + xhci_dbg(xhci, "Set dcbaa_ptr=%llx to AoC\n", xhci->dcbaa->dma); + } else { + xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), + &dma, flags); + if (!xhci->dcbaa) + return; + + xhci->dcbaa->dma = dma; + } +} + +static void free_dcbaa(struct xhci_hcd *xhci) +{ + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + + if (!xhci->dcbaa) + return; + + dma_free_coherent(dev, sizeof(*xhci->dcbaa), + xhci->dcbaa, xhci->dcbaa->dma); + + xhci->dcbaa = NULL; +} + +static int xhci_set_isoc_tr_info(u16 ep_id, u16 dir, struct xhci_ring *ep_ring) +{ + struct get_isoc_tr_info_args tr_info; + + tr_info.ep_id = ep_id; + tr_info.dir = dir; + tr_info.num_segs = ep_ring->num_segs; + tr_info.max_packet = ep_ring->bounce_buf_len; + tr_info.type = ep_ring->type; + tr_info.seg_ptr = ep_ring->first_seg->dma; + tr_info.cycle_state = ep_ring->cycle_state; + tr_info.num_trbs_free = ep_ring->num_trbs_free; + + return offload_driver_call(SET_ISOC_TR_INFO, &tr_info); +} + +static 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) +{ + struct xhci_ring *ep_ring; + u16 dir; + + ep_ring = xhci_ring_alloc(xhci, 1, 1, ring_type, max_packet, mem_flags); + dir = endpoint_type == ISOC_IN_EP ? 0 : 1; + + xhci_set_isoc_tr_info(0, dir, ep_ring); + + return ep_ring; +} + +static void free_transfer_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, + unsigned int ep_index) +{ + struct xhci_ring *ring, *new_ring; + struct xhci_ep_ctx *ep_ctx; + struct xhci_input_control_ctx *ctrl_ctx; + u32 ep_type; + u32 ep_is_added, ep_is_dropped; + + ring = virt_dev->eps[ep_index].ring; + new_ring = virt_dev->eps[ep_index].new_ring; + ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->out_ctx, ep_index); + ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); + + ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", __func__); + return; + } + ep_is_added = EP_IS_ADDED(ctrl_ctx, ep_index); + ep_is_dropped = EP_IS_DROPPED(ctrl_ctx, ep_index); + + xhci_dbg(xhci, "%s: ep %u is added(0x%x), is dropped(0x%x)\n", __func__, ep_index, + ep_is_added, ep_is_dropped); + + if (ring) { + xhci_dbg(xhci, "%s: ep_index=%u, ep_type=%u, ring type=%u, new_ring=%pK\n", + __func__, ep_index, ep_type, ring->type, new_ring); + + xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); + + virt_dev->eps[ep_index].ring = NULL; + + if (ep_is_added == 0 && ep_is_dropped == 0) + return; + } + + if (new_ring) { + xhci_dbg(xhci, "%s: ep_index=%u, ep_type=%u, new_ring type=%u\n", __func__, + ep_index, ep_type, new_ring->type); + + xhci_ring_free(xhci, virt_dev->eps[ep_index].new_ring); + + virt_dev->eps[ep_index].new_ring = NULL; + + return; + } +} + +static bool offload_skip_urb(struct xhci_hcd *xhci, struct urb *urb) +{ + struct xhci_virt_device *vdev = xhci->devs[urb->dev->slot_id]; + struct usb_endpoint_descriptor *desc = &urb->ep->desc; + int ep_type = usb_endpoint_type(desc); + unsigned int ep_index; + + if (ep_type == USB_ENDPOINT_XFER_CONTROL) + ep_index = (unsigned int)(usb_endpoint_num(desc)*2); + else + ep_index = (unsigned int)(usb_endpoint_num(desc)*2) + + (usb_endpoint_dir_in(desc) ? 1 : 0) - 1; + + xhci_dbg(xhci, "%s: ep_index=%u, ep_type=%d\n", __func__, ep_index, ep_type); + + if (is_offload_enabled(xhci, vdev, ep_index)) + return true; + + if (is_usb_bulk_transfer_enabled(xhci, urb)) + return true; + + return false; +} + +static struct xhci_offload_ops offload_ops = { + .offload_init = usb_audio_offload_init, + .offload_cleanup = usb_audio_offload_cleanup, + .is_offload_enabled = is_offload_enabled, + .alloc_dcbaa = alloc_dcbaa, + .free_dcbaa = free_dcbaa, + .alloc_transfer_ring = alloc_transfer_ring, + .free_transfer_ring = free_transfer_ring, + .usb_offload_skip_urb = offload_skip_urb, +}; + +int xhci_offload_helper_init(void) +{ + return xhci_plat_register_offload_ops(&offload_ops); +}