usb: 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 Mayank Rana
parent dcfa572221
commit 0a1c067c9e
5 changed files with 77 additions and 0 deletions

View File

@ -2300,6 +2300,14 @@ int usb_hcd_get_controller_id(struct usb_device *udev)
return hcd->driver->get_core_id(hcd);
}
int usb_hcd_stop_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
return hcd->driver->stop_endpoint(hcd, udev, ep);
}
#ifdef CONFIG_PM
int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)

View File

@ -871,6 +871,12 @@ int usb_get_controller_id(struct usb_device *dev)
}
EXPORT_SYMBOL(usb_get_controller_id);
int usb_stop_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
{
return usb_hcd_stop_endpoint(dev, ep);
}
EXPORT_SYMBOL(usb_stop_endpoint);
/*-------------------------------------------------------------------*/
/*
* __usb_get_extra_descriptor() finds a descriptor of specific type in the

View File

@ -4986,6 +4986,61 @@ int xhci_get_core_id(struct usb_hcd *hcd)
return xhci->core_id;
}
static int xhci_stop_endpoint(struct usb_hcd *hcd,
struct usb_device *udev, struct usb_host_endpoint *ep)
{
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;
cmd = xhci_alloc_command(xhci, false, 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;
}
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
@ -5050,6 +5105,7 @@ static const struct hc_driver xhci_hc_driver = {
.get_sec_event_ring_phys_addr = xhci_get_sec_event_ring_phys_addr,
.get_xfer_ring_phys_addr = xhci_get_xfer_ring_phys_addr,
.get_core_id = xhci_get_core_id,
.stop_endpoint = xhci_stop_endpoint,
};
void xhci_init_driver(struct hc_driver *drv,

View File

@ -826,6 +826,9 @@ extern phys_addr_t usb_get_xfer_ring_phys_addr(struct usb_device *dev,
struct usb_host_endpoint *ep, dma_addr_t *dma);
extern int usb_get_controller_id(struct usb_device *dev);
extern int usb_stop_endpoint(struct usb_device *dev,
struct usb_host_endpoint *ep);
/* Sets up a group of bulk endpoints to support multiple stream IDs. */
extern int usb_alloc_streams(struct usb_interface *interface,
struct usb_host_endpoint **eps, unsigned int num_eps,

View File

@ -408,6 +408,8 @@ struct hc_driver {
struct usb_device *udev, struct usb_host_endpoint *ep,
dma_addr_t *dma);
int (*get_core_id)(struct usb_hcd *hcd);
int (*stop_endpoint)(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep);
};
static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
@ -455,6 +457,8 @@ extern phys_addr_t usb_hcd_get_sec_event_ring_phys_addr(
extern phys_addr_t usb_hcd_get_xfer_ring_phys_addr(
struct usb_device *udev, struct usb_host_endpoint *ep, dma_addr_t *dma);
extern int usb_hcd_get_controller_id(struct usb_device *udev);
extern int usb_hcd_stop_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
struct device *sysdev, struct device *dev, const char *bus_name,