From: Yipeng Zou zouyipeng@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I6BO2R CVE: NA
--------------------------------
Now, There is some issues about LPI migration on ARM SMP platform.
For example, NIC device generates MSI and sends LPI to CPU0 via ITS, meanwhile irqbalance running on CPU1 set irq affinty of NIC to CPU1, the next interrupt will be sent to CPU2, due to the state of irq is still in progress, kernel does not end up performing irq handler on CPU2, which results in some userland service timeouts, the sequence of events is shown as follows:
NIC CPU0 CPU1
Generate IRQ#1 READ_IAR Lock irq_desc Set IRQD_IN_PROGRESS Unlock irq_desc Lock irq_desc Change LPI Affinity Unlock irq_desc Call irq_handler Generate IRQ#2 READ_IAR Lock irq_desc Check IRQD_IN_PROGRESS Unlock irq_desc Return from interrupt#2 Lock irq_desc Clear IRQD_IN_PROGRESS Unlock irq_desc return from interrupt#1
For this scenario, We can enable CONFIG_GENERIC_PENDING_IRQ to avoid this.
The CONFIG_GENERIC_PENDING_IRQ will delay all action that modify LPI affinity until the next interrupt eoi handler.
Signed-off-by: Yipeng Zou zouyipeng@huawei.com Reviewed-by: Liao Chang liaochang1@huawei.com Reviewed-by: Zhang Jianhua chris.zjh@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- drivers/irqchip/irq-gic-v3-its.c | 8 +++++++- kernel/irq/Kconfig | 4 +++- kernel/irq/migration.c | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 15a0292e8e61..7a0adf67761e 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1162,6 +1162,12 @@ static void its_unmask_irq(struct irq_data *d) lpi_update_config(d, 0, LPI_PROP_ENABLED); }
+static void its_irq_chip_eoi(struct irq_data *d) +{ + irq_move_irq(d); + irq_chip_eoi_parent(d); +} + static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { @@ -1485,7 +1491,7 @@ static struct irq_chip its_irq_chip = { .name = "ITS", .irq_mask = its_mask_irq, .irq_unmask = its_unmask_irq, - .irq_eoi = irq_chip_eoi_parent, + .irq_eoi = its_irq_chip_eoi, .irq_set_affinity = its_set_affinity, .irq_compose_msi_msg = its_irq_compose_msi_msg, .irq_set_irqchip_state = its_irq_set_irqchip_state, diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index 14a85d0161ea..eebbced84e44 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -32,7 +32,9 @@ config GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
# Support for delayed migration from interrupt context config GENERIC_PENDING_IRQ - bool + bool "Support for delayed migration from interrupt context" + depends on SMP + default n
# Support for generic irq migrating off cpu before the cpu is offline. config GENERIC_IRQ_MIGRATION diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index def48589ea48..bcb61ee69c20 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c @@ -117,3 +117,5 @@ void __irq_move_irq(struct irq_data *idata) if (!masked) idata->chip->irq_unmask(idata); } + +void __weak irq_force_complete_move(struct irq_desc *desc) { }