diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2007-10-12 07:44:12 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2007-10-16 05:27:32 -0400 |
commit | 78bdc3106a877cfa50439fa66b52acbc4e7868df (patch) | |
tree | 668b1f22ee9e645e76589ce103b42829f999822e /include/asm-powerpc/dma-mapping.h | |
parent | d1ed455e30e439e0d1483c2e236d7e15e1010704 (diff) |
PPC: sg chaining support
This updates the ppc iommu/pci dma mappers to sg chaining. Includes
further fixes from FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'include/asm-powerpc/dma-mapping.h')
-rw-r--r-- | include/asm-powerpc/dma-mapping.h | 158 |
1 files changed, 9 insertions, 149 deletions
diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h index 60eacde828c0..2af321f36aba 100644 --- a/include/asm-powerpc/dma-mapping.h +++ b/include/asm-powerpc/dma-mapping.h | |||
@@ -6,149 +6,6 @@ | |||
6 | */ | 6 | */ |
7 | #ifndef _ASM_DMA_MAPPING_H | 7 | #ifndef _ASM_DMA_MAPPING_H |
8 | #define _ASM_DMA_MAPPING_H | 8 | #define _ASM_DMA_MAPPING_H |
9 | #ifdef __KERNEL__ | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | #include <linux/cache.h> | ||
13 | /* need struct page definitions */ | ||
14 | #include <linux/mm.h> | ||
15 | #include <linux/scatterlist.h> | ||
16 | #include <asm/io.h> | ||
17 | |||
18 | #define DMA_ERROR_CODE (~(dma_addr_t)0x0) | ||
19 | |||
20 | #ifdef CONFIG_NOT_COHERENT_CACHE | ||
21 | /* | ||
22 | * DMA-consistent mapping functions for PowerPCs that don't support | ||
23 | * cache snooping. These allocate/free a region of uncached mapped | ||
24 | * memory space for use with DMA devices. Alternatively, you could | ||
25 | * allocate the space "normally" and use the cache management functions | ||
26 | * to ensure it is consistent. | ||
27 | */ | ||
28 | extern void *__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp); | ||
29 | extern void __dma_free_coherent(size_t size, void *vaddr); | ||
30 | extern void __dma_sync(void *vaddr, size_t size, int direction); | ||
31 | extern void __dma_sync_page(struct page *page, unsigned long offset, | ||
32 | size_t size, int direction); | ||
33 | |||
34 | #else /* ! CONFIG_NOT_COHERENT_CACHE */ | ||
35 | /* | ||
36 | * Cache coherent cores. | ||
37 | */ | ||
38 | |||
39 | #define __dma_alloc_coherent(gfp, size, handle) NULL | ||
40 | #define __dma_free_coherent(size, addr) ((void)0) | ||
41 | #define __dma_sync(addr, size, rw) ((void)0) | ||
42 | #define __dma_sync_page(pg, off, sz, rw) ((void)0) | ||
43 | |||
44 | #endif /* ! CONFIG_NOT_COHERENT_CACHE */ | ||
45 | |||
46 | #ifdef CONFIG_PPC64 | ||
47 | /* | ||
48 | * DMA operations are abstracted for G5 vs. i/pSeries, PCI vs. VIO | ||
49 | */ | ||
50 | struct dma_mapping_ops { | ||
51 | void * (*alloc_coherent)(struct device *dev, size_t size, | ||
52 | dma_addr_t *dma_handle, gfp_t flag); | ||
53 | void (*free_coherent)(struct device *dev, size_t size, | ||
54 | void *vaddr, dma_addr_t dma_handle); | ||
55 | dma_addr_t (*map_single)(struct device *dev, void *ptr, | ||
56 | size_t size, enum dma_data_direction direction); | ||
57 | void (*unmap_single)(struct device *dev, dma_addr_t dma_addr, | ||
58 | size_t size, enum dma_data_direction direction); | ||
59 | int (*map_sg)(struct device *dev, struct scatterlist *sg, | ||
60 | int nents, enum dma_data_direction direction); | ||
61 | void (*unmap_sg)(struct device *dev, struct scatterlist *sg, | ||
62 | int nents, enum dma_data_direction direction); | ||
63 | int (*dma_supported)(struct device *dev, u64 mask); | ||
64 | int (*set_dma_mask)(struct device *dev, u64 dma_mask); | ||
65 | }; | ||
66 | |||
67 | static inline struct dma_mapping_ops *get_dma_ops(struct device *dev) | ||
68 | { | ||
69 | /* We don't handle the NULL dev case for ISA for now. We could | ||
70 | * do it via an out of line call but it is not needed for now. The | ||
71 | * only ISA DMA device we support is the floppy and we have a hack | ||
72 | * in the floppy driver directly to get a device for us. | ||
73 | */ | ||
74 | if (unlikely(dev == NULL || dev->archdata.dma_ops == NULL)) | ||
75 | return NULL; | ||
76 | return dev->archdata.dma_ops; | ||
77 | } | ||
78 | |||
79 | static inline int dma_supported(struct device *dev, u64 mask) | ||
80 | { | ||
81 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | ||
82 | |||
83 | if (unlikely(dma_ops == NULL)) | ||
84 | return 0; | ||
85 | if (dma_ops->dma_supported == NULL) | ||
86 | return 1; | ||
87 | return dma_ops->dma_supported(dev, mask); | ||
88 | } | ||
89 | |||
90 | static inline int dma_set_mask(struct device *dev, u64 dma_mask) | ||
91 | { | ||
92 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | ||
93 | |||
94 | if (unlikely(dma_ops == NULL)) | ||
95 | return -EIO; | ||
96 | if (dma_ops->set_dma_mask != NULL) | ||
97 | return dma_ops->set_dma_mask(dev, dma_mask); | ||
98 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | ||
99 | return -EIO; | ||
100 | *dev->dma_mask = dma_mask; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static inline void *dma_alloc_coherent(struct device *dev, size_t size, | ||
105 | dma_addr_t *dma_handle, gfp_t flag) | ||
106 | { | ||
107 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | ||
108 | |||
109 | BUG_ON(!dma_ops); | ||
110 | return dma_ops->alloc_coherent(dev, size, dma_handle, flag); | ||
111 | } | ||
112 | |||
113 | static inline void dma_free_coherent(struct device *dev, size_t size, | ||
114 | void *cpu_addr, dma_addr_t dma_handle) | ||
115 | { | ||
116 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | ||
117 | |||
118 | BUG_ON(!dma_ops); | ||
119 | dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); | ||
120 | } | ||
121 | |||
122 | static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, | ||
123 | size_t size, | ||
124 | enum dma_data_direction direction) | ||
125 | { | ||
126 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | ||
127 | |||
128 | BUG_ON(!dma_ops); | ||
129 | return dma_ops->map_single(dev, cpu_addr, size, direction); | ||
130 | } | ||
131 | |||
132 | static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, | ||
133 | size_t size, | ||
134 | enum dma_data_direction direction) | ||
135 | { | ||
136 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | ||
137 | |||
138 | BUG_ON(!dma_ops); | ||
139 | dma_ops->unmap_single(dev, dma_addr, size, direction); | ||
140 | } | ||
141 | |||
142 | static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, | ||
143 | unsigned long offset, size_t size, | ||
144 | enum dma_data_direction direction) | ||
145 | { | ||
146 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | ||
147 | |||
148 | BUG_ON(!dma_ops); | ||
149 | return dma_ops->map_single(dev, page_address(page) + offset, size, | ||
150 | direction); | ||
151 | } | ||
152 | 9 | ||
153 | static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, | 10 | static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, |
154 | size_t size, | 11 | size_t size, |
@@ -276,14 +133,15 @@ static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, | |||
276 | } | 133 | } |
277 | 134 | ||
278 | static inline int | 135 | static inline int |
279 | dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, | 136 | dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents, |
280 | enum dma_data_direction direction) | 137 | enum dma_data_direction direction) |
281 | { | 138 | { |
139 | struct scatterlist *sg; | ||
282 | int i; | 140 | int i; |
283 | 141 | ||
284 | BUG_ON(direction == DMA_NONE); | 142 | BUG_ON(direction == DMA_NONE); |
285 | 143 | ||
286 | for (i = 0; i < nents; i++, sg++) { | 144 | for_each_sg(sgl, sg, nents, i) { |
287 | BUG_ON(!sg->page); | 145 | BUG_ON(!sg->page); |
288 | __dma_sync_page(sg->page, sg->offset, sg->length, direction); | 146 | __dma_sync_page(sg->page, sg->offset, sg->length, direction); |
289 | sg->dma_address = page_to_bus(sg->page) + sg->offset; | 147 | sg->dma_address = page_to_bus(sg->page) + sg->offset; |
@@ -318,26 +176,28 @@ static inline void dma_sync_single_for_device(struct device *dev, | |||
318 | } | 176 | } |
319 | 177 | ||
320 | static inline void dma_sync_sg_for_cpu(struct device *dev, | 178 | static inline void dma_sync_sg_for_cpu(struct device *dev, |
321 | struct scatterlist *sg, int nents, | 179 | struct scatterlist *sgl, int nents, |
322 | enum dma_data_direction direction) | 180 | enum dma_data_direction direction) |
323 | { | 181 | { |
182 | struct scatterlist *sg; | ||
324 | int i; | 183 | int i; |
325 | 184 | ||
326 | BUG_ON(direction == DMA_NONE); | 185 | BUG_ON(direction == DMA_NONE); |
327 | 186 | ||
328 | for (i = 0; i < nents; i++, sg++) | 187 | for_each_sg(sgl, sg, nents, i) |
329 | __dma_sync_page(sg->page, sg->offset, sg->length, direction); | 188 | __dma_sync_page(sg->page, sg->offset, sg->length, direction); |
330 | } | 189 | } |
331 | 190 | ||
332 | static inline void dma_sync_sg_for_device(struct device *dev, | 191 | static inline void dma_sync_sg_for_device(struct device *dev, |
333 | struct scatterlist *sg, int nents, | 192 | struct scatterlist *sgl, int nents, |
334 | enum dma_data_direction direction) | 193 | enum dma_data_direction direction) |
335 | { | 194 | { |
195 | struct scatterlist *sg; | ||
336 | int i; | 196 | int i; |
337 | 197 | ||
338 | BUG_ON(direction == DMA_NONE); | 198 | BUG_ON(direction == DMA_NONE); |
339 | 199 | ||
340 | for (i = 0; i < nents; i++, sg++) | 200 | for_each_sg(sgl, sg, nents, i) |
341 | __dma_sync_page(sg->page, sg->offset, sg->length, direction); | 201 | __dma_sync_page(sg->page, sg->offset, sg->length, direction); |
342 | } | 202 | } |
343 | 203 | ||