[PATCH 2/7 v2] usb: dwc3: a few fixes/improvements

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



- The loop in dwc3_gadget_set_link_state was using a udelay(500),
  which is a long time to delay in interrupt context. Change it to
  udelay(5) and increase the loop count to match.

- dwc3_gadget_wakeup was looping on !time_after(jiffies, timeout))
  with interrupts disabled, which is wrong. Fix it.

- dwc3_gadget_ep_set_wedge and dwc3_gadget_set_selfpowered were
  modifying dwc->flags/dwc->is_selfpowered without taking the lock.
  Since those modifications are non-atomic, that could cause other
  flags to be corrupted. Fix them both to take the lock.

- Transfer resource index is cleared in hardware when XFERCOMPLETE
  event is generated, so clear the driver's res_trans_idx variable
  immediately after that event is received. The upcoming
  hibernation patches also need this change.

Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx>
---
 drivers/usb/dwc3/core.c     |    2 +-
 drivers/usb/dwc3/core.h     |    1 +
 drivers/usb/dwc3/dwc3-pci.c |    4 +++-
 drivers/usb/dwc3/ep0.c      |    1 +
 drivers/usb/dwc3/gadget.c   |   24 +++++++++++++++++-------
 5 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 3b1d956..7124ec0 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -351,7 +351,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
 	dwc3_cache_hwparams(dwc);
 
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-	reg &= ~DWC3_GCTL_SCALEDOWN(3);
+	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
 
 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 7c4e0b5..6c7945b 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -161,6 +161,7 @@
 
 #define DWC3_GCTL_CORESOFTRESET	(1 << 11)
 #define DWC3_GCTL_SCALEDOWN(n)	((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
 #define DWC3_GCTL_DISSCRAMBLE	(1 << 3)
 #define DWC3_GCTL_DSBLCLKGTNG	(1 << 0)
 
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index df69169..1c64d6d 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -79,6 +79,8 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
 	pci_set_power_state(pci, PCI_D0);
 	pci_set_master(pci);
 
+	ret = -ENOMEM;
+
 	devid = dwc3_get_device_id();
 	if (devid < 0)
 		goto err2;
@@ -144,9 +146,9 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
 {
 	struct dwc3_pci	*glue = pci_get_drvdata(pci);
 
-	dwc3_put_device_id(glue->dwc3->id);
 	platform_device_unregister(glue->dwc3);
 	pci_set_drvdata(pci, NULL);
+	dwc3_put_device_id(glue->dwc3->id);
 	pci_disable_device(pci);
 	kfree(glue);
 }
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index bf48e2c..25910e2 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -617,6 +617,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
 	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
 
 	dep->flags &= ~DWC3_EP_BUSY;
+	dep->res_trans_idx = 0;
 	dwc->setup_packet_pending = false;
 
 	switch (dwc->ep0state) {
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 983d2b4..3b0ec64 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -93,11 +93,11 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
  * @state: the state to put link into
  *
  * Caller should take care of locking. This function will
- * return 0 on success or -EINVAL.
+ * return 0 on success or -ETIMEDOUT.
  */
 int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 {
-	int		retries = 100;
+	int		retries = 10000;
 	u32		reg;
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
@@ -111,11 +111,10 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 	while (--retries) {
 		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
 
-		/* in HS, means ON */
 		if (DWC3_DSTS_USBLNKST(reg) == state)
 			return 0;
 
-		udelay(500);
+		udelay(5);
 	}
 
 	dev_vdbg(dwc->dev, "link state change request timed out\n");
@@ -1134,8 +1133,12 @@ out:
 static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
 {
 	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+	unsigned long			flags;
 
+	spin_lock_irqsave(&dwc->lock, flags);
 	dep->flags |= DWC3_EP_WEDGE;
+	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return dwc3_gadget_ep_set_halt(ep, 1);
 }
@@ -1238,6 +1241,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
 	/* poll until Link State changes to ON */
 	timeout = jiffies + msecs_to_jiffies(100);
 
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
 	while (!time_after(jiffies, timeout)) {
 		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
 
@@ -1246,6 +1251,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
 			break;
 	}
 
+	spin_lock_irqsave(&dwc->lock, flags);
+
 	if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
 		dev_err(dwc->dev, "failed to send remote wakeup\n");
 		ret = -EINVAL;
@@ -1261,8 +1268,11 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
 		int is_selfpowered)
 {
 	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
 
+	spin_lock_irqsave(&dwc->lock, flags);
 	dwc->is_selfpowered = !!is_selfpowered;
+	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
 }
@@ -1559,10 +1569,8 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
 		status = -ECONNRESET;
 
 	clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
-	if (clean_busy) {
+	if (clean_busy)
 		dep->flags &= ~DWC3_EP_BUSY;
-		dep->res_trans_idx = 0;
-	}
 
 	/*
 	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
@@ -1673,6 +1681,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 
 	switch (event->endpoint_event) {
 	case DWC3_DEPEVT_XFERCOMPLETE:
+		dep->res_trans_idx = 0;
+
 		if (usb_endpoint_xfer_isoc(dep->desc)) {
 			dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
 					dep->name);
-- 
1.7.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux