On 04/05/2017 10:25 PM, Philipp Tomsich wrote:
> Merely using dma_alloc_coherent does not ensure that there is no stale
> data left in the caches for the allocated DMA buffer (i.e. that the
> affected cacheline may still be dirty).
> 
> The original code was doing the following (on AArch64, which
> translates a 'flush' into a 'clean + invalidate'):
>   # during initialisation:
>       1. allocate buffers via memalign
>                => buffers may still be modified (cached, dirty)
>   # during interrupt processing
>       2. clean + invalidate buffers
>                => may commit stale data from a modified cacheline
>       3. read from buffers
> 
> This could lead to garbage info being written to buffers before
> reading them during even-processing.
> 
> To make the event processing more robust, we use the following sequence
> for the cache-maintenance:
>   # during initialisation:
>       1. allocate buffers via memalign
>       2. clean + invalidate buffers
>                (we only need the 'invalidate' part, but dwc3_flush_cache()
>         always performs a 'clean + invalidate')
>   # during interrupt processing
>       3. read the buffers
>                (we know these lines are not cached, due to the previous
>         invalidation and no other code touching them in-between)
>       4. clean + invalidate buffers
>                => writes back any modification we may have made during event
>           processing and ensures that the lines are not in the cache
>           the next time we enter interrupt processing
> 
> Note that with the original sequence, we observe reproducible
> (depending on the cache state: i.e. running dhcp/usb start before will
> upset caches to get us around this) issues in the event processing (a
> fatal synchronous abort in dwc3_gadget_uboot_handle_interrupt on the
> first time interrupt handling is invoked) when running USB mass
> storage emulation on our RK3399-Q7 with data-caches on.
> 
> Signed-off-by: Philipp Tomsich <philipp.toms...@theobroma-systems.com>

The patch is fine, but it should really be two patches, one which
changes the types and one which fixes the caches, so it's clearly
bisectable. Can you do a V3 ? Thanks

> ---
> 
> Changes in v2:
> - Consistently use uintptr_t for dwc3_flush_cache(addr, length).
> 
>  drivers/usb/dwc3/core.c   |  2 ++
>  drivers/usb/dwc3/ep0.c    | 10 +++++-----
>  drivers/usb/dwc3/gadget.c | 15 ++++++++-------
>  drivers/usb/dwc3/io.h     |  2 +-
>  4 files changed, 16 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index b2c7eb1..1cbf179 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -125,6 +125,8 @@ static struct dwc3_event_buffer 
> *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
>       if (!evt->buf)
>               return ERR_PTR(-ENOMEM);
>  
> +     dwc3_flush_cache((uintptr_t)evt->buf, evt->length);
> +
>       return evt;
>  }
>  
> diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
> index 12b133f..e61d980 100644
> --- a/drivers/usb/dwc3/ep0.c
> +++ b/drivers/usb/dwc3/ep0.c
> @@ -81,8 +81,8 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, 
> dma_addr_t buf_dma,
>               trb->ctrl |= (DWC3_TRB_CTRL_IOC
>                               | DWC3_TRB_CTRL_LST);
>  
> -     dwc3_flush_cache((long)buf_dma, len);
> -     dwc3_flush_cache((long)trb, sizeof(*trb));
> +     dwc3_flush_cache((uintptr_t)buf_dma, len);
> +     dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
>  
>       if (chain)
>               return 0;
> @@ -790,7 +790,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
>       if (!r)
>               return;
>  
> -     dwc3_flush_cache((long)trb, sizeof(*trb));
> +     dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
>  
>       status = DWC3_TRB_SIZE_TRBSTS(trb->size);
>       if (status == DWC3_TRBSTS_SETUP_PENDING) {
> @@ -821,7 +821,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
>                       ur->actual += transferred;
>  
>                       trb++;
> -                     dwc3_flush_cache((long)trb, sizeof(*trb));
> +                     dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
>                       length = trb->size & DWC3_TRB_SIZE_MASK;
>  
>                       ep0->free_slot = 0;
> @@ -831,7 +831,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
>                                       maxp);
>               transferred = min_t(u32, ur->length - transferred,
>                                   transfer_size - length);
> -             dwc3_flush_cache((long)dwc->ep0_bounce, DWC3_EP0_BOUNCE_SIZE);
> +             dwc3_flush_cache((uintptr_t)dwc->ep0_bounce, 
> DWC3_EP0_BOUNCE_SIZE);
>               memcpy(buf, dwc->ep0_bounce, transferred);
>       } else {
>               transferred = ur->length - length;
> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index 1156662..e065c5a 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -244,7 +244,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct 
> dwc3_request *req,
>  
>       list_del(&req->list);
>       req->trb = NULL;
> -     dwc3_flush_cache((long)req->request.dma, req->request.length);
> +     dwc3_flush_cache((uintptr_t)req->request.dma, req->request.length);
>  
>       if (req->request.status == -EINPROGRESS)
>               req->request.status = status;
> @@ -771,8 +771,8 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
>  
>       trb->ctrl |= DWC3_TRB_CTRL_HWO;
>  
> -     dwc3_flush_cache((long)dma, length);
> -     dwc3_flush_cache((long)trb, sizeof(*trb));
> +     dwc3_flush_cache((uintptr_t)dma, length);
> +     dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
>  }
>  
>  /*
> @@ -1769,7 +1769,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, 
> struct dwc3_ep *dep,
>       slot %= DWC3_TRB_NUM;
>       trb = &dep->trb_pool[slot];
>  
> -     dwc3_flush_cache((long)trb, sizeof(*trb));
> +     dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
>       __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status);
>       dwc3_gadget_giveback(dep, req, status);
>  
> @@ -2668,11 +2668,12 @@ void dwc3_gadget_uboot_handle_interrupt(struct dwc3 
> *dwc)
>               int i;
>               struct dwc3_event_buffer *evt;
>  
> +             dwc3_thread_interrupt(0, dwc);
> +
> +             /* Clean + Invalidate the buffers after touching them */
>               for (i = 0; i < dwc->num_event_buffers; i++) {
>                       evt = dwc->ev_buffs[i];
> -                     dwc3_flush_cache((long)evt->buf, evt->length);
> +                     dwc3_flush_cache((uintptr_t)evt->buf, evt->length);
>               }
> -
> -             dwc3_thread_interrupt(0, dwc);
>       }
>  }
> diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
> index 0d9fa22..810980f 100644
> --- a/drivers/usb/dwc3/io.h
> +++ b/drivers/usb/dwc3/io.h
> @@ -48,7 +48,7 @@ static inline void dwc3_writel(void __iomem *base, u32 
> offset, u32 value)
>       writel(value, base + offs);
>  }
>  
> -static inline void dwc3_flush_cache(int addr, int length)
> +static inline void dwc3_flush_cache(uintptr_t addr, int length)
>  {
>       flush_dcache_range(addr, addr + ROUND(length, CACHELINE_SIZE));
>  }
> 


-- 
Best regards,
Marek Vasut
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to