diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/iommu.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/iommu.c | 49 |
1 files changed, 21 insertions, 28 deletions
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index a77bcaed80af..edea60b7ee90 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c | |||
@@ -140,7 +140,7 @@ static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, | |||
140 | return ret; | 140 | return ret; |
141 | } | 141 | } |
142 | 142 | ||
143 | static DEFINE_PER_CPU(u64 *, tce_page) = NULL; | 143 | static DEFINE_PER_CPU(u64 *, tce_page); |
144 | 144 | ||
145 | static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, | 145 | static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, |
146 | long npages, unsigned long uaddr, | 146 | long npages, unsigned long uaddr, |
@@ -323,14 +323,13 @@ static void iommu_table_setparms(struct pci_controller *phb, | |||
323 | static void iommu_table_setparms_lpar(struct pci_controller *phb, | 323 | static void iommu_table_setparms_lpar(struct pci_controller *phb, |
324 | struct device_node *dn, | 324 | struct device_node *dn, |
325 | struct iommu_table *tbl, | 325 | struct iommu_table *tbl, |
326 | const void *dma_window, | 326 | const void *dma_window) |
327 | int bussubno) | ||
328 | { | 327 | { |
329 | unsigned long offset, size; | 328 | unsigned long offset, size; |
330 | 329 | ||
331 | tbl->it_busno = bussubno; | ||
332 | of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size); | 330 | of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size); |
333 | 331 | ||
332 | tbl->it_busno = phb->bus->number; | ||
334 | tbl->it_base = 0; | 333 | tbl->it_base = 0; |
335 | tbl->it_blocksize = 16; | 334 | tbl->it_blocksize = 16; |
336 | tbl->it_type = TCE_PCI; | 335 | tbl->it_type = TCE_PCI; |
@@ -450,14 +449,10 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) | |||
450 | if (!ppci->iommu_table) { | 449 | if (!ppci->iommu_table) { |
451 | tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, | 450 | tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, |
452 | ppci->phb->node); | 451 | ppci->phb->node); |
453 | iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window, | 452 | iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); |
454 | bus->number); | ||
455 | ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); | 453 | ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); |
456 | pr_debug(" created table: %p\n", ppci->iommu_table); | 454 | pr_debug(" created table: %p\n", ppci->iommu_table); |
457 | } | 455 | } |
458 | |||
459 | if (pdn != dn) | ||
460 | PCI_DN(dn)->iommu_table = ppci->iommu_table; | ||
461 | } | 456 | } |
462 | 457 | ||
463 | 458 | ||
@@ -533,21 +528,11 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) | |||
533 | } | 528 | } |
534 | pr_debug(" parent is %s\n", pdn->full_name); | 529 | pr_debug(" parent is %s\n", pdn->full_name); |
535 | 530 | ||
536 | /* Check for parent == NULL so we don't try to setup the empty EADS | ||
537 | * slots on POWER4 machines. | ||
538 | */ | ||
539 | if (dma_window == NULL || pdn->parent == NULL) { | ||
540 | pr_debug(" no dma window for device, linking to parent\n"); | ||
541 | set_iommu_table_base(&dev->dev, PCI_DN(pdn)->iommu_table); | ||
542 | return; | ||
543 | } | ||
544 | |||
545 | pci = PCI_DN(pdn); | 531 | pci = PCI_DN(pdn); |
546 | if (!pci->iommu_table) { | 532 | if (!pci->iommu_table) { |
547 | tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, | 533 | tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, |
548 | pci->phb->node); | 534 | pci->phb->node); |
549 | iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window, | 535 | iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window); |
550 | pci->phb->bus->number); | ||
551 | pci->iommu_table = iommu_init_table(tbl, pci->phb->node); | 536 | pci->iommu_table = iommu_init_table(tbl, pci->phb->node); |
552 | pr_debug(" created table: %p\n", pci->iommu_table); | 537 | pr_debug(" created table: %p\n", pci->iommu_table); |
553 | } else { | 538 | } else { |
@@ -571,8 +556,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti | |||
571 | 556 | ||
572 | switch (action) { | 557 | switch (action) { |
573 | case PSERIES_RECONFIG_REMOVE: | 558 | case PSERIES_RECONFIG_REMOVE: |
574 | if (pci && pci->iommu_table && | 559 | if (pci && pci->iommu_table) |
575 | of_get_property(np, "ibm,dma-window", NULL)) | ||
576 | iommu_free_table(pci->iommu_table, np->full_name); | 560 | iommu_free_table(pci->iommu_table, np->full_name); |
577 | break; | 561 | break; |
578 | default: | 562 | default: |
@@ -589,13 +573,8 @@ static struct notifier_block iommu_reconfig_nb = { | |||
589 | /* These are called very early. */ | 573 | /* These are called very early. */ |
590 | void iommu_init_early_pSeries(void) | 574 | void iommu_init_early_pSeries(void) |
591 | { | 575 | { |
592 | if (of_chosen && of_get_property(of_chosen, "linux,iommu-off", NULL)) { | 576 | if (of_chosen && of_get_property(of_chosen, "linux,iommu-off", NULL)) |
593 | /* Direct I/O, IOMMU off */ | ||
594 | ppc_md.pci_dma_dev_setup = NULL; | ||
595 | ppc_md.pci_dma_bus_setup = NULL; | ||
596 | set_pci_dma_ops(&dma_direct_ops); | ||
597 | return; | 577 | return; |
598 | } | ||
599 | 578 | ||
600 | if (firmware_has_feature(FW_FEATURE_LPAR)) { | 579 | if (firmware_has_feature(FW_FEATURE_LPAR)) { |
601 | if (firmware_has_feature(FW_FEATURE_MULTITCE)) { | 580 | if (firmware_has_feature(FW_FEATURE_MULTITCE)) { |
@@ -622,3 +601,17 @@ void iommu_init_early_pSeries(void) | |||
622 | set_pci_dma_ops(&dma_iommu_ops); | 601 | set_pci_dma_ops(&dma_iommu_ops); |
623 | } | 602 | } |
624 | 603 | ||
604 | static int __init disable_multitce(char *str) | ||
605 | { | ||
606 | if (strcmp(str, "off") == 0 && | ||
607 | firmware_has_feature(FW_FEATURE_LPAR) && | ||
608 | firmware_has_feature(FW_FEATURE_MULTITCE)) { | ||
609 | printk(KERN_INFO "Disabling MULTITCE firmware feature\n"); | ||
610 | ppc_md.tce_build = tce_build_pSeriesLP; | ||
611 | ppc_md.tce_free = tce_free_pSeriesLP; | ||
612 | powerpc_firmware_features &= ~FW_FEATURE_MULTITCE; | ||
613 | } | ||
614 | return 1; | ||
615 | } | ||
616 | |||
617 | __setup("multitce=", disable_multitce); | ||