void __init init_IRQ(void) { if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq) irqchip_init(); else machine_desc->init_irq(); ==>{ DT_MACHINE_START(CNS3XXX_DT, "Cavium Networks CNS3xxx") .dt_compat = cns3xxx_dt_compat, .map_io = cns3xxx_map_io, .init_irq = cns3xxx_init_irq, =>/* used by entry-macro.S */ void __init cns3xxx_init_irq(void) { gic_init(0, 29, IOMEM(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT), IOMEM(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT)); =>void __init gic_init(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base) { struct gic_chip_data *gic = &gic_data[gic_nr]; gic->raw_dist_base = dist_base; gic->raw_cpu_base = cpu_base; __gic_init_bases(gic, irq_start, NULL); =>int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start, struct fwnode_handle *handle) { if (gic == &gic_data[0]) { /* * Initialize the CPU interface map to all CPUs. * It will be refined as each CPU probes its ID. * This is only necessary for the primary GIC. */ for (i = 0; i < NR_GIC_CPU_IF; i++) gic_cpu_map[i] = 0xff; set_smp_cross_call(gic_raise_softirq); cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING, "irqchip/arm/gic:starting", gic_starting_cpu, NULL); set_handle_irq(gic_handle_irq); } if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) { name = kasprintf(GFP_KERNEL, "GICv2"); gic_init_chip(gic, NULL, name, true); } else { name = kasprintf(GFP_KERNEL, "GIC-%d", (int)(gic-&gic_data[0])); gic_init_chip(gic, NULL, name, false); } ret = gic_init_bases(gic, irq_start, handle); =>int gic_init_bases(struct gic_chip_data *gic, int irq_start, struct fwnode_handle *handle) { irq_hw_number_t hwirq_base; int gic_irqs, irq_base, ret; if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) { /* Frankein-GIC without banked registers... */ unsigned int cpu; gic->dist_base.percpu_base = alloc_percpu(void __iomem *); gic->cpu_base.percpu_base = alloc_percpu(void __iomem *); for_each_possible_cpu(cpu) { u32 mpidr = cpu_logical_map(cpu); u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); unsigned long offset = gic->percpu_offset * core_id; *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = gic->raw_dist_base + offset; *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = gic->raw_cpu_base + offset; } gic_set_base_accessor(gic, gic_get_percpu_base); } else { /* Normal, sane GIC... */ WARN(gic->percpu_offset, "GIC_NON_BANKED not enabled, ignoring %08x offset!", gic->percpu_offset); gic->dist_base.common_base = gic->raw_dist_base; gic->cpu_base.common_base = gic->raw_cpu_base; gic_set_base_accessor(gic, gic_get_common_base); } /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; if (gic_irqs > 1020) gic_irqs = 1020; gic->gic_irqs = gic_irqs; if (handle) { /* DT/ACPI */ gic->domain = irq_domain_create_linear(handle, gic_irqs, &gic_irq_domain_hierarchy_ops, gic); } else { /* Legacy support */ /* * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. */ if (gic == &gic_data[0] && (irq_start & 31) > 0) { hwirq_base = 16; if (irq_start != -1) irq_start = (irq_start & ~31) + 16; } else { hwirq_base = 32; } gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); if (irq_base < 0) { WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", irq_start); irq_base = irq_start; } gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base, hwirq_base, &gic_irq_domain_ops, gic); =>struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, unsigned int size, unsigned int first_irq, irq_hw_number_t first_hwirq, const struct irq_domain_ops *ops, void *host_data) { struct irq_domain *domain; domain = __irq_domain_add(of_node_to_fwnode(of_node), first_hwirq + size, first_hwirq + size, 0, ops, host_data); if (domain) irq_domain_associate_many(domain, first_irq, first_hwirq, size); =>void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, irq_hw_number_t hwirq_base, int count) { struct device_node *of_node; int i; of_node = irq_domain_get_of_node(domain); for (i = 0; i < count; i++) { irq_domain_associate(domain, irq_base + i, hwirq_base + i); =>int irq_domain_associate(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) { struct irq_data *irq_data = irq_get_irq_data(virq); int ret; irq_data->hwirq = hwirq; irq_data->domain = domain; if (domain->ops->map) { ret = domain->ops->map(domain, virq, hwirq); /* If not already assigned, give the domain the chip's name */ if (!domain->name && irq_data->chip) domain->name = irq_data->chip->name; } domain->mapcount++; irq_domain_set_mapping(domain, hwirq, irq_data); =>void irq_domain_set_mapping(struct irq_domain *domain, irq_hw_number_t hwirq, struct irq_data *irq_data) { if (hwirq < domain->revmap_size) { domain->linear_revmap[hwirq] = irq_data->irq; } else { mutex_lock(&domain->revmap_tree_mutex); radix_tree_insert(&domain->revmap_tree, hwirq, irq_data); mutex_unlock(&domain->revmap_tree_mutex); } } irq_clear_status_flags(virq, IRQ_NOREQUEST); return 0; } } } return domain; } } gic_dist_init(gic); ret = gic_cpu_init(gic); ret = gic_pm_init(gic); return 0; return ret; } return ret; } } } MACHINE_END } ]