OSDN Git Service

Merge tag 'powerpc-6.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[tomoyo/tomoyo-test1.git] / arch / powerpc / platforms / powernv / pci-ioda.c
index 5a81f10..a02e9cd 100644 (file)
@@ -1554,6 +1554,10 @@ found:
        if (WARN_ON(!tbl))
                return;
 
+#ifdef CONFIG_IOMMU_API
+       pe->table_group.ops = &spapr_tce_table_group_ops;
+       pe->table_group.pgsizes = SZ_4K;
+#endif
        iommu_register_group(&pe->table_group, phb->hose->global_number,
                        pe->pe_number);
        pnv_pci_link_table_and_group(phb->hose->node, 0, tbl, &pe->table_group);
@@ -1888,13 +1892,20 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
        }
 }
 
-static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group)
+static long pnv_ioda2_take_ownership(struct iommu_table_group *table_group)
 {
        struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
                                                table_group);
        /* Store @tbl as pnv_pci_ioda2_unset_window() resets it */
        struct iommu_table *tbl = pe->table_group.tables[0];
 
+       /*
+        * iommu_ops transfers the ownership per a device and we mode
+        * the group ownership with the first device in the group.
+        */
+       if (!tbl)
+               return 0;
+
        pnv_pci_ioda2_set_bypass(pe, false);
        pnv_pci_ioda2_unset_window(&pe->table_group, 0);
        if (pe->pbus)
@@ -1902,6 +1913,8 @@ static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group)
        else if (pe->pdev)
                set_iommu_table_base(&pe->pdev->dev, NULL);
        iommu_tce_table_put(tbl);
+
+       return 0;
 }
 
 static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group)
@@ -1909,6 +1922,9 @@ static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group)
        struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
                                                table_group);
 
+       /* See the comment about iommu_ops above */
+       if (pe->table_group.tables[0])
+               return;
        pnv_pci_ioda2_setup_default_config(pe);
        if (pe->pbus)
                pnv_ioda_setup_bus_dma(pe, pe->pbus);
@@ -2915,6 +2931,27 @@ static void pnv_pci_ioda_dma_bus_setup(struct pci_bus *bus)
        }
 }
 
+#ifdef CONFIG_IOMMU_API
+static struct iommu_group *pnv_pci_device_group(struct pci_controller *hose,
+                                               struct pci_dev *pdev)
+{
+       struct pnv_phb *phb = hose->private_data;
+       struct pnv_ioda_pe *pe;
+
+       if (WARN_ON(!phb))
+               return ERR_PTR(-ENODEV);
+
+       pe = pnv_pci_bdfn_to_pe(phb, pdev->devfn | (pdev->bus->number << 8));
+       if (!pe)
+               return ERR_PTR(-ENODEV);
+
+       if (!pe->table_group.group)
+               return ERR_PTR(-ENODEV);
+
+       return iommu_group_ref_get(pe->table_group.group);
+}
+#endif
+
 static const struct pci_controller_ops pnv_pci_ioda_controller_ops = {
        .dma_dev_setup          = pnv_pci_ioda_dma_dev_setup,
        .dma_bus_setup          = pnv_pci_ioda_dma_bus_setup,
@@ -2925,6 +2962,9 @@ static const struct pci_controller_ops pnv_pci_ioda_controller_ops = {
        .setup_bridge           = pnv_pci_fixup_bridge_resources,
        .reset_secondary_bus    = pnv_pci_reset_secondary_bus,
        .shutdown               = pnv_pci_ioda_shutdown,
+#ifdef CONFIG_IOMMU_API
+       .device_group           = pnv_pci_device_group,
+#endif
 };
 
 static const struct pci_controller_ops pnv_npu_ocapi_ioda_controller_ops = {