Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (c) 2004 Hewlett-Packard Development Company, L.P. | |
3 | * Contributed by David Mosberger-Tang <davidm@hpl.hp.com> | |
4 | * | |
5 | * This is a pseudo I/O MMU which dispatches to the hardware I/O MMU | |
6 | * whenever possible. We assume that the hardware I/O MMU requires | |
7 | * full 32-bit addressability, as is the case, e.g., for HP zx1-based | |
8 | * systems (there, the I/O MMU window is mapped at 3-4GB). If a | |
9 | * device doesn't provide full 32-bit addressability, we fall back on | |
10 | * the sw I/O TLB. This is good enough to let us support broken | |
11 | * hardware such as soundcards which have a DMA engine that can | |
12 | * address only 28 bits. | |
13 | */ | |
14 | ||
15 | #include <linux/device.h> | |
16 | ||
17 | #include <asm/machvec.h> | |
18 | ||
19 | /* swiotlb declarations & definitions: */ | |
0b9afede | 20 | extern int swiotlb_late_init_with_default_size (size_t size); |
1da177e4 LT |
21 | extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent; |
22 | extern ia64_mv_dma_free_coherent swiotlb_free_coherent; | |
23 | extern ia64_mv_dma_map_single swiotlb_map_single; | |
24 | extern ia64_mv_dma_unmap_single swiotlb_unmap_single; | |
25 | extern ia64_mv_dma_map_sg swiotlb_map_sg; | |
26 | extern ia64_mv_dma_unmap_sg swiotlb_unmap_sg; | |
27 | extern ia64_mv_dma_supported swiotlb_dma_supported; | |
28 | extern ia64_mv_dma_mapping_error swiotlb_dma_mapping_error; | |
29 | ||
30 | /* hwiommu declarations & definitions: */ | |
31 | ||
32 | extern ia64_mv_dma_alloc_coherent sba_alloc_coherent; | |
33 | extern ia64_mv_dma_free_coherent sba_free_coherent; | |
34 | extern ia64_mv_dma_map_single sba_map_single; | |
35 | extern ia64_mv_dma_unmap_single sba_unmap_single; | |
36 | extern ia64_mv_dma_map_sg sba_map_sg; | |
37 | extern ia64_mv_dma_unmap_sg sba_unmap_sg; | |
38 | extern ia64_mv_dma_supported sba_dma_supported; | |
39 | extern ia64_mv_dma_mapping_error sba_dma_mapping_error; | |
40 | ||
41 | #define hwiommu_alloc_coherent sba_alloc_coherent | |
42 | #define hwiommu_free_coherent sba_free_coherent | |
43 | #define hwiommu_map_single sba_map_single | |
44 | #define hwiommu_unmap_single sba_unmap_single | |
45 | #define hwiommu_map_sg sba_map_sg | |
46 | #define hwiommu_unmap_sg sba_unmap_sg | |
47 | #define hwiommu_dma_supported sba_dma_supported | |
48 | #define hwiommu_dma_mapping_error sba_dma_mapping_error | |
49 | #define hwiommu_sync_single_for_cpu machvec_dma_sync_single | |
50 | #define hwiommu_sync_sg_for_cpu machvec_dma_sync_sg | |
51 | #define hwiommu_sync_single_for_device machvec_dma_sync_single | |
52 | #define hwiommu_sync_sg_for_device machvec_dma_sync_sg | |
53 | ||
54 | ||
55 | /* | |
56 | * Note: we need to make the determination of whether or not to use | |
57 | * the sw I/O TLB based purely on the device structure. Anything else | |
58 | * would be unreliable or would be too intrusive. | |
59 | */ | |
60 | static inline int | |
61 | use_swiotlb (struct device *dev) | |
62 | { | |
63 | return dev && dev->dma_mask && !hwiommu_dma_supported(dev, *dev->dma_mask); | |
64 | } | |
65 | ||
9a86bbb9 | 66 | void __init |
1da177e4 LT |
67 | hwsw_init (void) |
68 | { | |
69 | /* default to a smallish 2MB sw I/O TLB */ | |
0b9afede AW |
70 | if (swiotlb_late_init_with_default_size (2 * (1<<20)) != 0) { |
71 | #ifdef CONFIG_IA64_GENERIC | |
72 | /* Better to have normal DMA than panic */ | |
73 | printk(KERN_WARNING "%s: Failed to initialize software I/O TLB," | |
d4ed8084 | 74 | " reverting to hpzx1 platform vector\n", __func__); |
0b9afede AW |
75 | machvec_init("hpzx1"); |
76 | #else | |
77 | panic("Unable to initialize software I/O TLB services"); | |
78 | #endif | |
79 | } | |
1da177e4 LT |
80 | } |
81 | ||
82 | void * | |
06a54497 | 83 | hwsw_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags) |
1da177e4 LT |
84 | { |
85 | if (use_swiotlb(dev)) | |
86 | return swiotlb_alloc_coherent(dev, size, dma_handle, flags); | |
87 | else | |
88 | return hwiommu_alloc_coherent(dev, size, dma_handle, flags); | |
89 | } | |
90 | ||
91 | void | |
92 | hwsw_free_coherent (struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle) | |
93 | { | |
94 | if (use_swiotlb(dev)) | |
95 | swiotlb_free_coherent(dev, size, vaddr, dma_handle); | |
96 | else | |
97 | hwiommu_free_coherent(dev, size, vaddr, dma_handle); | |
98 | } | |
99 | ||
100 | dma_addr_t | |
101 | hwsw_map_single (struct device *dev, void *addr, size_t size, int dir) | |
102 | { | |
103 | if (use_swiotlb(dev)) | |
104 | return swiotlb_map_single(dev, addr, size, dir); | |
105 | else | |
106 | return hwiommu_map_single(dev, addr, size, dir); | |
107 | } | |
108 | ||
109 | void | |
110 | hwsw_unmap_single (struct device *dev, dma_addr_t iova, size_t size, int dir) | |
111 | { | |
112 | if (use_swiotlb(dev)) | |
113 | return swiotlb_unmap_single(dev, iova, size, dir); | |
114 | else | |
115 | return hwiommu_unmap_single(dev, iova, size, dir); | |
116 | } | |
117 | ||
118 | ||
119 | int | |
120 | hwsw_map_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir) | |
121 | { | |
122 | if (use_swiotlb(dev)) | |
123 | return swiotlb_map_sg(dev, sglist, nents, dir); | |
124 | else | |
125 | return hwiommu_map_sg(dev, sglist, nents, dir); | |
126 | } | |
127 | ||
128 | void | |
129 | hwsw_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir) | |
130 | { | |
131 | if (use_swiotlb(dev)) | |
132 | return swiotlb_unmap_sg(dev, sglist, nents, dir); | |
133 | else | |
134 | return hwiommu_unmap_sg(dev, sglist, nents, dir); | |
135 | } | |
136 | ||
137 | void | |
138 | hwsw_sync_single_for_cpu (struct device *dev, dma_addr_t addr, size_t size, int dir) | |
139 | { | |
140 | if (use_swiotlb(dev)) | |
141 | swiotlb_sync_single_for_cpu(dev, addr, size, dir); | |
142 | else | |
143 | hwiommu_sync_single_for_cpu(dev, addr, size, dir); | |
144 | } | |
145 | ||
146 | void | |
147 | hwsw_sync_sg_for_cpu (struct device *dev, struct scatterlist *sg, int nelems, int dir) | |
148 | { | |
149 | if (use_swiotlb(dev)) | |
150 | swiotlb_sync_sg_for_cpu(dev, sg, nelems, dir); | |
151 | else | |
152 | hwiommu_sync_sg_for_cpu(dev, sg, nelems, dir); | |
153 | } | |
154 | ||
155 | void | |
156 | hwsw_sync_single_for_device (struct device *dev, dma_addr_t addr, size_t size, int dir) | |
157 | { | |
158 | if (use_swiotlb(dev)) | |
159 | swiotlb_sync_single_for_device(dev, addr, size, dir); | |
160 | else | |
161 | hwiommu_sync_single_for_device(dev, addr, size, dir); | |
162 | } | |
163 | ||
164 | void | |
165 | hwsw_sync_sg_for_device (struct device *dev, struct scatterlist *sg, int nelems, int dir) | |
166 | { | |
167 | if (use_swiotlb(dev)) | |
168 | swiotlb_sync_sg_for_device(dev, sg, nelems, dir); | |
169 | else | |
170 | hwiommu_sync_sg_for_device(dev, sg, nelems, dir); | |
171 | } | |
172 | ||
173 | int | |
174 | hwsw_dma_supported (struct device *dev, u64 mask) | |
175 | { | |
176 | if (hwiommu_dma_supported(dev, mask)) | |
177 | return 1; | |
178 | return swiotlb_dma_supported(dev, mask); | |
179 | } | |
180 | ||
181 | int | |
182 | hwsw_dma_mapping_error (dma_addr_t dma_addr) | |
183 | { | |
184 | return hwiommu_dma_mapping_error (dma_addr) || swiotlb_dma_mapping_error(dma_addr); | |
185 | } | |
186 | ||
187 | EXPORT_SYMBOL(hwsw_dma_mapping_error); | |
188 | EXPORT_SYMBOL(hwsw_map_single); | |
189 | EXPORT_SYMBOL(hwsw_unmap_single); | |
190 | EXPORT_SYMBOL(hwsw_map_sg); | |
191 | EXPORT_SYMBOL(hwsw_unmap_sg); | |
192 | EXPORT_SYMBOL(hwsw_dma_supported); | |
193 | EXPORT_SYMBOL(hwsw_alloc_coherent); | |
194 | EXPORT_SYMBOL(hwsw_free_coherent); | |
671496af JB |
195 | EXPORT_SYMBOL(hwsw_sync_single_for_cpu); |
196 | EXPORT_SYMBOL(hwsw_sync_single_for_device); | |
197 | EXPORT_SYMBOL(hwsw_sync_sg_for_cpu); | |
198 | EXPORT_SYMBOL(hwsw_sync_sg_for_device); |