x86: retry allocation if failed
authorGlauber Costa <gcosta@redhat.com>
Wed, 9 Apr 2008 16:18:05 +0000 (13:18 -0300)
committerIngo Molnar <mingo@elte.hu>
Sat, 19 Apr 2008 17:19:58 +0000 (19:19 +0200)
This patch puts in the code to retry allocation in case it fails. By its
own, it does not make much sense but making the code look like x86_64.
But later patches in this series will make we try to allocate from
zones other than DMA first, which will possibly fail.

Signed-off-by: Glauber Costa <gcosta@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/kernel/pci-dma_32.c

index debe9119b7241ecbce6fa0992975f079b5a24aad..11f100a5f034f180aa43633422f42b799591e36b 100644 (file)
@@ -76,6 +76,8 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
        struct page *page;
        dma_addr_t bus;
        int order = get_order(size);
+       unsigned long dma_mask = 0;
+
        /* ignore region specifiers */
        gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
 
@@ -85,15 +87,37 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
        if (!dev)
                dev = &fallback_dev;
 
+       dma_mask = dev->coherent_dma_mask;
+       if (dma_mask == 0)
+               dma_mask = DMA_32BIT_MASK;
+
+ again:
        page = dma_alloc_pages(dev, gfp, order);
        if (page == NULL)
                return NULL;
 
-       ret = page_address(page);
-       bus = page_to_phys(page);
-
-       memset(ret, 0, size);
-       *dma_handle = bus;
+       {
+               int high, mmu;
+               bus = page_to_phys(page);
+               ret = page_address(page);
+               high = (bus + size) >= dma_mask;
+               mmu = high;
+               if (force_iommu && !(gfp & GFP_DMA))
+                       mmu = 1;
+               else if (high) {
+                       free_pages((unsigned long)ret,
+                                  get_order(size));
+
+                       /* Don't use the 16MB ZONE_DMA unless absolutely
+                          needed. It's better to use remapping first. */
+                       if (dma_mask < DMA_32BIT_MASK && !(gfp & GFP_DMA)) {
+                               gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
+                               goto again;
+                       }
+               }
+               memset(ret, 0, size);
+               *dma_handle = bus;
+       }
 
        return ret;
 }