]> err.no Git - linux-2.6/blobdiff - arch/x86/kernel/pci-dma.c
x86: use BOOTMEM_EXCLUSIVE on 32-bit
[linux-2.6] / arch / x86 / kernel / pci-dma.c
index 388b113a7d88ffbc0efaf52c348412af9e439a8c..dc00a1331acef73c204ed0979d8527450af5246f 100644 (file)
@@ -14,7 +14,7 @@ EXPORT_SYMBOL(forbid_dac);
 const struct dma_mapping_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
-int iommu_sac_force __read_mostly = 0;
+static int iommu_sac_force __read_mostly;
 
 #ifdef CONFIG_IOMMU_DEBUG
 int panic_on_overflow __read_mostly = 1;
@@ -378,6 +378,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
        struct page *page;
        unsigned long dma_mask = 0;
        dma_addr_t bus;
+       int noretry = 0;
 
        /* ignore region specifiers */
        gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
@@ -385,30 +386,37 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
        if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &memory))
                return memory;
 
-       if (!dev)
+       if (!dev) {
                dev = &fallback_dev;
+               gfp |= GFP_DMA;
+       }
        dma_mask = dev->coherent_dma_mask;
        if (dma_mask == 0)
-               dma_mask = DMA_32BIT_MASK;
+               dma_mask = (gfp & GFP_DMA) ? DMA_24BIT_MASK : DMA_32BIT_MASK;
 
        /* Device not DMA able */
        if (dev->dma_mask == NULL)
                return NULL;
 
-       /* Don't invoke OOM killer */
-       gfp |= __GFP_NORETRY;
+       /* Don't invoke OOM killer or retry in lower 16MB DMA zone */
+       if (gfp & __GFP_DMA)
+               noretry = 1;
 
 #ifdef CONFIG_X86_64
        /* Why <=? Even when the mask is smaller than 4GB it is often
           larger than 16MB and in this case we have a chance of
           finding fitting memory in the next higher zone first. If
           not retry with true GFP_DMA. -AK */
-       if (dma_mask <= DMA_32BIT_MASK)
+       if (dma_mask <= DMA_32BIT_MASK && !(gfp & GFP_DMA)) {
                gfp |= GFP_DMA32;
+               if (dma_mask < DMA_32BIT_MASK)
+                       noretry = 1;
+       }
 #endif
 
  again:
-       page = dma_alloc_pages(dev, gfp, get_order(size));
+       page = dma_alloc_pages(dev,
+               noretry ? gfp | __GFP_NORETRY : gfp, get_order(size));
        if (page == NULL)
                return NULL;