usb: xhci: Add helper API to issue stop endpoint command

This API is used to issue stop endpoint command on
requested endpoint in order to retire all active TRBs
in the transfer ring.

Change-Id: I312772367a2cd293982a66ea8b75e04a8b1f2fd0
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
This commit is contained in:
Hemant Kumar 2017-11-14 20:06:15 -08:00 • committed by Jack Pham
commit ccf7b32222
2 changed files with 64 additions and 0 deletions

View file

@ -5383,6 +5383,63 @@ phys_addr_t xhci_get_xfer_ring_phys_addr(struct usb_device *udev,
}
EXPORT_SYMBOL(xhci_get_xfer_ring_phys_addr);
int xhci_stop_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
unsigned int ep_index;
struct xhci_virt_device *virt_dev;
struct xhci_command *cmd;
unsigned long flags;
int ret = 0;
if (udev->state == USB_STATE_NOTATTACHED || !HCD_RH_RUNNING(hcd))
return 0;
cmd = xhci_alloc_command(xhci, true, GFP_NOIO);
if (!cmd)
return -ENOMEM;
spin_lock_irqsave(&xhci->lock, flags);
virt_dev = xhci->devs[udev->slot_id];
if (!virt_dev) {
ret = -ENODEV;
goto err;
}
ep_index = xhci_get_endpoint_index(&ep->desc);
if (virt_dev->eps[ep_index].ring &&
virt_dev->eps[ep_index].ring->dequeue) {
ret = xhci_queue_stop_endpoint(xhci, cmd, udev->slot_id,
ep_index, 0);
if (ret)
goto err;
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
/* Wait for stop endpoint command to finish */
wait_for_completion(cmd->completion);
if (cmd->status == COMP_COMMAND_ABORTED ||
cmd->status == COMP_STOPPED) {
xhci_warn(xhci,
"stop endpoint command timeout for ep%d%s\n",
usb_endpoint_num(&ep->desc),
usb_endpoint_dir_in(&ep->desc) ? "in" : "out");
ret = -ETIME;
}
goto free_cmd;
}
err:
spin_unlock_irqrestore(&xhci->lock, flags);
free_cmd:
xhci_free_command(xhci, cmd);
return ret;
}
EXPORT_SYMBOL(xhci_stop_endpoint);
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",

View file

@ -17,6 +17,7 @@ phys_addr_t xhci_get_sec_event_ring_phys_addr(struct usb_device *udev,
unsigned int intr_num, dma_addr_t *dma);
phys_addr_t xhci_get_xfer_ring_phys_addr(struct usb_device *udev,
struct usb_host_endpoint *ep, dma_addr_t *dma);
int xhci_stop_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep);
#else
static inline int xhci_sec_event_ring_setup(struct usb_device *udev,
unsigned int intr_num);
@ -42,6 +43,12 @@ static inline phys_addr_t xhci_get_xfer_ring_phys_addr(struct usb_device *udev,
{
return NULL;
}
static inline int xhci_stop_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
return -ENODEV;
}
#endif
#endif /* __LINUX_XHCI_SEC_H */