[PATCH kernel v11 20/34] powerpc/powernv/ioda2: Move TCE kill register address to PE

Gavin Shan gwshan at linux.vnet.ibm.com
Fri Jun 5 10:22:16 AEST 2015


On Fri, May 29, 2015 at 06:44:44PM +1000, Alexey Kardashevskiy wrote:
>At the moment the DMA setup code looks for the "ibm,opal-tce-kill"
>property which contains the TCE kill register address. Writing to
>this register invalidates TCE cache on IODA/IODA2 hub.
>
>This moves the register address from iommu_table to pnv_pnb as this
>register belongs to PHB and invalidates TCE cache for all tables of
>all attached PEs.
>
>This moves the property reading/remapping code to a helper which is
>called when DMA is being configured for PE and which does DMA setup
>for both IODA1 and IODA2.
>
>This adds a new pnv_pci_ioda2_tce_invalidate_entire() helper which
>invalidates cache for the entire table. It should be called after
>every call to opal_pci_map_pe_dma_window(). It was not required before
>because there was just a single TCE table and 64bit DMA was handled via
>bypass window (which has no table so no cache was used) but this is going
>to change with Dynamic DMA windows (DDW).
>
>Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>

Reviewed-by: Gavin Shan <gwshan at linux.vnet.ibm.com>

Thanks,
Gavin

>---
>Changes:
>v11:
>* s/pnv_pci_ioda2_tvt_invalidate/pnv_pci_ioda2_tce_invalidate_entire/g
>(cannot think of better-and-shorter name)
>* moved tce_inval_reg_phys/tce_inval_reg to pnv_phb
>
>v10:
>* fixed error from checkpatch.pl
>* removed comment at "ibm,opal-tce-kill" parsing as irrelevant
>* s/addr/val/ in pnv_pci_ioda2_tvt_invalidate() as it was not a kernel address
>
>v9:
>* new in the series
>---
> arch/powerpc/platforms/powernv/pci-ioda.c | 66 ++++++++++++++++++-------------
> arch/powerpc/platforms/powernv/pci.h      |  7 +++-
> 2 files changed, 44 insertions(+), 29 deletions(-)
>
>diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
>index 1d0bb5b..3fd8b18 100644
>--- a/arch/powerpc/platforms/powernv/pci-ioda.c
>+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
>@@ -1679,8 +1679,8 @@ static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
> 	struct pnv_ioda_pe *pe = container_of(tgl->table_group,
> 			struct pnv_ioda_pe, table_group);
> 	__be64 __iomem *invalidate = rm ?
>-		(__be64 __iomem *)pe->tce_inval_reg_phys :
>-		(__be64 __iomem *)tbl->it_index;
>+		(__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys :
>+		pe->phb->ioda.tce_inval_reg;
> 	unsigned long start, end, inc;
> 	const unsigned shift = tbl->it_page_shift;
>
>@@ -1751,6 +1751,19 @@ static struct iommu_table_ops pnv_ioda1_iommu_ops = {
> 	.get = pnv_tce_get,
> };
>
>+static inline void pnv_pci_ioda2_tce_invalidate_entire(struct pnv_ioda_pe *pe)
>+{
>+	/* 01xb - invalidate TCEs that match the specified PE# */
>+	unsigned long val = (0x4ull << 60) | (pe->pe_number & 0xFF);
>+	struct pnv_phb *phb = pe->phb;
>+
>+	if (!phb->ioda.tce_inval_reg)
>+		return;
>+
>+	mb(); /* Ensure above stores are visible */
>+	__raw_writeq(cpu_to_be64(val), phb->ioda.tce_inval_reg);
>+}
>+
> static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
> 		unsigned long index, unsigned long npages, bool rm)
> {
>@@ -1761,8 +1774,8 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
> 			struct pnv_ioda_pe, table_group);
> 	unsigned long start, end, inc;
> 	__be64 __iomem *invalidate = rm ?
>-		(__be64 __iomem *)pe->tce_inval_reg_phys :
>-		(__be64 __iomem *)tbl->it_index;
>+		(__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys :
>+		pe->phb->ioda.tce_inval_reg;
> 	const unsigned shift = tbl->it_page_shift;
>
> 	/* We'll invalidate DMA address in PE scope */
>@@ -1820,7 +1833,6 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
> {
>
> 	struct page *tce_mem = NULL;
>-	const __be64 *swinvp;
> 	struct iommu_table *tbl;
> 	unsigned int i;
> 	int64_t rc;
>@@ -1877,20 +1889,11 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
> 				  base << 28, IOMMU_PAGE_SHIFT_4K);
>
> 	/* OPAL variant of P7IOC SW invalidated TCEs */
>-	swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL);
>-	if (swinvp) {
>-		/* We need a couple more fields -- an address and a data
>-		 * to or.  Since the bus is only printed out on table free
>-		 * errors, and on the first pass the data will be a relative
>-		 * bus number, print that out instead.
>-		 */
>-		pe->tce_inval_reg_phys = be64_to_cpup(swinvp);
>-		tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys,
>-				8);
>+	if (phb->ioda.tce_inval_reg)
> 		tbl->it_type |= (TCE_PCI_SWINV_CREATE |
> 				 TCE_PCI_SWINV_FREE   |
> 				 TCE_PCI_SWINV_PAIR);
>-	}
>+
> 	tbl->it_ops = &pnv_ioda1_iommu_ops;
> 	iommu_init_table(tbl, phb->hose->node);
>
>@@ -1971,12 +1974,24 @@ static struct iommu_table_group_ops pnv_pci_ioda2_ops = {
> };
> #endif
>
>+static void pnv_pci_ioda_setup_opal_tce_kill(struct pnv_phb *phb)
>+{
>+	const __be64 *swinvp;
>+
>+	/* OPAL variant of PHB3 invalidated TCEs */
>+	swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL);
>+	if (!swinvp)
>+		return;
>+
>+	phb->ioda.tce_inval_reg_phys = be64_to_cpup(swinvp);
>+	phb->ioda.tce_inval_reg = ioremap(phb->ioda.tce_inval_reg_phys, 8);
>+}
>+
> static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
> 				       struct pnv_ioda_pe *pe)
> {
> 	struct page *tce_mem = NULL;
> 	void *addr;
>-	const __be64 *swinvp;
> 	struct iommu_table *tbl;
> 	unsigned int tce_table_size, end;
> 	int64_t rc;
>@@ -2023,23 +2038,16 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
> 		goto fail;
> 	}
>
>+	pnv_pci_ioda2_tce_invalidate_entire(pe);
>+
> 	/* Setup linux iommu table */
> 	pnv_pci_setup_iommu_table(tbl, addr, tce_table_size, 0,
> 			IOMMU_PAGE_SHIFT_4K);
>
> 	/* OPAL variant of PHB3 invalidated TCEs */
>-	swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL);
>-	if (swinvp) {
>-		/* We need a couple more fields -- an address and a data
>-		 * to or.  Since the bus is only printed out on table free
>-		 * errors, and on the first pass the data will be a relative
>-		 * bus number, print that out instead.
>-		 */
>-		pe->tce_inval_reg_phys = be64_to_cpup(swinvp);
>-		tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys,
>-				8);
>+	if (phb->ioda.tce_inval_reg)
> 		tbl->it_type |= (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE);
>-	}
>+
> 	tbl->it_ops = &pnv_ioda2_iommu_ops;
> 	iommu_init_table(tbl, phb->hose->node);
> #ifdef CONFIG_IOMMU_API
>@@ -2095,6 +2103,8 @@ static void pnv_ioda_setup_dma(struct pnv_phb *phb)
> 	pr_info("PCI: %d PE# for a total weight of %d\n",
> 		phb->ioda.dma_pe_count, phb->ioda.dma_weight);
>
>+	pnv_pci_ioda_setup_opal_tce_kill(phb);
>+
> 	/* Walk our PE list and configure their DMA segments, hand them
> 	 * out one base segment plus any residual segments based on
> 	 * weight
>diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
>index 87bdd4f..d1e6978 100644
>--- a/arch/powerpc/platforms/powernv/pci.h
>+++ b/arch/powerpc/platforms/powernv/pci.h
>@@ -58,7 +58,6 @@ struct pnv_ioda_pe {
> 	int			tce32_seg;
> 	int			tce32_segcount;
> 	struct iommu_table_group table_group;
>-	phys_addr_t		tce_inval_reg_phys;
>
> 	/* 64-bit TCE bypass region */
> 	bool			tce_bypass_enabled;
>@@ -187,6 +186,12 @@ struct pnv_phb {
> 			 * boot for resource allocation purposes
> 			 */
> 			struct list_head	pe_dma_list;
>+
>+			/* TCE cache invalidate registers (physical and
>+			 * remapped)
>+			 */
>+			phys_addr_t		tce_inval_reg_phys;
>+			__be64 __iomem		*tce_inval_reg;
> 		} ioda;
> 	};
>
>-- 
>2.4.0.rc3.8.gfb3e7d5
>



More information about the Linuxppc-dev mailing list