arm: mm: fix DMA pool affiliation check
authorThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Mon, 10 Sep 2012 14:14:16 +0000 (16:14 +0200)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Mon, 10 Sep 2012 14:15:48 +0000 (16:15 +0200)
The __free_from_pool() function was changed in
e9da6e9905e639b0f842a244bc770b48ad0523e9. Unfortunately, the test that
checks whether the provided (start,size) is within the DMA pool has
been improperly modified. It used to be:

  if (start < coherent_head.vm_start || end > coherent_head.vm_end)

Where coherent_head.vm_end was non-inclusive (i.e, it did not include
the first byte after the pool). The test has been changed to:

  if (start < pool->vaddr || start > pool->vaddr + pool->size)

So now pool->vaddr + pool->size is inclusive (i.e, it includes the
first byte after the pool), so the test should be >= instead of >.

This bug causes the following message when freeing the *first* DMA
coherent buffer that has been allocated, because its virtual address
is exactly equal to pool->vaddr + pool->size :

WARNING: at /home/thomas/projets/linux-2.6/arch/arm/mm/dma-mapping.c:463 __free_from_pool+0xa4/0xc0()
freeing wrong coherent size from pool

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Lior Amsalem <alior@marvell.com>
Cc: Maen Suleiman <maen@marvell.com>
Cc: Tawfik Bayouk <tawfik@marvell.com>
Cc: Shadi Ammouri <shadi@marvell.com>
Cc: Eran Ben-Avi <benavi@marvell.com>
Cc: Yehuda Yitschak <yehuday@marvell.com>
Cc: Nadav Haklai <nadavh@marvell.com>
[m.szyprowski: rebased onto v3.6-rc5 and resolved conflict]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
arch/arm/mm/dma-mapping.c

index 051204f..e59c4ab 100644 (file)
@@ -489,7 +489,7 @@ static bool __in_atomic_pool(void *start, size_t size)
        void *pool_start = pool->vaddr;
        void *pool_end = pool->vaddr + pool->size;
 
-       if (start < pool_start || start > pool_end)
+       if (start < pool_start || start >= pool_end)
                return false;
 
        if (end <= pool_end)