From mboxrd@z Thu Jan 1 00:00:00 1970 From: Simon Glass Date: Sat, 1 Apr 2017 12:05:39 -0600 Subject: [U-Boot] [PATCH v5 02/19] usb: dwc2: Use separate input and output buffers In-Reply-To: <20170401180556.2416-1-sjg@chromium.org> References: <20170401180556.2416-1-sjg@chromium.org> Message-ID: <20170401180556.2416-3-sjg@chromium.org> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 --- 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