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

Commit 02b09d2b authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa
Browse files

USB: dwc3: msm: Fix stop endpoint command timeout issue



Currently HSPHY SUSP bit is set while starting host mode and
it is not cleared till stopping host mode. As part of urb dequeue,
xhci stack will queue stop endpoint command for flushing endpoint
which is getting timedout due to this HSPHY SUSP bit. Hence clear
this bit before queuing stop endpoint command and set it back after
stop endpoint command completion. Otherwise xhci stack treats this
timeout as fatal error and halts host controller.

Crs-Fixed: 580268
Change-Id: I784407386e6f87bcabd8569fcbae4e3af167144d
Signed-off-by: default avatarVijayavardhan Vennapusa <vvreddy@codeaurora.org>
parent 480c7178
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -2338,6 +2338,27 @@ unreg_chrdev:
	return ret;
}

static int msm_dwc3_hsphy_autosuspend(struct usb_phy *x, struct device *dev,
				int enable_autosuspend)
{
	struct dwc3_msm *mdwc = dev_get_drvdata(dev->parent->parent);
	struct dwc3 *dwc = dev_get_drvdata(dev->parent);
	u32 reg;

	if (dwc->hsphy_auto_suspend_disable)
		return 0;

	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0));
	if (enable_autosuspend)
		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
	else
		reg &= ~(DWC3_GUSB2PHYCFG_SUSPHY);

	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0), reg);

	return 0;
}

static int dwc3_msm_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node, *dwc3_node;
@@ -2683,6 +2704,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
		ret = PTR_ERR(mdwc->hs_phy);
		goto put_dwc3;
	}
	mdwc->hs_phy->set_phy_autosuspend = msm_dwc3_hsphy_autosuspend;

	mdwc->ss_phy = devm_usb_get_phy_by_phandle(&mdwc->dwc3->dev,
							"usb-phy", 1);
+20 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/pm_runtime.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb/phy.h>

#include "xhci.h"

@@ -53,6 +54,20 @@ static int xhci_plat_setup(struct usb_hcd *hcd)
	return xhci_gen_setup(hcd, xhci_plat_quirks);
}

static void xhci_plat_phy_autosuspend(struct usb_hcd *hcd,
						int enable_autosuspend)
{
	struct device		*dev = hcd->self.controller;
	struct usb_phy		*phy = hcd->phy;

	if (!phy || !phy->set_phy_autosuspend)
		return;

	usb_phy_set_autosuspend(phy, dev, enable_autosuspend);

	return;
}

static const struct hc_driver xhci_plat_xhci_driver = {
	.description =		"xhci-hcd",
	.product_desc =		"xHCI Host Controller",
@@ -100,6 +115,7 @@ static const struct hc_driver xhci_plat_xhci_driver = {
	.hub_status_data =	xhci_hub_status_data,
	.bus_suspend =		xhci_bus_suspend,
	.bus_resume =		xhci_bus_resume,
	.set_autosuspend =	xhci_plat_phy_autosuspend,
};

static int xhci_plat_probe(struct platform_device *pdev)
@@ -110,6 +126,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
	struct usb_hcd		*hcd;
	int			ret;
	int			irq;
	struct usb_phy		*phy;

	if (usb_disabled())
		return -ENODEV;
@@ -159,6 +176,8 @@ static int xhci_plat_probe(struct platform_device *pdev)

	/* USB 2.0 roothub is stored in the platform_device now. */
	hcd = dev_get_drvdata(&pdev->dev);
	phy = devm_usb_get_phy_by_phandle(pdev->dev.parent, "usb-phy", 0);
	hcd->phy = phy;
	xhci = hcd_to_xhci(hcd);
	xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
			dev_name(&pdev->dev), hcd);
@@ -168,6 +187,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
	}

	hcd_to_bus(xhci->shared_hcd)->skip_resume = true;
	xhci->shared_hcd->phy = phy;
	/*
	 * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
	 * is called by usb_add_hcd().
+4 −0
Original line number Diff line number Diff line
@@ -790,6 +790,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,

	struct xhci_dequeue_state deq_state;

	if (xhci->main_hcd->driver->set_autosuspend)
		xhci->main_hcd->driver->set_autosuspend(xhci->main_hcd, 1);
	if (unlikely(TRB_TO_SUSPEND_PORT(
			     le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])))) {
		slot_id = TRB_TO_SLOT_ID(
@@ -952,6 +954,8 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)

	spin_lock_irqsave(&xhci->lock, flags);

	if (xhci->main_hcd->driver->set_autosuspend)
		xhci->main_hcd->driver->set_autosuspend(xhci->main_hcd, 1);
	ep->stop_cmds_pending--;
	if (xhci->xhc_state & XHCI_STATE_DYING) {
		xhci_dbg(xhci, "Stop EP timer ran, but another timer marked "
+2 −0
Original line number Diff line number Diff line
@@ -1563,6 +1563,8 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
		ep->stop_cmd_timer.expires = jiffies +
			XHCI_STOP_EP_CMD_TIMEOUT * HZ;
		add_timer(&ep->stop_cmd_timer);
		if (hcd->driver->set_autosuspend)
			hcd->driver->set_autosuspend(hcd, 0);
		xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index, 0);
		xhci_ring_cmd_db(xhci);
	}
+1 −0
Original line number Diff line number Diff line
@@ -366,6 +366,7 @@ struct hc_driver {
	void	(*dump_regs)(struct usb_hcd *);
	void	(*set_autosuspend_delay)(struct usb_device *);
	void	(*reset_sof_bug_handler)(struct usb_hcd *hcd, u32 val);
	void	(*set_autosuspend)(struct usb_hcd *hcd, int enable_autosuspend);
};

extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
Loading