[PATCH 5/5] powerpc/powernv: TCE invalidation for PHB3

2013-04-23 Thread Gavin Shan
The TCE should be invalidated while it's created or free'd. The
approach to do that for IODA1 and IODA2 compliant PHBs are different.
So the patch differentiate them with virtualized interface hooked
to the PHB. It's notable that the PCI address is used to invalidate
the corresponding TCE on IODA2 compliant PHB3.

Signed-off-by: Gavin Shan sha...@linux.vnet.ibm.com
---
 arch/powerpc/include/asm/iommu.h|1 +
 arch/powerpc/platforms/powernv/pci-ioda.c   |   79 ++-
 arch/powerpc/platforms/powernv/pci-p5ioc2.c |2 +
 arch/powerpc/platforms/powernv/pci.c|   48 ++---
 arch/powerpc/platforms/powernv/pci.h|2 +
 5 files changed, 86 insertions(+), 46 deletions(-)

diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index cbfe678..0db308e 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -76,6 +76,7 @@ struct iommu_table {
struct iommu_pool large_pool;
struct iommu_pool pools[IOMMU_NR_POOLS];
unsigned long *it_map;   /* A simple allocation bitmap for now */
+   void *sysdata;
 };
 
 struct scatterlist;
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c 
b/arch/powerpc/platforms/powernv/pci-ioda.c
index 8ec77a7..a4b1c9a 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -448,6 +448,73 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, 
struct pci_bus *bus)
}
 }
 
+static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
+u64 *startp, u64 *endp)
+{
+   u64 __iomem *invalidate = (u64 __iomem *)tbl-it_index;
+   unsigned long start, end, inc;
+
+   start = __pa(startp);
+   end = __pa(endp);
+
+   /* BML uses this case for p6/p7/galaxy2: Shift addr and put in node */
+   if (tbl-it_busno) {
+   start = 12;
+   end = 12;
+   inc = 128  12;
+   start |= tbl-it_busno;
+   end |= tbl-it_busno;
+   } else if (tbl-it_type  TCE_PCI_SWINV_PAIR) {
+   /* p7ioc-style invalidation, 2 TCEs per write */
+   start |= (1ull  63);
+   end |= (1ull  63);
+   inc = 16;
+} else {
+   /* Default (older HW) */
+inc = 128;
+   }
+
+end |= inc - 1;/* round up end to be different than start */
+
+mb(); /* Ensure above stores are visible */
+while (start = end) {
+__raw_writeq(start, invalidate);
+start += inc;
+}
+
+   /*
+* The iommu layer will do another mb() for us on build()
+* and we don't care on free()
+*/
+}
+
+static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
+u64 *startp, u64 *endp)
+{
+   unsigned long start, end, inc;
+   u64 __iomem *invalidate = (u64 __iomem *)tbl-it_index;
+   struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe,
+ tce32_table);
+
+   /* We'll invalidate DMA address in PE scope */
+   start = 0x2ul  60;
+   start |= (pe-pe_number  0xFF);
+   end = start;
+
+   /* Figure out the start, end and step */
+   inc = tbl-it_offset + (((u64)startp - tbl-it_base) / sizeof(u64));
+   start |= (inc  12);
+   inc = tbl-it_offset + (((u64)endp - tbl-it_base) / sizeof(u64));
+   end |= (inc  12);
+   inc = (0x1ul  12);
+   mb();
+
+   while (start = end) {
+   __raw_writeq(start, invalidate);
+   start += inc;
+   }
+}
+
 static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
  struct pnv_ioda_pe *pe, unsigned int base,
  unsigned int segs)
@@ -509,6 +576,9 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
pnv_pci_setup_iommu_table(tbl, addr, TCE32_TABLE_SIZE * segs,
  base  28);
 
+   /* Hook the IOMMU table to PHB */
+   tbl-sysdata = phb;
+
/* OPAL variant of P7IOC SW invalidated TCEs */
swinvp = of_get_property(phb-hose-dn, ibm,opal-tce-kill, NULL);
if (swinvp) {
@@ -519,8 +589,9 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
 */
tbl-it_busno = 0;
tbl-it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8);
-   tbl-it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE
-   | TCE_PCI_SWINV_PAIR;
+   tbl-it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE;
+   if (phb-type == PNV_PHB_IODA1)
+   tbl-it_type |= TCE_PCI_SWINV_PAIR;
}
iommu_init_table(tbl, phb-hose-node);
 
@@ -1032,6 +1103,10 @@ void __init pnv_pci_init_ioda_phb(struct device_node 
*np, int 

Re: [PATCH 5/5] powerpc/powernv: TCE invalidation for PHB3

2013-04-23 Thread Benjamin Herrenschmidt
On Tue, 2013-04-23 at 19:03 +0800, Gavin Shan wrote:
  * of flags if that becomes the case
  */
 if (tbl-it_type  TCE_PCI_SWINV_CREATE)
 -   pnv_tce_invalidate(tbl, tces, tcep - 1);
 +   phb-dma_tce_invalidate(tbl, tces, tcep - 1);
  
 return 0;
  }

TCE invalidate is very performance sensitive, we might be better off
doing the if (ioda_type == PNV_PHB_IODA1) ... else ... here (which
the CPU can generally predict) rather than a function pointer call
which can be more tricky.

Cheers,
Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 5/5] powerpc/powernv: TCE invalidation for PHB3

2013-04-23 Thread Gavin Shan
On Wed, Apr 24, 2013 at 01:25:08AM +1000, Benjamin Herrenschmidt wrote:
On Tue, 2013-04-23 at 19:03 +0800, Gavin Shan wrote:
  * of flags if that becomes the case
  */
 if (tbl-it_type  TCE_PCI_SWINV_CREATE)
 -   pnv_tce_invalidate(tbl, tces, tcep - 1);
 +   phb-dma_tce_invalidate(tbl, tces, tcep - 1);
  
 return 0;
  }

TCE invalidate is very performance sensitive, we might be better off
doing the if (ioda_type == PNV_PHB_IODA1) ... else ... here (which
the CPU can generally predict) rather than a function pointer call
which can be more tricky.


Ok. I'll change it in next version ;-)

Thanks,
Gavin

___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev