Commit | Line | Data |
---|---|---|
14aa7e8b AJ |
1 | /* |
2 | * Copyright (C) 2011 Texas Instruments Incorporated | |
3 | * Author: Mark Salter <msalter@redhat.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | */ | |
9 | #include <linux/module.h> | |
10 | #include <linux/dma-mapping.h> | |
11 | #include <linux/mm.h> | |
12 | #include <linux/mm_types.h> | |
13 | #include <linux/scatterlist.h> | |
14 | ||
15 | #include <asm/cacheflush.h> | |
16 | ||
17 | static void c6x_dma_sync(dma_addr_t handle, size_t size, | |
18 | enum dma_data_direction dir) | |
19 | { | |
20 | unsigned long paddr = handle; | |
21 | ||
22 | BUG_ON(!valid_dma_direction(dir)); | |
23 | ||
24 | switch (dir) { | |
25 | case DMA_FROM_DEVICE: | |
26 | L2_cache_block_invalidate(paddr, paddr + size); | |
27 | break; | |
28 | case DMA_TO_DEVICE: | |
29 | L2_cache_block_writeback(paddr, paddr + size); | |
30 | break; | |
31 | case DMA_BIDIRECTIONAL: | |
32 | L2_cache_block_writeback_invalidate(paddr, paddr + size); | |
33 | break; | |
34 | default: | |
35 | break; | |
36 | } | |
37 | } | |
38 | ||
4605f04b CH |
39 | static dma_addr_t c6x_dma_map_page(struct device *dev, struct page *page, |
40 | unsigned long offset, size_t size, enum dma_data_direction dir, | |
00085f1e | 41 | unsigned long attrs) |
14aa7e8b | 42 | { |
4605f04b | 43 | dma_addr_t handle = virt_to_phys(page_address(page) + offset); |
14aa7e8b | 44 | |
4605f04b CH |
45 | c6x_dma_sync(handle, size, dir); |
46 | return handle; | |
14aa7e8b | 47 | } |
14aa7e8b | 48 | |
4605f04b | 49 | static void c6x_dma_unmap_page(struct device *dev, dma_addr_t handle, |
00085f1e | 50 | size_t size, enum dma_data_direction dir, unsigned long attrs) |
14aa7e8b AJ |
51 | { |
52 | c6x_dma_sync(handle, size, dir); | |
14aa7e8b | 53 | } |
14aa7e8b | 54 | |
4605f04b | 55 | static int c6x_dma_map_sg(struct device *dev, struct scatterlist *sglist, |
00085f1e | 56 | int nents, enum dma_data_direction dir, unsigned long attrs) |
14aa7e8b AJ |
57 | { |
58 | struct scatterlist *sg; | |
59 | int i; | |
60 | ||
4605f04b CH |
61 | for_each_sg(sglist, sg, nents, i) { |
62 | sg->dma_address = sg_phys(sg); | |
63 | c6x_dma_sync(sg->dma_address, sg->length, dir); | |
64 | } | |
14aa7e8b AJ |
65 | |
66 | return nents; | |
67 | } | |
14aa7e8b | 68 | |
4605f04b | 69 | static void c6x_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, |
00085f1e | 70 | int nents, enum dma_data_direction dir, unsigned long attrs) |
14aa7e8b AJ |
71 | { |
72 | struct scatterlist *sg; | |
73 | int i; | |
74 | ||
75 | for_each_sg(sglist, sg, nents, i) | |
4605f04b | 76 | c6x_dma_sync(sg_dma_address(sg), sg->length, dir); |
14aa7e8b | 77 | |
14aa7e8b | 78 | } |
14aa7e8b | 79 | |
4605f04b CH |
80 | static void c6x_dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, |
81 | size_t size, enum dma_data_direction dir) | |
14aa7e8b AJ |
82 | { |
83 | c6x_dma_sync(handle, size, dir); | |
84 | ||
14aa7e8b | 85 | } |
14aa7e8b | 86 | |
4605f04b CH |
87 | static void c6x_dma_sync_single_for_device(struct device *dev, |
88 | dma_addr_t handle, size_t size, enum dma_data_direction dir) | |
14aa7e8b AJ |
89 | { |
90 | c6x_dma_sync(handle, size, dir); | |
91 | ||
14aa7e8b | 92 | } |
14aa7e8b | 93 | |
4605f04b CH |
94 | static void c6x_dma_sync_sg_for_cpu(struct device *dev, |
95 | struct scatterlist *sglist, int nents, | |
96 | enum dma_data_direction dir) | |
14aa7e8b AJ |
97 | { |
98 | struct scatterlist *sg; | |
99 | int i; | |
100 | ||
101 | for_each_sg(sglist, sg, nents, i) | |
4605f04b | 102 | c6x_dma_sync_single_for_cpu(dev, sg_dma_address(sg), |
14aa7e8b AJ |
103 | sg->length, dir); |
104 | ||
14aa7e8b | 105 | } |
14aa7e8b | 106 | |
4605f04b CH |
107 | static void c6x_dma_sync_sg_for_device(struct device *dev, |
108 | struct scatterlist *sglist, int nents, | |
109 | enum dma_data_direction dir) | |
14aa7e8b AJ |
110 | { |
111 | struct scatterlist *sg; | |
112 | int i; | |
113 | ||
114 | for_each_sg(sglist, sg, nents, i) | |
4605f04b | 115 | c6x_dma_sync_single_for_device(dev, sg_dma_address(sg), |
14aa7e8b AJ |
116 | sg->length, dir); |
117 | ||
14aa7e8b | 118 | } |
14aa7e8b | 119 | |
4605f04b CH |
120 | struct dma_map_ops c6x_dma_ops = { |
121 | .alloc = c6x_dma_alloc, | |
122 | .free = c6x_dma_free, | |
123 | .map_page = c6x_dma_map_page, | |
124 | .unmap_page = c6x_dma_unmap_page, | |
125 | .map_sg = c6x_dma_map_sg, | |
126 | .unmap_sg = c6x_dma_unmap_sg, | |
127 | .sync_single_for_device = c6x_dma_sync_single_for_device, | |
128 | .sync_single_for_cpu = c6x_dma_sync_single_for_cpu, | |
129 | .sync_sg_for_device = c6x_dma_sync_sg_for_device, | |
130 | .sync_sg_for_cpu = c6x_dma_sync_sg_for_cpu, | |
131 | }; | |
132 | EXPORT_SYMBOL(c6x_dma_ops); | |
14aa7e8b AJ |
133 | |
134 | /* Number of entries preallocated for DMA-API debugging */ | |
135 | #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) | |
136 | ||
137 | static int __init dma_init(void) | |
138 | { | |
139 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); | |
140 | ||
141 | return 0; | |
142 | } | |
143 | fs_initcall(dma_init); |