Skip to content

Commit cc9f04f

Browse files
avpatelMarc Zyngier
authored andcommitted
irqchip/sifive-plic: Implement irq_set_affinity() for SMP host
Currently on SMP host, all CPUs take external interrupts routed via PLIC. All CPUs will try to claim a given external interrupt but only one of them will succeed while other CPUs would simply resume whatever they were doing before. This means if we have N CPUs then for every external interrupt N-1 CPUs will always fail to claim it and waste their CPU time. Instead of above, external interrupts should be taken by only one CPU and we should have provision to explicitly specify IRQ affinity from kernel-space or user-space. This patch provides irq_set_affinity() implementation for PLIC driver. It also updates irq_enable() such that PLIC interrupts are only enabled for one of CPUs specified in IRQ affinity mask. With this patch in-place, we can change IRQ affinity at any-time from user-space using procfs. Example: / # cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 8: 44 0 0 0 SiFive PLIC 8 virtio0 10: 48 0 0 0 SiFive PLIC 10 ttyS0 IPI0: 55 663 58 363 Rescheduling interrupts IPI1: 0 1 3 16 Function call interrupts / # / # / # echo 4 > /proc/irq/10/smp_affinity / # / # cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 8: 45 0 0 0 SiFive PLIC 8 virtio0 10: 160 0 17 0 SiFive PLIC 10 ttyS0 IPI0: 68 693 77 410 Rescheduling interrupts IPI1: 0 2 3 16 Function call interrupts Signed-off-by: Anup Patel <anup@brainfault.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent 6adfe8d commit cc9f04f

File tree

1 file changed

+39
-6
lines changed

1 file changed

+39
-6
lines changed

drivers/irqchip/irq-sifive-plic.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,29 +83,59 @@ static inline void plic_toggle(struct plic_handler *handler,
8383
raw_spin_unlock(&handler->enable_lock);
8484
}
8585

86-
static inline void plic_irq_toggle(struct irq_data *d, int enable)
86+
static inline void plic_irq_toggle(const struct cpumask *mask,
87+
int hwirq, int enable)
8788
{
8889
int cpu;
8990

90-
writel(enable, plic_regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
91-
for_each_cpu(cpu, irq_data_get_affinity_mask(d)) {
91+
writel(enable, plic_regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
92+
for_each_cpu(cpu, mask) {
9293
struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
9394

9495
if (handler->present)
95-
plic_toggle(handler, d->hwirq, enable);
96+
plic_toggle(handler, hwirq, enable);
9697
}
9798
}
9899

99100
static void plic_irq_enable(struct irq_data *d)
100101
{
101-
plic_irq_toggle(d, 1);
102+
unsigned int cpu = cpumask_any_and(irq_data_get_affinity_mask(d),
103+
cpu_online_mask);
104+
if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
105+
return;
106+
plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1);
102107
}
103108

104109
static void plic_irq_disable(struct irq_data *d)
105110
{
106-
plic_irq_toggle(d, 0);
111+
plic_irq_toggle(cpu_possible_mask, d->hwirq, 0);
107112
}
108113

114+
#ifdef CONFIG_SMP
115+
static int plic_set_affinity(struct irq_data *d,
116+
const struct cpumask *mask_val, bool force)
117+
{
118+
unsigned int cpu;
119+
120+
if (force)
121+
cpu = cpumask_first(mask_val);
122+
else
123+
cpu = cpumask_any_and(mask_val, cpu_online_mask);
124+
125+
if (cpu >= nr_cpu_ids)
126+
return -EINVAL;
127+
128+
if (!irqd_irq_disabled(d)) {
129+
plic_irq_toggle(cpu_possible_mask, d->hwirq, 0);
130+
plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1);
131+
}
132+
133+
irq_data_update_effective_affinity(d, cpumask_of(cpu));
134+
135+
return IRQ_SET_MASK_OK_DONE;
136+
}
137+
#endif
138+
109139
static struct irq_chip plic_chip = {
110140
.name = "SiFive PLIC",
111141
/*
@@ -114,6 +144,9 @@ static struct irq_chip plic_chip = {
114144
*/
115145
.irq_enable = plic_irq_enable,
116146
.irq_disable = plic_irq_disable,
147+
#ifdef CONFIG_SMP
148+
.irq_set_affinity = plic_set_affinity,
149+
#endif
117150
};
118151

119152
static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,

0 commit comments

Comments
 (0)