[U-Boot] [PATCH v5 02/19] usb: dwc2: Use separate input and output buffers

Simon Glass sjg at chromium.org
Sat Apr 1 18:05:39 UTC 2017


On Raspberry Pi 2 and 3 a problem was noticed when enabling driver model
for USB: the cache invalidate after an incoming transfer does not seem to
work correctly.

This may be a problem with the underlying caching implementation on armv7
and armv8 but this seems very unlikely. As a work-around, use separate
buffers for input and output. This ensures that the input buffer will not
hold dirty cache data.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v5:
- Add new patch for dwc2 to se separate input and output buffers

Changes in v4: None
Changes in v3: None

 drivers/usb/host/dwc2.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index d253b946f3..a65ed4f66c 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -31,10 +31,14 @@ DECLARE_GLOBAL_DATA_PTR;
 
 struct dwc2_priv {
 #ifdef CONFIG_DM_USB
-	uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
+	uint8_t aligned_buffer_in[DWC2_DATA_BUF_SIZE]
+			__aligned(ARCH_DMA_MINALIGN);
+	uint8_t aligned_buffer_out[DWC2_DATA_BUF_SIZE]
+			__aligned(ARCH_DMA_MINALIGN);
 	uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
 #else
-	uint8_t *aligned_buffer;
+	uint8_t *aligned_buffer_in;
+	uint8_t *aligned_buffer_out;
 	uint8_t *status_buffer;
 #endif
 	u8 in_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
@@ -769,10 +773,12 @@ static int dwc2_eptype[] = {
 	DWC2_HCCHAR_EPTYPE_BULK,
 };
 
-static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer,
-			  u8 *pid, int in, void *buffer, int num_packets,
-			  int xfer_len, int *actual_len, int odd_frame)
+static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer_in,
+			  void *aligned_buffer_out, u8 *pid, int in,
+			  void *buffer, int num_packets, int xfer_len,
+			  int *actual_len, int odd_frame)
 {
+	void *aligned_buffer;
 	int ret = 0;
 	uint32_t sub;
 
@@ -785,11 +791,14 @@ static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer,
 	       &hc_regs->hctsiz);
 
 	if (!in && xfer_len) {
+		aligned_buffer = aligned_buffer_in;
 		memcpy(aligned_buffer, buffer, xfer_len);
 
 		flush_dcache_range((unsigned long)aligned_buffer,
 				   (unsigned long)aligned_buffer +
 				   roundup(xfer_len, ARCH_DMA_MINALIGN));
+	} else {
+		aligned_buffer = aligned_buffer_out;
 	}
 
 	writel(phys_to_bus((unsigned long)aligned_buffer), &hc_regs->hcdma);
@@ -901,7 +910,8 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
 				odd_frame = 1;
 		}
 
-		ret = transfer_chunk(hc_regs, priv->aligned_buffer, pid,
+		ret = transfer_chunk(hc_regs, priv->aligned_buffer_in,
+				     priv->aligned_buffer_out, pid,
 				     in, (char *)buffer + done, num_packets,
 				     xfer_len, &actual_len, odd_frame);
 
@@ -1136,7 +1146,10 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 	memset(priv, '\0', sizeof(*priv));
 	priv->root_hub_devnum = 0;
 	priv->regs = (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
-	priv->aligned_buffer = aligned_buffer_addr;
+
+	/* We can use the same buffer for input and output */
+	priv->aligned_buffer_in = aligned_buffer_addr;
+	priv->aligned_buffer_out = aligned_buffer_addr;
 	priv->status_buffer = status_buffer_addr;
 
 	/* board-dependant init */
-- 
2.12.2.564.g063fe858b8-goog



More information about the U-Boot mailing list