int __init register_intc_controller()

in intc/core.c [197:395]


int __init register_intc_controller(struct intc_desc *desc)
{
	unsigned int i, k, smp;
	struct intc_hw_desc *hw = &desc->hw;
	struct intc_desc_int *d;
	struct resource *res;

	pr_info("Registered controller '%s' with %u IRQs\n",
		desc->name, hw->nr_vectors);

	d = kzalloc(sizeof(*d), GFP_NOWAIT);
	if (!d)
		goto err0;

	INIT_LIST_HEAD(&d->list);
	list_add_tail(&d->list, &intc_list);

	raw_spin_lock_init(&d->lock);
	INIT_RADIX_TREE(&d->tree, GFP_ATOMIC);

	d->index = nr_intc_controllers;

	if (desc->num_resources) {
		d->nr_windows = desc->num_resources;
		d->window = kcalloc(d->nr_windows, sizeof(*d->window),
				    GFP_NOWAIT);
		if (!d->window)
			goto err1;

		for (k = 0; k < d->nr_windows; k++) {
			res = desc->resource + k;
			WARN_ON(resource_type(res) != IORESOURCE_MEM);
			d->window[k].phys = res->start;
			d->window[k].size = resource_size(res);
			d->window[k].virt = ioremap(res->start,
						    resource_size(res));
			if (!d->window[k].virt)
				goto err2;
		}
	}

	d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
#ifdef CONFIG_INTC_BALANCING
	if (d->nr_reg)
		d->nr_reg += hw->nr_mask_regs;
#endif
	d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
	d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
	d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
	d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0;

	d->reg = kcalloc(d->nr_reg, sizeof(*d->reg), GFP_NOWAIT);
	if (!d->reg)
		goto err2;

#ifdef CONFIG_SMP
	d->smp = kcalloc(d->nr_reg, sizeof(*d->smp), GFP_NOWAIT);
	if (!d->smp)
		goto err3;
#endif
	k = 0;

	if (hw->mask_regs) {
		for (i = 0; i < hw->nr_mask_regs; i++) {
			smp = IS_SMP(hw->mask_regs[i]);
			k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
			k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
#ifdef CONFIG_INTC_BALANCING
			k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
#endif
		}
	}

	if (hw->prio_regs) {
		d->prio = kcalloc(hw->nr_vectors, sizeof(*d->prio),
				  GFP_NOWAIT);
		if (!d->prio)
			goto err4;

		for (i = 0; i < hw->nr_prio_regs; i++) {
			smp = IS_SMP(hw->prio_regs[i]);
			k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
			k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
		}

		sort(d->prio, hw->nr_prio_regs, sizeof(*d->prio),
		     intc_handle_int_cmp, NULL);
	}

	if (hw->sense_regs) {
		d->sense = kcalloc(hw->nr_vectors, sizeof(*d->sense),
				   GFP_NOWAIT);
		if (!d->sense)
			goto err5;

		for (i = 0; i < hw->nr_sense_regs; i++)
			k += save_reg(d, k, hw->sense_regs[i].reg, 0);

		sort(d->sense, hw->nr_sense_regs, sizeof(*d->sense),
		     intc_handle_int_cmp, NULL);
	}

	if (hw->subgroups)
		for (i = 0; i < hw->nr_subgroups; i++)
			if (hw->subgroups[i].reg)
				k+= save_reg(d, k, hw->subgroups[i].reg, 0);

	memcpy(&d->chip, &intc_irq_chip, sizeof(struct irq_chip));
	d->chip.name = desc->name;

	if (hw->ack_regs)
		for (i = 0; i < hw->nr_ack_regs; i++)
			k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
	else
		d->chip.irq_mask_ack = d->chip.irq_disable;

	/* disable bits matching force_disable before registering irqs */
	if (desc->force_disable)
		intc_enable_disable_enum(desc, d, desc->force_disable, 0);

	/* disable bits matching force_enable before registering irqs */
	if (desc->force_enable)
		intc_enable_disable_enum(desc, d, desc->force_enable, 0);

	BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */

	intc_irq_domain_init(d, hw);

	/* register the vectors one by one */
	for (i = 0; i < hw->nr_vectors; i++) {
		struct intc_vect *vect = hw->vectors + i;
		unsigned int irq = evt2irq(vect->vect);

		if (!vect->enum_id)
			continue;

		if (!intc_map(d->domain, irq))
			continue;

		intc_irq_xlate_set(irq, vect->enum_id, d);
		intc_register_irq(desc, d, vect->enum_id, irq);

		for (k = i + 1; k < hw->nr_vectors; k++) {
			struct intc_vect *vect2 = hw->vectors + k;
			unsigned int irq2 = evt2irq(vect2->vect);

			if (vect->enum_id != vect2->enum_id)
				continue;

			/*
			 * In the case of multi-evt handling and sparse
			 * IRQ support, each vector still needs to have
			 * its own backing irq_desc.
			 */
			if (!intc_map(d->domain, irq2))
				continue;

			vect2->enum_id = 0;

			/* redirect this interrupts to the first one */
			irq_set_chip(irq2, &dummy_irq_chip);
			irq_set_chained_handler_and_data(irq2,
							 intc_redirect_irq,
							 (void *)irq);
		}
	}

	intc_subgroup_init(desc, d);

	/* enable bits matching force_enable after registering irqs */
	if (desc->force_enable)
		intc_enable_disable_enum(desc, d, desc->force_enable, 1);

	d->skip_suspend = desc->skip_syscore_suspend;

	nr_intc_controllers++;

	return 0;
err5:
	kfree(d->prio);
err4:
#ifdef CONFIG_SMP
	kfree(d->smp);
err3:
#endif
	kfree(d->reg);
err2:
	for (k = 0; k < d->nr_windows; k++)
		if (d->window[k].virt)
			iounmap(d->window[k].virt);

	kfree(d->window);
err1:
	kfree(d);
err0:
	pr_err("unable to allocate INTC memory\n");

	return -ENOMEM;
}