diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2008-08-19 10:32:42 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-08-22 02:34:48 -0400 |
commit | c5e835f9641e9fcb95d1afb24906821e98b2c6a8 (patch) | |
tree | 75a79300bc4592060331bd1a928662055b976427 /arch/x86/kernel/pci-nommu.c | |
parent | e4ad68b651f22fa71820c0b30bb2807999b2b49f (diff) |
x86: add alloc_coherent dma_ops callback to NOMMU driver
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/pci-nommu.c')
-rw-r--r-- | arch/x86/kernel/pci-nommu.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c index 3f91f71cdc3e..b8ce83c98211 100644 --- a/arch/x86/kernel/pci-nommu.c +++ b/arch/x86/kernel/pci-nommu.c | |||
@@ -72,7 +72,62 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg, | |||
72 | return nents; | 72 | return nents; |
73 | } | 73 | } |
74 | 74 | ||
75 | static void * | ||
76 | nommu_alloc_coherent(struct device *hwdev, size_t size, | ||
77 | dma_addr_t *dma_addr, gfp_t gfp) | ||
78 | { | ||
79 | unsigned long dma_mask; | ||
80 | int node; | ||
81 | struct page *page; | ||
82 | |||
83 | if (hwdev->dma_mask == NULL) | ||
84 | return NULL; | ||
85 | |||
86 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); | ||
87 | gfp |= __GFP_ZERO; | ||
88 | |||
89 | dma_mask = hwdev->coherent_dma_mask; | ||
90 | if (!dma_mask) | ||
91 | dma_mask = *(hwdev->dma_mask); | ||
92 | |||
93 | if (dma_mask < DMA_24BIT_MASK) | ||
94 | return NULL; | ||
95 | |||
96 | node = dev_to_node(hwdev); | ||
97 | |||
98 | #ifdef CONFIG_X86_64 | ||
99 | if (dma_mask <= DMA_32BIT_MASK) | ||
100 | gfp |= GFP_DMA32; | ||
101 | #endif | ||
102 | |||
103 | /* No alloc-free penalty for ISA devices */ | ||
104 | if (dma_mask == DMA_24BIT_MASK) | ||
105 | gfp |= GFP_DMA; | ||
106 | |||
107 | again: | ||
108 | page = alloc_pages_node(node, gfp, get_order(size)); | ||
109 | if (!page) | ||
110 | return NULL; | ||
111 | |||
112 | if ((page_to_phys(page) + size > dma_mask) && !(gfp & GFP_DMA)) { | ||
113 | free_pages((unsigned long)page_address(page), get_order(size)); | ||
114 | gfp |= GFP_DMA; | ||
115 | goto again; | ||
116 | } | ||
117 | |||
118 | *dma_addr = page_to_phys(page); | ||
119 | if (check_addr("alloc_coherent", hwdev, *dma_addr, size)) { | ||
120 | flush_write_buffers(); | ||
121 | return page_address(page); | ||
122 | } | ||
123 | |||
124 | free_pages((unsigned long)page_address(page), get_order(size)); | ||
125 | |||
126 | return NULL; | ||
127 | } | ||
128 | |||
75 | struct dma_mapping_ops nommu_dma_ops = { | 129 | struct dma_mapping_ops nommu_dma_ops = { |
130 | .alloc_coherent = nommu_alloc_coherent, | ||
76 | .map_single = nommu_map_single, | 131 | .map_single = nommu_map_single, |
77 | .map_sg = nommu_map_sg, | 132 | .map_sg = nommu_map_sg, |
78 | .is_phys = 1, | 133 | .is_phys = 1, |