All of lore.kernel.org
 help / color / mirror / Atom feed
From: Albert Wang <albertccwang@google.com>
To: mathias.nyman@intel.com, gregkh@linuxfoundation.org
Cc: badhri@google.com, howardyen@google.com, pumahsu@google.com,
	raychi@google.com, linux-kernel@vger.kernel.org,
	linux-usb@vger.kernel.org, Albert Wang <albertccwang@google.com>
Subject: [PATCH v3 3/3] usb: host: add the xhci offload hooks implementations
Date: Tue, 13 Dec 2022 14:10:05 +0000	[thread overview]
Message-ID: <20221213141005.3068792-4-albertccwang@google.com> (raw)
In-Reply-To: <20221213141005.3068792-1-albertccwang@google.com>

Add the offload hooks implementations which are used in the xHCI driver
for vendor offload function, and some functions will call to
co-processor driver for further offload operations.

Signed-off-by: Albert Wang <albertccwang@google.com>
Signed-off-by: Howard Yen <howardyen@google.com>
---
Changes in v3:
- Add new implementation driver file in v3

---
 drivers/usb/host/aoc-usb.c           | 198 ++++++++++++++
 drivers/usb/host/aoc-usb.h           | 108 ++++++++
 drivers/usb/host/xhci-offload-impl.c | 396 +++++++++++++++++++++++++++
 3 files changed, 702 insertions(+)
 create mode 100644 drivers/usb/host/aoc-usb.c
 create mode 100644 drivers/usb/host/aoc-usb.h
 create mode 100644 drivers/usb/host/xhci-offload-impl.c

diff --git a/drivers/usb/host/aoc-usb.c b/drivers/usb/host/aoc-usb.c
new file mode 100644
index 000000000000..b51f26755a63
--- /dev/null
+++ b/drivers/usb/host/aoc-usb.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright 2022 Google LLC. All Rights Reserved.
+ *
+ * Interface to the AoC USB control service
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+
+#include "aoc-usb.h"
+
+#define AOC_USB_NAME "aoc_usb"
+
+extern struct blocking_notifier_head aoc_usb_notifier_list;
+
+int xhci_set_offload_state(bool enabled)
+{
+	return blocking_notifier_call_chain(&aoc_usb_notifier_list, SET_OFFLOAD_STATE, &enabled);
+}
+
+int xhci_set_dcbaa_ptr(u64 aoc_dcbaa_ptr)
+{
+	return blocking_notifier_call_chain(&aoc_usb_notifier_list, SET_DCBAA_PTR, &aoc_dcbaa_ptr);
+}
+
+int xhci_setup_done(void)
+{
+	return blocking_notifier_call_chain(&aoc_usb_notifier_list, SETUP_DONE, NULL);
+}
+
+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 args;
+
+	args.bus_id = bus_id;
+	args.dev_num = dev_num;
+	args.slot_id = slot_id;
+	args.conn_stat = conn_stat;
+
+	return blocking_notifier_call_chain(&aoc_usb_notifier_list, SYNC_CONN_STAT, &args);
+}
+
+int usb_host_mode_state_notify(enum usb_conn_state usb_state)
+{
+	return xhci_sync_conn_stat(0, 0, 0, usb_state);
+}
+
+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 blocking_notifier_call_chain(&aoc_usb_notifier_list, SET_ISOC_TR_INFO, &tr_info);
+}
+
+static int aoc_usb_match(struct device *dev, void *data)
+{
+	if (sysfs_streq(dev_driver_string(dev), "xhci-hcd-exynos"))
+		return 1;
+
+	return 0;
+}
+
+static bool aoc_usb_is_hcd_working(void)
+{
+	struct device_node *np;
+	struct platform_device *pdev;
+	struct device *udev;
+	int ret;
+
+	np = of_find_node_by_name(NULL, "dwc3");
+	if (!np || !of_device_is_available(np)) {
+		pr_err("Cannot find dwc3 device node\n");
+		return false;
+	}
+
+	pdev = of_find_device_by_node(np);
+	if (!pdev)
+		return false;
+
+	udev = device_find_child(&pdev->dev, NULL, aoc_usb_match);
+	if (!udev)
+		return false;
+
+	ret = usb_host_mode_state_notify(USB_CONNECTED);
+	if (ret)
+		dev_err(udev, "Notifying AoC for xhci driver status is failed.\n");
+
+	return true;
+}
+
+static struct work_struct usb_host_mode_checking_ws;
+static void usb_host_mode_checking_work(struct work_struct *ws)
+{
+	if (aoc_usb_is_hcd_working())
+		pr_info("USB HCD is working, send notification to AoC\n");
+}
+
+/*
+ * This variable used to present if aoc_usb module was probed done. If offload
+ * is enabled, the controller needs to wait for the aoc_usb probe done and then
+ * continue the controller's probe.
+ */
+static bool aoc_usb_probe_done;
+static int aoc_usb_probe(struct aoc_service_dev *adev)
+{
+	struct device *dev = &adev->dev;
+	struct aoc_usb_drvdata *drvdata;
+
+	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->adev = adev;
+
+	mutex_init(&drvdata->lock);
+
+	drvdata->ws = wakeup_source_register(dev, dev_name(dev));
+	if (!drvdata->ws) {
+		dev_err(&drvdata->adev->dev, "wakeup_source_register failed!\n");
+		return -ENOMEM;
+	}
+
+	drvdata->usb_conn_state = 0;
+	dev_set_drvdata(dev, drvdata);
+
+	aoc_usb_probe_done = true;
+
+	schedule_work(&usb_host_mode_checking_ws);
+
+	return 0;
+}
+
+static int aoc_usb_remove(struct aoc_service_dev *adev)
+{
+	struct aoc_usb_drvdata *drvdata = dev_get_drvdata(&adev->dev);
+
+	wakeup_source_unregister(drvdata->ws);
+	mutex_destroy(&drvdata->lock);
+
+	kfree(drvdata);
+
+	aoc_usb_probe_done = false;
+
+	return 0;
+}
+
+bool is_aoc_usb_probe_done(void)
+{
+	return aoc_usb_probe_done;
+}
+
+static const char *const aoc_usb_service_names[] = {
+	"usb_control",
+	NULL,
+};
+
+static struct aoc_driver aoc_usb_driver = {
+	.drv = {
+		.name = AOC_USB_NAME,
+	},
+	.service_names = aoc_usb_service_names,
+	.probe = aoc_usb_probe,
+	.remove = aoc_usb_remove,
+};
+
+static int __init aoc_usb_init(void)
+{
+	xhci_offload_helper_init();
+
+	INIT_WORK(&usb_host_mode_checking_ws, usb_host_mode_checking_work);
+
+	return driver_register(&aoc_usb_driver.drv);
+}
+
+static void __exit aoc_usb_exit(void)
+{
+	driver_unregister(&aoc_usb_driver.drv);
+}
+
+module_init(aoc_usb_init);
+module_exit(aoc_usb_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Howard Yen (Google)");
+MODULE_DESCRIPTION("USB driver for AoC");
diff --git a/drivers/usb/host/aoc-usb.h b/drivers/usb/host/aoc-usb.h
new file mode 100644
index 000000000000..a756abd00d01
--- /dev/null
+++ b/drivers/usb/host/aoc-usb.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 Google Corp.
+ *
+ * Author:
+ *  Howard.Yen <howardyen@google.com>
+ */
+
+#ifndef __LINUX_AOC_USB_H
+#define __LINUX_AOC_USB_H
+
+#include "xhci.h"
+
+struct aoc_service_dev {
+	struct device dev;
+	wait_queue_head_t read_queue;
+	wait_queue_head_t write_queue;
+
+	void *ipc_base;
+	void *prvdata;
+	uint64_t suspend_rx_count;
+
+	uint8_t mbox_index;
+	uint8_t service_index;
+
+	bool dead;
+	bool wake_capable;
+};
+
+struct aoc_driver {
+	struct device_driver drv;
+
+	/* Array of service names to match against.  Last entry must be NULL */
+	const char * const *service_names;
+	int (*probe)(struct aoc_service_dev *dev);
+	int (*remove)(struct aoc_service_dev *dev);
+};
+
+enum usb_offload_msg {
+	SET_DCBAA_PTR,
+	GET_TR_DEQUEUE_PTR,
+	SETUP_DONE,
+	SET_ISOC_TR_INFO,
+	SYNC_CONN_STAT,
+	SET_OFFLOAD_STATE
+};
+
+enum usb_offload_op_mode {
+	USB_OFFLOAD_STOP,
+	USB_OFFLOAD_DRAM
+};
+
+enum usb_conn_state {
+	USB_DISCONNECTED,
+	USB_CONNECTED
+};
+
+enum usb_recover_state {
+	NONE,
+	RECOVER_HOST_OFF,
+	RECOVER_HOST_ON,
+	RECOVERED
+};
+
+struct aoc_usb_drvdata {
+	struct aoc_service_dev *adev;
+
+	struct mutex lock;
+	struct wakeup_source *ws;
+
+	struct notifier_block nb;
+
+	unsigned int usb_conn_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;
+};
+
+int xhci_set_offload_state(bool enabled);
+int xhci_set_dcbaa_ptr(u64 aoc_dcbaa_ptr);
+int xhci_setup_done(void);
+int xhci_sync_conn_stat(unsigned int bus_id, unsigned int dev_num, unsigned int slot_id,
+			       unsigned int conn_stat);
+int usb_host_mode_state_notify(enum usb_conn_state usb_state);
+int xhci_set_isoc_tr_info(u16 ep_id, u16 dir, struct xhci_ring *ep_ring);
+
+bool is_aoc_usb_probe_done(void);
+
+int xhci_offload_helper_init(void);
+
+#endif /* __LINUX_AOC_USB_H */
diff --git a/drivers/usb/host/xhci-offload-impl.c b/drivers/usb/host/xhci-offload-impl.c
new file mode 100644
index 000000000000..738595382f7e
--- /dev/null
+++ b/drivers/usb/host/xhci-offload-impl.c
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Google Corp.
+ *
+ * Author:
+ *  Howard.Yen <howardyen@google.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <linux/usb/hcd.h>
+
+#include "aoc-usb.h"
+#include "xhci-plat.h"
+
+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;
+}
+
+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;
+
+	if (!is_aoc_usb_probe_done()) {
+		dev_info(dev, "%s: deferring the probe\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
+	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);
+}
+
+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 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 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);
+}
-- 
2.39.0.rc1.256.g54fd8350bd-goog


      parent reply	other threads:[~2022-12-13 14:12 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-13 14:10 [PATCH v3 0/3] add xhci hooks for USB offload Albert Wang
2022-12-13 14:10 ` [PATCH v3 1/3] usb: host: " Albert Wang
2022-12-16  6:15   ` kernel test robot
2022-12-13 14:10 ` [PATCH v3 2/3] usb: xhci-plat: add xhci_plat_priv_overwrite Albert Wang
2022-12-13 14:10 ` Albert Wang [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221213141005.3068792-4-albertccwang@google.com \
    --to=albertccwang@google.com \
    --cc=badhri@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=howardyen@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    --cc=pumahsu@google.com \
    --cc=raychi@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.