[PATCH OLK-6.6 v2 0/3] arm64: entry: Support hardware xint and xcall

Support hardware xint and xcall. Changes in v2: - Reuse irq_is_nmi(). - Reuse the xint set and check logic in xint 1.0. - Introduce fast_handle_xint(). - Rename enable_xint_xcall() to enable_xfunc() and rename test_has_xint_xcall() to test_has_xfunc(). - Fix a typo. - Add a blank line after declarations. - Remove an excess semicolon. Jinjie Ruan (3): genirq: Reuse irq_is_nmi() arm64: entry: Support hardware xint arm64: entry: Support hardware xcall arch/Kconfig | 14 ++-- arch/arm64/Kconfig | 12 ++++ arch/arm64/include/asm/sysreg.h | 7 ++ arch/arm64/kernel/cpufeature.c | 107 ++++++++++++++++++++++++++++- arch/arm64/kernel/entry-common.c | 39 ++++++++--- arch/arm64/kernel/entry.S | 74 ++++++++++++++++++-- arch/arm64/tools/cpucaps | 4 +- drivers/irqchip/irq-gic-v3.c | 89 ++++++++++++++++++++++-- include/linux/irqchip/arm-gic-v3.h | 6 +- kernel/irq/debugfs.c | 6 +- kernel/irq/internals.h | 8 ++- kernel/irq/irqdesc.c | 5 -- kernel/irq/manage.c | 16 ++--- kernel/irq/resend.c | 2 +- 14 files changed, 341 insertions(+), 48 deletions(-) -- 2.34.1

mainline inclusion from mainline-v6.10-rc1 commit 6678ae1918ff554f7438ff3f1a3be22d6d01f2fb category: cleanup bugzilla: https://gitee.com/openeuler/release-management/issues/IBV2E4 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- Move irq_is_nmi() to the internal header file and reuse it all over the place. Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/r/20240423024037.3331215-1-ruanjinjie@huawei.com Conflicts: kernel/irq/irqdesc.c [Context conflict for irq_is_nmi().] Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- kernel/irq/internals.h | 5 +++++ kernel/irq/irqdesc.c | 5 ----- kernel/irq/manage.c | 16 ++++++++-------- kernel/irq/resend.c | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 26effac7fc82..2fb08139a9e4 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -278,6 +278,11 @@ static inline int irq_desc_is_chained(struct irq_desc *desc) return (desc->action && desc->action == &chained_action); } +static inline bool irq_is_nmi(struct irq_desc *desc) +{ + return desc->istate & IRQS_NMI; +} + #ifdef CONFIG_PM_SLEEP bool irq_pm_check_wakeup(struct irq_desc *desc); void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 46094f0c9fcd..913c523d472d 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -960,11 +960,6 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; } -static bool irq_is_nmi(struct irq_desc *desc) -{ - return desc->istate & IRQS_NMI; -} - static unsigned int kstat_irqs(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 8a936c1ffad3..3bc7eec6e859 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -560,7 +560,7 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) /* The release function is promised process context */ might_sleep(); - if (!desc || desc->istate & IRQS_NMI) + if (!desc || irq_is_nmi(desc)) return -EINVAL; /* Complete initialisation of *notify */ @@ -898,7 +898,7 @@ int irq_set_irq_wake(unsigned int irq, unsigned int on) return -EINVAL; /* Don't use NMIs as wake up interrupts please */ - if (desc->istate & IRQS_NMI) { + if (irq_is_nmi(desc)) { ret = -EINVAL; goto out_unlock; } @@ -1627,7 +1627,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) */ unsigned int oldtype; - if (desc->istate & IRQS_NMI) { + if (irq_is_nmi(desc)) { pr_err("Invalid attempt to share NMI for %s (irq %d) on irqchip %s.\n", new->name, irq, desc->irq_data.chip->name); ret = -EINVAL; @@ -2080,7 +2080,7 @@ const void *free_nmi(unsigned int irq, void *dev_id) unsigned long flags; const void *devname; - if (!desc || WARN_ON(!(desc->istate & IRQS_NMI))) + if (!desc || WARN_ON(!irq_is_nmi(desc))) return NULL; if (WARN_ON(irq_settings_is_per_cpu_devid(desc))) @@ -2546,7 +2546,7 @@ void free_percpu_nmi(unsigned int irq, void __percpu *dev_id) if (!desc || !irq_settings_is_per_cpu_devid(desc)) return; - if (WARN_ON(!(desc->istate & IRQS_NMI))) + if (WARN_ON(!irq_is_nmi(desc))) return; kfree(__free_percpu_irq(irq, dev_id)); @@ -2682,7 +2682,7 @@ int request_percpu_nmi(unsigned int irq, irq_handler_t handler, return -EINVAL; /* The line cannot already be NMI */ - if (desc->istate & IRQS_NMI) + if (irq_is_nmi(desc)) return -EINVAL; action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -2743,7 +2743,7 @@ int prepare_percpu_nmi(unsigned int irq) if (!desc) return -EINVAL; - if (WARN(!(desc->istate & IRQS_NMI), + if (WARN(!irq_is_nmi(desc), KERN_ERR "prepare_percpu_nmi called for a non-NMI interrupt: irq %u\n", irq)) { ret = -EINVAL; @@ -2785,7 +2785,7 @@ void teardown_percpu_nmi(unsigned int irq) if (!desc) return; - if (WARN_ON(!(desc->istate & IRQS_NMI))) + if (WARN_ON(!irq_is_nmi(desc))) goto out; irq_nmi_teardown(desc); diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 5f2c66860ac6..b07a2d732ffb 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -190,7 +190,7 @@ int irq_inject_interrupt(unsigned int irq) * - not NMI type * - activated */ - if ((desc->istate & IRQS_NMI) || !irqd_is_activated(&desc->irq_data)) + if (irq_is_nmi(desc) || !irqd_is_activated(&desc->irq_data)) err = -EINVAL; else err = check_irq_resend(desc, true); -- 2.34.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/release-management/issues/IBV2E4 -------------------------------- Support hardware xint. Hardware xint provides a separate entry for interrupt handling, so we can use it to customize and respond to interrupts relatively quickly. Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- v2: - Reuse the xint set and check logic in xint 1.0. - Introduce fast_handle_xint(). - Rename enable_xint_xcall() to enable_xfunc(). - Rename test_has_xint_xcall() to test_has_xfunc(). - Fix a typo, Harware -> Hardware. - Add a blank line after declarations in el0t_64_xint_handler(). --- arch/arm64/Kconfig | 7 +++ arch/arm64/include/asm/sysreg.h | 4 ++ arch/arm64/kernel/cpufeature.c | 75 ++++++++++++++++++++++++- arch/arm64/kernel/entry-common.c | 35 +++++++++--- arch/arm64/kernel/entry.S | 40 +++++++++++++- arch/arm64/tools/cpucaps | 2 +- drivers/irqchip/irq-gic-v3.c | 89 ++++++++++++++++++++++++++++-- include/linux/irqchip/arm-gic-v3.h | 6 +- kernel/irq/debugfs.c | 6 +- kernel/irq/internals.h | 3 +- 10 files changed, 244 insertions(+), 23 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 9da9d58f1c02..57d05cfbd29e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1717,6 +1717,13 @@ config ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG config ARCH_SUPPORTS_CRASH_DUMP def_bool y +config ARCH_SUPPORTS_XINT + bool "Hardware xint support" + default n + depends on ARM64_NMI + depends on ARM_GIC_V3 + depends on !COMPAT + config TRANS_TABLE def_bool y depends on HIBERNATION || KEXEC_CORE diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 435634a703c6..b34e8cc4476b 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -269,6 +269,10 @@ #define SYS_REVIDR_EL1 sys_reg(3, 0, 0, 0, 6) #define SYS_ACTLR_EL1 sys_reg(3, 0, 1, 0, 1) + +#define ACTLR_ELx_XINT_SHIFT 21 +#define ACTLR_ELx_XINT (BIT(ACTLR_ELx_XINT_SHIFT)) + #define SYS_RGSR_EL1 sys_reg(3, 0, 1, 0, 5) #define SYS_GCR_EL1 sys_reg(3, 0, 1, 0, 6) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index a1736e9044da..b4de05241f7d 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2406,8 +2406,12 @@ static bool has_xcall_support(const struct arm64_cpu_capabilities *entry, int __ } #endif -#ifdef CONFIG_FAST_IRQ +#if defined(CONFIG_FAST_IRQ) || defined(CONFIG_ARCH_SUPPORTS_XINT) bool is_xint_support; +bool hw_xint_support; +#endif + +#ifdef CONFIG_FAST_IRQ static int __init xint_setup(char *str) { if (!cpus_have_cap(ARM64_HAS_GIC_CPUIF_SYSREGS)) @@ -2424,6 +2428,66 @@ static bool has_xint_support(const struct arm64_cpu_capabilities *entry, int __u } #endif +#ifdef CONFIG_ARCH_SUPPORTS_XINT +static bool test_has_xfunc(void) +{ + u64 new, old = read_sysreg(actlr_el1); + + write_sysreg(old | ACTLR_ELx_XINT, actlr_el1); + isb(); + new = read_sysreg(actlr_el1); + if (new & ACTLR_ELx_XINT) { + write_sysreg(old, actlr_el1); + hw_xint_support = true; + return true; + } + + return false; +} + +static void enable_xfunc(void) +{ + u64 actlr_el1, actlr_el2; + u64 el; + + el = read_sysreg(CurrentEL); + if (el == CurrentEL_EL2) { + actlr_el2 = read_sysreg(actlr_el2); + actlr_el2 |= ACTLR_ELx_XINT; + write_sysreg(actlr_el2, actlr_el2); + isb(); + actlr_el2 = read_sysreg(actlr_el2); + pr_info("actlr_el2: %llx, cpu:%d\n", actlr_el2, smp_processor_id()); + } + + actlr_el1 = read_sysreg(actlr_el1); + actlr_el1 |= ACTLR_ELx_XINT; + write_sysreg(actlr_el1, actlr_el1); + isb(); + actlr_el1 = read_sysreg(actlr_el1); + pr_info("actlr_el1: %llx, cpu:%d\n", actlr_el1, smp_processor_id()); +} + +static bool test_has_xint(const struct arm64_cpu_capabilities *entry, int scope) +{ + if (!IS_ENABLED(CONFIG_ARM64_NMI)) + pr_info("CONFIG_ARM64_NMI disabled, using XINTs for guests only\n"); +#ifdef CONFIG_ARM64_PSEUDO_NMI + else if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && enable_pseudo_nmi) { + pr_info("Pseudo NMI enabled, not using architected XINT\n"); + return false; + } +#endif + + return test_has_xfunc(); +} + +static void xint_enable(const struct arm64_cpu_capabilities *__unused) +{ + enable_xfunc(); +} +#endif + static const struct arm64_cpu_capabilities arm64_features[] = { { .capability = ARM64_ALWAYS_BOOT, @@ -2971,6 +3035,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .type = ARM64_CPUCAP_SYSTEM_FEATURE, .matches = has_xint_support, }, +#endif +#ifdef CONFIG_ARCH_SUPPORTS_XINT + { + .desc = "Hardware xint Support", + .capability = ARM64_HAS_HW_XINT, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = test_has_xint, + .cpu_enable = xint_enable, + }, #endif {}, }; diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c index 4602c107c40a..d09029dfcf02 100644 --- a/arch/arm64/kernel/entry-common.c +++ b/arch/arm64/kernel/entry-common.c @@ -6,6 +6,9 @@ */ #include <linux/context_tracking.h> +#ifdef CONFIG_ARCH_SUPPORTS_XINT +#include <linux/irqchip/arm-gic-v3.h> +#endif #include <linux/kasan.h> #include <linux/linkage.h> #include <linux/lockdep.h> @@ -607,7 +610,7 @@ static void noinstr el0_xint(struct pt_regs *regs, u64 nmi_flag, } -asmlinkage void noinstr el0t_64_xint_handler(struct pt_regs *regs) +asmlinkage void noinstr el0t_64_sw_xint_handler(struct pt_regs *regs) { el0_xint(regs, ISR_EL1_IS, handle_arch_irq, handle_arch_nmi_irq); } @@ -966,6 +969,30 @@ asmlinkage void noinstr el0t_64_error_handler(struct pt_regs *regs) __el0_error_handler_common(regs); } +#ifdef CONFIG_ARCH_SUPPORTS_XINT +asmlinkage void noinstr el0t_64_xint_handler(struct pt_regs *regs) +{ + u32 irqnr = read_sysreg_s(SYS_ICC_HPPIR1_EL1); + + if (gic_irqnr_is_special(irqnr)) + return; + + if (is_xint(irqnr)) + fast_handle_xint(regs, irqnr); + else + el0t_64_irq_handler(regs); +} +#else +#ifdef CONFIG_AARCH32_EL0 +asmlinkage void noinstr el0t_32_irq_handler(struct pt_regs *regs) +{ + __el0_irq_handler_common(regs); +} +#else /* CONFIG_AARCH32_EL0 */ +UNHANDLED(el0t, 32, irq) +#endif +#endif + #ifdef CONFIG_AARCH32_EL0 static void noinstr el0_cp15(struct pt_regs *regs, unsigned long esr) { @@ -1028,11 +1055,6 @@ asmlinkage void noinstr el0t_32_sync_handler(struct pt_regs *regs) } } -asmlinkage void noinstr el0t_32_irq_handler(struct pt_regs *regs) -{ - __el0_irq_handler_common(regs); -} - asmlinkage void noinstr el0t_32_fiq_handler(struct pt_regs *regs) { __el0_fiq_handler_common(regs); @@ -1044,7 +1066,6 @@ asmlinkage void noinstr el0t_32_error_handler(struct pt_regs *regs) } #else /* CONFIG_AARCH32_EL0 */ UNHANDLED(el0t, 32, sync) -UNHANDLED(el0t, 32, irq) UNHANDLED(el0t, 32, fiq) UNHANDLED(el0t, 32, error) #endif /* CONFIG_AARCH32_EL0 */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index da3809632f0f..046225fa2f90 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -565,7 +565,11 @@ SYM_CODE_START(vectors) kernel_ventry 0, t, 64, error // Error 64-bit EL0 kernel_ventry 0, t, 32, sync // Synchronous 32-bit EL0 +#ifdef CONFIG_ARCH_SUPPORTS_XINT + kernel_ventry 0, t, 64, xint // XINT 64-bit EL0 +#else kernel_ventry 0, t, 32, irq // IRQ 32-bit EL0 +#endif kernel_ventry 0, t, 32, fiq // FIQ 32-bit EL0 kernel_ventry 0, t, 32, error // Error 32-bit EL0 SYM_CODE_END(vectors) @@ -696,7 +700,7 @@ SYM_CODE_END(__bad_stack) kernel_entry 0, 64 #endif mov x0, sp - bl el0t_64_xint_handler + bl el0t_64_sw_xint_handler #ifdef CONFIG_SECURITY_FEATURE_BYPASS kernel_exit 0, xint #else @@ -729,6 +733,18 @@ SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label) check_xint_pre_kernel_entry .Lskip_check_xint\@: .endif +#endif +#ifdef CONFIG_ARCH_SUPPORTS_XINT + .if \el == 0 && \regsize == 64 && \label == xint + alternative_if_not ARM64_HAS_HW_XINT + b .Lskip_hw_xint\@ + alternative_else_nop_endif + kernel_entry 0, 64, xint + mov x0, sp + bl el0t_64_xint_handler + kernel_exit 0, xint +.Lskip_hw_xint\@: + .endif #endif kernel_entry \el, \regsize mov x0, sp @@ -760,7 +776,11 @@ SYM_CODE_END(el\el\ht\()_\regsize\()_\label) entry_handler 0, t, 64, error entry_handler 0, t, 32, sync +#ifdef CONFIG_ARCH_SUPPORTS_XINT + entry_handler 0, t, 64, xint +#else entry_handler 0, t, 32, irq +#endif entry_handler 0, t, 32, fiq entry_handler 0, t, 32, error @@ -905,7 +925,14 @@ alternative_else_nop_endif .rept 4 tramp_ventry .Lvector_start\@, 64, \kpti, \bhb .endr - .rept 4 + +#ifdef CONFIG_ARCH_SUPPORTS_XINT + tramp_ventry .Lvector_start\@, 64, \kpti, \bhb +#else + tramp_ventry .Lvector_start\@, 32, \kpti, \bhb +#endif + + .rept 3 tramp_ventry .Lvector_start\@, 32, \kpti, \bhb .endr .endm @@ -955,7 +982,14 @@ SYM_CODE_END(tramp_exit) .rept 4 tramp_ventry .Lvector_start\@, 64, 0, \bhb .endr - .rept 4 + +#ifdef CONFIG_ARCH_SUPPORTS_XINT + tramp_ventry .Lvector_start\@, 64, 0, \bhb +#else + tramp_ventry .Lvector_start\@, 32, 0, \bhb +#endif + + .rept 3 tramp_ventry .Lvector_start\@, 32, 0, \bhb .endr .endm diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index f2ddced689b5..b1f109f17e4f 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -110,7 +110,7 @@ WORKAROUND_HISI_HIP08_RU_PREFETCH WORKAROUND_HISILICON_1980005 HAS_XCALL HAS_XINT -KABI_RESERVE_3 +HAS_HW_XINT KABI_RESERVE_4 KABI_RESERVE_5 KABI_RESERVE_6 diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 4cc8b95d533f..32ffdf06f61e 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -35,7 +35,7 @@ #include "irq-gic-common.h" -#ifdef CONFIG_FAST_IRQ +#if defined(CONFIG_FAST_IRQ) || defined(CONFIG_ARCH_SUPPORTS_XINT) #include "../../../kernel/irq/internals.h" #endif @@ -828,7 +828,7 @@ static bool gic_rpr_is_nmi_prio(void) return unlikely(gic_read_rpr() == GICD_INT_RPR_PRI(GICD_INT_NMI_PRI)); } -static bool gic_irqnr_is_special(u32 irqnr) +bool gic_irqnr_is_special(u32 irqnr) { return irqnr >= 1020 && irqnr <= 1023; } @@ -993,7 +993,11 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs __gic_handle_irq_from_irqson(regs); } -#ifdef CONFIG_FAST_IRQ +#ifdef CONFIG_ARCH_SUPPORTS_XINT +DECLARE_BITMAP(irqnr_nmi_map, 1024); +#endif + +#if defined(CONFIG_FAST_IRQ) || defined(CONFIG_ARCH_SUPPORTS_XINT) DECLARE_BITMAP(irqnr_xint_map, 1024); static bool can_set_xint(unsigned int hwirq) @@ -1002,12 +1006,18 @@ static bool can_set_xint(unsigned int hwirq) __get_intid_range(hwirq) == SPI_RANGE) return true; +#ifdef CONFIG_ARCH_SUPPORTS_XINT + if (hw_xint_support && __get_intid_range(hwirq) == PPI_RANGE) + return true; +#endif + return false; } static bool xint_transform(int irqno, enum xint_op op) { struct irq_data *data = irq_get_irq_data(irqno); + struct irq_desc *desc; int hwirq; while (data->parent_data) @@ -1018,14 +1028,29 @@ static bool xint_transform(int irqno, enum xint_op op) if (!can_set_xint(hwirq)) return false; + desc = irq_data_to_desc(data); + switch (op) { case IRQ_TO_XINT: set_bit(hwirq, irqnr_xint_map); xint_add_debugfs_entry(irqno); +#ifdef CONFIG_ARCH_SUPPORTS_XINT + if (has_v3_3_nmi() && hw_xint_support && !irq_is_nmi(desc)) { + gic_irq_enable_nmi(data); + set_bit(hwirq, irqnr_nmi_map); + } +#endif return true; case XINT_TO_IRQ: clear_bit(hwirq, irqnr_xint_map); xint_remove_debugfs_entry(irqno); +#ifdef CONFIG_ARCH_SUPPORTS_XINT + if (has_v3_3_nmi() && hw_xint_support && irq_is_nmi(desc) && + test_bit(hwirq, irqnr_nmi_map)) { + gic_irq_disable_nmi(data); + clear_bit(hwirq, irqnr_nmi_map); + } +#endif return false; case XINT_SET_CHECK: return test_bit(hwirq, irqnr_xint_map); @@ -1096,7 +1121,7 @@ static const struct proc_ops xint_proc_ops = { void register_irqchip_proc(struct irq_desc *desc, void *irqp) { - if (!is_xint_support) + if (!is_xint_support && !hw_xint_support) return; /* create /proc/irq/<irq>/xint */ @@ -1105,12 +1130,63 @@ void register_irqchip_proc(struct irq_desc *desc, void *irqp) void unregister_irqchip_proc(struct irq_desc *desc) { - if (!is_xint_support) + if (!is_xint_support && !hw_xint_support) return; remove_proc_entry("xint", desc->dir); } -#endif /* CONFIG_FAST_IRQ */ +#endif + +#ifdef CONFIG_ARCH_SUPPORTS_XINT +bool is_xint(unsigned long hwirq) +{ + return test_bit(hwirq, irqnr_xint_map); +} + +static bool is_spi(unsigned long hwirq) +{ + if (__get_intid_range(hwirq) == SPI_RANGE || + __get_intid_range(hwirq) == ESPI_RANGE) + return true; + + return false; +} + +void fast_handle_xint(struct pt_regs *regs, u32 irqnr) +{ + struct pt_regs *old_regs; + struct irq_domain *domain; + struct irqaction *action; + struct irq_desc *desc; + struct irq_data *data; + + arch_nmi_enter(); + BUG_ON(in_nmi() == NMI_MASK); + __preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); + old_regs = set_irq_regs(regs); + + domain = irq_get_default_host(); + data = radix_tree_lookup(&domain->revmap_tree, irqnr); + + desc = irq_data_to_desc(data); + action = desc->action; + + gic_read_nmiar(); + write_gicreg(irqnr, ICC_EOIR1_EL1); + isb(); + + if (is_spi(irqnr)) + action->handler(data->irq, action->dev_id); + else + action->handler(data->irq, raw_cpu_ptr(action->percpu_dev_id)); + gic_write_dir(irqnr); + + set_irq_regs(old_regs); + BUG_ON(!in_nmi()); + __preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); + arch_nmi_exit(); +} +#endif static u32 gic_get_pribits(void) { @@ -2358,6 +2434,7 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base, goto out_free; } + irq_set_default_host(gic_data.domain); irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED); gic_data.has_rss = !!(typer & GICD_TYPER_RSS); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 548b8a5c46cf..3c0f04b86c15 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -721,8 +721,9 @@ static inline enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq) } } -#ifdef CONFIG_FAST_IRQ +#if defined(CONFIG_FAST_IRQ) || defined(CONFIG_ARCH_SUPPORTS_XINT) extern bool is_xint_support; +extern bool hw_xint_support; enum xint_op { XINT_TO_IRQ, @@ -733,6 +734,9 @@ enum xint_op { void register_irqchip_proc(struct irq_desc *desc, void *irqp); void unregister_irqchip_proc(struct irq_desc *desc); +bool gic_irqnr_is_special(u32 irqnr); +bool is_xint(unsigned long hwirq); +void fast_handle_xint(struct pt_regs *regs, u32 irqnr); #endif #endif diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c index dc94c360b54b..2152125f8ae2 100644 --- a/kernel/irq/debugfs.c +++ b/kernel/irq/debugfs.c @@ -242,7 +242,7 @@ void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc) &dfs_irq_ops); } -#ifdef CONFIG_FAST_IRQ +#if defined(CONFIG_FAST_IRQ) || defined(CONFIG_ARCH_SUPPORTS_XINT) static struct dentry *xint_dir; void xint_add_debugfs_entry(unsigned int irq) @@ -281,8 +281,8 @@ static int __init irq_debugfs_init(void) irq_dir = debugfs_create_dir("irqs", root_dir); -#ifdef CONFIG_FAST_IRQ - if (is_xint_support) +#if defined(CONFIG_FAST_IRQ) || defined(CONFIG_ARCH_SUPPORTS_XINT) + if (is_xint_support || hw_xint_support) xint_dir = debugfs_create_dir("xints", root_dir); #endif diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 2fb08139a9e4..1c64854102f5 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -506,8 +506,9 @@ static inline void irq_remove_debugfs_entry(struct irq_desc *desc) kfree(desc->dev_name); } -#ifdef CONFIG_FAST_IRQ +#if defined(CONFIG_FAST_IRQ) || defined(CONFIG_ARCH_SUPPORTS_XINT) extern bool is_xint_support; +extern bool hw_xint_support; void xint_add_debugfs_entry(unsigned int irq); void xint_remove_debugfs_entry(unsigned int irq); -- 2.34.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/release-management/issues/IBV2E4 -------------------------------- Support hardware xcall. Hardware xcall provides a separate entry for el0 syscall handling, so we can use it to customize and respond to system call relatively quickly. Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- v2: - Remove an excess semicolon. - Fix a typo. --- arch/Kconfig | 14 ++++----- arch/arm64/Kconfig | 5 ++++ arch/arm64/include/asm/sysreg.h | 3 ++ arch/arm64/kernel/cpufeature.c | 50 ++++++++++++++++++++++++++------ arch/arm64/kernel/entry-common.c | 4 +-- arch/arm64/kernel/entry.S | 38 ++++++++++++++++++++++-- arch/arm64/tools/cpucaps | 2 +- 7 files changed, 94 insertions(+), 22 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index a4ed5d338dad..dd7b91f19edc 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1574,12 +1574,12 @@ config FAST_IRQ framework for latency-sensitive interrupts. config DEBUG_FEATURE_BYPASS - bool "Bypass debug feature in fast syscall" - depends on FAST_SYSCALL || FAST_IRQ + bool "Bypass debug feature in fast syscall/irq and hardware xcall" + depends on FAST_SYSCALL || FAST_IRQ || ARCH_SUPPORTS_XCALL depends on !LOCKDEP default y help - This to bypass debug feature in fast syscall. + This to bypass debug feature in fast syscall/irq and hardware xcall. The svc exception handling process, which includes auxiliary functions for debug/trace and core functions like KPTI, has been identified as overly "lengthy". @@ -1587,12 +1587,12 @@ config DEBUG_FEATURE_BYPASS Disable this config to keep debug feature in fast syscall. config SECURITY_FEATURE_BYPASS - bool "Bypass security feature in fast syscall" - depends on FAST_SYSCALL || FAST_IRQ + bool "Bypass security feature in fast syscall and hardware xcall" + depends on FAST_SYSCALL || FAST_IRQ || ARCH_SUPPORTS_XCALL default y help - This to bypass security feature in fast syscall. - The svc exception handling process, which includes auxiliary + This to bypass security feature in fast syscall/irq and hardware + xcall. The svc exception handling process, which includes auxiliary functions for debug/trace and core functions like KPTI, has been identified as overly "lengthy". In fast syscall we only considers necessary features. diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 57d05cfbd29e..14b818fce7a1 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1724,6 +1724,11 @@ config ARCH_SUPPORTS_XINT depends on ARM_GIC_V3 depends on !COMPAT +config ARCH_SUPPORTS_XCALL + bool "Hardware xcall support" + depends on !COMPAT + default n + config TRANS_TABLE def_bool y depends on HIBERNATION || KEXEC_CORE diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index b34e8cc4476b..f97b2b400266 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -270,6 +270,9 @@ #define SYS_ACTLR_EL1 sys_reg(3, 0, 1, 0, 1) +#define ACTLR_ELx_XCALL_SHIFT 20 +#define ACTLR_ELx_XCALL (BIT(ACTLR_ELx_XCALL_SHIFT)) + #define ACTLR_ELx_XINT_SHIFT 21 #define ACTLR_ELx_XINT (BIT(ACTLR_ELx_XINT_SHIFT)) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index b4de05241f7d..055eb16309e2 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2428,24 +2428,33 @@ static bool has_xint_support(const struct arm64_cpu_capabilities *entry, int __u } #endif -#ifdef CONFIG_ARCH_SUPPORTS_XINT -static bool test_has_xfunc(void) +#if defined(CONFIG_ARCH_SUPPORTS_XINT) || defined(CONFIG_ARCH_SUPPORTS_XCALL) +static bool test_has_xfunc(bool is_xint) { u64 new, old = read_sysreg(actlr_el1); - write_sysreg(old | ACTLR_ELx_XINT, actlr_el1); + if (is_xint) + write_sysreg(old | ACTLR_ELx_XINT, actlr_el1); + else + write_sysreg(old | ACTLR_ELx_XCALL, actlr_el1); + isb(); new = read_sysreg(actlr_el1); - if (new & ACTLR_ELx_XINT) { + if (is_xint && (new & ACTLR_ELx_XINT)) { write_sysreg(old, actlr_el1); hw_xint_support = true; return true; } + if (!is_xint && (new & ACTLR_ELx_XCALL)) { + write_sysreg(old, actlr_el1); + return true; + } + return false; } -static void enable_xfunc(void) +static void enable_xfunc(bool is_xint) { u64 actlr_el1, actlr_el2; u64 el; @@ -2453,7 +2462,7 @@ static void enable_xfunc(void) el = read_sysreg(CurrentEL); if (el == CurrentEL_EL2) { actlr_el2 = read_sysreg(actlr_el2); - actlr_el2 |= ACTLR_ELx_XINT; + actlr_el2 |= (is_xint ? ACTLR_ELx_XINT : ACTLR_ELx_XCALL); write_sysreg(actlr_el2, actlr_el2); isb(); actlr_el2 = read_sysreg(actlr_el2); @@ -2461,13 +2470,15 @@ static void enable_xfunc(void) } actlr_el1 = read_sysreg(actlr_el1); - actlr_el1 |= ACTLR_ELx_XINT; + actlr_el1 |= (is_xint ? ACTLR_ELx_XINT : ACTLR_ELx_XCALL); write_sysreg(actlr_el1, actlr_el1); isb(); actlr_el1 = read_sysreg(actlr_el1); pr_info("actlr_el1: %llx, cpu:%d\n", actlr_el1, smp_processor_id()); } +#endif +#ifdef CONFIG_ARCH_SUPPORTS_XINT static bool test_has_xint(const struct arm64_cpu_capabilities *entry, int scope) { if (!IS_ENABLED(CONFIG_ARM64_NMI)) @@ -2479,12 +2490,24 @@ static bool test_has_xint(const struct arm64_cpu_capabilities *entry, int scope) } #endif - return test_has_xfunc(); + return test_has_xfunc(true); } static void xint_enable(const struct arm64_cpu_capabilities *__unused) { - enable_xfunc(); + enable_xfunc(true); +} +#endif + +#ifdef CONFIG_ARCH_SUPPORTS_XCALL +static bool test_has_xcall(const struct arm64_cpu_capabilities *entry, int scope) +{ + return test_has_xfunc(false); +} + +static void xcall_enable(const struct arm64_cpu_capabilities *__unused) +{ + enable_xfunc(false); } #endif @@ -3044,6 +3067,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = test_has_xint, .cpu_enable = xint_enable, }, +#endif +#ifdef CONFIG_ARCH_SUPPORTS_XCALL + { + .desc = "Hardware xcall Support", + .capability = ARM64_HAS_HW_XCALL, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = test_has_xcall, + .cpu_enable = xcall_enable, + }, #endif {}, }; diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c index d09029dfcf02..ea78eb729ff6 100644 --- a/arch/arm64/kernel/entry-common.c +++ b/arch/arm64/kernel/entry-common.c @@ -154,7 +154,7 @@ asmlinkage void noinstr asm_exit_to_user_mode(struct pt_regs *regs) exit_to_user_mode(regs); } -#if defined(CONFIG_FAST_SYSCALL) || defined(CONFIG_FAST_IRQ) +#if defined(CONFIG_FAST_SYSCALL) || defined(CONFIG_FAST_IRQ) || defined(CONFIG_ARCH_SUPPORTS_XCALL) /* * Copy from exit_to_user_mode_prepare */ @@ -818,7 +818,7 @@ static void noinstr el0_fpac(struct pt_regs *regs, unsigned long esr) exit_to_user_mode(regs); } -#ifdef CONFIG_FAST_SYSCALL +#if defined(CONFIG_FAST_SYSCALL) || defined(CONFIG_ARCH_SUPPORTS_XCALL) /* Copy from el0_sync */ static void noinstr el0_xcall(struct pt_regs *regs) { diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 046225fa2f90..23c1b255e02e 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -564,7 +564,11 @@ SYM_CODE_START(vectors) kernel_ventry 0, t, 64, fiq // FIQ 64-bit EL0 kernel_ventry 0, t, 64, error // Error 64-bit EL0 +#ifdef CONFIG_ARCH_SUPPORTS_XCALL + kernel_ventry 0, t, 64, xcall // xcall synchronous 64-bit EL0 +#else kernel_ventry 0, t, 32, sync // Synchronous 32-bit EL0 +#endif #ifdef CONFIG_ARCH_SUPPORTS_XINT kernel_ventry 0, t, 64, xint // XINT 64-bit EL0 #else @@ -722,7 +726,19 @@ SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label) b .Lret_to_kernel_entry\@ alternative_else_nop_endif check_xcall_pre_kernel_entry - .Lret_to_kernel_entry\@: +.Lret_to_kernel_entry\@: + .endif +#endif +#ifdef CONFIG_ARCH_SUPPORTS_XCALL + .if \el == 0 && \regsize == 64 && \label == xcall + alternative_if_not ARM64_HAS_HW_XCALL + b .Lskip_hw_xcall\@ + alternative_else_nop_endif + kernel_entry 0, 64, xcall + mov x0, sp + bl el0t_64_xcall_handler + kernel_exit 0, xcall +.Lskip_hw_xcall\@: .endif #endif #ifdef CONFIG_FAST_IRQ @@ -775,7 +791,11 @@ SYM_CODE_END(el\el\ht\()_\regsize\()_\label) entry_handler 0, t, 64, fiq entry_handler 0, t, 64, error +#ifdef CONFIG_ARCH_SUPPORTS_XCALL + entry_handler 0, t, 64, xcall +#else entry_handler 0, t, 32, sync +#endif #ifdef CONFIG_ARCH_SUPPORTS_XINT entry_handler 0, t, 64, xint #else @@ -926,13 +946,19 @@ alternative_else_nop_endif tramp_ventry .Lvector_start\@, 64, \kpti, \bhb .endr +#ifdef CONFIG_ARCH_SUPPORTS_XCALL + tramp_ventry .Lvector_start\@, 64, \kpti, \bhb +#else + tramp_ventry .Lvector_start\@, 32, \kpti, \bhb +#endif + #ifdef CONFIG_ARCH_SUPPORTS_XINT tramp_ventry .Lvector_start\@, 64, \kpti, \bhb #else tramp_ventry .Lvector_start\@, 32, \kpti, \bhb #endif - .rept 3 + .rept 2 tramp_ventry .Lvector_start\@, 32, \kpti, \bhb .endr .endm @@ -983,13 +1009,19 @@ SYM_CODE_END(tramp_exit) tramp_ventry .Lvector_start\@, 64, 0, \bhb .endr +#ifdef CONFIG_ARCH_SUPPORTS_XCALL + tramp_ventry .Lvector_start\@, 64, 0, \bhb +#else + tramp_ventry .Lvector_start\@, 32, 0, \bhb +#endif + #ifdef CONFIG_ARCH_SUPPORTS_XINT tramp_ventry .Lvector_start\@, 64, 0, \bhb #else tramp_ventry .Lvector_start\@, 32, 0, \bhb #endif - .rept 3 + .rept 2 tramp_ventry .Lvector_start\@, 32, 0, \bhb .endr .endm diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index b1f109f17e4f..3a6e38f45618 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -110,8 +110,8 @@ WORKAROUND_HISI_HIP08_RU_PREFETCH WORKAROUND_HISILICON_1980005 HAS_XCALL HAS_XINT +HAS_HW_XCALL HAS_HW_XINT -KABI_RESERVE_4 KABI_RESERVE_5 KABI_RESERVE_6 KABI_RESERVE_7 -- 2.34.1

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/15616 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/UIK... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/15616 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/UIK...
participants (2)
-
Jinjie Ruan
-
patchwork bot