Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ccf7b322 authored by Hemant Kumar's avatar Hemant Kumar Committed by Jack Pham
Browse files

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: default avatarHemant Kumar <hemantk@codeaurora.org>
parent 18e5c7ed
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
@@ -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",
+7 −0
Original line number Diff line number Diff line
@@ -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 */