![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
On 8/23/24 22:00, Wesley Cheng wrote:
From: Mathias Nyman mathias.nyman@linux.intel.com
Expose xhci_stop_endpoint_sync() which is a synchronous variant of xhci_queue_stop_endpoint(). This is useful for client drivers that are using the secondary interrupters, and need to stop/clean up the current session. The stop endpoint command handler will also take care of cleaning up the ring.
Signed-off-by: Mathias Nyman mathias.nyman@linux.intel.com Signed-off-by: Wesley Cheng quic_wcheng@quicinc.com
drivers/usb/host/xhci.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 2 ++ 2 files changed, 41 insertions(+)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 37eb37b0affa..3a051ed32907 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2784,6 +2784,45 @@ static int xhci_reserve_bandwidth(struct xhci_hcd *xhci, return -ENOMEM; }
+/*
- Synchronous XHCI stop endpoint helper. Issues the stop endpoint command and
- waits for the command completion before returning.
- */
+int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, int suspend,
gfp_t gfp_flags)
+{
- struct xhci_command *command;
- unsigned long flags;
- int ret;
- command = xhci_alloc_command(xhci, true, gfp_flags);
- if (!command)
return -ENOMEM;
- spin_lock_irqsave(&xhci->lock, flags);
- ret = xhci_queue_stop_endpoint(xhci, command, ep->vdev->slot_id,
ep->ep_index, suspend);
- if (ret < 0) {
spin_unlock_irqrestore(&xhci->lock, flags);
goto out;
- }
- xhci_ring_cmd_db(xhci);
- spin_unlock_irqrestore(&xhci->lock, flags);
- wait_for_completion(command->completion);
- if (command->status == COMP_COMMAND_ABORTED ||
command->status == COMP_COMMAND_RING_STOPPED) {
xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");
nit-pick: is this really a timeout? In that case you would have used wait_for_completion_timeout(), no?
ret = -ETIME;
- }
+out:
- xhci_free_command(xhci, command);
- return ret;
+} +EXPORT_SYMBOL_GPL(xhci_stop_endpoint_sync);
/* Issue a configure endpoint command or evaluate context command
- and wait for it to finish.
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 30415158ed3c..1c6126ed55b0 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1914,6 +1914,8 @@ void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci, void xhci_cleanup_command_queue(struct xhci_hcd *xhci); void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring); unsigned int count_trbs(u64 addr, u64 len); +int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
int suspend, gfp_t gfp_flags);
/* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,