arm/160431: [patch] Disable interrupts during busdma cache sync operations.

Mark Tinguely marktinguely at gmail.com
Sun Oct 16 20:30:16 UTC 2011


The following reply was made to PR arm/160431; it has been noted by GNATS.

From: Mark Tinguely <marktinguely at gmail.com>
To: bug-followup at FreeBSD.org, freebsd at damnhippie.dyndns.org
Cc:  
Subject: Re: arm/160431: [patch] Disable interrupts during busdma cache sync
 operations.
Date: Sun, 16 Oct 2011 14:57:50 -0500

 This is a multi-part message in MIME format.
 --------------090706000403080305010106
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 Ian and I have been sending emails this week about this problem. He and 
 I have examples where turning off interrupts will not be enough, but I 
 think this is a good start.
 
 If we cache align the allocation sizes that are less than a PAGE_SIZE in 
 bus_dmamem_alloc(), then it may help avoid this routine. Attached is a 
 crude alignment concept code.
 
 --Mark.
 
 --------------090706000403080305010106
 Content-Type: text/plain;
  name="arm_busdma_machdep_c.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="arm_busdma_machdep_c.diff"
 
 --- sys/arm/arm/busdma_machdep.c.orig	2011-10-16 13:09:49.000000000 -0500
 +++ sys/arm/arm/busdma_machdep.c	2011-10-16 14:20:27.000000000 -0500
 @@ -579,6 +579,7 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
  {
  	bus_dmamap_t newmap = NULL;
  
 +	bus_size_t len;
  	int mflags;
  
  	if (flags & BUS_DMA_NOWAIT)
 @@ -598,17 +599,23 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
  	*mapp = newmap;
  	newmap->dmat = dmat;
  	
 -        if (dmat->maxsize <= PAGE_SIZE &&
 -	   (dmat->alignment < dmat->maxsize) &&
 +	if (dmat->maxsize < PAGE_SIZE)
 +		/* round up to nearest cache line size */
 +		len = (dmat->maxsize + arm_dcache_align_mask) &
 +			 ~arm_dcache_align_mask;
 +	else
 +		len = dmat->maxsize;
 +        if (len <= PAGE_SIZE &&
 +	   (dmat->alignment < len) &&
  	   !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) {
 -                *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags);
 +                *vaddr = malloc(len, M_DEVBUF, mflags);
          } else {
                  /*
                   * XXX Use Contigmalloc until it is merged into this facility
                   *     and handles multi-seg allocations.  Nobody is doing
                   *     multi-seg allocations yet though.
                   */
 -                *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags,
 +                *vaddr = contigmalloc(len, M_DEVBUF, mflags,
                      0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul,
                      dmat->boundary);
          }
 @@ -623,7 +630,7 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
  	if (flags & BUS_DMA_COHERENT) {
  		void *tmpaddr = arm_remap_nocache(
  		    (void *)((vm_offset_t)*vaddr &~ PAGE_MASK),
 -		    dmat->maxsize + ((vm_offset_t)*vaddr & PAGE_MASK));
 +		    len + ((vm_offset_t)*vaddr & PAGE_MASK));
  
  		if (tmpaddr) {
  			tmpaddr = (void *)((vm_offset_t)(tmpaddr) +
 @@ -645,19 +652,28 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
  void
  bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
  {
 +	bus_size_t len;
 +
 +	if (dmat->maxsize < PAGE_SIZE)
 +		/* round up to nearest cache line size */
 +		len = (dmat->maxsize + arm_dcache_align_mask) &
 +			 ~arm_dcache_align_mask;
 +	else
 +		len = dmat->maxsize;
 +
  	if (map->allocbuffer) {
  		KASSERT(map->allocbuffer == vaddr,
  		    ("Trying to freeing the wrong DMA buffer"));
  		vaddr = map->origbuffer;
  		arm_unmap_nocache(map->allocbuffer,
 -		    dmat->maxsize + ((vm_offset_t)vaddr & PAGE_MASK));
 +		    len + ((vm_offset_t)vaddr & PAGE_MASK));
  	}
 -        if (dmat->maxsize <= PAGE_SIZE &&
 -	   dmat->alignment < dmat->maxsize &&
 +        if (len <= PAGE_SIZE &&
 +	   dmat->alignment < len &&
  	    !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr))
  		free(vaddr, M_DEVBUF);
          else {
 -		contigfree(vaddr, dmat->maxsize, M_DEVBUF);
 +		contigfree(vaddr, len, M_DEVBUF);
  	}
  	dmat->map_count--;
  	_busdma_free_dmamap(map);
 
 --------------090706000403080305010106--


More information about the freebsd-arm mailing list