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) { }
From: Yipeng Zou zouyipeng@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I6BO2R CVE: NA
-------------------------------
Since CONFIG_GENERIC_PENDING_IRQ has been introduced for gic-v3-its, there has some kabi changed(irq_desc->pending_mask).
Introduce CONFIG_GENERIC_PENDING_IRQ_FIX_KABI to fix it.
The main way is to use an static array(irq_pending_mask) to replace pending_mask in irq_desc.
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 --- include/linux/irqdesc.h | 3 ++- kernel/irq/Kconfig | 6 ++++++ kernel/irq/debugfs.c | 2 +- kernel/irq/internals.h | 19 +++++++++++++++++++ kernel/irq/irqdesc.c | 8 +++++--- kernel/irq/manage.c | 6 ++++++ kernel/irq/migration.c | 13 ++++++++----- kernel/irq/proc.c | 2 +- 8 files changed, 48 insertions(+), 11 deletions(-)
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 8140d8ca5b83..b27701efbe6c 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -77,7 +77,8 @@ struct irq_desc { #ifdef CONFIG_SMP const struct cpumask *affinity_hint; struct irq_affinity_notify *affinity_notify; -#ifdef CONFIG_GENERIC_PENDING_IRQ +#if defined(CONFIG_GENERIC_PENDING_IRQ) && \ + !defined(CONFIG_GENERIC_PENDING_IRQ_FIX_KABI) cpumask_var_t pending_mask; #endif #endif diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index eebbced84e44..743afe22fdfc 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -138,6 +138,12 @@ config GENERIC_IRQ_DEBUGFS
If you don't know what to do here, say N.
+# Support for delayed migration from interrupt context without kabi modification +config GENERIC_PENDING_IRQ_FIX_KABI + bool "Support for delayed migration from interrupt context without kabi modification " + depends on GENERIC_PENDING_IRQ + default n + endmenu
config GENERIC_IRQ_MULTI_HANDLER diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c index 216db115b68a..dd93b740a9e7 100644 --- a/kernel/irq/debugfs.c +++ b/kernel/irq/debugfs.c @@ -39,7 +39,7 @@ static void irq_debug_show_masks(struct seq_file *m, struct irq_desc *desc) seq_printf(m, "effectiv: %*pbl\n", cpumask_pr_args(msk)); #endif #ifdef CONFIG_GENERIC_PENDING_IRQ - msk = desc->pending_mask; + msk = irq_desc_get_pending_mask(desc); seq_printf(m, "pending: %*pbl\n", cpumask_pr_args(msk)); #endif } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index f29d6982b3ce..bf7e5b434e1c 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -410,6 +410,7 @@ static inline bool irq_move_pending(struct irq_data *data) { return irqd_is_setaffinity_pending(data); } +#ifndef CONFIG_GENERIC_PENDING_IRQ_FIX_KABI static inline void irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) { @@ -424,6 +425,24 @@ static inline struct cpumask *irq_desc_get_pending_mask(struct irq_desc *desc) { return desc->pending_mask; } +#else +extern struct cpumask irq_pending_mask[IRQ_BITMAP_BITS]; + +static inline void +irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) +{ + cpumask_copy(&irq_pending_mask[irq_desc_get_irq(desc)], mask); +} +static inline void +irq_get_pending(struct cpumask *mask, struct irq_desc *desc) +{ + cpumask_copy(mask, &irq_pending_mask[irq_desc_get_irq(desc)]); +} +static inline struct cpumask *irq_desc_get_pending_mask(struct irq_desc *desc) +{ + return &irq_pending_mask[irq_desc_get_irq(desc)]; +} +#endif static inline bool handle_enforce_irqctx(struct irq_data *data) { return irqd_is_handle_enforce_irqctx(data); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index c0248d4dde19..1ce4b701f26a 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -66,7 +66,8 @@ static int alloc_masks(struct irq_desc *desc, int node) } #endif
-#ifdef CONFIG_GENERIC_PENDING_IRQ +#if defined(CONFIG_GENERIC_PENDING_IRQ) && \ + !defined(CONFIG_GENERIC_PENDING_IRQ_FIX_KABI) if (!zalloc_cpumask_var_node(&desc->pending_mask, GFP_KERNEL, node)) { #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK free_cpumask_var(desc->irq_common_data.effective_affinity); @@ -86,7 +87,7 @@ static void desc_smp_init(struct irq_desc *desc, int node, cpumask_copy(desc->irq_common_data.affinity, affinity);
#ifdef CONFIG_GENERIC_PENDING_IRQ - cpumask_clear(desc->pending_mask); + cpumask_clear(irq_desc_get_pending_mask(desc)); #endif #ifdef CONFIG_NUMA desc->irq_common_data.node = node; @@ -361,7 +362,8 @@ static void delete_irq_desc(unsigned int irq) #ifdef CONFIG_SMP static void free_masks(struct irq_desc *desc) { -#ifdef CONFIG_GENERIC_PENDING_IRQ +#if defined(CONFIG_GENERIC_PENDING_IRQ) && \ + !defined(CONFIG_GENERIC_PENDING_IRQ_FIX_KABI) free_cpumask_var(desc->pending_mask); #endif free_cpumask_var(desc->irq_common_data.affinity); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d3ee0b8bea5f..213f88f7fdfb 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -23,6 +23,12 @@
#include "internals.h"
+#ifdef CONFIG_GENERIC_PENDING_IRQ_FIX_KABI +struct cpumask irq_pending_mask[IRQ_BITMAP_BITS] = { + [0 ... IRQ_BITMAP_BITS - 1] = { CPU_BITS_NONE } +}; +#endif + #ifdef CONFIG_IRQ_FORCED_THREADING __read_mostly bool force_irqthreads; EXPORT_SYMBOL_GPL(force_irqthreads); diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index bcb61ee69c20..01b2669ed29f 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c @@ -26,7 +26,8 @@ bool irq_fixup_move_pending(struct irq_desc *desc, bool force_clear) * The outgoing CPU might be the last online target in a pending * interrupt move. If that's the case clear the pending move bit. */ - if (cpumask_any_and(desc->pending_mask, cpu_online_mask) >= nr_cpu_ids) { + if (cpumask_any_and(irq_desc_get_pending_mask(desc), + cpu_online_mask) >= nr_cpu_ids) { irqd_clr_move_pending(data); return false; } @@ -54,7 +55,7 @@ void irq_move_masked_irq(struct irq_data *idata) return; }
- if (unlikely(cpumask_empty(desc->pending_mask))) + if (unlikely(cpumask_empty(irq_desc_get_pending_mask(desc)))) return;
if (!chip->irq_set_affinity) @@ -74,10 +75,12 @@ void irq_move_masked_irq(struct irq_data *idata) * For correct operation this depends on the caller * masking the irqs. */ - if (cpumask_any_and(desc->pending_mask, cpu_online_mask) < nr_cpu_ids) { + if (cpumask_any_and(irq_desc_get_pending_mask(desc), + cpu_online_mask) < nr_cpu_ids) { int ret;
- ret = irq_do_set_affinity(data, desc->pending_mask, false); + ret = irq_do_set_affinity(data, irq_desc_get_pending_mask(desc), + false); /* * If the there is a cleanup pending in the underlying * vector management, reschedule the move for the next @@ -88,7 +91,7 @@ void irq_move_masked_irq(struct irq_data *idata) return; } } - cpumask_clear(desc->pending_mask); + cpumask_clear(irq_desc_get_pending_mask(desc)); }
void __irq_move_irq(struct irq_data *idata) diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index e8c655b7a430..a914f1772c62 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -54,7 +54,7 @@ static int show_irq_affinity(int type, struct seq_file *m) mask = desc->irq_common_data.affinity; #ifdef CONFIG_GENERIC_PENDING_IRQ if (irqd_is_setaffinity_pending(&desc->irq_data)) - mask = desc->pending_mask; + mask = irq_desc_get_pending_mask(desc); #endif break; case EFFECTIVE:
From: Yipeng Zou zouyipeng@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I6BO2R CVE: NA
-------------------------------
Enable config for openeuler: 1. CONFIG_GENERIC_PENDING_IRQ 2. CONFIG_GENERIC_PENDING_IRQ_FIX_KABI
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 --- arch/arm64/configs/openeuler_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 95225e2dbe52..5349949fc834 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -43,6 +43,7 @@ CONFIG_AUDIT_TREE=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_IRQ_SHOW=y CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_PENDING_IRQ=y CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y CONFIG_GENERIC_IRQ_MIGRATION=y CONFIG_HARDIRQS_SW_RESEND=y @@ -55,6 +56,7 @@ CONFIG_HANDLE_DOMAIN_IRQ=y CONFIG_IRQ_FORCED_THREADING=y CONFIG_SPARSE_IRQ=y # CONFIG_GENERIC_IRQ_DEBUGFS is not set +CONFIG_GENERIC_PENDING_IRQ_FIX_KABI=y CONFIG_GENERIC_IRQ_MULTI_HANDLER=y CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_GENERIC_TIME_VSYSCALL=y