These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / irqchip / irq-gic-v3-its.c
index c00e2db..a159529 100644 (file)
 #include <linux/percpu.h>
 #include <linux/slab.h>
 
+#include <linux/irqchip.h>
 #include <linux/irqchip/arm-gic-v3.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cputype.h>
 #include <asm/exception.h>
 
-#include "irqchip.h"
+#include "irq-gic-common.h"
 
-#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING          (1 << 0)
+#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING          (1ULL << 0)
+#define ITS_FLAGS_WORKAROUND_CAVIUM_22375      (1ULL << 1)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
 
@@ -54,14 +56,12 @@ struct its_collection {
 
 /*
  * The ITS structure - contains most of the infrastructure, with the
- * msi_controller, the command queue, the collections, and the list of
- * devices writing to it.
+ * top-level MSI domain, the command queue, the collections, and the
+ * list of devices writing to it.
  */
 struct its_node {
        raw_spinlock_t          lock;
        struct list_head        entry;
-       struct msi_controller   msi_chip;
-       struct irq_domain       *domain;
        void __iomem            *base;
        unsigned long           phys_base;
        struct its_cmd_block    *cmd_base;
@@ -597,11 +597,6 @@ static void its_unmask_irq(struct irq_data *d)
        lpi_set_config(d, true);
 }
 
-static void its_eoi_irq(struct irq_data *d)
-{
-       gic_write_eoir(d->hwirq);
-}
-
 static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
                            bool force)
 {
@@ -638,31 +633,11 @@ static struct irq_chip its_irq_chip = {
        .name                   = "ITS",
        .irq_mask               = its_mask_irq,
        .irq_unmask             = its_unmask_irq,
-       .irq_eoi                = its_eoi_irq,
+       .irq_eoi                = irq_chip_eoi_parent,
        .irq_set_affinity       = its_set_affinity,
        .irq_compose_msi_msg    = its_irq_compose_msi_msg,
 };
 
-static void its_mask_msi_irq(struct irq_data *d)
-{
-       pci_msi_mask_irq(d);
-       irq_chip_mask_parent(d);
-}
-
-static void its_unmask_msi_irq(struct irq_data *d)
-{
-       pci_msi_unmask_irq(d);
-       irq_chip_unmask_parent(d);
-}
-
-static struct irq_chip its_msi_irq_chip = {
-       .name                   = "ITS-MSI",
-       .irq_unmask             = its_unmask_msi_irq,
-       .irq_mask               = its_mask_msi_irq,
-       .irq_eoi                = irq_chip_eoi_parent,
-       .irq_write_msi_msg      = pci_msi_domain_write_msg,
-};
-
 /*
  * How we allocate LPIs:
  *
@@ -742,6 +717,9 @@ static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids)
 out:
        spin_unlock(&lpi_lock);
 
+       if (!bitmap)
+               *base = *nr_ids = 0;
+
        return bitmap;
 }
 
@@ -831,13 +809,28 @@ static void its_free_tables(struct its_node *its)
        }
 }
 
-static int its_alloc_tables(struct its_node *its)
+static int its_alloc_tables(const char *node_name, struct its_node *its)
 {
        int err;
        int i;
        int psz = SZ_64K;
        u64 shr = GITS_BASER_InnerShareable;
-       u64 cache = GITS_BASER_WaWb;
+       u64 cache;
+       u64 typer;
+       u32 ids;
+
+       if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_22375) {
+               /*
+                * erratum 22375: only alloc 8MB table size
+                * erratum 24313: ignore memory access type
+                */
+               cache   = 0;
+               ids     = 0x14;                 /* 20 bits, 8MB */
+       } else {
+               cache   = GITS_BASER_WaWb;
+               typer   = readq_relaxed(its->base + GITS_TYPER);
+               ids     = GITS_TYPER_DEVBITS(typer);
+       }
 
        for (i = 0; i < GITS_BASER_NR_REGS; i++) {
                u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
@@ -845,6 +838,7 @@ static int its_alloc_tables(struct its_node *its)
                u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
                int order = get_order(psz);
                int alloc_size;
+               int alloc_pages;
                u64 tmp;
                void *base;
 
@@ -860,9 +854,6 @@ static int its_alloc_tables(struct its_node *its)
                 * For other tables, only allocate a single page.
                 */
                if (type == GITS_BASER_TYPE_DEVICE) {
-                       u64 typer = readq_relaxed(its->base + GITS_TYPER);
-                       u32 ids = GITS_TYPER_DEVBITS(typer);
-
                        /*
                         * 'order' was initialized earlier to the default page
                         * granule of the the ITS.  We can't have an allocation
@@ -874,11 +865,19 @@ static int its_alloc_tables(struct its_node *its)
                        if (order >= MAX_ORDER) {
                                order = MAX_ORDER - 1;
                                pr_warn("%s: Device Table too large, reduce its page order to %u\n",
-                                       its->msi_chip.of_node->full_name, order);
+                                       node_name, order);
                        }
                }
 
                alloc_size = (1 << order) * PAGE_SIZE;
+               alloc_pages = (alloc_size / psz);
+               if (alloc_pages > GITS_BASER_PAGES_MAX) {
+                       alloc_pages = GITS_BASER_PAGES_MAX;
+                       order = get_order(GITS_BASER_PAGES_MAX * psz);
+                       pr_warn("%s: Device Table too large, reduce its page order to %u (%u pages)\n",
+                               node_name, order, alloc_pages);
+               }
+
                base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
                if (!base) {
                        err = -ENOMEM;
@@ -907,7 +906,7 @@ retry_baser:
                        break;
                }
 
-               val |= (alloc_size / psz) - 1;
+               val |= alloc_pages - 1;
 
                writeq_relaxed(val, its->base + GITS_BASER + i * 8);
                tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
@@ -921,8 +920,10 @@ retry_baser:
                         * non-cacheable as well.
                         */
                        shr = tmp & GITS_BASER_SHAREABILITY_MASK;
-                       if (!shr)
+                       if (!shr) {
                                cache = GITS_BASER_nC;
+                               __flush_dcache_area(base, alloc_size);
+                       }
                        goto retry_baser;
                }
 
@@ -944,7 +945,7 @@ retry_baser:
 
                if (val != tmp) {
                        pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n",
-                              its->msi_chip.of_node->full_name, i,
+                              node_name, i,
                               (unsigned long) val, (unsigned long) tmp);
                        err = -ENXIO;
                        goto out_free;
@@ -1163,6 +1164,8 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
                return NULL;
        }
 
+       __flush_dcache_area(itt, sz);
+
        dev->its = its;
        dev->itt = itt;
        dev->nr_ites = nr_ites;
@@ -1209,98 +1212,67 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
        return 0;
 }
 
-struct its_pci_alias {
-       struct pci_dev  *pdev;
-       u32             dev_id;
-       u32             count;
-};
-
-static int its_pci_msi_vec_count(struct pci_dev *pdev)
-{
-       int msi, msix;
-
-       msi = max(pci_msi_vec_count(pdev), 0);
-       msix = max(pci_msix_vec_count(pdev), 0);
-
-       return max(msi, msix);
-}
-
-static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
-{
-       struct its_pci_alias *dev_alias = data;
-
-       dev_alias->dev_id = alias;
-       if (pdev != dev_alias->pdev)
-               dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev);
-
-       return 0;
-}
-
 static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
                           int nvec, msi_alloc_info_t *info)
 {
-       struct pci_dev *pdev;
        struct its_node *its;
        struct its_device *its_dev;
-       struct its_pci_alias dev_alias;
-
-       if (!dev_is_pci(dev))
-               return -EINVAL;
+       struct msi_domain_info *msi_info;
+       u32 dev_id;
 
-       pdev = to_pci_dev(dev);
-       dev_alias.pdev = pdev;
-       dev_alias.count = nvec;
+       /*
+        * We ignore "dev" entierely, and rely on the dev_id that has
+        * been passed via the scratchpad. This limits this domain's
+        * usefulness to upper layers that definitely know that they
+        * are built on top of the ITS.
+        */
+       dev_id = info->scratchpad[0].ul;
 
-       pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
-       its = domain->parent->host_data;
+       msi_info = msi_get_domain_info(domain);
+       its = msi_info->data;
 
-       its_dev = its_find_device(its, dev_alias.dev_id);
+       its_dev = its_find_device(its, dev_id);
        if (its_dev) {
                /*
                 * We already have seen this ID, probably through
                 * another alias (PCI bridge of some sort). No need to
                 * create the device.
                 */
-               dev_dbg(dev, "Reusing ITT for devID %x\n", dev_alias.dev_id);
+               pr_debug("Reusing ITT for devID %x\n", dev_id);
                goto out;
        }
 
-       its_dev = its_create_device(its, dev_alias.dev_id, dev_alias.count);
+       its_dev = its_create_device(its, dev_id, nvec);
        if (!its_dev)
                return -ENOMEM;
 
-       dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n",
-               dev_alias.count, ilog2(dev_alias.count));
+       pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec));
 out:
        info->scratchpad[0].ptr = its_dev;
-       info->scratchpad[1].ptr = dev;
        return 0;
 }
 
-static struct msi_domain_ops its_pci_msi_ops = {
+static struct msi_domain_ops its_msi_domain_ops = {
        .msi_prepare    = its_msi_prepare,
 };
 
-static struct msi_domain_info its_pci_msi_domain_info = {
-       .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-                  MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
-       .ops    = &its_pci_msi_ops,
-       .chip   = &its_msi_irq_chip,
-};
-
 static int its_irq_gic_domain_alloc(struct irq_domain *domain,
                                    unsigned int virq,
                                    irq_hw_number_t hwirq)
 {
-       struct of_phandle_args args;
+       struct irq_fwspec fwspec;
 
-       args.np = domain->parent->of_node;
-       args.args_count = 3;
-       args.args[0] = GIC_IRQ_TYPE_LPI;
-       args.args[1] = hwirq;
-       args.args[2] = IRQ_TYPE_EDGE_RISING;
+       if (irq_domain_get_of_node(domain->parent)) {
+               fwspec.fwnode = domain->parent->fwnode;
+               fwspec.param_count = 3;
+               fwspec.param[0] = GIC_IRQ_TYPE_LPI;
+               fwspec.param[1] = hwirq;
+               fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+       } else {
+               return -EINVAL;
+       }
 
-       return irq_domain_alloc_irqs_parent(domain, virq, 1, &args);
+       return irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
 }
 
 static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
@@ -1323,9 +1295,9 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 
                irq_domain_set_hwirq_and_chip(domain, virq + i,
                                              hwirq, &its_irq_chip, its_dev);
-               dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n",
-                       (int)(hwirq - its_dev->event_map.lpi_base),
-                       (int)hwirq, virq + i);
+               pr_debug("ID:%d pID:%d vID:%d\n",
+                        (int)(hwirq - its_dev->event_map.lpi_base),
+                        (int) hwirq, virq + i);
        }
 
        return 0;
@@ -1421,11 +1393,39 @@ static int its_force_quiescent(void __iomem *base)
        }
 }
 
+static void __maybe_unused its_enable_quirk_cavium_22375(void *data)
+{
+       struct its_node *its = data;
+
+       its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375;
+}
+
+static const struct gic_quirk its_quirks[] = {
+#ifdef CONFIG_CAVIUM_ERRATUM_22375
+       {
+               .desc   = "ITS: Cavium errata 22375, 24313",
+               .iidr   = 0xa100034c,   /* ThunderX pass 1.x */
+               .mask   = 0xffff0fff,
+               .init   = its_enable_quirk_cavium_22375,
+       },
+#endif
+       {
+       }
+};
+
+static void its_enable_quirks(struct its_node *its)
+{
+       u32 iidr = readl_relaxed(its->base + GITS_IIDR);
+
+       gic_enable_quirks(iidr, its_quirks, its);
+}
+
 static int its_probe(struct device_node *node, struct irq_domain *parent)
 {
        struct resource res;
        struct its_node *its;
        void __iomem *its_base;
+       struct irq_domain *inner_domain;
        u32 val;
        u64 baser, tmp;
        int err;
@@ -1469,7 +1469,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
        INIT_LIST_HEAD(&its->its_device_list);
        its->base = its_base;
        its->phys_base = res.start;
-       its->msi_chip.of_node = node;
        its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
 
        its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
@@ -1479,7 +1478,9 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
        }
        its->cmd_write = its->cmd_base;
 
-       err = its_alloc_tables(its);
+       its_enable_quirks(its);
+
+       err = its_alloc_tables(node->full_name, its);
        if (err)
                goto out_free_cmd;
 
@@ -1515,26 +1516,27 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
        writeq_relaxed(0, its->base + GITS_CWRITER);
        writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
 
-       if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) {
-               its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its);
-               if (!its->domain) {
+       if (of_property_read_bool(node, "msi-controller")) {
+               struct msi_domain_info *info;
+
+               info = kzalloc(sizeof(*info), GFP_KERNEL);
+               if (!info) {
                        err = -ENOMEM;
                        goto out_free_tables;
                }
 
-               its->domain->parent = parent;
-
-               its->msi_chip.domain = pci_msi_create_irq_domain(node,
-                                                                &its_pci_msi_domain_info,
-                                                                its->domain);
-               if (!its->msi_chip.domain) {
+               inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
+               if (!inner_domain) {
                        err = -ENOMEM;
-                       goto out_free_domains;
+                       kfree(info);
+                       goto out_free_tables;
                }
 
-               err = of_pci_msi_chip_add(&its->msi_chip);
-               if (err)
-                       goto out_free_domains;
+               inner_domain->parent = parent;
+               inner_domain->bus_token = DOMAIN_BUS_NEXUS;
+               info->ops = &its_msi_domain_ops;
+               info->data = its;
+               inner_domain->host_data = info;
        }
 
        spin_lock(&its_lock);
@@ -1543,11 +1545,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
 
        return 0;
 
-out_free_domains:
-       if (its->msi_chip.domain)
-               irq_domain_remove(its->msi_chip.domain);
-       if (its->domain)
-               irq_domain_remove(its->domain);
 out_free_tables:
        its_free_tables(its);
 out_free_cmd: