pci-dma_64.c 3.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 * Dynamic DMA mapping support.
 */

#include <linux/types.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/module.h>
10
#include <linux/dmar.h>
Y
Yinghai Lu 已提交
11 12
#include <linux/bootmem.h>
#include <asm/proto.h>
L
Linus Torvalds 已提交
13
#include <asm/io.h>
J
Joerg Roedel 已提交
14
#include <asm/gart.h>
15
#include <asm/calgary.h>
L
Linus Torvalds 已提交
16

17 18 19 20 21 22

/* Dummy device used for NULL arguments (normally ISA). Better would
   be probably a smaller DMA mask, but this is bug-to-bug compatible
   to i386. */
struct device fallback_dev = {
	.bus_id = "fallback device",
23
	.coherent_dma_mask = DMA_32BIT_MASK,
24 25 26 27 28 29 30 31
	.dma_mask = &fallback_dev.coherent_dma_mask,
};

/* Allocate DMA memory on node near device */
noinline static void *
dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order)
{
	int node;
32 33

	node = dev_to_node(dev);
34

35
	return alloc_pages_node(node, gfp, order);
36 37
}

38 39
#define dma_alloc_from_coherent_mem(dev, size, handle, ret) (0)
#define dma_release_coherent(dev, order, vaddr) (0)
40 41
/*
 * Allocate memory for a coherent mapping.
L
Linus Torvalds 已提交
42
 */
43 44 45
void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
		   gfp_t gfp)
L
Linus Torvalds 已提交
46
{
47
	void *memory;
48
	struct page *page;
49 50 51
	unsigned long dma_mask = 0;
	u64 bus;

G
Glauber Costa 已提交
52 53
	/* ignore region specifiers */
	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
54 55 56 57

	if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &memory))
		return memory;

58 59 60 61
	if (!dev)
		dev = &fallback_dev;
	dma_mask = dev->coherent_dma_mask;
	if (dma_mask == 0)
62
		dma_mask = DMA_32BIT_MASK;
63

64 65 66 67
	/* Device not DMA able */
	if (dev->dma_mask == NULL)
		return NULL;

68 69 70
	/* Don't invoke OOM killer */
	gfp |= __GFP_NORETRY;

71 72 73 74
	/* 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 */
75
	if (dma_mask <= DMA_32BIT_MASK)
76 77 78
		gfp |= GFP_DMA32;

 again:
79 80
	page = dma_alloc_pages(dev, gfp, get_order(size));
	if (page == NULL)
81 82 83 84
		return NULL;

	{
		int high, mmu;
85 86
		bus = page_to_phys(page);
		memory = page_address(page);
87 88 89 90 91 92 93 94 95 96
	        high = (bus + size) >= dma_mask;
		mmu = high;
		if (force_iommu && !(gfp & GFP_DMA))
			mmu = 1;
		else if (high) {
			free_pages((unsigned long)memory,
				   get_order(size));

			/* Don't use the 16MB ZONE_DMA unless absolutely
			   needed. It's better to use remapping first. */
97
			if (dma_mask < DMA_32BIT_MASK && !(gfp & GFP_DMA)) {
98 99 100 101
				gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
				goto again;
			}

102 103 104
			/* Let low level make its own zone decisions */
			gfp &= ~(GFP_DMA32|GFP_DMA);

105 106 107 108 109 110 111 112
			if (dma_ops->alloc_coherent)
				return dma_ops->alloc_coherent(dev, size,
							   dma_handle, gfp);
			return NULL;
		}

		memset(memory, 0, size);
		if (!mmu) {
113
			*dma_handle = bus;
114 115 116 117 118 119 120 121 122 123 124
			return memory;
		}
	}

	if (dma_ops->alloc_coherent) {
		free_pages((unsigned long)memory, get_order(size));
		gfp &= ~(GFP_DMA|GFP_DMA32);
		return dma_ops->alloc_coherent(dev, size, dma_handle, gfp);
	}

	if (dma_ops->map_simple) {
I
Ingo Molnar 已提交
125
		*dma_handle = dma_ops->map_simple(dev, virt_to_phys(memory),
126 127 128 129
					      size,
					      PCI_DMA_BIDIRECTIONAL);
		if (*dma_handle != bad_dma_address)
			return memory;
L
Linus Torvalds 已提交
130 131
	}

132 133 134 135 136 137
	if (panic_on_overflow)
		panic("dma_alloc_coherent: IOMMU overflow by %lu bytes\n",size);
	free_pages((unsigned long)memory, get_order(size));
	return NULL;
}
EXPORT_SYMBOL(dma_alloc_coherent);
L
Linus Torvalds 已提交
138

139 140 141
/*
 * Unmap coherent memory.
 * The caller must ensure that the device has finished accessing the mapping.
L
Linus Torvalds 已提交
142
 */
143 144 145
void dma_free_coherent(struct device *dev, size_t size,
			 void *vaddr, dma_addr_t bus)
{
146
	int order = get_order(size);
147
	WARN_ON(irqs_disabled());	/* for portability */
148 149
	if (dma_release_coherent(dev, order, vaddr))
		return;
150 151
	if (dma_ops->unmap_single)
		dma_ops->unmap_single(dev, bus, size, 0);
152
	free_pages((unsigned long)vaddr, order);
153 154
}
EXPORT_SYMBOL(dma_free_coherent);