Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87161ccd authored by David Daney's avatar David Daney Committed by Ralf Baechle
Browse files

MIPS: Octeon: Fix broken interrupt controller code.



Since 3.6.0-rc1,  We are getting many messages like:

WARNING: at kernel/irq/irqdomain.c:444 irq_domain_associate_many+0x23c/0x260()
Modules linked in:
Call Trace:
[<ffffffff814cb698>] dump_stack+0x8/0x34
[<ffffffff81133d00>] warn_slowpath_common+0x78/0xa8
[<ffffffff81187e44>] irq_domain_associate_many+0x23c/0x260
[<ffffffff81187f38>] irq_create_mapping+0xd0/0x220
[<ffffffff81188104>] irq_create_of_mapping+0x7c/0x158
[<ffffffff813e5f08>] irq_of_parse_and_map+0x28/0x40
.
.
.

Both the CIU and GPIO interrupt domains were somewhat screwed up.

For the CIU domain, we need to call irq_domain_associate() for each of
the preassigned irq numbers.  For the GPIO domain, we were applying
the register bit offset in octeon_irq_gpio_xlat, but it should be done
in octeon_irq_gpio_map instead.

Also: Reserve all 8 'core' irqs for the 'core' irq_chip so that they
don't get used by the other domains.  Remove unused OCTEON_IRQ_*
symbols.

Signed-off-by: default avatarDavid Daney <david.daney@cavium.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/4190/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent d9875690
Loading
Loading
Loading
Loading
+43 −46
Original line number Diff line number Diff line
@@ -61,6 +61,12 @@ static void octeon_irq_set_ciu_mapping(int irq, int line, int bit,
	octeon_irq_ciu_to_irq[line][bit] = irq;
}

static void octeon_irq_force_ciu_mapping(struct irq_domain *domain,
					 int irq, int line, int bit)
{
	irq_domain_associate(domain, irq, line << 6 | bit);
}

static int octeon_coreid_for_cpu(int cpu)
{
#ifdef CONFIG_SMP
@@ -183,19 +189,9 @@ static void __init octeon_irq_init_core(void)
		mutex_init(&cd->core_irq_mutex);

		irq = OCTEON_IRQ_SW0 + i;
		switch (irq) {
		case OCTEON_IRQ_TIMER:
		case OCTEON_IRQ_SW0:
		case OCTEON_IRQ_SW1:
		case OCTEON_IRQ_5:
		case OCTEON_IRQ_PERF:
		irq_set_chip_data(irq, cd);
		irq_set_chip_and_handler(irq, &octeon_irq_chip_core,
					 handle_percpu_irq);
			break;
		default:
			break;
		}
	}
}

@@ -890,7 +886,6 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d,
	unsigned int type;
	unsigned int pin;
	unsigned int trigger;
	struct octeon_irq_gpio_domain_data *gpiod;

	if (d->of_node != node)
		return -EINVAL;
@@ -925,8 +920,7 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d,
		break;
	}
	*out_type = type;
	gpiod = d->host_data;
	*out_hwirq = gpiod->base_hwirq + pin;
	*out_hwirq = pin;

	return 0;
}
@@ -996,19 +990,21 @@ static int octeon_irq_ciu_map(struct irq_domain *d,
static int octeon_irq_gpio_map(struct irq_domain *d,
			       unsigned int virq, irq_hw_number_t hw)
{
	unsigned int line = hw >> 6;
	unsigned int bit = hw & 63;
	struct octeon_irq_gpio_domain_data *gpiod = d->host_data;
	unsigned int line, bit;

	if (!octeon_irq_virq_in_range(virq))
		return -EINVAL;

	hw += gpiod->base_hwirq;
	line = hw >> 6;
	bit = hw & 63;
	if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
		return -EINVAL;

	octeon_irq_set_ciu_mapping(virq, line, bit,
				   octeon_irq_gpio_chip,
				   octeon_irq_handle_gpio);

	return 0;
}

@@ -1149,6 +1145,7 @@ static void __init octeon_irq_init_ciu(void)
	struct irq_chip *chip_wd;
	struct device_node *gpio_node;
	struct device_node *ciu_node;
	struct irq_domain *ciu_domain = NULL;

	octeon_irq_init_ciu_percpu();
	octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu;
@@ -1177,31 +1174,6 @@ static void __init octeon_irq_init_ciu(void)
	/* Mips internal */
	octeon_irq_init_core();

	/* CIU_0 */
	for (i = 0; i < 16; i++)
		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq);

	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);

	for (i = 0; i < 4; i++)
		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_INT0, 0, i + 36, chip, handle_level_irq);
	for (i = 0; i < 4; i++)
		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_MSI0, 0, i + 40, chip, handle_level_irq);

	octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq);
	for (i = 0; i < 4; i++)
		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq);

	octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq);
	octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq);

	/* CIU_1 */
	for (i = 0; i < 16; i++)
		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq);

	octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq);

	gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio");
	if (gpio_node) {
		struct octeon_irq_gpio_domain_data *gpiod;
@@ -1219,10 +1191,35 @@ static void __init octeon_irq_init_ciu(void)

	ciu_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-ciu");
	if (ciu_node) {
		irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL);
		ciu_domain = irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL);
		of_node_put(ciu_node);
	} else
		pr_warn("Cannot find device node for cavium,octeon-3860-ciu.\n");
		panic("Cannot find device node for cavium,octeon-3860-ciu.");

	/* CIU_0 */
	for (i = 0; i < 16; i++)
		octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_WORKQ0, 0, i + 0);

	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);

	for (i = 0; i < 4; i++)
		octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_INT0, 0, i + 36);
	for (i = 0; i < 4; i++)
		octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_MSI0, 0, i + 40);

	octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_RML, 0, 46);
	for (i = 0; i < 4; i++)
		octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52);

	octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 0, 56);
	octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_BOOTDMA, 0, 63);

	/* CIU_1 */
	for (i = 0; i < 16; i++)
		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq);

	octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB1, 1, 17);

	/* Enable the CIU lines */
	set_c0_status(STATUSF_IP3 | STATUSF_IP2);
+1 −9
Original line number Diff line number Diff line
@@ -21,14 +21,10 @@ enum octeon_irq {
	OCTEON_IRQ_TIMER,
/* sources in CIU_INTX_EN0 */
	OCTEON_IRQ_WORKQ0,
	OCTEON_IRQ_GPIO0 = OCTEON_IRQ_WORKQ0 + 16,
	OCTEON_IRQ_WDOG0 = OCTEON_IRQ_GPIO0 + 16,
	OCTEON_IRQ_WDOG0 = OCTEON_IRQ_WORKQ0 + 16,
	OCTEON_IRQ_WDOG15 = OCTEON_IRQ_WDOG0 + 15,
	OCTEON_IRQ_MBOX0 = OCTEON_IRQ_WDOG0 + 16,
	OCTEON_IRQ_MBOX1,
	OCTEON_IRQ_UART0,
	OCTEON_IRQ_UART1,
	OCTEON_IRQ_UART2,
	OCTEON_IRQ_PCI_INT0,
	OCTEON_IRQ_PCI_INT1,
	OCTEON_IRQ_PCI_INT2,
@@ -38,8 +34,6 @@ enum octeon_irq {
	OCTEON_IRQ_PCI_MSI2,
	OCTEON_IRQ_PCI_MSI3,

	OCTEON_IRQ_TWSI,
	OCTEON_IRQ_TWSI2,
	OCTEON_IRQ_RML,
	OCTEON_IRQ_TIMER0,
	OCTEON_IRQ_TIMER1,
@@ -47,8 +41,6 @@ enum octeon_irq {
	OCTEON_IRQ_TIMER3,
	OCTEON_IRQ_USB0,
	OCTEON_IRQ_USB1,
	OCTEON_IRQ_MII0,
	OCTEON_IRQ_MII1,
	OCTEON_IRQ_BOOTDMA,
#ifndef CONFIG_PCI_MSI
	OCTEON_IRQ_LAST = 127