[PATCH v6 72/87] usb: dwc3: ep0: flush and invalidate cache around ep0 transfers
Anders Roxell <[email protected]>
| Newsgroups | gmane.comp.boot-loaders.u-boot.general,gmane.comp.boot-loaders.u-boot |
|---|---|
| Message-ID | <[email protected]> |
The dwc3 driver was synced from Linux v6.16. In Linux the DMA api keeps the trb and the buffers in sync with the controller. In u-boot the ep0 trb and buffers come from dma_alloc_coherent, which is just cached memory, not coherent. Nothing syncs them around the controller dma, so we must flush and invalidate by hand. U-boot did this before, the resync dropped it. Without cache maintenance the controller reads a stale trb and a stale buffer, and reads back stale status. The device answers GET_DESCRIPTOR with garbage, so the host fails to enumerate with -71 (EPROTO). Flush the trb and the buffer before the controller reads them. Invalidate the setup packet, the status write back and the OUT data buffer after the controller writes them. Reported-by: Anshul Dalal <[email protected]> Signed-off-by: Anders Roxell <[email protected]> --- drivers/usb/dwc3/ep0.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index e81404e11405..f82c0f7e6dec 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -55,6 +55,9 @@ static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, else trb->ctrl |= (DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_LST); + + dwc3_flush_cache((uintptr_t)buf_dma, len); + dwc3_flush_cache((uintptr_t)trb, sizeof(*trb)); } static int dwc3_ep0_start_trans(struct dwc3_ep *dep) @@ -812,6 +815,8 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, int ret = -EINVAL; u32 len; + dwc3_invalidate_cache((uintptr_t)ctrl, sizeof(*ctrl)); + if (!dwc->gadget_driver || !dwc->softconnect || !dwc->connected) goto out; @@ -857,6 +862,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; trb = dwc->ep0_trb; + dwc3_invalidate_cache((uintptr_t)trb, sizeof(*trb) * 2); + r = next_request(&ep0->pending_list); if (!r) return; @@ -874,6 +881,9 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, length = trb->size & DWC3_TRB_SIZE_MASK; transferred = ur->length - length; + + if (ur->buf && !r->direction) + dwc3_invalidate_cache((uintptr_t)ur->dma, ur->length); ur->actual += transferred; if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) && -- 2.53.0