aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/dma.c
diff options
context:
space:
mode:
authorMilton Miller <miltonm@bga.com>2011-06-24 05:05:22 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-09-01 02:00:19 -0400
commit6a5c7be5e484bda5b2639fedf7dbe3f25c15c962 (patch)
treecdb637e152a4403bc1feaa9034f184c579560057 /arch/powerpc/kernel/dma.c
parentce395088832bfd56bd28824b31a6a3685f3fd339 (diff)
powerpc: Override dma_get_required_mask by platform hook and ops
The hook dma_get_required_mask is supposed to return the mask required by the platform to operate efficently. The generic version of dma_get_required_mask in driver/base/platform.c returns a mask based only on max_pfn. However, this is likely too big for iommu systems and could be too small for platforms that require a dma offset or have a secondary window at a high offset. Override the default, provide a hook in ppc_md used by pseries lpar and cell, and provide the default answer based on memblock_end_of_DRAM(), with hooks for get_dma_offset, and provide an implementation for iommu that looks at the defined table size. Coverting from the end address to the required bit mask is based on the generic implementation. The need for this was discovered when the qla2xxx driver switched to 64 bit dma then reverted to 32 bit when dma_get_required_mask said 32 bits was sufficient. Signed-off-by: Milton Miller <miltonm@bga.com> Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org Cc: benh@kernel.crashing.org Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/dma.c')
-rw-r--r--arch/powerpc/kernel/dma.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 4f0959fbfbee..503093efa202 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -170,6 +170,45 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
170} 170}
171EXPORT_SYMBOL(dma_set_mask); 171EXPORT_SYMBOL(dma_set_mask);
172 172
173u64 dma_get_required_mask(struct device *dev)
174{
175 struct dma_map_ops *dma_ops = get_dma_ops(dev);
176 u64 mask, end = 0;
177
178 if (ppc_md.dma_get_required_mask)
179 return ppc_md.dma_get_required_mask(dev);
180
181 if (unlikely(dma_ops == NULL))
182 return 0;
183
184#ifdef CONFIG_PPC64
185 else if (dma_ops == &dma_iommu_ops)
186 return dma_iommu_get_required_mask(dev);
187#endif
188#ifdef CONFIG_SWIOTLB
189 else if (dma_ops == &swiotlb_dma_ops) {
190 u64 max_direct_dma_addr = dev->archdata.max_direct_dma_addr;
191
192 end = memblock_end_of_DRAM();
193 if (max_direct_dma_addr && end > max_direct_dma_addr)
194 end = max_direct_dma_addr;
195 end += get_dma_offset(dev);
196 }
197#endif
198 else if (dma_ops == &dma_direct_ops)
199 end = memblock_end_of_DRAM() + get_dma_offset(dev);
200 else {
201 WARN_ONCE(1, "%s: unknown ops %p\n", __func__, dma_ops);
202 end = memblock_end_of_DRAM();
203 }
204
205 mask = 1ULL << (fls64(end) - 1);
206 mask += mask - 1;
207
208 return mask;
209}
210EXPORT_SYMBOL_GPL(dma_get_required_mask);
211
173static int __init dma_init(void) 212static int __init dma_init(void)
174{ 213{
175 dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); 214 dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);