Skip to content

Commit 6054c09

Browse files
Electron752popcornmix
authored andcommitted
ARM64: Round-Robin dispatch IRQs between CPUs.
IRQ-CPU mapping is round robined on ARM64 to increase concurrency and allow multiple interrupts to be serviced at a time. This reduces the need for FIQ. Signed-off-by: Michael Zoran <[email protected]> drivers: irqchip: irq-bcm2835: Concurrency fix The commit shown in Fixes: aims to improve interrupt throughput by getting the handlers invoked on different CPU cores. It does so (*) by using an irq_ack hook to change the interrupt routing. Unfortunately, the IRQ status bits must be cleared at source, which only happens once the interrupt handler has run - there is no easy way for one core to claim one of the IRQs before sending the remainder to the next core on the list, so waking another core immediately results in a race with a chance of both cores handling the same IRQ. It is probably for this reason that the routing change is deferred to irq_ack, but that doesn't guarantee no clashes - after irq_ack is called, control returns to bcm2836_chained_handler_irq which proceeds to check for other pending IRQs at a time when the next core is probably doing the same thing. Since the whole point of the original commit is to distribute the IRQ handling, there is no reason to attempt to handle multiple IRQs in one interrupt callback, so the problem can be solved (or at least made much harder to reproduce) by changing a "while" into an "if", so that each invocation only handles one IRQ. (*) I'm not convinced it's as effective as claimed since irq_ack is called _after_ the interrupt handler, but the author thought it made a difference. See: #5214 #1794 Fixes: fd4c978 ("ARM64: Round-Robin dispatch IRQs between CPUs.") Signed-off-by: Phil Elwell <[email protected]> irqchip: irq-bcm2836: Avoid prototype warning Declare bcm2836_arm_irqchip_spin_gpu_irq in irq-bcm2836.h to avoid a compiler warning about a missing prototype. Signed-off-by: Phil Elwell <[email protected]>
1 parent ceabbf9 commit 6054c09

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

drivers/irqchip/irq-bcm2835.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <linux/of_address.h>
4141
#include <linux/of_irq.h>
4242
#include <linux/irqchip.h>
43+
#include <linux/irqchip/irq-bcm2836.h>
4344
#include <linux/irqdomain.h>
4445

4546
#include <asm/exception.h>
@@ -154,12 +155,24 @@ static void armctrl_unmask_irq(struct irq_data *d)
154155
}
155156
}
156157

158+
#ifdef CONFIG_ARM64
159+
160+
static void armctrl_ack_irq(struct irq_data *d)
161+
{
162+
bcm2836_arm_irqchip_spin_gpu_irq();
163+
}
164+
165+
#endif
166+
157167
static struct irq_chip armctrl_chip = {
158168
.name = "ARMCTRL-level",
159169
.irq_mask = armctrl_mask_irq,
160170
.irq_unmask = armctrl_unmask_irq,
161171
.flags = IRQCHIP_MASK_ON_SUSPEND |
162172
IRQCHIP_SKIP_SET_WAKE,
173+
#ifdef CONFIG_ARM64
174+
.irq_ack = armctrl_ack_irq
175+
#endif
163176
};
164177

165178
static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
@@ -332,7 +345,8 @@ static void bcm2836_chained_handle_irq(struct irq_desc *desc)
332345
{
333346
u32 hwirq;
334347

335-
while ((hwirq = get_next_armctrl_hwirq()) != ~0)
348+
hwirq = get_next_armctrl_hwirq();
349+
if (hwirq != ~0)
336350
generic_handle_domain_irq(intc.domain, hwirq);
337351
}
338352

drivers/irqchip/irq-bcm2836.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,27 @@ static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d)
8989
{
9090
}
9191

92+
#ifdef CONFIG_ARM64
93+
94+
void bcm2836_arm_irqchip_spin_gpu_irq(void)
95+
{
96+
u32 i;
97+
void __iomem *gpurouting = (intc.base + LOCAL_GPU_ROUTING);
98+
u32 routing_val = readl(gpurouting);
99+
100+
for (i = 1; i <= 3; i++) {
101+
u32 new_routing_val = (routing_val + i) & 3;
102+
103+
if (cpu_active(new_routing_val)) {
104+
writel(new_routing_val, gpurouting);
105+
return;
106+
}
107+
}
108+
}
109+
EXPORT_SYMBOL(bcm2836_arm_irqchip_spin_gpu_irq);
110+
111+
#endif
112+
92113
static struct irq_chip bcm2836_arm_irqchip_gpu = {
93114
.name = "bcm2836-gpu",
94115
.irq_mask = bcm2836_arm_irqchip_mask_gpu_irq,

include/linux/irqchip/irq-bcm2836.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,5 @@
5959
#define LOCAL_IRQ_GPU_FAST 8
6060
#define LOCAL_IRQ_PMU_FAST 9
6161
#define LAST_IRQ LOCAL_IRQ_PMU_FAST
62+
63+
void bcm2836_arm_irqchip_spin_gpu_irq(void);

0 commit comments

Comments
 (0)