Re: ensure dma_alloc_coherent always returns zeroed memory

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 12/28/18 9:58 AM, hch@xxxxxx wrote:
> On Fri, Dec 28, 2018 at 05:46:32PM +0000, Eugeniy Paltsev wrote:
>> What happens:
>>
>> First coherent allocation (PAL#1):
>> 1) allocate page via alloc_pages(__GFP_ZERO), got page vith paddr 0xbf2d6000
>> 2) zero it via memset [deep inside alloc_pages()]
>> 3) remap it as uncached via ioremap_nocache(), got vaddr 0x70004000
>> 4) flush and invalidate L1 and L2 lines which belongs to allocated page.
>> Everything is OK for now.
>>
>> Second coherent allocation (PAL#2):
>> 1) allocate page via alloc_pages(__GFP_ZERO), got page vith paddr 0xbf2d4000
>> 2) zero it via memset [deep inside alloc_pages()].
>> -> Ooops: ARC memset implementation (due to SW bug) calls 'prefetchw' instruction
>> for address which lies outside of memset area (it will be 0xbf2d6000 in this case)
>> So we got one modified (dirty) cache line in the beginning of previous coherent
>> buffer which has been already flushed and invalidated (in PAL#1).
>>
>> So if we put some real data in this buffer [via virtual (uncached) address)]
>> before this line is flushed - we will got corrupted data.
> We could instead do the memset on the remapped address, which would
> work around this prefetching issue:

Right, it probably would, but that would still be too fragile, there are other bad
things in non-dma scenarios which happen due to this.
This needed fixing and Eugeniy's fix is in upstream/master now

    2019-01-14 e6a72b7daeeb ARCv2: lib: memeset: fix doing prefetchw outside of
buffer 


>
> diff --git a/arch/arc/mm/dma.c b/arch/arc/mm/dma.c
> index 1525ac00fd02..7c3b47019079 100644
> --- a/arch/arc/mm/dma.c
> +++ b/arch/arc/mm/dma.c
> @@ -33,7 +33,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
>  	 */
>  	BUG_ON(gfp & __GFP_HIGHMEM);
>  
> -	page = alloc_pages(gfp | __GFP_ZERO, order);
> +	page = alloc_pages(gfp, order);
>  	if (!page)
>  		return NULL;
>  
> @@ -69,6 +69,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
>  	if (need_coh)
>  		dma_cache_wback_inv(paddr, size);
>  
> +	memset(kvaddr, 0, size);
>  	return kvaddr;
>  }


_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/linux-snps-arc



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux