Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc: Add support for swiotlb on 32-bit

This patch includes the basic infrastructure to use swiotlb
bounce buffering on 32-bit powerpc. It is not yet enabled on
any platforms. Probably the most interesting bit is the
addition of addr_needs_map to dma_ops - we need this as
a dma_op because the decision of whether or not an addr
can be mapped by a device is device-specific.

Signed-off-by: Becky Bruce <beckyb@kernel.crashing.org>
Acked-by: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Becky Bruce and committed by
Benjamin Herrenschmidt
ec3cf2ec 1babddbc

+226 -2
+11 -1
arch/powerpc/Kconfig
··· 300 300 config IOMMU_HELPER 301 301 def_bool PPC64 302 302 303 + config SWIOTLB 304 + bool "SWIOTLB support" 305 + default n 306 + select IOMMU_HELPER 307 + ---help--- 308 + Support for IO bounce buffering for systems without an IOMMU. 309 + This allows us to DMA to the full physical address space on 310 + platforms where the size of a physical address is larger 311 + than the bus address. Not all platforms support this. 312 + 303 313 config PPC_NEED_DMA_SYNC_OPS 304 314 def_bool y 305 - depends on NOT_COHERENT_CACHE 315 + depends on (NOT_COHERENT_CACHE || SWIOTLB) 306 316 307 317 config HOTPLUG_CPU 308 318 bool "Support for enabling/disabling CPUs"
+11
arch/powerpc/include/asm/dma-mapping.h
··· 15 15 #include <linux/scatterlist.h> 16 16 #include <linux/dma-attrs.h> 17 17 #include <asm/io.h> 18 + #include <asm/swiotlb.h> 18 19 19 20 #define DMA_ERROR_CODE (~(dma_addr_t)0x0) 21 + 22 + /* Some dma direct funcs must be visible for use in other dma_ops */ 23 + extern void *dma_direct_alloc_coherent(struct device *dev, size_t size, 24 + dma_addr_t *dma_handle, gfp_t flag); 25 + extern void dma_direct_free_coherent(struct device *dev, size_t size, 26 + void *vaddr, dma_addr_t dma_handle); 27 + 28 + extern unsigned long get_dma_direct_offset(struct device *dev); 20 29 21 30 #ifdef CONFIG_NOT_COHERENT_CACHE 22 31 /* ··· 87 78 dma_addr_t dma_address, size_t size, 88 79 enum dma_data_direction direction, 89 80 struct dma_attrs *attrs); 81 + int (*addr_needs_map)(struct device *dev, dma_addr_t addr, 82 + size_t size); 90 83 #ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS 91 84 void (*sync_single_range_for_cpu)(struct device *hwdev, 92 85 dma_addr_t dma_handle, unsigned long offset,
+27
arch/powerpc/include/asm/swiotlb.h
··· 1 + /* 2 + * Copyright (C) 2009 Becky Bruce, Freescale Semiconductor 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms of the GNU General Public License as published by the 6 + * Free Software Foundation; either version 2 of the License, or (at your 7 + * option) any later version. 8 + * 9 + */ 10 + 11 + #ifndef __ASM_SWIOTLB_H 12 + #define __ASM_SWIOTLB_H 13 + 14 + #include <linux/swiotlb.h> 15 + 16 + extern struct dma_mapping_ops swiotlb_dma_ops; 17 + extern struct dma_mapping_ops swiotlb_pci_dma_ops; 18 + 19 + int swiotlb_arch_address_needs_mapping(struct device *, dma_addr_t, 20 + size_t size); 21 + 22 + static inline void dma_mark_clean(void *addr, size_t size) {} 23 + 24 + extern unsigned int ppc_swiotlb_enable; 25 + int __init swiotlb_setup_bus_notifier(void); 26 + 27 + #endif /* __ASM_SWIOTLB_H */
+1
arch/powerpc/kernel/Makefile
··· 82 82 obj-$(CONFIG_KPROBES) += kprobes.o 83 83 obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o 84 84 obj-$(CONFIG_STACKTRACE) += stacktrace.o 85 + obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o 85 86 86 87 pci64-$(CONFIG_PPC64) += pci_dn.o isa-bridge.o 87 88 obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
+163
arch/powerpc/kernel/dma-swiotlb.c
··· 1 + /* 2 + * Contains routines needed to support swiotlb for ppc. 3 + * 4 + * Copyright (C) 2009 Becky Bruce, Freescale Semiconductor 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License as published by the 8 + * Free Software Foundation; either version 2 of the License, or (at your 9 + * option) any later version. 10 + * 11 + */ 12 + 13 + #include <linux/dma-mapping.h> 14 + #include <linux/pfn.h> 15 + #include <linux/of_platform.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/pci.h> 18 + 19 + #include <asm/machdep.h> 20 + #include <asm/swiotlb.h> 21 + #include <asm/dma.h> 22 + #include <asm/abs_addr.h> 23 + 24 + int swiotlb __read_mostly; 25 + unsigned int ppc_swiotlb_enable; 26 + 27 + void *swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t addr) 28 + { 29 + unsigned long pfn = PFN_DOWN(swiotlb_bus_to_phys(hwdev, addr)); 30 + void *pageaddr = page_address(pfn_to_page(pfn)); 31 + 32 + if (pageaddr != NULL) 33 + return pageaddr + (addr % PAGE_SIZE); 34 + return NULL; 35 + } 36 + 37 + dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) 38 + { 39 + return paddr + get_dma_direct_offset(hwdev); 40 + } 41 + 42 + phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) 43 + 44 + { 45 + return baddr - get_dma_direct_offset(hwdev); 46 + } 47 + 48 + /* 49 + * Determine if an address needs bounce buffering via swiotlb. 50 + * Going forward I expect the swiotlb code to generalize on using 51 + * a dma_ops->addr_needs_map, and this function will move from here to the 52 + * generic swiotlb code. 53 + */ 54 + int 55 + swiotlb_arch_address_needs_mapping(struct device *hwdev, dma_addr_t addr, 56 + size_t size) 57 + { 58 + struct dma_mapping_ops *dma_ops = get_dma_ops(hwdev); 59 + 60 + BUG_ON(!dma_ops); 61 + return dma_ops->addr_needs_map(hwdev, addr, size); 62 + } 63 + 64 + /* 65 + * Determine if an address is reachable by a pci device, or if we must bounce. 66 + */ 67 + static int 68 + swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size) 69 + { 70 + u64 mask = dma_get_mask(hwdev); 71 + dma_addr_t max; 72 + struct pci_controller *hose; 73 + struct pci_dev *pdev = to_pci_dev(hwdev); 74 + 75 + hose = pci_bus_to_host(pdev->bus); 76 + max = hose->dma_window_base_cur + hose->dma_window_size; 77 + 78 + /* check that we're within mapped pci window space */ 79 + if ((addr + size > max) | (addr < hose->dma_window_base_cur)) 80 + return 1; 81 + 82 + return !is_buffer_dma_capable(mask, addr, size); 83 + } 84 + 85 + static int 86 + swiotlb_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size) 87 + { 88 + return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size); 89 + } 90 + 91 + 92 + /* 93 + * At the moment, all platforms that use this code only require 94 + * swiotlb to be used if we're operating on HIGHMEM. Since 95 + * we don't ever call anything other than map_sg, unmap_sg, 96 + * map_page, and unmap_page on highmem, use normal dma_ops 97 + * for everything else. 98 + */ 99 + struct dma_mapping_ops swiotlb_dma_ops = { 100 + .alloc_coherent = dma_direct_alloc_coherent, 101 + .free_coherent = dma_direct_free_coherent, 102 + .map_sg = swiotlb_map_sg_attrs, 103 + .unmap_sg = swiotlb_unmap_sg_attrs, 104 + .dma_supported = swiotlb_dma_supported, 105 + .map_page = swiotlb_map_page, 106 + .unmap_page = swiotlb_unmap_page, 107 + .addr_needs_map = swiotlb_addr_needs_map, 108 + .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu, 109 + .sync_single_range_for_device = swiotlb_sync_single_range_for_device, 110 + .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, 111 + .sync_sg_for_device = swiotlb_sync_sg_for_device 112 + }; 113 + 114 + struct dma_mapping_ops swiotlb_pci_dma_ops = { 115 + .alloc_coherent = dma_direct_alloc_coherent, 116 + .free_coherent = dma_direct_free_coherent, 117 + .map_sg = swiotlb_map_sg_attrs, 118 + .unmap_sg = swiotlb_unmap_sg_attrs, 119 + .dma_supported = swiotlb_dma_supported, 120 + .map_page = swiotlb_map_page, 121 + .unmap_page = swiotlb_unmap_page, 122 + .addr_needs_map = swiotlb_pci_addr_needs_map, 123 + .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu, 124 + .sync_single_range_for_device = swiotlb_sync_single_range_for_device, 125 + .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, 126 + .sync_sg_for_device = swiotlb_sync_sg_for_device 127 + }; 128 + 129 + static int ppc_swiotlb_bus_notify(struct notifier_block *nb, 130 + unsigned long action, void *data) 131 + { 132 + struct device *dev = data; 133 + 134 + /* We are only intereted in device addition */ 135 + if (action != BUS_NOTIFY_ADD_DEVICE) 136 + return 0; 137 + 138 + /* May need to bounce if the device can't address all of DRAM */ 139 + if (dma_get_mask(dev) < lmb_end_of_DRAM()) 140 + set_dma_ops(dev, &swiotlb_dma_ops); 141 + 142 + return NOTIFY_DONE; 143 + } 144 + 145 + static struct notifier_block ppc_swiotlb_plat_bus_notifier = { 146 + .notifier_call = ppc_swiotlb_bus_notify, 147 + .priority = 0, 148 + }; 149 + 150 + static struct notifier_block ppc_swiotlb_of_bus_notifier = { 151 + .notifier_call = ppc_swiotlb_bus_notify, 152 + .priority = 0, 153 + }; 154 + 155 + int __init swiotlb_setup_bus_notifier(void) 156 + { 157 + bus_register_notifier(&platform_bus_type, 158 + &ppc_swiotlb_plat_bus_notifier); 159 + bus_register_notifier(&of_platform_bus_type, 160 + &ppc_swiotlb_of_bus_notifier); 161 + 162 + return 0; 163 + }
+1 -1
arch/powerpc/kernel/dma.c
··· 19 19 * default the offset is PCI_DRAM_OFFSET. 20 20 */ 21 21 22 - static unsigned long get_dma_direct_offset(struct device *dev) 22 + unsigned long get_dma_direct_offset(struct device *dev) 23 23 { 24 24 if (dev) 25 25 return (unsigned long)dev->archdata.dma_data;
+6
arch/powerpc/kernel/setup_32.c
··· 39 39 #include <asm/serial.h> 40 40 #include <asm/udbg.h> 41 41 #include <asm/mmu_context.h> 42 + #include <asm/swiotlb.h> 42 43 43 44 #include "setup.h" 44 45 ··· 332 331 if (ppc_md.setup_arch) 333 332 ppc_md.setup_arch(); 334 333 if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); 334 + 335 + #ifdef CONFIG_SWIOTLB 336 + if (ppc_swiotlb_enable) 337 + swiotlb_init(); 338 + #endif 335 339 336 340 paging_init(); 337 341
+6
arch/powerpc/kernel/setup_64.c
··· 61 61 #include <asm/xmon.h> 62 62 #include <asm/udbg.h> 63 63 #include <asm/kexec.h> 64 + #include <asm/swiotlb.h> 64 65 65 66 #include "setup.h" 66 67 ··· 527 526 528 527 if (ppc_md.setup_arch) 529 528 ppc_md.setup_arch(); 529 + 530 + #ifdef CONFIG_SWIOTLB 531 + if (ppc_swiotlb_enable) 532 + swiotlb_init(); 533 + #endif 530 534 531 535 paging_init(); 532 536 ppc64_boot_msg(0x15, "Setup Done");