aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2013-11-21 01:43:14 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-12-05 00:08:17 -0500
commitd905c5df9aef38d63df268f6f5e7b13894f626d3 (patch)
tree621cbfdcb57729e5ec60c6ffe19aa670818381b8 /arch
parent7e1ce5a492e18449fd47ef6305b26e0c572d26e9 (diff)
PPC: POWERNV: move iommu_add_device earlier
The current implementation of IOMMU on sPAPR does not use iommu_ops and therefore does not call IOMMU API's bus_set_iommu() which 1) sets iommu_ops for a bus 2) registers a bus notifier Instead, PCI devices are added to IOMMU groups from subsys_initcall_sync(tce_iommu_init) which does basically the same thing without using iommu_ops callbacks. However Freescale PAMU driver (https://lkml.org/lkml/2013/7/1/158) implements iommu_ops and when tce_iommu_init is called, every PCI device is already added to some group so there is a conflict. This patch does 2 things: 1. removes the loop in which PCI devices were added to groups and adds explicit iommu_add_device() calls to add devices as soon as they get the iommu_table pointer assigned to them. 2. moves a bus notifier to powernv code in order to avoid conflict with the notifier from Freescale driver. iommu_add_device() and iommu_del_device() are public now. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/iommu.h26
-rw-r--r--arch/powerpc/kernel/iommu.c48
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c8
-rw-r--r--arch/powerpc/platforms/powernv/pci-p5ioc2.c2
-rw-r--r--arch/powerpc/platforms/powernv/pci.c33
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c8
6 files changed, 72 insertions, 53 deletions
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index c34656a8925e..774fa2776907 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -101,8 +101,34 @@ extern void iommu_free_table(struct iommu_table *tbl, const char *node_name);
101 */ 101 */
102extern struct iommu_table *iommu_init_table(struct iommu_table * tbl, 102extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
103 int nid); 103 int nid);
104#ifdef CONFIG_IOMMU_API
104extern void iommu_register_group(struct iommu_table *tbl, 105extern void iommu_register_group(struct iommu_table *tbl,
105 int pci_domain_number, unsigned long pe_num); 106 int pci_domain_number, unsigned long pe_num);
107extern int iommu_add_device(struct device *dev);
108extern void iommu_del_device(struct device *dev);
109#else
110static inline void iommu_register_group(struct iommu_table *tbl,
111 int pci_domain_number,
112 unsigned long pe_num)
113{
114}
115
116static inline int iommu_add_device(struct device *dev)
117{
118 return 0;
119}
120
121static inline void iommu_del_device(struct device *dev)
122{
123}
124#endif /* !CONFIG_IOMMU_API */
125
126static inline void set_iommu_table_base_and_group(struct device *dev,
127 void *base)
128{
129 set_iommu_table_base(dev, base);
130 iommu_add_device(dev);
131}
106 132
107extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, 133extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
108 struct scatterlist *sglist, int nelems, 134 struct scatterlist *sglist, int nelems,
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 572bb5b95f35..d22abe0b08e3 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -1105,7 +1105,7 @@ void iommu_release_ownership(struct iommu_table *tbl)
1105} 1105}
1106EXPORT_SYMBOL_GPL(iommu_release_ownership); 1106EXPORT_SYMBOL_GPL(iommu_release_ownership);
1107 1107
1108static int iommu_add_device(struct device *dev) 1108int iommu_add_device(struct device *dev)
1109{ 1109{
1110 struct iommu_table *tbl; 1110 struct iommu_table *tbl;
1111 int ret = 0; 1111 int ret = 0;
@@ -1134,52 +1134,12 @@ static int iommu_add_device(struct device *dev)
1134 1134
1135 return ret; 1135 return ret;
1136} 1136}
1137EXPORT_SYMBOL_GPL(iommu_add_device);
1137 1138
1138static void iommu_del_device(struct device *dev) 1139void iommu_del_device(struct device *dev)
1139{ 1140{
1140 iommu_group_remove_device(dev); 1141 iommu_group_remove_device(dev);
1141} 1142}
1142 1143EXPORT_SYMBOL_GPL(iommu_del_device);
1143static int iommu_bus_notifier(struct notifier_block *nb,
1144 unsigned long action, void *data)
1145{
1146 struct device *dev = data;
1147
1148 switch (action) {
1149 case BUS_NOTIFY_ADD_DEVICE:
1150 return iommu_add_device(dev);
1151 case BUS_NOTIFY_DEL_DEVICE:
1152 iommu_del_device(dev);
1153 return 0;
1154 default:
1155 return 0;
1156 }
1157}
1158
1159static struct notifier_block tce_iommu_bus_nb = {
1160 .notifier_call = iommu_bus_notifier,
1161};
1162
1163static int __init tce_iommu_init(void)
1164{
1165 struct pci_dev *pdev = NULL;
1166
1167 BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
1168
1169 for_each_pci_dev(pdev)
1170 iommu_add_device(&pdev->dev);
1171
1172 bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
1173 return 0;
1174}
1175
1176subsys_initcall_sync(tce_iommu_init);
1177
1178#else
1179
1180void iommu_register_group(struct iommu_table *tbl,
1181 int pci_domain_number, unsigned long pe_num)
1182{
1183}
1184 1144
1185#endif /* CONFIG_IOMMU_API */ 1145#endif /* CONFIG_IOMMU_API */
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 084cdfa40682..614356cac466 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -460,7 +460,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
460 return; 460 return;
461 461
462 pe = &phb->ioda.pe_array[pdn->pe_number]; 462 pe = &phb->ioda.pe_array[pdn->pe_number];
463 set_iommu_table_base(&pdev->dev, &pe->tce32_table); 463 set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table);
464} 464}
465 465
466static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) 466static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
@@ -468,7 +468,7 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
468 struct pci_dev *dev; 468 struct pci_dev *dev;
469 469
470 list_for_each_entry(dev, &bus->devices, bus_list) { 470 list_for_each_entry(dev, &bus->devices, bus_list) {
471 set_iommu_table_base(&dev->dev, &pe->tce32_table); 471 set_iommu_table_base_and_group(&dev->dev, &pe->tce32_table);
472 if (dev->subordinate) 472 if (dev->subordinate)
473 pnv_ioda_setup_bus_dma(pe, dev->subordinate); 473 pnv_ioda_setup_bus_dma(pe, dev->subordinate);
474 } 474 }
@@ -644,7 +644,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
644 iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number); 644 iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number);
645 645
646 if (pe->pdev) 646 if (pe->pdev)
647 set_iommu_table_base(&pe->pdev->dev, tbl); 647 set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
648 else 648 else
649 pnv_ioda_setup_bus_dma(pe, pe->pbus); 649 pnv_ioda_setup_bus_dma(pe, pe->pbus);
650 650
@@ -722,7 +722,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
722 iommu_init_table(tbl, phb->hose->node); 722 iommu_init_table(tbl, phb->hose->node);
723 723
724 if (pe->pdev) 724 if (pe->pdev)
725 set_iommu_table_base(&pe->pdev->dev, tbl); 725 set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
726 else 726 else
727 pnv_ioda_setup_bus_dma(pe, pe->pbus); 727 pnv_ioda_setup_bus_dma(pe, pe->pbus);
728 728
diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
index f8b4bd8afb2e..e3807d69393e 100644
--- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c
+++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
@@ -92,7 +92,7 @@ static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb,
92 pci_domain_nr(phb->hose->bus), phb->opal_id); 92 pci_domain_nr(phb->hose->bus), phb->opal_id);
93 } 93 }
94 94
95 set_iommu_table_base(&pdev->dev, &phb->p5ioc2.iommu_table); 95 set_iommu_table_base_and_group(&pdev->dev, &phb->p5ioc2.iommu_table);
96} 96}
97 97
98static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id, 98static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id,
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 4eb33a9ed532..6f3d49c18d64 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -536,7 +536,7 @@ static void pnv_pci_dma_fallback_setup(struct pci_controller *hose,
536 pdn->iommu_table = pnv_pci_setup_bml_iommu(hose); 536 pdn->iommu_table = pnv_pci_setup_bml_iommu(hose);
537 if (!pdn->iommu_table) 537 if (!pdn->iommu_table)
538 return; 538 return;
539 set_iommu_table_base(&pdev->dev, pdn->iommu_table); 539 set_iommu_table_base_and_group(&pdev->dev, pdn->iommu_table);
540} 540}
541 541
542static void pnv_pci_dma_dev_setup(struct pci_dev *pdev) 542static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
@@ -657,3 +657,34 @@ void __init pnv_pci_init(void)
657 ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs; 657 ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs;
658#endif 658#endif
659} 659}
660
661static int tce_iommu_bus_notifier(struct notifier_block *nb,
662 unsigned long action, void *data)
663{
664 struct device *dev = data;
665
666 switch (action) {
667 case BUS_NOTIFY_ADD_DEVICE:
668 return iommu_add_device(dev);
669 case BUS_NOTIFY_DEL_DEVICE:
670 if (dev->iommu_group)
671 iommu_del_device(dev);
672 return 0;
673 default:
674 return 0;
675 }
676}
677
678static struct notifier_block tce_iommu_bus_nb = {
679 .notifier_call = tce_iommu_bus_notifier,
680};
681
682static int __init tce_iommu_bus_notifier_init(void)
683{
684 BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
685
686 bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
687 return 0;
688}
689
690subsys_initcall_sync(tce_iommu_bus_notifier_init);
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index f253361552ae..a80af6c20cba 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -687,7 +687,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
687 iommu_table_setparms(phb, dn, tbl); 687 iommu_table_setparms(phb, dn, tbl);
688 PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node); 688 PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node);
689 iommu_register_group(tbl, pci_domain_nr(phb->bus), 0); 689 iommu_register_group(tbl, pci_domain_nr(phb->bus), 0);
690 set_iommu_table_base(&dev->dev, PCI_DN(dn)->iommu_table); 690 set_iommu_table_base_and_group(&dev->dev,
691 PCI_DN(dn)->iommu_table);
691 return; 692 return;
692 } 693 }
693 694
@@ -699,7 +700,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
699 dn = dn->parent; 700 dn = dn->parent;
700 701
701 if (dn && PCI_DN(dn)) 702 if (dn && PCI_DN(dn))
702 set_iommu_table_base(&dev->dev, PCI_DN(dn)->iommu_table); 703 set_iommu_table_base_and_group(&dev->dev,
704 PCI_DN(dn)->iommu_table);
703 else 705 else
704 printk(KERN_WARNING "iommu: Device %s has no iommu table\n", 706 printk(KERN_WARNING "iommu: Device %s has no iommu table\n",
705 pci_name(dev)); 707 pci_name(dev));
@@ -1193,7 +1195,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
1193 pr_debug(" found DMA window, table: %p\n", pci->iommu_table); 1195 pr_debug(" found DMA window, table: %p\n", pci->iommu_table);
1194 } 1196 }
1195 1197
1196 set_iommu_table_base(&dev->dev, pci->iommu_table); 1198 set_iommu_table_base_and_group(&dev->dev, pci->iommu_table);
1197} 1199}
1198 1200
1199static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) 1201static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)