Skip to content

Commit a648eb3

Browse files
committed
genirq: Provide IRQCHIP_MOVE_DEFERRED
The logic of GENERIC_PENDING_IRQ is backwards for historical reasons. Most interrupt controllers allow to move the interrupt from arbitrary contexts. If GENERIC_PENDING_IRQ is enabled by an architecture to support a chip, which requires the affinity change to happen in interrupt context, all other chips have to be marked with IRQF_MOVE_PCNTXT. That's tedious and there is no real good reason for the extra flags in the irq descriptor and the irq data status fields. In fact the decision whether interrupts can be moved in arbitrary context or not is a property of the interrupt chip. To simplify adoption for RISC-V provide a new mechanism which is enabled via a config switch and allows to add a flag to irq_chip::flags to request that interrupt affinity changes are deferred. Setting the top level chip of an interrupt evaluates the flag and maps it into the existing logic. The config switch and the various PCNTXT flags are temporary until x86 is converted over to this scheme. This intermediate step also allows trivial backporting of the mechanism to plug the affinity change race of various RISC-V interrupt controllers. Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent 65d09d2 commit a648eb3

File tree

4 files changed

+22
-3
lines changed

4 files changed

+22
-3
lines changed

include/linux/irq.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ struct irq_chip {
567567
* in the suspend path if they are in disabled state
568568
* IRQCHIP_AFFINITY_PRE_STARTUP: Default affinity update before startup
569569
* IRQCHIP_IMMUTABLE: Don't ever change anything in this chip
570+
* IRQCHIP_MOVE_DEFERRED: Move the interrupt in actual interrupt context
570571
*/
571572
enum {
572573
IRQCHIP_SET_TYPE_MASKED = (1 << 0),
@@ -581,6 +582,7 @@ enum {
581582
IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND = (1 << 9),
582583
IRQCHIP_AFFINITY_PRE_STARTUP = (1 << 10),
583584
IRQCHIP_IMMUTABLE = (1 << 11),
585+
IRQCHIP_MOVE_DEFERRED = (1 << 12),
584586
};
585587

586588
#include <linux/irqdesc.h>

kernel/irq/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ config GENERIC_IRQ_EFFECTIVE_AFF_MASK
3131
config GENERIC_PENDING_IRQ
3232
bool
3333

34+
# Deduce delayed migration from top-level interrupt chip flags
35+
config GENERIC_PENDING_IRQ_CHIPFLAGS
36+
bool
37+
3438
# Support for generic irq migrating off cpu before the cpu is offline.
3539
config GENERIC_IRQ_MIGRATION
3640
bool

kernel/irq/chip.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ int irq_set_chip(unsigned int irq, const struct irq_chip *chip)
4747
return -EINVAL;
4848

4949
desc->irq_data.chip = (struct irq_chip *)(chip ?: &no_irq_chip);
50+
51+
if (IS_ENABLED(CONFIG_GENERIC_PENDING_IRQ_CHIPFLAGS) && chip) {
52+
if (chip->flags & IRQCHIP_MOVE_DEFERRED)
53+
irqd_clear(&desc->irq_data, IRQD_MOVE_PCNTXT);
54+
else
55+
irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);
56+
}
5057
irq_put_desc_unlock(desc, flags);
5158
/*
5259
* For !CONFIG_SPARSE_IRQ make the irq show up in
@@ -1114,16 +1121,21 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
11141121
trigger = irqd_get_trigger_type(&desc->irq_data);
11151122

11161123
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
1117-
IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
1124+
IRQD_TRIGGER_MASK | IRQD_LEVEL);
11181125
if (irq_settings_has_no_balance_set(desc))
11191126
irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
11201127
if (irq_settings_is_per_cpu(desc))
11211128
irqd_set(&desc->irq_data, IRQD_PER_CPU);
1122-
if (irq_settings_can_move_pcntxt(desc))
1123-
irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);
11241129
if (irq_settings_is_level(desc))
11251130
irqd_set(&desc->irq_data, IRQD_LEVEL);
11261131

1132+
/* Keep this around until x86 is converted over */
1133+
if (!IS_ENABLED(CONFIG_GENERIC_PENDING_IRQ_CHIPFLAGS)) {
1134+
irqd_clear(&desc->irq_data, IRQD_MOVE_PCNTXT);
1135+
if (irq_settings_can_move_pcntxt(desc))
1136+
irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);
1137+
}
1138+
11271139
tmp = irq_settings_get_trigger_mask(desc);
11281140
if (tmp != IRQ_TYPE_NONE)
11291141
trigger = tmp;

kernel/irq/debugfs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ static const struct irq_bit_descr irqchip_flags[] = {
5353
BIT_MASK_DESCR(IRQCHIP_SUPPORTS_NMI),
5454
BIT_MASK_DESCR(IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND),
5555
BIT_MASK_DESCR(IRQCHIP_IMMUTABLE),
56+
BIT_MASK_DESCR(IRQCHIP_MOVE_DEFERRED),
5657
};
5758

5859
static void

0 commit comments

Comments
 (0)