diff mbox

[U-Boot] usb: dwc2: fix bulk transfers

Message ID 1427173261-17099-1-git-send-email-swarren@wwwdotorg.org
State Accepted
Delegated to: Marek Vasut
Headers show

Commit Message

Stephen Warren March 24, 2015, 5:01 a.m. UTC
When I created wait_for_chhltd(), I noticed that some instances of the
code it replaced expected the ACK bit to be set and others didn't. I
assumed this was an accidental inconsistency in the code, so wrote
wait_for_chhltd() to always expect ACK to be set. This code appeared to
work correctly for both enumeration of USB keyboards and operation of
USB Ethernet devices. However, this change broke USB Mass Storage (at
least my USB SD card reader). This change reverts to exactly the
original behaviour. I'm not sure why the ACK bit isn't always set
(perhaps a quirk in the USB HW or DWC2 controller), but the code works
this way!

Fixes: 5be4ca7d6ac8 ("usb: dwc2: unify waiting for transfer completion")
Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
---
 drivers/usb/host/dwc2.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

Comments

Marek Vasut March 25, 2015, 12:07 p.m. UTC | #1
On Tuesday, March 24, 2015 at 06:01:01 AM, Stephen Warren wrote:
> When I created wait_for_chhltd(), I noticed that some instances of the
> code it replaced expected the ACK bit to be set and others didn't. I
> assumed this was an accidental inconsistency in the code, so wrote
> wait_for_chhltd() to always expect ACK to be set. This code appeared to
> work correctly for both enumeration of USB keyboards and operation of
> USB Ethernet devices. However, this change broke USB Mass Storage (at
> least my USB SD card reader). This change reverts to exactly the
> original behaviour. I'm not sure why the ACK bit isn't always set
> (perhaps a quirk in the USB HW or DWC2 controller), but the code works
> this way!
> 
> Fixes: 5be4ca7d6ac8 ("usb: dwc2: unify waiting for transfer completion")
> Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>

Applied to topic/dwc2 , which will go to -next. Thanks!

Best regards,
Marek Vasut
diff mbox

Patch

diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index e370d29ffc8e..5f4ca7abf7bf 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -703,10 +703,9 @@  static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
 	return stat;
 }
 
-int wait_for_chhltd(uint32_t *sub, int *toggle)
+int wait_for_chhltd(uint32_t *sub, int *toggle, bool ignore_ack)
 {
-	const uint32_t hcint_comp_hlt_ack = DWC2_HCINT_XFERCOMP |
-		DWC2_HCINT_CHHLTD | DWC2_HCINT_ACK;
+	uint32_t hcint_comp_hlt_ack = DWC2_HCINT_XFERCOMP | DWC2_HCINT_CHHLTD;
 	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
 	int ret;
 	uint32_t hcint, hctsiz;
@@ -716,6 +715,10 @@  int wait_for_chhltd(uint32_t *sub, int *toggle)
 		return ret;
 
 	hcint = readl(&hc_regs->hcint);
+	if (ignore_ack)
+		hcint &= ~DWC2_HCINT_ACK;
+	else
+		hcint_comp_hlt_ack |= DWC2_HCINT_ACK;
 	if (hcint != hcint_comp_hlt_ack) {
 		debug("%s: Error (HCINT=%08x)\n", __func__, hcint);
 		return -EINVAL;
@@ -739,7 +742,7 @@  static int dwc2_eptype[] = {
 };
 
 int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
-	      void *buffer, int len)
+	      void *buffer, int len, bool ignore_ack)
 {
 	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
 	int devnum = usb_pipedevice(pipe);
@@ -800,7 +803,7 @@  int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
 				(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
 				DWC2_HCCHAR_CHEN);
 
-		ret = wait_for_chhltd(&sub, pid);
+		ret = wait_for_chhltd(&sub, pid, ignore_ack);
 		if (ret) {
 			stop_transfer = 1;
 			break;
@@ -839,7 +842,7 @@  int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	}
 
 	return chunk_msg(dev, pipe, &bulk_data_toggle[devnum][ep],
-			 usb_pipein(pipe), buffer, len);
+			 usb_pipein(pipe), buffer, len, true);
 }
 
 int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
@@ -857,14 +860,14 @@  int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	}
 
 	pid = DWC2_HC_PID_SETUP;
-	ret = chunk_msg(dev, pipe, &pid, 0, setup, 8);
+	ret = chunk_msg(dev, pipe, &pid, 0, setup, 8, true);
 	if (ret)
 		return ret;
 
 	if (buffer) {
 		pid = DWC2_HC_PID_DATA1;
 		ret = chunk_msg(dev, pipe, &pid, usb_pipein(pipe), buffer,
-				len);
+				len, false);
 		if (ret)
 			return ret;
 		act_len = dev->act_len;
@@ -879,7 +882,8 @@  int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 		status_direction = 0;
 
 	pid = DWC2_HC_PID_DATA1;
-	ret = chunk_msg(dev, pipe, &pid, status_direction, status_buffer, 0);
+	ret = chunk_msg(dev, pipe, &pid, status_direction, status_buffer, 0,
+		false);
 	if (ret)
 		return ret;