diff options
Diffstat (limited to 'arch/powerpc/sysdev/dart_iommu.c')
-rw-r--r-- | arch/powerpc/sysdev/dart_iommu.c | 74 |
1 files changed, 64 insertions, 10 deletions
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 559db2b846a9..17cf15ec38be 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c | |||
@@ -70,6 +70,8 @@ static int iommu_table_dart_inited; | |||
70 | static int dart_dirty; | 70 | static int dart_dirty; |
71 | static int dart_is_u4; | 71 | static int dart_is_u4; |
72 | 72 | ||
73 | #define DART_U4_BYPASS_BASE 0x8000000000ull | ||
74 | |||
73 | #define DBG(...) | 75 | #define DBG(...) |
74 | 76 | ||
75 | static inline void dart_tlb_invalidate_all(void) | 77 | static inline void dart_tlb_invalidate_all(void) |
@@ -292,12 +294,20 @@ static void iommu_table_dart_setup(void) | |||
292 | set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map); | 294 | set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map); |
293 | } | 295 | } |
294 | 296 | ||
295 | static void pci_dma_dev_setup_dart(struct pci_dev *dev) | 297 | static void dma_dev_setup_dart(struct device *dev) |
296 | { | 298 | { |
297 | /* We only have one iommu table on the mac for now, which makes | 299 | /* We only have one iommu table on the mac for now, which makes |
298 | * things simple. Setup all PCI devices to point to this table | 300 | * things simple. Setup all PCI devices to point to this table |
299 | */ | 301 | */ |
300 | set_iommu_table_base(&dev->dev, &iommu_table_dart); | 302 | if (get_dma_ops(dev) == &dma_direct_ops) |
303 | set_dma_offset(dev, DART_U4_BYPASS_BASE); | ||
304 | else | ||
305 | set_iommu_table_base(dev, &iommu_table_dart); | ||
306 | } | ||
307 | |||
308 | static void pci_dma_dev_setup_dart(struct pci_dev *dev) | ||
309 | { | ||
310 | dma_dev_setup_dart(&dev->dev); | ||
301 | } | 311 | } |
302 | 312 | ||
303 | static void pci_dma_bus_setup_dart(struct pci_bus *bus) | 313 | static void pci_dma_bus_setup_dart(struct pci_bus *bus) |
@@ -315,6 +325,45 @@ static void pci_dma_bus_setup_dart(struct pci_bus *bus) | |||
315 | PCI_DN(dn)->iommu_table = &iommu_table_dart; | 325 | PCI_DN(dn)->iommu_table = &iommu_table_dart; |
316 | } | 326 | } |
317 | 327 | ||
328 | static bool dart_device_on_pcie(struct device *dev) | ||
329 | { | ||
330 | struct device_node *np = of_node_get(dev->of_node); | ||
331 | |||
332 | while(np) { | ||
333 | if (of_device_is_compatible(np, "U4-pcie") || | ||
334 | of_device_is_compatible(np, "u4-pcie")) { | ||
335 | of_node_put(np); | ||
336 | return true; | ||
337 | } | ||
338 | np = of_get_next_parent(np); | ||
339 | } | ||
340 | return false; | ||
341 | } | ||
342 | |||
343 | static int dart_dma_set_mask(struct device *dev, u64 dma_mask) | ||
344 | { | ||
345 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | ||
346 | return -EIO; | ||
347 | |||
348 | /* U4 supports a DART bypass, we use it for 64-bit capable | ||
349 | * devices to improve performances. However, that only works | ||
350 | * for devices connected to U4 own PCIe interface, not bridged | ||
351 | * through hypertransport. We need the device to support at | ||
352 | * least 40 bits of addresses. | ||
353 | */ | ||
354 | if (dart_device_on_pcie(dev) && dma_mask >= DMA_BIT_MASK(40)) { | ||
355 | dev_info(dev, "Using 64-bit DMA iommu bypass\n"); | ||
356 | set_dma_ops(dev, &dma_direct_ops); | ||
357 | } else { | ||
358 | dev_info(dev, "Using 32-bit DMA via iommu\n"); | ||
359 | set_dma_ops(dev, &dma_iommu_ops); | ||
360 | } | ||
361 | dma_dev_setup_dart(dev); | ||
362 | |||
363 | *dev->dma_mask = dma_mask; | ||
364 | return 0; | ||
365 | } | ||
366 | |||
318 | void __init iommu_init_early_dart(void) | 367 | void __init iommu_init_early_dart(void) |
319 | { | 368 | { |
320 | struct device_node *dn; | 369 | struct device_node *dn; |
@@ -328,20 +377,25 @@ void __init iommu_init_early_dart(void) | |||
328 | dart_is_u4 = 1; | 377 | dart_is_u4 = 1; |
329 | } | 378 | } |
330 | 379 | ||
380 | /* Initialize the DART HW */ | ||
381 | if (dart_init(dn) != 0) | ||
382 | goto bail; | ||
383 | |||
331 | /* Setup low level TCE operations for the core IOMMU code */ | 384 | /* Setup low level TCE operations for the core IOMMU code */ |
332 | ppc_md.tce_build = dart_build; | 385 | ppc_md.tce_build = dart_build; |
333 | ppc_md.tce_free = dart_free; | 386 | ppc_md.tce_free = dart_free; |
334 | ppc_md.tce_flush = dart_flush; | 387 | ppc_md.tce_flush = dart_flush; |
335 | 388 | ||
336 | /* Initialize the DART HW */ | 389 | /* Setup bypass if supported */ |
337 | if (dart_init(dn) == 0) { | 390 | if (dart_is_u4) |
338 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart; | 391 | ppc_md.dma_set_mask = dart_dma_set_mask; |
339 | ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart; | ||
340 | 392 | ||
341 | /* Setup pci_dma ops */ | 393 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart; |
342 | set_pci_dma_ops(&dma_iommu_ops); | 394 | ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart; |
343 | return; | 395 | |
344 | } | 396 | /* Setup pci_dma ops */ |
397 | set_pci_dma_ops(&dma_iommu_ops); | ||
398 | return; | ||
345 | 399 | ||
346 | bail: | 400 | bail: |
347 | /* If init failed, use direct iommu and null setup functions */ | 401 | /* If init failed, use direct iommu and null setup functions */ |