18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_IRQ_STACK_H
38c2ecf20Sopenharmony_ci#define _ASM_X86_IRQ_STACK_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/ptrace.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <asm/processor.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
108c2ecf20Sopenharmony_cistatic __always_inline bool irqstack_active(void)
118c2ecf20Sopenharmony_ci{
128c2ecf20Sopenharmony_ci	return __this_cpu_read(irq_count) != -1;
138c2ecf20Sopenharmony_ci}
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_civoid asm_call_on_stack(void *sp, void (*func)(void), void *arg);
168c2ecf20Sopenharmony_civoid asm_call_sysvec_on_stack(void *sp, void (*func)(struct pt_regs *regs),
178c2ecf20Sopenharmony_ci			      struct pt_regs *regs);
188c2ecf20Sopenharmony_civoid asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc),
198c2ecf20Sopenharmony_ci			   struct irq_desc *desc);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic __always_inline void __run_on_irqstack(void (*func)(void))
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	void *tos = __this_cpu_read(hardirq_stack_ptr);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	__this_cpu_add(irq_count, 1);
268c2ecf20Sopenharmony_ci	asm_call_on_stack(tos - 8, func, NULL);
278c2ecf20Sopenharmony_ci	__this_cpu_sub(irq_count, 1);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic __always_inline void
318c2ecf20Sopenharmony_ci__run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs),
328c2ecf20Sopenharmony_ci			 struct pt_regs *regs)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	void *tos = __this_cpu_read(hardirq_stack_ptr);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	__this_cpu_add(irq_count, 1);
378c2ecf20Sopenharmony_ci	asm_call_sysvec_on_stack(tos - 8, func, regs);
388c2ecf20Sopenharmony_ci	__this_cpu_sub(irq_count, 1);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic __always_inline void
428c2ecf20Sopenharmony_ci__run_irq_on_irqstack(void (*func)(struct irq_desc *desc),
438c2ecf20Sopenharmony_ci		      struct irq_desc *desc)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	void *tos = __this_cpu_read(hardirq_stack_ptr);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	__this_cpu_add(irq_count, 1);
488c2ecf20Sopenharmony_ci	asm_call_irq_on_stack(tos - 8, func, desc);
498c2ecf20Sopenharmony_ci	__this_cpu_sub(irq_count, 1);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#else /* CONFIG_X86_64 */
538c2ecf20Sopenharmony_cistatic inline bool irqstack_active(void) { return false; }
548c2ecf20Sopenharmony_cistatic inline void __run_on_irqstack(void (*func)(void)) { }
558c2ecf20Sopenharmony_cistatic inline void __run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs),
568c2ecf20Sopenharmony_ci					    struct pt_regs *regs) { }
578c2ecf20Sopenharmony_cistatic inline void __run_irq_on_irqstack(void (*func)(struct irq_desc *desc),
588c2ecf20Sopenharmony_ci					 struct irq_desc *desc) { }
598c2ecf20Sopenharmony_ci#endif /* !CONFIG_X86_64 */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic __always_inline bool irq_needs_irq_stack(struct pt_regs *regs)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_X86_32))
648c2ecf20Sopenharmony_ci		return false;
658c2ecf20Sopenharmony_ci	if (!regs)
668c2ecf20Sopenharmony_ci		return !irqstack_active();
678c2ecf20Sopenharmony_ci	return !user_mode(regs) && !irqstack_active();
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic __always_inline void run_on_irqstack_cond(void (*func)(void),
728c2ecf20Sopenharmony_ci						 struct pt_regs *regs)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	lockdep_assert_irqs_disabled();
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (irq_needs_irq_stack(regs))
778c2ecf20Sopenharmony_ci		__run_on_irqstack(func);
788c2ecf20Sopenharmony_ci	else
798c2ecf20Sopenharmony_ci		func();
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic __always_inline void
838c2ecf20Sopenharmony_cirun_sysvec_on_irqstack_cond(void (*func)(struct pt_regs *regs),
848c2ecf20Sopenharmony_ci			    struct pt_regs *regs)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	lockdep_assert_irqs_disabled();
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (irq_needs_irq_stack(regs))
898c2ecf20Sopenharmony_ci		__run_sysvec_on_irqstack(func, regs);
908c2ecf20Sopenharmony_ci	else
918c2ecf20Sopenharmony_ci		func(regs);
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic __always_inline void
958c2ecf20Sopenharmony_cirun_irq_on_irqstack_cond(void (*func)(struct irq_desc *desc), struct irq_desc *desc,
968c2ecf20Sopenharmony_ci			 struct pt_regs *regs)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	lockdep_assert_irqs_disabled();
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (irq_needs_irq_stack(regs))
1018c2ecf20Sopenharmony_ci		__run_irq_on_irqstack(func, desc);
1028c2ecf20Sopenharmony_ci	else
1038c2ecf20Sopenharmony_ci		func(desc);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#endif
107