]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/platforms/powernv/pci-ioda.c
powerpc/powernv/ioda: Fix TCE invalidate to work in real mode again
[karo-tx-linux.git] / arch / powerpc / platforms / powernv / pci-ioda.c
index 104c0405f47cadf38a4331a022c3e018a178db11..dedbbe9785ba1538b39378abd2f4ed24d8e8ff97 100644 (file)
@@ -191,9 +191,6 @@ static int pnv_ioda2_init_m64(struct pnv_phb *phb)
                goto fail;
        }
 
-       /* Mark the M64 BAR assigned */
-       set_bit(phb->ioda.m64_bar_idx, &phb->ioda.m64_bar_alloc);
-
        /*
         * Exclude the segments for reserved and root bus PE, which
         * are first or last two PEs.
@@ -404,6 +401,7 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
        struct pci_controller *hose = phb->hose;
        struct device_node *dn = hose->dn;
        struct resource *res;
+       u32 m64_range[2], i;
        const u32 *r;
        u64 pci_addr;
 
@@ -424,6 +422,30 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
                return;
        }
 
+       /*
+        * Find the available M64 BAR range and pickup the last one for
+        * covering the whole 64-bits space. We support only one range.
+        */
+       if (of_property_read_u32_array(dn, "ibm,opal-available-m64-ranges",
+                                      m64_range, 2)) {
+               /* In absence of the property, assume 0..15 */
+               m64_range[0] = 0;
+               m64_range[1] = 16;
+       }
+       /* We only support 64 bits in our allocator */
+       if (m64_range[1] > 63) {
+               pr_warn("%s: Limiting M64 range to 63 (from %d) on PHB#%x\n",
+                       __func__, m64_range[1], phb->hose->global_number);
+               m64_range[1] = 63;
+       }
+       /* Empty range, no m64 */
+       if (m64_range[1] <= m64_range[0]) {
+               pr_warn("%s: M64 empty, disabling M64 usage on PHB#%x\n",
+                       __func__, phb->hose->global_number);
+               return;
+       }
+
+       /* Configure M64 informations */
        res = &hose->mem_resources[1];
        res->name = dn->full_name;
        res->start = of_translate_address(dn, r + 2);
@@ -436,11 +458,28 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
        phb->ioda.m64_segsize = phb->ioda.m64_size / phb->ioda.total_pe_num;
        phb->ioda.m64_base = pci_addr;
 
-       pr_info(" MEM64 0x%016llx..0x%016llx -> 0x%016llx\n",
-                       res->start, res->end, pci_addr);
+       /* This lines up nicely with the display from processing OF ranges */
+       pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx (M64 #%d..%d)\n",
+               res->start, res->end, pci_addr, m64_range[0],
+               m64_range[0] + m64_range[1] - 1);
+
+       /* Mark all M64 used up by default */
+       phb->ioda.m64_bar_alloc = (unsigned long)-1;
 
        /* Use last M64 BAR to cover M64 window */
-       phb->ioda.m64_bar_idx = 15;
+       m64_range[1]--;
+       phb->ioda.m64_bar_idx = m64_range[0] + m64_range[1];
+
+       pr_info(" Using M64 #%d as default window\n", phb->ioda.m64_bar_idx);
+
+       /* Mark remaining ones free */
+       for (i = m64_range[0]; i < m64_range[1]; i++)
+               clear_bit(i, &phb->ioda.m64_bar_alloc);
+
+       /*
+        * Setup init functions for M64 based on IODA version, IODA3 uses
+        * the IODA2 code.
+        */
        if (phb->type == PNV_PHB_IODA1)
                phb->init_m64 = pnv_ioda1_init_m64;
        else
@@ -1721,7 +1760,14 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
        }
 }
 
-static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
+static inline __be64 __iomem *pnv_ioda_get_inval_reg(struct pnv_phb *phb,
+                                                    bool real_mode)
+{
+       return real_mode ? (__be64 __iomem *)(phb->regs_phys + 0x210) :
+               (phb->regs + 0x210);
+}
+
+static void pnv_pci_p7ioc_tce_invalidate(struct iommu_table *tbl,
                unsigned long index, unsigned long npages, bool rm)
 {
        struct iommu_table_group_link *tgl = list_first_entry_or_null(
@@ -1729,33 +1775,17 @@ static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
                        next);
        struct pnv_ioda_pe *pe = container_of(tgl->table_group,
                        struct pnv_ioda_pe, table_group);
-       __be64 __iomem *invalidate = rm ?
-               (__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys :
-               pe->phb->ioda.tce_inval_reg;
+       __be64 __iomem *invalidate = pnv_ioda_get_inval_reg(pe->phb, rm);
        unsigned long start, end, inc;
-       const unsigned shift = tbl->it_page_shift;
 
        start = __pa(((__be64 *)tbl->it_base) + index - tbl->it_offset);
        end = __pa(((__be64 *)tbl->it_base) + index - tbl->it_offset +
                        npages - 1);
 
-       /* BML uses this case for p6/p7/galaxy2: Shift addr and put in node */
-       if (tbl->it_busno) {
-               start <<= shift;
-               end <<= shift;
-               inc = 128ull << shift;
-               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;
-       }
-
+       /* p7ioc-style invalidation, 2 TCEs per write */
+       start |= (1ull << 63);
+       end |= (1ull << 63);
+       inc = 16;
         end |= inc - 1;        /* round up end to be different than start */
 
         mb(); /* Ensure above stores are visible */
@@ -1776,13 +1806,13 @@ static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
 static int pnv_ioda1_tce_build(struct iommu_table *tbl, long index,
                long npages, unsigned long uaddr,
                enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
                        attrs);
 
-       if (!ret && (tbl->it_type & TCE_PCI_SWINV_CREATE))
-               pnv_pci_ioda1_tce_invalidate(tbl, index, npages, false);
+       if (!ret)
+               pnv_pci_p7ioc_tce_invalidate(tbl, index, npages, false);
 
        return ret;
 }
@@ -1793,9 +1823,8 @@ static int pnv_ioda1_tce_xchg(struct iommu_table *tbl, long index,
 {
        long ret = pnv_tce_xchg(tbl, index, hpa, direction);
 
-       if (!ret && (tbl->it_type &
-                       (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE)))
-               pnv_pci_ioda1_tce_invalidate(tbl, index, 1, false);
+       if (!ret)
+               pnv_pci_p7ioc_tce_invalidate(tbl, index, 1, false);
 
        return ret;
 }
@@ -1806,8 +1835,7 @@ static void pnv_ioda1_tce_free(struct iommu_table *tbl, long index,
 {
        pnv_tce_free(tbl, index, npages);
 
-       if (tbl->it_type & TCE_PCI_SWINV_FREE)
-               pnv_pci_ioda1_tce_invalidate(tbl, index, npages, false);
+       pnv_pci_p7ioc_tce_invalidate(tbl, index, npages, false);
 }
 
 static struct iommu_table_ops pnv_ioda1_iommu_ops = {
@@ -1819,45 +1847,42 @@ static struct iommu_table_ops pnv_ioda1_iommu_ops = {
        .get = pnv_tce_get,
 };
 
-#define TCE_KILL_INVAL_ALL  PPC_BIT(0)
-#define TCE_KILL_INVAL_PE   PPC_BIT(1)
-#define TCE_KILL_INVAL_TCE  PPC_BIT(2)
+#define PHB3_TCE_KILL_INVAL_ALL                PPC_BIT(0)
+#define PHB3_TCE_KILL_INVAL_PE         PPC_BIT(1)
+#define PHB3_TCE_KILL_INVAL_ONE                PPC_BIT(2)
 
-void pnv_pci_ioda2_tce_invalidate_entire(struct pnv_phb *phb, bool rm)
+void pnv_pci_phb3_tce_invalidate_entire(struct pnv_phb *phb, bool rm)
 {
-       const unsigned long val = TCE_KILL_INVAL_ALL;
+       __be64 __iomem *invalidate = pnv_ioda_get_inval_reg(phb, rm);
+       const unsigned long val = PHB3_TCE_KILL_INVAL_ALL;
 
        mb(); /* Ensure previous TCE table stores are visible */
        if (rm)
-               __raw_rm_writeq(cpu_to_be64(val),
-                               (__be64 __iomem *)
-                               phb->ioda.tce_inval_reg_phys);
+               __raw_rm_writeq(cpu_to_be64(val), invalidate);
        else
-               __raw_writeq(cpu_to_be64(val), phb->ioda.tce_inval_reg);
+               __raw_writeq(cpu_to_be64(val), invalidate);
 }
 
-static inline void pnv_pci_ioda2_tce_invalidate_pe(struct pnv_ioda_pe *pe)
+static inline void pnv_pci_phb3_tce_invalidate_pe(struct pnv_ioda_pe *pe)
 {
        /* 01xb - invalidate TCEs that match the specified PE# */
-       unsigned long val = TCE_KILL_INVAL_PE | (pe->pe_number & 0xFF);
-       struct pnv_phb *phb = pe->phb;
-
-       if (!phb->ioda.tce_inval_reg)
-               return;
+       __be64 __iomem *invalidate = pnv_ioda_get_inval_reg(pe->phb, false);
+       unsigned long val = PHB3_TCE_KILL_INVAL_PE | (pe->pe_number & 0xFF);
 
        mb(); /* Ensure above stores are visible */
-       __raw_writeq(cpu_to_be64(val), phb->ioda.tce_inval_reg);
+       __raw_writeq(cpu_to_be64(val), invalidate);
 }
 
-static void pnv_pci_ioda2_do_tce_invalidate(unsigned pe_number, bool rm,
-               __be64 __iomem *invalidate, unsigned shift,
-               unsigned long index, unsigned long npages)
+static void pnv_pci_phb3_tce_invalidate(struct pnv_ioda_pe *pe, bool rm,
+                                       unsigned shift, unsigned long index,
+                                       unsigned long npages)
 {
+       __be64 __iomem *invalidate = pnv_ioda_get_inval_reg(pe->phb, rm);
        unsigned long start, end, inc;
 
        /* We'll invalidate DMA address in PE scope */
-       start = TCE_KILL_INVAL_TCE;
-       start |= (pe_number & 0xFF);
+       start = PHB3_TCE_KILL_INVAL_ONE;
+       start |= (pe->pe_number & 0xFF);
        end = start;
 
        /* Figure out the start, end and step */
@@ -1875,6 +1900,17 @@ static void pnv_pci_ioda2_do_tce_invalidate(unsigned pe_number, bool rm,
        }
 }
 
+static inline void pnv_pci_ioda2_tce_invalidate_pe(struct pnv_ioda_pe *pe)
+{
+       struct pnv_phb *phb = pe->phb;
+
+       if (phb->model == PNV_PHB_MODEL_PHB3 && phb->regs)
+               pnv_pci_phb3_tce_invalidate_pe(pe);
+       else
+               opal_pci_tce_kill(phb->opal_id, OPAL_PCI_TCE_KILL_PE,
+                                 pe->pe_number, 0, 0, 0);
+}
+
 static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
                unsigned long index, unsigned long npages, bool rm)
 {
@@ -1883,34 +1919,43 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
        list_for_each_entry_rcu(tgl, &tbl->it_group_list, next) {
                struct pnv_ioda_pe *pe = container_of(tgl->table_group,
                                struct pnv_ioda_pe, table_group);
-               __be64 __iomem *invalidate = rm ?
-                       (__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys :
-                       pe->phb->ioda.tce_inval_reg;
+               struct pnv_phb *phb = pe->phb;
+               unsigned int shift = tbl->it_page_shift;
 
-               if (pe->phb->type == PNV_PHB_NPU) {
+               if (phb->type == PNV_PHB_NPU) {
                        /*
                         * The NVLink hardware does not support TCE kill
                         * per TCE entry so we have to invalidate
                         * the entire cache for it.
                         */
-                       pnv_pci_ioda2_tce_invalidate_entire(pe->phb, rm);
+                       pnv_pci_phb3_tce_invalidate_entire(phb, rm);
                        continue;
                }
-               pnv_pci_ioda2_do_tce_invalidate(pe->pe_number, rm,
-                       invalidate, tbl->it_page_shift,
-                       index, npages);
+               if (phb->model == PNV_PHB_MODEL_PHB3 && phb->regs)
+                       pnv_pci_phb3_tce_invalidate(pe, rm, shift,
+                                                   index, npages);
+               else if (rm)
+                       opal_rm_pci_tce_kill(phb->opal_id,
+                                            OPAL_PCI_TCE_KILL_PAGES,
+                                            pe->pe_number, 1u << shift,
+                                            index << shift, npages);
+               else
+                       opal_pci_tce_kill(phb->opal_id,
+                                         OPAL_PCI_TCE_KILL_PAGES,
+                                         pe->pe_number, 1u << shift,
+                                         index << shift, npages);
        }
 }
 
 static int pnv_ioda2_tce_build(struct iommu_table *tbl, long index,
                long npages, unsigned long uaddr,
                enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
                        attrs);
 
-       if (!ret && (tbl->it_type & TCE_PCI_SWINV_CREATE))
+       if (!ret)
                pnv_pci_ioda2_tce_invalidate(tbl, index, npages, false);
 
        return ret;
@@ -1922,8 +1967,7 @@ static int pnv_ioda2_tce_xchg(struct iommu_table *tbl, long index,
 {
        long ret = pnv_tce_xchg(tbl, index, hpa, direction);
 
-       if (!ret && (tbl->it_type &
-                       (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE)))
+       if (!ret)
                pnv_pci_ioda2_tce_invalidate(tbl, index, 1, false);
 
        return ret;
@@ -1935,8 +1979,7 @@ static void pnv_ioda2_tce_free(struct iommu_table *tbl, long index,
 {
        pnv_tce_free(tbl, index, npages);
 
-       if (tbl->it_type & TCE_PCI_SWINV_FREE)
-               pnv_pci_ioda2_tce_invalidate(tbl, index, npages, false);
+       pnv_pci_ioda2_tce_invalidate(tbl, index, npages, false);
 }
 
 static void pnv_ioda2_table_free(struct iommu_table *tbl)
@@ -2105,12 +2148,6 @@ found:
                                  base * PNV_IODA1_DMA32_SEGSIZE,
                                  IOMMU_PAGE_SHIFT_4K);
 
-       /* OPAL variant of P7IOC SW invalidated TCEs */
-       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;
        pe->table_group.tce32_start = tbl->it_offset << tbl->it_page_shift;
        pe->table_group.tce32_size = tbl->it_size << tbl->it_page_shift;
@@ -2172,7 +2209,7 @@ static long pnv_pci_ioda2_set_window(struct iommu_table_group *table_group,
 
        pnv_pci_link_table_and_group(phb->hose->node, num,
                        tbl, &pe->table_group);
-       pnv_pci_ioda2_tce_invalidate_pe(pe);
+       pnv_pci_phb3_tce_invalidate_pe(pe);
 
        return 0;
 }
@@ -2233,8 +2270,6 @@ static long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group,
        }
 
        tbl->it_ops = &pnv_ioda2_iommu_ops;
-       if (pe->phb->ioda.tce_inval_reg)
-               tbl->it_type |= (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE);
 
        *ptbl = tbl;
 
@@ -2283,10 +2318,6 @@ static long pnv_pci_ioda2_setup_default_config(struct pnv_ioda_pe *pe)
        if (!pnv_iommu_bypass_disabled)
                pnv_pci_ioda2_set_bypass(pe, true);
 
-       /* OPAL variant of PHB3 invalidated TCEs */
-       if (pe->phb->ioda.tce_inval_reg)
-               tbl->it_type |= (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE);
-
        /*
         * Setting table base here only for carrying iommu_group
         * further down to let iommu_add_device() do the job.
@@ -2316,7 +2347,7 @@ static long pnv_pci_ioda2_unset_window(struct iommu_table_group *table_group,
        if (ret)
                pe_warn(pe, "Unmapping failed, ret = %ld\n", ret);
        else
-               pnv_pci_ioda2_tce_invalidate_pe(pe);
+               pnv_pci_phb3_tce_invalidate_pe(pe);
 
        pnv_pci_unlink_table_and_group(table_group->tables[num], table_group);
 
@@ -2497,19 +2528,6 @@ static void pnv_pci_ioda_setup_iommu_api(void)
 static void pnv_pci_ioda_setup_iommu_api(void) { };
 #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 __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
                unsigned levels, unsigned long limit,
                unsigned long *current_offset, unsigned long *total_allocated)
@@ -2705,7 +2723,8 @@ void pnv_set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq)
        struct irq_data *idata;
        struct irq_chip *ichip;
 
-       if (phb->type != PNV_PHB_IODA2)
+       /* The MSI EOI OPAL call is only needed on PHB3 */
+       if (phb->model != PNV_PHB_MODEL_PHB3)
                return;
 
        if (!phb->ioda.irq_chip_init) {
@@ -3285,7 +3304,7 @@ static void pnv_pci_ioda1_release_pe_dma(struct pnv_ioda_pe *pe)
        if (rc != OPAL_SUCCESS)
                return;
 
-       pnv_pci_ioda1_tce_invalidate(tbl, tbl->it_offset, tbl->it_size, false);
+       pnv_pci_p7ioc_tce_invalidate(tbl, tbl->it_offset, tbl->it_size, false);
        if (pe->table_group.group) {
                iommu_group_put(pe->table_group.group);
                WARN_ON(pe->table_group.group);
@@ -3465,6 +3484,10 @@ static const struct pci_controller_ops pnv_npu_ioda_controller_ops = {
 const struct pci_controller_ops pnv_cxl_cx4_ioda_controller_ops = {
        .dma_dev_setup          = pnv_pci_dma_dev_setup,
        .dma_bus_setup          = pnv_pci_dma_bus_setup,
+#ifdef CONFIG_PCI_MSI
+       .setup_msi_irqs         = pnv_cxl_cx4_setup_msi_irqs,
+       .teardown_msi_irqs      = pnv_cxl_cx4_teardown_msi_irqs,
+#endif
        .enable_device_hook     = pnv_cxl_enable_device_hook,
        .disable_device         = pnv_cxl_disable_device,
        .release_device         = pnv_pci_release_device,
@@ -3484,6 +3507,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
        struct pnv_phb *phb;
        unsigned long size, m64map_off, m32map_off, pemap_off;
        unsigned long iomap_off = 0, dma32map_off = 0;
+       struct resource r;
        const __be64 *prop64;
        const __be32 *prop32;
        int len;
@@ -3492,6 +3516,9 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
        void *aux;
        long rc;
 
+       if (!of_device_is_available(np))
+               return;
+
        pr_info("Initializing %s PHB (%s)\n",
                pnv_phb_names[ioda_type], of_node_full_name(np));
 
@@ -3544,12 +3571,12 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
        pci_process_bridge_OF_ranges(hose, np, !hose->global_number);
 
        /* Get registers */
-       phb->regs = of_iomap(np, 0);
-       if (phb->regs == NULL)
-               pr_err("  Failed to map registers !\n");
-
-       /* Initialize TCE kill register */
-       pnv_pci_ioda_setup_opal_tce_kill(phb);
+       if (!of_address_to_resource(np, 0, &r)) {
+               phb->regs_phys = r.start;
+               phb->regs = ioremap(r.start, resource_size(&r));
+               if (phb->regs == NULL)
+                       pr_err("  Failed to map registers !\n");
+       }
 
        /* Initialize more IODA stuff */
        phb->ioda.total_pe_num = 1;