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