2022-03-04 12:30:48

by Jung Daehwan

[permalink] [raw]
Subject: [PATCH v1 2/4] usb: host: add xhci hooks for USB offload

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.
@queue_irq_work:
- called to queue vendor specific irq work.
@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 <[email protected]>
---
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 | 8 +++
drivers/usb/host/xhci-ring.c | 13 ++++
drivers/usb/host/xhci.c | 94 ++++++++++++++++++++++++-
drivers/usb/host/xhci.h | 48 +++++++++++++
7 files changed, 325 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 6c1b8d748d0f..f7ed19cba8ad 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 e6d56ef91ddb..5defbaf427ed 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -367,6 +367,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.
*
@@ -419,7 +467,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;
}

@@ -478,6 +530,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;
@@ -491,7 +544,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;
@@ -502,9 +560,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);
}

@@ -897,7 +962,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);
@@ -1495,8 +1560,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;

@@ -1844,6 +1917,24 @@ void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
}
EXPORT_SYMBOL_GPL(xhci_free_erst);

+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;
@@ -1898,9 +1989,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);
@@ -2441,15 +2536,21 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
* xHCI section 5.4.6 - doorbell 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 c1edcc9b13ce..21280a6d589e 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -184,6 +184,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;
@@ -339,6 +374,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;

@@ -418,8 +457,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 561d0b7bce09..e726a572321d 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_vendor_data *vendor_data;
int (*plat_setup)(struct usb_hcd *);
void (*plat_start)(struct usb_hcd *);
int (*init_quirk)(struct usb_hcd *);
@@ -22,4 +23,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-ring.c b/drivers/usb/host/xhci-ring.c
index 2e99393560e5..e611f8d7d587 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3075,6 +3075,15 @@ void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
}
EXPORT_SYMBOL_GPL(xhci_update_erst_dequeue);

+static irqreturn_t xhci_vendor_queue_irq_work(struct xhci_hcd *xhci)
+{
+ struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci);
+
+ if (ops && ops->queue_irq_work)
+ return ops->queue_irq_work(xhci);
+ return IRQ_NONE;
+}
+
/*
* xHCI spec says we can get an interrupt, and if the HC has an error condition,
* we might get bad data out of the event ring. Section 4.10.2.7 has a list of
@@ -3108,6 +3117,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
goto out;
}

+ ret = xhci_vendor_queue_irq_work(xhci);
+ if (ret == IRQ_HANDLED)
+ goto out;
+
/*
* Clear the op reg interrupt status first,
* so we can receive interrupts from other MSI-X interrupters.
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 041a65a6f175..10d5e20b710d 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1621,6 +1621,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) &&
@@ -2964,6 +2969,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;
}

@@ -3107,7 +3120,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;
}
}
@@ -3272,6 +3289,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 */
@@ -3303,6 +3327,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);
@@ -3848,6 +3877,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.
@@ -4093,6 +4129,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);
@@ -4223,6 +4267,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.
@@ -4371,6 +4422,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);

@@ -4395,6 +4454,30 @@ 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;
+}
+
+bool xhci_vendor_usb_offload_skip_urb(struct xhci_hcd *xhci, struct urb *urb)
+{
+ struct xhci_vendor_ops *ops = xhci_vendor_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 */
@@ -5131,6 +5214,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 5a75fe563123..2efe8ddaab5f 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1928,6 +1928,7 @@ struct xhci_hcd {
struct list_head regset_list;

void *dbc;
+
/* platform-specific data -- must come last */
unsigned long priv[] __aligned(sizeof(s64));
};
@@ -2206,6 +2207,53 @@ 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
+ * @queue_irq_work: called to queue vendor specific irq work
+ * @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);
+ irqreturn_t (*queue_irq_work)(struct xhci_hcd *xhci);
+
+ 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);
+ bool (*usb_offload_skip_urb)(struct xhci_hcd *xhci, struct urb *urb);
+ 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);
+bool xhci_vendor_usb_offload_skip_urb(struct xhci_hcd *xhci, struct urb *urb);
+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
--
2.31.1



2022-03-08 11:45:02

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 2/4] usb: host: add xhci hooks for USB offload

Hi Daehwan,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on krzk/for-next]
[also build test ERROR on char-misc/char-misc-testing v5.17-rc7]
[cannot apply to usb/usb-testing next-20220308]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Daehwan-Jung/usb-host-export-symbols-for-xhci-hooks-usage/20220304-143406
base: https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git for-next
config: arm-hisi_defconfig (https://download.01.org/0day-ci/archive/20220308/[email protected]/config)
compiler: arm-linux-gnueabi-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/2b6a5d700c2bbb0a3ccfcd6e83a7f7b2ea049db9
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Daehwan-Jung/usb-host-export-symbols-for-xhci-hooks-usage/20220304-143406
git checkout 2b6a5d700c2bbb0a3ccfcd6e83a7f7b2ea049db9
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arm SHELL=/bin/bash drivers/usb/host/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

drivers/usb/host/xhci.c:4361:5: warning: no previous prototype for 'xhci_address_device' [-Wmissing-prototypes]
4361 | int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
| ^~~~~~~~~~~~~~~~~~~
drivers/usb/host/xhci.c: In function 'xhci_vendor_get_ops':
>> drivers/usb/host/xhci.c:4459:20: error: 'struct xhci_hcd' has no member named 'vendor_ops'
4459 | return xhci->vendor_ops;
| ^~
drivers/usb/host/xhci.c:4460:1: error: control reaches end of non-void function [-Werror=return-type]
4460 | }
| ^
cc1: some warnings being treated as errors


vim +4459 drivers/usb/host/xhci.c

4360
> 4361 int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
4362 {
4363 return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS);
4364 }
4365 EXPORT_SYMBOL_GPL(xhci_address_device);
4366
4367 static int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
4368 {
4369 return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY);
4370 }
4371
4372 /*
4373 * Transfer the port index into real index in the HW port status
4374 * registers. Caculate offset between the port's PORTSC register
4375 * and port status base. Divide the number of per port register
4376 * to get the real index. The raw port number bases 1.
4377 */
4378 int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
4379 {
4380 struct xhci_hub *rhub;
4381
4382 rhub = xhci_get_rhub(hcd);
4383 return rhub->ports[port1 - 1]->hw_portnum + 1;
4384 }
4385
4386 /*
4387 * Issue an Evaluate Context command to change the Maximum Exit Latency in the
4388 * slot context. If that succeeds, store the new MEL in the xhci_virt_device.
4389 */
4390 static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
4391 struct usb_device *udev, u16 max_exit_latency)
4392 {
4393 struct xhci_virt_device *virt_dev;
4394 struct xhci_command *command;
4395 struct xhci_input_control_ctx *ctrl_ctx;
4396 struct xhci_slot_ctx *slot_ctx;
4397 unsigned long flags;
4398 int ret;
4399
4400 spin_lock_irqsave(&xhci->lock, flags);
4401
4402 virt_dev = xhci->devs[udev->slot_id];
4403
4404 /*
4405 * virt_dev might not exists yet if xHC resumed from hibernate (S4) and
4406 * xHC was re-initialized. Exit latency will be set later after
4407 * hub_port_finish_reset() is done and xhci->devs[] are re-allocated
4408 */
4409
4410 if (!virt_dev || max_exit_latency == virt_dev->current_mel) {
4411 spin_unlock_irqrestore(&xhci->lock, flags);
4412 return 0;
4413 }
4414
4415 /* Attempt to issue an Evaluate Context command to change the MEL. */
4416 command = xhci->lpm_command;
4417 ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
4418 if (!ctrl_ctx) {
4419 spin_unlock_irqrestore(&xhci->lock, flags);
4420 xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
4421 __func__);
4422 return -ENOMEM;
4423 }
4424
4425 ret = xhci_vendor_sync_dev_ctx(xhci, udev->slot_id);
4426 if (ret) {
4427 spin_unlock_irqrestore(&xhci->lock, flags);
4428 xhci_warn(xhci, "%s: Failed to sync device context failed, err=%d",
4429 __func__, ret);
4430 return ret;
4431 }
4432
4433 xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx);
4434 spin_unlock_irqrestore(&xhci->lock, flags);
4435
4436 ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
4437 slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
4438 slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
4439 slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
4440 slot_ctx->dev_state = 0;
4441
4442 xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
4443 "Set up evaluate context for LPM MEL change.");
4444
4445 /* Issue and wait for the evaluate context command. */
4446 ret = xhci_configure_endpoint(xhci, udev, command,
4447 true, true);
4448
4449 if (!ret) {
4450 spin_lock_irqsave(&xhci->lock, flags);
4451 virt_dev->current_mel = max_exit_latency;
4452 spin_unlock_irqrestore(&xhci->lock, flags);
4453 }
4454 return ret;
4455 }
4456
4457 struct xhci_vendor_ops *xhci_vendor_get_ops(struct xhci_hcd *xhci)
4458 {
> 4459 return xhci->vendor_ops;
4460 }
4461 EXPORT_SYMBOL_GPL(xhci_vendor_get_ops);
4462

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]

2022-03-09 00:06:45

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 2/4] usb: host: add xhci hooks for USB offload

Hi Daehwan,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on krzk/for-next]
[also build test ERROR on char-misc/char-misc-testing v5.17-rc7]
[cannot apply to usb/usb-testing next-20220307]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Daehwan-Jung/usb-host-export-symbols-for-xhci-hooks-usage/20220304-143406
base: https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git for-next
config: hexagon-randconfig-r045-20220304 (https://download.01.org/0day-ci/archive/20220308/[email protected]/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project d271fc04d5b97b12e6b797c6067d3c96a8d7470e)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/2b6a5d700c2bbb0a3ccfcd6e83a7f7b2ea049db9
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Daehwan-Jung/usb-host-export-symbols-for-xhci-hooks-usage/20220304-143406
git checkout 2b6a5d700c2bbb0a3ccfcd6e83a7f7b2ea049db9
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/usb/host/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

drivers/usb/host/xhci.c:4361:5: warning: no previous prototype for function 'xhci_address_device' [-Wmissing-prototypes]
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
^
drivers/usb/host/xhci.c:4361:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
^
static
>> drivers/usb/host/xhci.c:4459:15: error: no member named 'vendor_ops' in 'struct xhci_hcd'
return xhci->vendor_ops;
~~~~ ^
drivers/usb/host/xhci.c:5421:23: warning: shift count >= width of type [-Wshift-count-overflow]
!dma_set_mask(dev, DMA_BIT_MASK(64))) {
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
include/linux/dma-mapping.h:76:54: note: expanded from macro 'DMA_BIT_MASK'
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
^
include/linux/compiler.h:56:47: note: expanded from macro 'if'
#define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:58:52: note: expanded from macro '__trace_if_var'
#define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
^~~~
drivers/usb/host/xhci.c:5421:23: warning: shift count >= width of type [-Wshift-count-overflow]
!dma_set_mask(dev, DMA_BIT_MASK(64))) {
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
include/linux/dma-mapping.h:76:54: note: expanded from macro 'DMA_BIT_MASK'
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
^
include/linux/compiler.h:56:47: note: expanded from macro 'if'
#define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:58:61: note: expanded from macro '__trace_if_var'
#define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
^~~~
drivers/usb/host/xhci.c:5421:23: warning: shift count >= width of type [-Wshift-count-overflow]
!dma_set_mask(dev, DMA_BIT_MASK(64))) {
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
include/linux/dma-mapping.h:76:54: note: expanded from macro 'DMA_BIT_MASK'
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
^
include/linux/compiler.h:56:47: note: expanded from macro 'if'
#define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:58:86: note: expanded from macro '__trace_if_var'
#define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
~~~~~~~~~~~~~~~~~^~~~~
include/linux/compiler.h:69:3: note: expanded from macro '__trace_if_value'
(cond) ? \
^~~~
drivers/usb/host/xhci.c:5423:30: warning: shift count >= width of type [-Wshift-count-overflow]
dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
^~~~~~~~~~~~~~~~
include/linux/dma-mapping.h:76:54: note: expanded from macro 'DMA_BIT_MASK'
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
^ ~~~
5 warnings and 1 error generated.
--
>> drivers/usb/host/xhci-plat.c:205:15: error: no member named 'vendor_ops' in 'struct xhci_hcd'
ops = xhci->vendor_ops = xhci_plat_vendor_overwrite.vendor_ops;
~~~~ ^
drivers/usb/host/xhci-plat.c:219:8: error: no member named 'vendor_ops' in 'struct xhci_hcd'
xhci->vendor_ops = NULL;
~~~~ ^
drivers/usb/host/xhci-plat.c:268:10: warning: shift count >= width of type [-Wshift-count-overflow]
DMA_BIT_MASK(64));
^~~~~~~~~~~~~~~~
include/linux/dma-mapping.h:76:54: note: expanded from macro 'DMA_BIT_MASK'
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
^ ~~~
drivers/usb/host/xhci-plat.c:270:43: warning: shift count >= width of type [-Wshift-count-overflow]
ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
^~~~~~~~~~~~~~~~
include/linux/dma-mapping.h:76:54: note: expanded from macro 'DMA_BIT_MASK'
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
^ ~~~
2 warnings and 2 errors generated.


vim +4459 drivers/usb/host/xhci.c

4456
4457 struct xhci_vendor_ops *xhci_vendor_get_ops(struct xhci_hcd *xhci)
4458 {
> 4459 return xhci->vendor_ops;
4460 }
4461 EXPORT_SYMBOL_GPL(xhci_vendor_get_ops);
4462

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]