diff options
-rw-r--r-- | arch/powerpc/include/asm/dma-mapping.h | 3 | ||||
-rw-r--r-- | arch/powerpc/include/asm/machdep.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/dma-iommu.c | 13 | ||||
-rw-r--r-- | arch/powerpc/kernel/dma.c | 39 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/iommu.c | 12 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/iommu.c | 27 |
6 files changed, 96 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index dd70fac57ec8..8135e66a4bb9 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h | |||
@@ -20,6 +20,8 @@ | |||
20 | 20 | ||
21 | #define DMA_ERROR_CODE (~(dma_addr_t)0x0) | 21 | #define DMA_ERROR_CODE (~(dma_addr_t)0x0) |
22 | 22 | ||
23 | #define ARCH_HAS_DMA_GET_REQUIRED_MASK | ||
24 | |||
23 | /* Some dma direct funcs must be visible for use in other dma_ops */ | 25 | /* Some dma direct funcs must be visible for use in other dma_ops */ |
24 | extern void *dma_direct_alloc_coherent(struct device *dev, size_t size, | 26 | extern void *dma_direct_alloc_coherent(struct device *dev, size_t size, |
25 | dma_addr_t *dma_handle, gfp_t flag); | 27 | dma_addr_t *dma_handle, gfp_t flag); |
@@ -69,6 +71,7 @@ static inline unsigned long device_to_mask(struct device *dev) | |||
69 | */ | 71 | */ |
70 | #ifdef CONFIG_PPC64 | 72 | #ifdef CONFIG_PPC64 |
71 | extern struct dma_map_ops dma_iommu_ops; | 73 | extern struct dma_map_ops dma_iommu_ops; |
74 | extern u64 dma_iommu_get_required_mask(struct device *dev); | ||
72 | #endif | 75 | #endif |
73 | extern struct dma_map_ops dma_direct_ops; | 76 | extern struct dma_map_ops dma_direct_ops; |
74 | 77 | ||
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 47cacddb14cf..58fc21623014 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h | |||
@@ -85,8 +85,9 @@ struct machdep_calls { | |||
85 | void (*pci_dma_dev_setup)(struct pci_dev *dev); | 85 | void (*pci_dma_dev_setup)(struct pci_dev *dev); |
86 | void (*pci_dma_bus_setup)(struct pci_bus *bus); | 86 | void (*pci_dma_bus_setup)(struct pci_bus *bus); |
87 | 87 | ||
88 | /* Platform set_dma_mask override */ | 88 | /* Platform set_dma_mask and dma_get_required_mask overrides */ |
89 | int (*dma_set_mask)(struct device *dev, u64 dma_mask); | 89 | int (*dma_set_mask)(struct device *dev, u64 dma_mask); |
90 | u64 (*dma_get_required_mask)(struct device *dev); | ||
90 | 91 | ||
91 | int (*probe)(void); | 92 | int (*probe)(void); |
92 | void (*setup_arch)(void); /* Optional, may be NULL */ | 93 | void (*setup_arch)(void); /* Optional, may be NULL */ |
diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index e7554154a6de..1f2a711a261e 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c | |||
@@ -90,6 +90,19 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask) | |||
90 | return 1; | 90 | return 1; |
91 | } | 91 | } |
92 | 92 | ||
93 | u64 dma_iommu_get_required_mask(struct device *dev) | ||
94 | { | ||
95 | struct iommu_table *tbl = get_iommu_table_base(dev); | ||
96 | u64 mask; | ||
97 | if (!tbl) | ||
98 | return 0; | ||
99 | |||
100 | mask = 1ULL < (fls_long(tbl->it_offset + tbl->it_size) - 1); | ||
101 | mask += mask - 1; | ||
102 | |||
103 | return mask; | ||
104 | } | ||
105 | |||
93 | struct dma_map_ops dma_iommu_ops = { | 106 | struct dma_map_ops dma_iommu_ops = { |
94 | .alloc_coherent = dma_iommu_alloc_coherent, | 107 | .alloc_coherent = dma_iommu_alloc_coherent, |
95 | .free_coherent = dma_iommu_free_coherent, | 108 | .free_coherent = dma_iommu_free_coherent, |
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 | } |
171 | EXPORT_SYMBOL(dma_set_mask); | 171 | EXPORT_SYMBOL(dma_set_mask); |
172 | 172 | ||
173 | u64 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 | } | ||
210 | EXPORT_SYMBOL_GPL(dma_get_required_mask); | ||
211 | |||
173 | static int __init dma_init(void) | 212 | static int __init dma_init(void) |
174 | { | 213 | { |
175 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); | 214 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); |
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 26a067122a54..5ef55f3b0987 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c | |||
@@ -1159,6 +1159,17 @@ static int __init setup_iommu_fixed(char *str) | |||
1159 | } | 1159 | } |
1160 | __setup("iommu_fixed=", setup_iommu_fixed); | 1160 | __setup("iommu_fixed=", setup_iommu_fixed); |
1161 | 1161 | ||
1162 | static u64 cell_dma_get_required_mask(struct device *dev) | ||
1163 | { | ||
1164 | if (!dev->dma_mask) | ||
1165 | return 0; | ||
1166 | |||
1167 | if (iommu_fixed_disabled && get_dma_ops(dev) == &dma_iommu_ops) | ||
1168 | return dma_iommu_get_required_mask(dev); | ||
1169 | |||
1170 | return DMA_BIT_MASK(64); | ||
1171 | } | ||
1172 | |||
1162 | static int __init cell_iommu_init(void) | 1173 | static int __init cell_iommu_init(void) |
1163 | { | 1174 | { |
1164 | struct device_node *np; | 1175 | struct device_node *np; |
@@ -1175,6 +1186,7 @@ static int __init cell_iommu_init(void) | |||
1175 | 1186 | ||
1176 | /* Setup various ppc_md. callbacks */ | 1187 | /* Setup various ppc_md. callbacks */ |
1177 | ppc_md.pci_dma_dev_setup = cell_pci_dma_dev_setup; | 1188 | ppc_md.pci_dma_dev_setup = cell_pci_dma_dev_setup; |
1189 | ppc_md.dma_get_required_mask = cell_dma_get_required_mask; | ||
1178 | ppc_md.tce_build = tce_build_cell; | 1190 | ppc_md.tce_build = tce_build_cell; |
1179 | ppc_md.tce_free = tce_free_cell; | 1191 | ppc_md.tce_free = tce_free_cell; |
1180 | 1192 | ||
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 01faab9456ca..fe5ededf0d60 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c | |||
@@ -1077,12 +1077,38 @@ check_mask: | |||
1077 | return 0; | 1077 | return 0; |
1078 | } | 1078 | } |
1079 | 1079 | ||
1080 | static u64 dma_get_required_mask_pSeriesLP(struct device *dev) | ||
1081 | { | ||
1082 | if (!dev->dma_mask) | ||
1083 | return 0; | ||
1084 | |||
1085 | if (!disable_ddw && dev_is_pci(dev)) { | ||
1086 | struct pci_dev *pdev = to_pci_dev(dev); | ||
1087 | struct device_node *dn; | ||
1088 | |||
1089 | dn = pci_device_to_OF_node(pdev); | ||
1090 | |||
1091 | /* search upwards for ibm,dma-window */ | ||
1092 | for (; dn && PCI_DN(dn) && !PCI_DN(dn)->iommu_table; | ||
1093 | dn = dn->parent) | ||
1094 | if (of_get_property(dn, "ibm,dma-window", NULL)) | ||
1095 | break; | ||
1096 | /* if there is a ibm,ddw-applicable property require 64 bits */ | ||
1097 | if (dn && PCI_DN(dn) && | ||
1098 | of_get_property(dn, "ibm,ddw-applicable", NULL)) | ||
1099 | return DMA_BIT_MASK(64); | ||
1100 | } | ||
1101 | |||
1102 | return dma_iommu_get_required_mask(dev); | ||
1103 | } | ||
1104 | |||
1080 | #else /* CONFIG_PCI */ | 1105 | #else /* CONFIG_PCI */ |
1081 | #define pci_dma_bus_setup_pSeries NULL | 1106 | #define pci_dma_bus_setup_pSeries NULL |
1082 | #define pci_dma_dev_setup_pSeries NULL | 1107 | #define pci_dma_dev_setup_pSeries NULL |
1083 | #define pci_dma_bus_setup_pSeriesLP NULL | 1108 | #define pci_dma_bus_setup_pSeriesLP NULL |
1084 | #define pci_dma_dev_setup_pSeriesLP NULL | 1109 | #define pci_dma_dev_setup_pSeriesLP NULL |
1085 | #define dma_set_mask_pSeriesLP NULL | 1110 | #define dma_set_mask_pSeriesLP NULL |
1111 | #define dma_get_required_mask_pSeriesLP NULL | ||
1086 | #endif /* !CONFIG_PCI */ | 1112 | #endif /* !CONFIG_PCI */ |
1087 | 1113 | ||
1088 | static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, | 1114 | static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, |
@@ -1186,6 +1212,7 @@ void iommu_init_early_pSeries(void) | |||
1186 | ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP; | 1212 | ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP; |
1187 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP; | 1213 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP; |
1188 | ppc_md.dma_set_mask = dma_set_mask_pSeriesLP; | 1214 | ppc_md.dma_set_mask = dma_set_mask_pSeriesLP; |
1215 | ppc_md.dma_get_required_mask = dma_get_required_mask_pSeriesLP; | ||
1189 | } else { | 1216 | } else { |
1190 | ppc_md.tce_build = tce_build_pSeries; | 1217 | ppc_md.tce_build = tce_build_pSeries; |
1191 | ppc_md.tce_free = tce_free_pSeries; | 1218 | ppc_md.tce_free = tce_free_pSeries; |