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, | |
41 | struct dma_attrs *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 CH |
49 | static void c6x_dma_unmap_page(struct device *dev, dma_addr_t handle, |
50 | size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) | |
14aa7e8b AJ |
51 | { |
52 | c6x_dma_sync(handle, size, dir); | |
14aa7e8b | 53 | } |
14aa7e8b | 54 | |
4605f04b CH |
55 | static int c6x_dma_map_sg(struct device *dev, struct scatterlist *sglist, |
56 | int nents, enum dma_data_direction dir, struct dma_attrs *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 CH |
69 | static void c6x_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, |
70 | int nents, enum dma_data_direction dir, | |
71 | struct dma_attrs *attrs) | |
14aa7e8b AJ |
72 | { |
73 | struct scatterlist *sg; | |
74 | int i; | |
75 | ||
76 | for_each_sg(sglist, sg, nents, i) | |
4605f04b | 77 | c6x_dma_sync(sg_dma_address(sg), sg->length, dir); |
14aa7e8b | 78 | |
14aa7e8b | 79 | } |
14aa7e8b | 80 | |
4605f04b CH |
81 | static void c6x_dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, |
82 | size_t size, enum dma_data_direction dir) | |
14aa7e8b AJ |
83 | { |
84 | c6x_dma_sync(handle, size, dir); | |
85 | ||
14aa7e8b | 86 | } |
14aa7e8b | 87 | |
4605f04b CH |
88 | static void c6x_dma_sync_single_for_device(struct device *dev, |
89 | dma_addr_t handle, size_t size, enum dma_data_direction dir) | |
14aa7e8b AJ |
90 | { |
91 | c6x_dma_sync(handle, size, dir); | |
92 | ||
14aa7e8b | 93 | } |
14aa7e8b | 94 | |
4605f04b CH |
95 | static void c6x_dma_sync_sg_for_cpu(struct device *dev, |
96 | struct scatterlist *sglist, int nents, | |
97 | enum dma_data_direction dir) | |
14aa7e8b AJ |
98 | { |
99 | struct scatterlist *sg; | |
100 | int i; | |
101 | ||
102 | for_each_sg(sglist, sg, nents, i) | |
4605f04b | 103 | c6x_dma_sync_single_for_cpu(dev, sg_dma_address(sg), |
14aa7e8b AJ |
104 | sg->length, dir); |
105 | ||
14aa7e8b | 106 | } |
14aa7e8b | 107 | |
4605f04b CH |
108 | static void c6x_dma_sync_sg_for_device(struct device *dev, |
109 | struct scatterlist *sglist, int nents, | |
110 | enum dma_data_direction dir) | |
14aa7e8b AJ |
111 | { |
112 | struct scatterlist *sg; | |
113 | int i; | |
114 | ||
115 | for_each_sg(sglist, sg, nents, i) | |
4605f04b | 116 | c6x_dma_sync_single_for_device(dev, sg_dma_address(sg), |
14aa7e8b AJ |
117 | sg->length, dir); |
118 | ||
14aa7e8b | 119 | } |
14aa7e8b | 120 | |
4605f04b CH |
121 | struct dma_map_ops c6x_dma_ops = { |
122 | .alloc = c6x_dma_alloc, | |
123 | .free = c6x_dma_free, | |
124 | .map_page = c6x_dma_map_page, | |
125 | .unmap_page = c6x_dma_unmap_page, | |
126 | .map_sg = c6x_dma_map_sg, | |
127 | .unmap_sg = c6x_dma_unmap_sg, | |
128 | .sync_single_for_device = c6x_dma_sync_single_for_device, | |
129 | .sync_single_for_cpu = c6x_dma_sync_single_for_cpu, | |
130 | .sync_sg_for_device = c6x_dma_sync_sg_for_device, | |
131 | .sync_sg_for_cpu = c6x_dma_sync_sg_for_cpu, | |
132 | }; | |
133 | EXPORT_SYMBOL(c6x_dma_ops); | |
14aa7e8b AJ |
134 | |
135 | /* Number of entries preallocated for DMA-API debugging */ | |
136 | #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) | |
137 | ||
138 | static int __init dma_init(void) | |
139 | { | |
140 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); | |
141 | ||
142 | return 0; | |
143 | } | |
144 | fs_initcall(dma_init); |