Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /* * arch/ppc64/kernel/pci_iommu.c * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation * * Rewrite, cleanup, new allocation schemes: * Copyright (C) 2004 Olof Johansson, IBM Corporation * * Dynamic DMA mapping support, platform-independent parts. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/config.h> #include <linux/init.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/spinlock.h> #include <linux/string.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/iommu.h> #include <asm/pci-bridge.h> #include <asm/machdep.h> #include "pci.h" #ifdef CONFIG_PPC_ISERIES #include <asm/iSeries/iSeries_pci.h> #endif /* CONFIG_PPC_ISERIES */ /* * We can use ->sysdata directly and avoid the extra work in * pci_device_to_OF_node since ->sysdata will have been initialised * in the iommu init code for all devices. */ #define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata)) static inline struct iommu_table *devnode_table(struct pci_dev *dev) { if (!dev) dev = ppc64_isabridge_dev; if (!dev) return NULL; #ifdef CONFIG_PPC_ISERIES return ISERIES_DEVNODE(dev)->iommu_table; #endif /* CONFIG_PPC_ISERIES */ #ifdef CONFIG_PPC_MULTIPLATFORM return PCI_GET_DN(dev)->iommu_table; #endif /* CONFIG_PPC_MULTIPLATFORM */ } /* Allocates a contiguous real buffer and creates mappings over it. * Returns the virtual address of the buffer and sets dma_handle * to the dma address (mapping) of the first page. */ static void *pci_iommu_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { return iommu_alloc_consistent(devnode_table(hwdev), size, dma_handle); } static void pci_iommu_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { iommu_free_consistent(devnode_table(hwdev), size, vaddr, dma_handle); } /* Creates TCEs for a user provided buffer. The user buffer must be * contiguous real kernel storage (not vmalloc). The address of the buffer * passed here is the kernel (virtual) address of the buffer. The buffer * need not be page aligned, the dma_addr_t returned will point to the same * byte within the page as vaddr. */ static dma_addr_t pci_iommu_map_single(struct pci_dev *hwdev, void *vaddr, size_t size, enum dma_data_direction direction) { return iommu_map_single(devnode_table(hwdev), vaddr, size, direction); } static void pci_iommu_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { iommu_unmap_single(devnode_table(hwdev), dma_handle, size, direction); } static int pci_iommu_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { return iommu_map_sg(&pdev->dev, devnode_table(pdev), sglist, nelems, direction); } static void pci_iommu_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { iommu_unmap_sg(devnode_table(pdev), sglist, nelems, direction); } /* We support DMA to/from any memory page via the iommu */ static int pci_iommu_dma_supported(struct pci_dev *pdev, u64 mask) { return 1; } void pci_iommu_init(void) { pci_dma_ops.pci_alloc_consistent = pci_iommu_alloc_consistent; pci_dma_ops.pci_free_consistent = pci_iommu_free_consistent; pci_dma_ops.pci_map_single = pci_iommu_map_single; pci_dma_ops.pci_unmap_single = pci_iommu_unmap_single; pci_dma_ops.pci_map_sg = pci_iommu_map_sg; pci_dma_ops.pci_unmap_sg = pci_iommu_unmap_sg; pci_dma_ops.pci_dma_supported = pci_iommu_dma_supported; } |