]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - arch/powerpc/platforms/powernv/pci-ioda.c
powerpc/powernv: Fix iommu table size calculation hook for small tables
[linux.git] / arch / powerpc / platforms / powernv / pci-ioda.c
index 6901a06da2f90bddf70386667eaea5c4fe3505a7..16fd322b2eeab0d231aef74bf87bfd0e7f4d3d84 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/crash_dump.h>
-#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
@@ -38,7 +37,7 @@
 #include <asm/iommu.h>
 #include <asm/tce.h>
 #include <asm/xics.h>
-#include <asm/debug.h>
+#include <asm/debugfs.h>
 #include <asm/firmware.h>
 #include <asm/pnv-pci.h>
 #include <asm/mmzone.h>
@@ -1262,6 +1261,8 @@ static void pnv_pci_ioda_setup_PEs(void)
                        /* PE#0 is needed for error reporting */
                        pnv_ioda_reserve_pe(phb, 0);
                        pnv_ioda_setup_npu_PEs(hose->bus);
+                       if (phb->model == PNV_PHB_MODEL_NPU2)
+                               pnv_npu2_init(phb);
                }
        }
 }
@@ -1424,8 +1425,7 @@ static void pnv_pci_ioda2_release_dma_pe(struct pci_dev *dev, struct pnv_ioda_pe
                iommu_group_put(pe->table_group.group);
                BUG_ON(pe->table_group.group);
        }
-       pnv_pci_ioda2_table_free_pages(tbl);
-       iommu_free_table(tbl, of_node_full_name(dev->dev.of_node));
+       iommu_tce_table_put(tbl);
 }
 
 static void pnv_ioda_release_vf_PE(struct pci_dev *pdev)
@@ -1775,17 +1775,20 @@ static u64 pnv_pci_ioda_dma_get_required_mask(struct pci_dev *pdev)
 }
 
 static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
-                                  struct pci_bus *bus)
+                                  struct pci_bus *bus,
+                                  bool add_to_group)
 {
        struct pci_dev *dev;
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                set_iommu_table_base(&dev->dev, pe->table_group.tables[0]);
                set_dma_offset(&dev->dev, pe->tce_bypass_base);
-               iommu_add_device(&dev->dev);
+               if (add_to_group)
+                       iommu_add_device(&dev->dev);
 
                if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate)
-                       pnv_ioda_setup_bus_dma(pe, dev->subordinate);
+                       pnv_ioda_setup_bus_dma(pe, dev->subordinate,
+                                       add_to_group);
        }
 }
 
@@ -1857,6 +1860,17 @@ static int pnv_ioda1_tce_xchg(struct iommu_table *tbl, long index,
 
        return ret;
 }
+
+static int pnv_ioda1_tce_xchg_rm(struct iommu_table *tbl, long index,
+               unsigned long *hpa, enum dma_data_direction *direction)
+{
+       long ret = pnv_tce_xchg(tbl, index, hpa, direction);
+
+       if (!ret)
+               pnv_pci_p7ioc_tce_invalidate(tbl, index, 1, true);
+
+       return ret;
+}
 #endif
 
 static void pnv_ioda1_tce_free(struct iommu_table *tbl, long index,
@@ -1871,6 +1885,7 @@ static struct iommu_table_ops pnv_ioda1_iommu_ops = {
        .set = pnv_ioda1_tce_build,
 #ifdef CONFIG_IOMMU_API
        .exchange = pnv_ioda1_tce_xchg,
+       .exchange_rm = pnv_ioda1_tce_xchg_rm,
 #endif
        .clear = pnv_ioda1_tce_free,
        .get = pnv_tce_get,
@@ -1945,7 +1960,7 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
 {
        struct iommu_table_group_link *tgl;
 
-       list_for_each_entry_rcu(tgl, &tbl->it_group_list, next) {
+       list_for_each_entry_lockless(tgl, &tbl->it_group_list, next) {
                struct pnv_ioda_pe *pe = container_of(tgl->table_group,
                                struct pnv_ioda_pe, table_group);
                struct pnv_phb *phb = pe->phb;
@@ -2001,6 +2016,17 @@ static int pnv_ioda2_tce_xchg(struct iommu_table *tbl, long index,
 
        return ret;
 }
+
+static int pnv_ioda2_tce_xchg_rm(struct iommu_table *tbl, long index,
+               unsigned long *hpa, enum dma_data_direction *direction)
+{
+       long ret = pnv_tce_xchg(tbl, index, hpa, direction);
+
+       if (!ret)
+               pnv_pci_ioda2_tce_invalidate(tbl, index, 1, true);
+
+       return ret;
+}
 #endif
 
 static void pnv_ioda2_tce_free(struct iommu_table *tbl, long index,
@@ -2014,13 +2040,13 @@ static void pnv_ioda2_tce_free(struct iommu_table *tbl, long index,
 static void pnv_ioda2_table_free(struct iommu_table *tbl)
 {
        pnv_pci_ioda2_table_free_pages(tbl);
-       iommu_free_table(tbl, "pnv");
 }
 
 static struct iommu_table_ops pnv_ioda2_iommu_ops = {
        .set = pnv_ioda2_tce_build,
 #ifdef CONFIG_IOMMU_API
        .exchange = pnv_ioda2_tce_xchg,
+       .exchange_rm = pnv_ioda2_tce_xchg_rm,
 #endif
        .clear = pnv_ioda2_tce_free,
        .get = pnv_tce_get,
@@ -2125,6 +2151,9 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb,
 
 found:
        tbl = pnv_pci_table_alloc(phb->hose->node);
+       if (WARN_ON(!tbl))
+               return;
+
        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);
@@ -2191,7 +2220,7 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb,
                set_iommu_table_base(&pe->pdev->dev, tbl);
                iommu_add_device(&pe->pdev->dev);
        } else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
-               pnv_ioda_setup_bus_dma(pe, pe->pbus);
+               pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
 
        return;
  fail:
@@ -2200,7 +2229,7 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb,
                __free_pages(tce_mem, get_order(tce32_segsz * segs));
        if (tbl) {
                pnv_pci_unlink_table_and_group(tbl, &pe->table_group);
-               iommu_free_table(tbl, "pnv");
+               iommu_tce_table_put(tbl);
        }
 }
 
@@ -2290,16 +2319,16 @@ static long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group,
        if (!tbl)
                return -ENOMEM;
 
+       tbl->it_ops = &pnv_ioda2_iommu_ops;
+
        ret = pnv_pci_ioda2_table_alloc_pages(nid,
                        bus_offset, page_shift, window_size,
                        levels, tbl);
        if (ret) {
-               iommu_free_table(tbl, "pnv");
+               iommu_tce_table_put(tbl);
                return ret;
        }
 
-       tbl->it_ops = &pnv_ioda2_iommu_ops;
-
        *ptbl = tbl;
 
        return 0;
@@ -2340,7 +2369,7 @@ static long pnv_pci_ioda2_setup_default_config(struct pnv_ioda_pe *pe)
        if (rc) {
                pe_err(pe, "Failed to configure 32-bit TCE table, err %ld\n",
                                rc);
-               pnv_ioda2_table_free(tbl);
+               iommu_tce_table_put(tbl);
                return rc;
        }
 
@@ -2411,7 +2440,8 @@ static unsigned long pnv_pci_ioda2_get_table_size(__u32 page_shift,
 
                tce_table_size /= direct_table_size;
                tce_table_size <<= 3;
-               tce_table_size = _ALIGN_UP(tce_table_size, direct_table_size);
+               tce_table_size = max_t(unsigned long,
+                               tce_table_size, direct_table_size);
        }
 
        return bytes;
@@ -2426,7 +2456,9 @@ static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group)
 
        pnv_pci_ioda2_set_bypass(pe, false);
        pnv_pci_ioda2_unset_window(&pe->table_group, 0);
-       pnv_ioda2_table_free(tbl);
+       if (pe->pbus)
+               pnv_ioda_setup_bus_dma(pe, pe->pbus, false);
+       iommu_tce_table_put(tbl);
 }
 
 static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group)
@@ -2435,6 +2467,8 @@ static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group)
                                                table_group);
 
        pnv_pci_ioda2_setup_default_config(pe);
+       if (pe->pbus)
+               pnv_ioda_setup_bus_dma(pe, pe->pbus, false);
 }
 
 static struct iommu_table_group_ops pnv_pci_ioda2_ops = {
@@ -2624,6 +2658,9 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
        level_shift = entries_shift + 3;
        level_shift = max_t(unsigned, level_shift, PAGE_SHIFT);
 
+       if ((level_shift - 3) * levels + page_shift >= 60)
+               return -EINVAL;
+
        /* Allocate TCE table */
        addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift,
                        levels, tce_table_size, &offset, &total_allocated);
@@ -2725,10 +2762,8 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
        if (rc)
                return;
 
-       if (pe->flags & PNV_IODA_PE_DEV)
-               iommu_add_device(&pe->pdev->dev);
-       else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
-               pnv_ioda_setup_bus_dma(pe, pe->pbus);
+       if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
+               pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
 }
 
 #ifdef CONFIG_PCI_MSI
@@ -3396,7 +3431,7 @@ static void pnv_pci_ioda1_release_pe_dma(struct pnv_ioda_pe *pe)
        }
 
        free_pages(tbl->it_base, get_order(tbl->it_size << 3));
-       iommu_free_table(tbl, "pnv");
+       iommu_tce_table_put(tbl);
 }
 
 static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
@@ -3423,7 +3458,7 @@ static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
        }
 
        pnv_pci_ioda2_table_free_pages(tbl);
-       iommu_free_table(tbl, "pnv");
+       iommu_tce_table_put(tbl);
 }
 
 static void pnv_ioda_free_pe_seg(struct pnv_ioda_pe *pe,