|
@@ -1680,8 +1680,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;
|
|
|
|
|
@@ -1752,6 +1752,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)
|
|
|
{
|
|
@@ -1762,8 +1775,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 */
|
|
@@ -1821,7 +1834,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;
|
|
@@ -1878,20 +1890,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);
|
|
|
|
|
@@ -1972,12 +1975,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;
|
|
@@ -2024,23 +2039,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
|
|
@@ -2096,6 +2104,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
|