[U-Boot] [PATCH v2] usb: dwc3: gadget: make cache-maintenance on event buffers more robust

Marek Vasut marex at denx.de
Wed Apr 5 21:50:08 UTC 2017


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.tomsich at 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


More information about the U-Boot mailing list