From: Tomasz Nowicki tomasz.nowicki@linaro.org
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Robert Richter rrichter@cavium.com Signed-off-by: Vadim Lomovtsev Vadim.Lomovtsev@caviumnetworks.com --- drivers/irqchip/irq-gic-v3-its.c | 131 +++++++++++++++++++------------------ drivers/irqchip/irq-gic-v3.c | 4 +- include/linux/irqchip/arm-gic-v3.h | 4 +- 3 files changed, 71 insertions(+), 68 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index cb7f33d..3b7f352 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -99,7 +99,6 @@ struct its_device {
static LIST_HEAD(its_nodes); static DEFINE_SPINLOCK(its_lock); -static struct device_node *gic_root_node; static struct rdists *gic_rdists;
#define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist)) @@ -888,8 +887,8 @@ static int its_alloc_tables(struct its_node *its) order); 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); + pr_warn("ITS: Device Table too large, reduce its page order to %u\n", + order); } }
@@ -898,8 +897,8 @@ static int its_alloc_tables(struct its_node *its) 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", - its->msi_chip.of_node->full_name, order, alloc_pages); + pr_warn("ITS: Device Table too large, reduce its page order to %u (%u pages)\n", + order, alloc_pages); }
base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); @@ -966,9 +965,8 @@ 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, - (unsigned long) val, (unsigned long) tmp); + pr_err("ITS: GITS_BASER%d doesn't stick: %lx %lx\n", + i, (unsigned long)val, (unsigned long)tmp); err = -ENXIO; goto out_free; } @@ -1481,43 +1479,33 @@ static void its_check_capabilities(struct its_node *its) gic_check_capabilities(iidr, its_errata, its); }
-static int its_probe(struct device_node *node, struct irq_domain *parent) +static struct its_node *its_probe(unsigned long phys_base, unsigned long size) { - struct resource res; struct its_node *its; void __iomem *its_base; u32 val; u64 baser, tmp; int err;
- err = of_address_to_resource(node, 0, &res); - if (err) { - pr_warn("%s: no regs?\n", node->full_name); - return -ENXIO; - } - - its_base = ioremap(res.start, resource_size(&res)); + its_base = ioremap(phys_base, size); if (!its_base) { - pr_warn("%s: unable to map registers\n", node->full_name); - return -ENOMEM; + pr_warn("Unable to map registers\n"); + return NULL; }
val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK; if (val != 0x30 && val != 0x40) { - pr_warn("%s: no ITS detected, giving up\n", node->full_name); + pr_warn("No ITS detected, giving up\n"); err = -ENODEV; goto out_unmap; }
err = its_force_quiescent(its_base); if (err) { - pr_warn("%s: failed to quiesce, giving up\n", - node->full_name); + pr_warn("ITS: Failed to quiesce, giving up: %d\n", err); goto out_unmap; }
- pr_info("ITS: %s\n", node->full_name); - its = kzalloc(sizeof(*its), GFP_KERNEL); if (!its) { err = -ENOMEM; @@ -1528,8 +1516,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) INIT_LIST_HEAD(&its->entry); INIT_LIST_HEAD(&its->its_device_list); its->base = its_base; - its->phys_base = res.start; - its->msi_chip.of_node = node; + its->phys_base = phys_base; its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); @@ -1577,39 +1564,12 @@ 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) { - 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) { - err = -ENOMEM; - goto out_free_domains; - } - - err = of_pci_msi_chip_add(&its->msi_chip); - if (err) - goto out_free_domains; - } - spin_lock(&its_lock); list_add(&its->entry, &its_nodes); spin_unlock(&its_lock);
- return 0; + return its;
-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: @@ -1618,8 +1578,8 @@ out_free_its: kfree(its); out_unmap: iounmap(its_base); - pr_err("ITS: failed probing %s (%d)\n", node->full_name, err); - return err; + pr_err("ITS: failed probing (%d)\n", err); + return NULL; }
static bool gic_rdists_supports_plpis(void) @@ -1641,31 +1601,72 @@ int its_cpu_init(void) return 0; }
+static int its_init_domain(struct device_node *node, struct its_node *its) +{ + its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its); + if (!its->domain) + return -ENOMEM; + + its->msi_chip.domain = pci_msi_create_irq_domain(node, + &its_pci_msi_domain_info, + its->domain); + if (!its->msi_chip.domain) { + irq_domain_remove(its->domain); + return -ENOMEM; + } + + return 0; +} + static struct of_device_id its_device_id[] = { { .compatible = "arm,gic-v3-its", }, {}, };
-int its_init(struct device_node *node, struct rdists *rdists, - struct irq_domain *parent_domain) +void its_of_probe(struct device_node *node) { struct device_node *np; + struct its_node *its; + struct resource res;
for (np = of_find_matching_node(node, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { - its_probe(np, parent_domain); + if (of_address_to_resource(np, 0, &res)) { + pr_warn("%s: no regs?\n", node->full_name); + continue; + } + + pr_info("ITS: %s\n", np->full_name); + its = its_probe(res.start, resource_size(&res)); + if (!its) + continue; + + its->msi_chip.of_node = np; + if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) { + if (its_init_domain(np, its)) + continue; + + of_pci_msi_chip_add(&its->msi_chip); + } } +} + +void its_init(struct rdists *rdists, struct irq_domain *domain) +{ + struct its_node *its;
- if (list_empty(&its_nodes)) { - pr_warn("ITS: No ITS available, not enabling LPIs\n"); - return -ENXIO; + if (list_empty(&its_nodes)) + pr_info("ITS: No ITS available, not enabling LPIs\n"); + + spin_lock(&its_lock); + list_for_each_entry(its, &its_nodes, entry) { + if (its->domain) + its->domain->parent = domain; } + spin_unlock(&its_lock);
gic_rdists = rdists; - gic_root_node = node;
its_alloc_lpi_tables(); its_lpi_init(rdists->id_bits); - - return 0; } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index db82724..d78589c 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -869,7 +869,7 @@ static int __init gic_init_bases(void __iomem *dist_base, set_handle_irq(gic_handle_irq);
if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()) - its_init(node, &gic_data.rdists, gic_data.domain); + its_init(&gic_data.rdists, gic_data.domain);
gic_smp_init(); gic_dist_init(); @@ -928,6 +928,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) redist_stride = 0;
+ its_of_probe(node); + err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, redist_stride, node); if (!err) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 5bbd47c..2c8f0f5 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -399,8 +399,8 @@ static inline void gic_write_eoir(u64 irq)
struct irq_domain; int its_cpu_init(void); -int its_init(struct device_node *node, struct rdists *rdists, - struct irq_domain *domain); +void its_init(struct rdists *rdists, struct irq_domain *domain); +void its_of_probe(struct device_node *node);
typedef u32 (*its_pci_requester_id_t)(struct pci_dev *, u16); void set_its_pci_requester_id(its_pci_requester_id_t fn);