Message ID | 20200901144324.1071694-11-maz@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm/arm64: Turning IPIs into normal interrupts | expand |
Hi Marc, On 01.09.2020 16:43, Marc Zyngier wrote: > In order to switch the bcm2836 driver to privide standard interrupts > for IPIs, it first needs to stop lying about the way things work. > > The mailbox interrupt is actually a multiplexer, with enough > bits to store 32 pending interrupts per CPU. So let's turn it > into a chained irqchip. > > Once this is done, we can instanciate the corresponding IPIs, > and pass them to the architecture code. > > Signed-off-by: Marc Zyngier <maz@kernel.org> This one also fails. It breaks booting of Raspberry Pi 3b boards (both in ARM and ARM64 mode): NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16 8<--- cut here --- Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = (ptrval) [00000000] *pgd=80000000004003, *pmd=00000000 Internal error: Oops: 80000206 [#1] SMP ARM Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.9.0-rc4+ #9166 Hardware name: BCM2835 PC is at 0x0 LR is at irq_percpu_enable+0x40/0x50 pc : [<00000000>] lr : [<c0274638>] psr: 600000d3 sp : c1201e00 ip : c1201e18 fp : c1201e14 r10: c0ef23dc r9 : c120583c r8 : 00000000 r7 : 00000011 r6 : eb032d00 r5 : 00000000 r4 : eb032d00 r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : eb032d18 Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment user Control: 30c5383d Table: 00003000 DAC: fffffffd Process swapper/0 (pid: 0, stack limit = 0x(ptrval)) Stack: (0xc1201e00 to 0xc1202000) ... Backtrace: [<c02745f8>] (irq_percpu_enable) from [<c0272498>] (enable_percpu_irq+0xa4/0xd8) r5:c1204ec8 r4:00000000 [<c02723f4>] (enable_percpu_irq) from [<c020ded0>] (ipi_setup.part.0+0x3c/0x48) r8:c107ba80 r7:00000018 r6:00000011 r5:c1204ee0 r4:00000001 [<c020de94>] (ipi_setup.part.0) from [<c1005684>] (set_smp_ipi_range+0xd8/0xf8) r5:c1204ee0 r4:00000008 [<c10055ac>] (set_smp_ipi_range) from [<c1023388>] (bcm2836_arm_irqchip_l1_intc_of_init+0x1c0/0x22c) r8:c1366820 r7:c1204ec8 r6:00000010 r5:00000001 r4:00000000 [<c10231c8>] (bcm2836_arm_irqchip_l1_intc_of_init) from [<c102f28c>] (of_irq_init+0x18c/0x2dc) r9:00000000 r8:c1201f34 r7:c1204ec8 r6:c1201f2c r5:c1201f2c r4:eb004880 [<c102f100>] (of_irq_init) from [<c1022f4c>] (irqchip_init+0x1c/0x24) r10:0000006c r9:00000000 r8:00000000 r7:ffffffff r6:cccccccd r5:c0eb7abe r4:c103ba30 [<c1022f30>] (irqchip_init) from [<c1003960>] (init_IRQ+0x30/0x98) [<c1003930>] (init_IRQ) from [<c1000ebc>] (start_kernel+0x3b4/0x628) r5:c0eb7abe r4:c12c1000 [<c1000b08>] (start_kernel) from [<00000000>] (0x0) r10:30c5387d r9:410fd034 r8:02600000 r7:00000000 r6:30c0387d r5:00000000 r4:c1000330 Code: bad PC value random: get_random_bytes called from init_oops_id+0x30/0x4c with crng_init=0 ---[ end trace 0000000000000000 ]--- Kernel panic - not syncing: Attempted to kill the idle task! ---[ end Kernel panic - not syncing: Attempted to kill the idle task! ]--- > --- > drivers/irqchip/irq-bcm2836.c | 151 ++++++++++++++++++++++++++++------ > 1 file changed, 125 insertions(+), 26 deletions(-) > > ... Best regards
Hi Marek, On 2020-09-14 15:32, Marek Szyprowski wrote: > Hi Marc, > > On 01.09.2020 16:43, Marc Zyngier wrote: >> In order to switch the bcm2836 driver to privide standard interrupts >> for IPIs, it first needs to stop lying about the way things work. >> >> The mailbox interrupt is actually a multiplexer, with enough >> bits to store 32 pending interrupts per CPU. So let's turn it >> into a chained irqchip. >> >> Once this is done, we can instanciate the corresponding IPIs, >> and pass them to the architecture code. >> >> Signed-off-by: Marc Zyngier <maz@kernel.org> > > This one also fails. It breaks booting of Raspberry Pi 3b boards (both > in ARM and ARM64 mode): Damn. This used to work. Looks like I was eager to delete stuff at some point. Can you give this a go and let me know if that works for you (only tested in QEMU with the raspi2 model): diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index 85df6ddad9be..97838eb705f9 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -193,6 +193,8 @@ static void bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d, static struct irq_chip bcm2836_arm_irqchip_ipi = { .name = "IPI", + .irq_mask = bcm2836_arm_irqchip_dummy_op, + .irq_unmask = bcm2836_arm_irqchip_dummy_op, .irq_eoi = bcm2836_arm_irqchip_ipi_eoi, .ipi_send_mask = bcm2836_arm_irqchip_ipi_send_mask, }; Thanks again, M.
Hi Marc, On 14.09.2020 18:10, Marc Zyngier wrote: > On 2020-09-14 15:32, Marek Szyprowski wrote: >> On 01.09.2020 16:43, Marc Zyngier wrote: >>> In order to switch the bcm2836 driver to privide standard interrupts >>> for IPIs, it first needs to stop lying about the way things work. >>> >>> The mailbox interrupt is actually a multiplexer, with enough >>> bits to store 32 pending interrupts per CPU. So let's turn it >>> into a chained irqchip. >>> >>> Once this is done, we can instanciate the corresponding IPIs, >>> and pass them to the architecture code. >>> >>> Signed-off-by: Marc Zyngier <maz@kernel.org> >> >> This one also fails. It breaks booting of Raspberry Pi 3b boards (both >> in ARM and ARM64 mode): > > Damn. This used to work. Looks like I was eager to delete stuff at > some point. Can you give this a go and let me know if that works > for you (only tested in QEMU with the raspi2 model): > > diff --git a/drivers/irqchip/irq-bcm2836.c > b/drivers/irqchip/irq-bcm2836.c > index 85df6ddad9be..97838eb705f9 100644 > --- a/drivers/irqchip/irq-bcm2836.c > +++ b/drivers/irqchip/irq-bcm2836.c > @@ -193,6 +193,8 @@ static void > bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d, > > static struct irq_chip bcm2836_arm_irqchip_ipi = { > .name = "IPI", > + .irq_mask = bcm2836_arm_irqchip_dummy_op, > + .irq_unmask = bcm2836_arm_irqchip_dummy_op, > .irq_eoi = bcm2836_arm_irqchip_ipi_eoi, > .ipi_send_mask = bcm2836_arm_irqchip_ipi_send_mask, > }; > > > Thanks again, This fixes boot on my RPi3b. Thanks! Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Best regards
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index 2038693f074c..85df6ddad9be 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -10,6 +10,7 @@ #include <linux/of_irq.h> #include <linux/irqchip.h> #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/irq-bcm2836.h> #include <asm/exception.h> @@ -89,12 +90,24 @@ static struct irq_chip bcm2836_arm_irqchip_gpu = { .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, }; +static void bcm2836_arm_irqchip_dummy_op(struct irq_data *d) +{ +} + +static struct irq_chip bcm2836_arm_irqchip_dummy = { + .name = "bcm2836-dummy", + .irq_eoi = bcm2836_arm_irqchip_dummy_op, +}; + static int bcm2836_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { struct irq_chip *chip; switch (hw) { + case LOCAL_IRQ_MAILBOX0: + chip = &bcm2836_arm_irqchip_dummy; + break; case LOCAL_IRQ_CNTPSIRQ: case LOCAL_IRQ_CNTPNSIRQ: case LOCAL_IRQ_CNTHPIRQ: @@ -127,17 +140,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) u32 stat; stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu); - if (stat & BIT(LOCAL_IRQ_MAILBOX0)) { -#ifdef CONFIG_SMP - void __iomem *mailbox0 = (intc.base + - LOCAL_MAILBOX0_CLR0 + 16 * cpu); - u32 mbox_val = readl(mailbox0); - u32 ipi = ffs(mbox_val) - 1; - - writel(1 << ipi, mailbox0); - handle_IPI(ipi, regs); -#endif - } else if (stat) { + if (stat) { u32 hwirq = ffs(stat) - 1; handle_domain_irq(intc.domain, hwirq, regs); @@ -145,8 +148,35 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) } #ifdef CONFIG_SMP -static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask, - unsigned int ipi) +static struct irq_domain *ipi_domain; + +static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + int cpu = smp_processor_id(); + u32 mbox_val; + + chained_irq_enter(chip, desc); + + mbox_val = readl_relaxed(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu); + if (mbox_val) { + int hwirq = ffs(mbox_val) - 1; + generic_handle_irq(irq_find_mapping(ipi_domain, hwirq)); + } + + chained_irq_exit(chip, desc); +} + +static void bcm2836_arm_irqchip_ipi_eoi(struct irq_data *d) +{ + int cpu = smp_processor_id(); + + writel_relaxed(BIT(d->hwirq), + intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu); +} + +static void bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d, + const struct cpumask *mask) { int cpu; void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0; @@ -157,11 +187,45 @@ static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask, */ smp_wmb(); - for_each_cpu(cpu, mask) { - writel(1 << ipi, mailbox0_base + 16 * cpu); + for_each_cpu(cpu, mask) + writel_relaxed(BIT(d->hwirq), mailbox0_base + 16 * cpu); +} + +static struct irq_chip bcm2836_arm_irqchip_ipi = { + .name = "IPI", + .irq_eoi = bcm2836_arm_irqchip_ipi_eoi, + .ipi_send_mask = bcm2836_arm_irqchip_ipi_send_mask, +}; + +static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d, + unsigned int virq, + unsigned int nr_irqs, void *args) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + irq_set_percpu_devid(virq + i); + irq_domain_set_info(d, virq + i, i, &bcm2836_arm_irqchip_ipi, + d->host_data, + handle_percpu_devid_fasteoi_ipi, + NULL, NULL); } + + return 0; } +static void bcm2836_arm_irqchip_ipi_free(struct irq_domain *d, + unsigned int virq, + unsigned int nr_irqs) +{ + /* Not freeing IPIs */ +} + +static const struct irq_domain_ops ipi_domain_ops = { + .alloc = bcm2836_arm_irqchip_ipi_alloc, + .free = bcm2836_arm_irqchip_ipi_free, +}; + static int bcm2836_cpu_starting(unsigned int cpu) { bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_MAILBOX_INT_CONTROL0, 0, @@ -175,25 +239,58 @@ static int bcm2836_cpu_dying(unsigned int cpu) cpu); return 0; } -#endif -static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = { - .xlate = irq_domain_xlate_onetwocell, - .map = bcm2836_map, -}; +#define BITS_PER_MBOX 32 -static void -bcm2836_arm_irqchip_smp_init(void) +static void bcm2836_arm_irqchip_smp_init(void) { -#ifdef CONFIG_SMP + struct irq_fwspec ipi_fwspec = { + .fwnode = intc.domain->fwnode, + .param_count = 1, + .param = { + [0] = LOCAL_IRQ_MAILBOX0, + }, + }; + int base_ipi, mux_irq; + + mux_irq = irq_create_fwspec_mapping(&ipi_fwspec); + if (WARN_ON(mux_irq <= 0)) + return; + + ipi_domain = irq_domain_create_linear(intc.domain->fwnode, + BITS_PER_MBOX, &ipi_domain_ops, + NULL); + if (WARN_ON(!ipi_domain)) + return; + + ipi_domain->flags |= IRQ_DOMAIN_FLAG_IPI_SINGLE; + irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI); + + base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, BITS_PER_MBOX, + NUMA_NO_NODE, NULL, + false, NULL); + + if (WARN_ON(!base_ipi)) + return; + + set_smp_ipi_range(base_ipi, BITS_PER_MBOX); + + irq_set_chained_handler_and_data(mux_irq, + bcm2836_arm_irqchip_handle_ipi, NULL); + /* Unmask IPIs to the boot CPU. */ cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING, "irqchip/bcm2836:starting", bcm2836_cpu_starting, bcm2836_cpu_dying); - - set_smp_cross_call(bcm2836_arm_irqchip_send_ipi); -#endif } +#else +#define bcm2836_arm_irqchip_smp_init() do { } while(0) +#endif + +static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = { + .xlate = irq_domain_xlate_onetwocell, + .map = bcm2836_map, +}; /* * The LOCAL_IRQ_CNT* timer firings are based off of the external @@ -232,6 +329,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node, if (!intc.domain) panic("%pOF: unable to create IRQ domain\n", node); + irq_domain_update_bus_token(intc.domain, DOMAIN_BUS_WIRED); + bcm2836_arm_irqchip_smp_init(); set_handle_irq(bcm2836_arm_irqchip_handle_irq);
In order to switch the bcm2836 driver to privide standard interrupts for IPIs, it first needs to stop lying about the way things work. The mailbox interrupt is actually a multiplexer, with enough bits to store 32 pending interrupts per CPU. So let's turn it into a chained irqchip. Once this is done, we can instanciate the corresponding IPIs, and pass them to the architecture code. Signed-off-by: Marc Zyngier <maz@kernel.org> --- drivers/irqchip/irq-bcm2836.c | 151 ++++++++++++++++++++++++++++------ 1 file changed, 125 insertions(+), 26 deletions(-)