diff options
| -rw-r--r-- | arch/powerpc/kernel/dma_64.c | 5 | ||||
| -rw-r--r-- | arch/powerpc/kernel/ibmebus.c | 11 | ||||
| -rw-r--r-- | arch/powerpc/kernel/iommu.c | 23 | ||||
| -rw-r--r-- | include/asm-powerpc/dma-mapping.h | 158 | ||||
| -rw-r--r-- | include/asm-powerpc/scatterlist.h | 2 |
5 files changed, 34 insertions, 165 deletions
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c index 7b0e754383cf..9001104b56b0 100644 --- a/arch/powerpc/kernel/dma_64.c +++ b/arch/powerpc/kernel/dma_64.c | |||
| @@ -154,12 +154,13 @@ static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr, | |||
| 154 | { | 154 | { |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | static int dma_direct_map_sg(struct device *dev, struct scatterlist *sg, | 157 | static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, |
| 158 | int nents, enum dma_data_direction direction) | 158 | int nents, enum dma_data_direction direction) |
| 159 | { | 159 | { |
| 160 | struct scatterlist *sg; | ||
| 160 | int i; | 161 | int i; |
| 161 | 162 | ||
| 162 | for (i = 0; i < nents; i++, sg++) { | 163 | for_each_sg(sgl, sg, nents, i) { |
| 163 | sg->dma_address = (page_to_phys(sg->page) + sg->offset) | | 164 | sg->dma_address = (page_to_phys(sg->page) + sg->offset) | |
| 164 | dma_direct_offset; | 165 | dma_direct_offset; |
| 165 | sg->dma_length = sg->length; | 166 | sg->dma_length = sg->length; |
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 53bf64623bd8..2e16ca5778a3 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c | |||
| @@ -87,15 +87,16 @@ static void ibmebus_unmap_single(struct device *dev, | |||
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | static int ibmebus_map_sg(struct device *dev, | 89 | static int ibmebus_map_sg(struct device *dev, |
| 90 | struct scatterlist *sg, | 90 | struct scatterlist *sgl, |
| 91 | int nents, enum dma_data_direction direction) | 91 | int nents, enum dma_data_direction direction) |
| 92 | { | 92 | { |
| 93 | struct scatterlist *sg; | ||
| 93 | int i; | 94 | int i; |
| 94 | 95 | ||
| 95 | for (i = 0; i < nents; i++) { | 96 | for_each_sg(sgl, sg, nents, i) { |
| 96 | sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) | 97 | sg->dma_address = (dma_addr_t)page_address(sg->page) |
| 97 | + sg[i].offset; | 98 | + sg->offset; |
| 98 | sg[i].dma_length = sg[i].length; | 99 | sg->dma_length = sg->length; |
| 99 | } | 100 | } |
| 100 | 101 | ||
| 101 | return nents; | 102 | return nents; |
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index e4ec6eee81a8..306a6f75b6c5 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c | |||
| @@ -277,7 +277,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 277 | dma_addr_t dma_next = 0, dma_addr; | 277 | dma_addr_t dma_next = 0, dma_addr; |
| 278 | unsigned long flags; | 278 | unsigned long flags; |
| 279 | struct scatterlist *s, *outs, *segstart; | 279 | struct scatterlist *s, *outs, *segstart; |
| 280 | int outcount, incount; | 280 | int outcount, incount, i; |
| 281 | unsigned long handle; | 281 | unsigned long handle; |
| 282 | 282 | ||
| 283 | BUG_ON(direction == DMA_NONE); | 283 | BUG_ON(direction == DMA_NONE); |
| @@ -297,7 +297,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 297 | 297 | ||
| 298 | spin_lock_irqsave(&(tbl->it_lock), flags); | 298 | spin_lock_irqsave(&(tbl->it_lock), flags); |
| 299 | 299 | ||
| 300 | for (s = outs; nelems; nelems--, s++) { | 300 | for_each_sg(sglist, s, nelems, i) { |
| 301 | unsigned long vaddr, npages, entry, slen; | 301 | unsigned long vaddr, npages, entry, slen; |
| 302 | 302 | ||
| 303 | slen = s->length; | 303 | slen = s->length; |
| @@ -341,7 +341,8 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 341 | if (novmerge || (dma_addr != dma_next)) { | 341 | if (novmerge || (dma_addr != dma_next)) { |
| 342 | /* Can't merge: create a new segment */ | 342 | /* Can't merge: create a new segment */ |
| 343 | segstart = s; | 343 | segstart = s; |
| 344 | outcount++; outs++; | 344 | outcount++; |
| 345 | outs = sg_next(outs); | ||
| 345 | DBG(" can't merge, new segment.\n"); | 346 | DBG(" can't merge, new segment.\n"); |
| 346 | } else { | 347 | } else { |
| 347 | outs->dma_length += s->length; | 348 | outs->dma_length += s->length; |
| @@ -374,7 +375,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 374 | * next entry of the sglist if we didn't fill the list completely | 375 | * next entry of the sglist if we didn't fill the list completely |
| 375 | */ | 376 | */ |
| 376 | if (outcount < incount) { | 377 | if (outcount < incount) { |
| 377 | outs++; | 378 | outs = sg_next(outs); |
| 378 | outs->dma_address = DMA_ERROR_CODE; | 379 | outs->dma_address = DMA_ERROR_CODE; |
| 379 | outs->dma_length = 0; | 380 | outs->dma_length = 0; |
| 380 | } | 381 | } |
| @@ -385,7 +386,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 385 | return outcount; | 386 | return outcount; |
| 386 | 387 | ||
| 387 | failure: | 388 | failure: |
| 388 | for (s = &sglist[0]; s <= outs; s++) { | 389 | for_each_sg(sglist, s, nelems, i) { |
| 389 | if (s->dma_length != 0) { | 390 | if (s->dma_length != 0) { |
| 390 | unsigned long vaddr, npages; | 391 | unsigned long vaddr, npages; |
| 391 | 392 | ||
| @@ -395,6 +396,8 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 395 | s->dma_address = DMA_ERROR_CODE; | 396 | s->dma_address = DMA_ERROR_CODE; |
| 396 | s->dma_length = 0; | 397 | s->dma_length = 0; |
| 397 | } | 398 | } |
| 399 | if (s == outs) | ||
| 400 | break; | ||
| 398 | } | 401 | } |
| 399 | spin_unlock_irqrestore(&(tbl->it_lock), flags); | 402 | spin_unlock_irqrestore(&(tbl->it_lock), flags); |
| 400 | return 0; | 403 | return 0; |
| @@ -404,6 +407,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 404 | void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, | 407 | void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, |
| 405 | int nelems, enum dma_data_direction direction) | 408 | int nelems, enum dma_data_direction direction) |
| 406 | { | 409 | { |
| 410 | struct scatterlist *sg; | ||
| 407 | unsigned long flags; | 411 | unsigned long flags; |
| 408 | 412 | ||
| 409 | BUG_ON(direction == DMA_NONE); | 413 | BUG_ON(direction == DMA_NONE); |
| @@ -413,15 +417,16 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 413 | 417 | ||
| 414 | spin_lock_irqsave(&(tbl->it_lock), flags); | 418 | spin_lock_irqsave(&(tbl->it_lock), flags); |
| 415 | 419 | ||
| 420 | sg = sglist; | ||
| 416 | while (nelems--) { | 421 | while (nelems--) { |
| 417 | unsigned int npages; | 422 | unsigned int npages; |
| 418 | dma_addr_t dma_handle = sglist->dma_address; | 423 | dma_addr_t dma_handle = sg->dma_address; |
| 419 | 424 | ||
| 420 | if (sglist->dma_length == 0) | 425 | if (sg->dma_length == 0) |
| 421 | break; | 426 | break; |
| 422 | npages = iommu_num_pages(dma_handle,sglist->dma_length); | 427 | npages = iommu_num_pages(dma_handle, sg->dma_length); |
| 423 | __iommu_free(tbl, dma_handle, npages); | 428 | __iommu_free(tbl, dma_handle, npages); |
| 424 | sglist++; | 429 | sg = sg_next(sg); |
| 425 | } | 430 | } |
| 426 | 431 | ||
| 427 | /* Flush/invalidate TLBs if necessary. As for iommu_free(), we | 432 | /* Flush/invalidate TLBs if necessary. As for iommu_free(), we |
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 | ||
diff --git a/include/asm-powerpc/scatterlist.h b/include/asm-powerpc/scatterlist.h index 8c992d1491d4..b075f619c3b7 100644 --- a/include/asm-powerpc/scatterlist.h +++ b/include/asm-powerpc/scatterlist.h | |||
| @@ -41,5 +41,7 @@ struct scatterlist { | |||
| 41 | #define ISA_DMA_THRESHOLD (~0UL) | 41 | #define ISA_DMA_THRESHOLD (~0UL) |
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | #define ARCH_HAS_SG_CHAIN | ||
| 45 | |||
| 44 | #endif /* __KERNEL__ */ | 46 | #endif /* __KERNEL__ */ |
| 45 | #endif /* _ASM_POWERPC_SCATTERLIST_H */ | 47 | #endif /* _ASM_POWERPC_SCATTERLIST_H */ |
