Skip to content
Permalink
Browse files
powerpc: interrupt handler wrapper functions
Add wrapper functions (derived from x86 macros) for interrupt handler
functions. This allows interrupt entry code to be written in C.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
  • Loading branch information
npiggin authored and intel-lab-lkp committed Nov 11, 2020
1 parent b2ec3fb commit 36805b0ebcf1760588efad86b8b5db5344329148
Show file tree
Hide file tree
Showing 21 changed files with 303 additions and 92 deletions.
@@ -56,35 +56,6 @@ int exit_vmx_usercopy(void);
int enter_vmx_ops(void);
void *exit_vmx_ops(void *dest);

/* Traps */
long machine_check_early(struct pt_regs *regs);
long hmi_exception_realmode(struct pt_regs *regs);
void SMIException(struct pt_regs *regs);
void handle_hmi_exception(struct pt_regs *regs);
void instruction_breakpoint_exception(struct pt_regs *regs);
void RunModeException(struct pt_regs *regs);
void single_step_exception(struct pt_regs *regs);
void program_check_exception(struct pt_regs *regs);
void alignment_exception(struct pt_regs *regs);
void StackOverflow(struct pt_regs *regs);
void stack_overflow_exception(struct pt_regs *regs);
void kernel_fp_unavailable_exception(struct pt_regs *regs);
void altivec_unavailable_exception(struct pt_regs *regs);
void vsx_unavailable_exception(struct pt_regs *regs);
void fp_unavailable_tm(struct pt_regs *regs);
void altivec_unavailable_tm(struct pt_regs *regs);
void vsx_unavailable_tm(struct pt_regs *regs);
void facility_unavailable_exception(struct pt_regs *regs);
void TAUException(struct pt_regs *regs);
void altivec_assist_exception(struct pt_regs *regs);
void unrecoverable_exception(struct pt_regs *regs);
void kernel_bad_stack(struct pt_regs *regs);
void system_reset_exception(struct pt_regs *regs);
void machine_check_exception(struct pt_regs *regs);
void emulation_assist_interrupt(struct pt_regs *regs);
long do_slb_fault(struct pt_regs *regs);
void do_bad_slb_fault(struct pt_regs *regs);

/* signals, syscalls and interrupts */
long sys_swapcontext(struct ucontext __user *old_ctx,
struct ucontext __user *new_ctx,
@@ -453,7 +453,6 @@ static inline unsigned long hpt_hash(unsigned long vpn,
#define HPTE_LOCAL_UPDATE 0x1
#define HPTE_NOHPTE_UPDATE 0x2

long do_hash_fault(struct pt_regs *regs);
extern int __hash_page_4K(unsigned long ea, unsigned long access,
unsigned long vsid, pte_t *ptep, unsigned long trap,
unsigned long flags, int ssize, int subpage_prot);
@@ -50,15 +50,6 @@

#ifndef __ASSEMBLY__

extern void replay_system_reset(void);
extern void replay_soft_interrupts(void);

extern void timer_interrupt(struct pt_regs *);
extern void timer_broadcast_interrupt(void);
extern void performance_monitor_exception(struct pt_regs *regs);
extern void WatchdogException(struct pt_regs *regs);
extern void unknown_exception(struct pt_regs *regs);

#ifdef CONFIG_PPC64
#include <asm/paca.h>

@@ -0,0 +1,203 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _ASM_POWERPC_INTERRUPT_H
#define _ASM_POWERPC_INTERRUPT_H

#include <linux/context_tracking.h>
#include <asm/ftrace.h>

/**
* DECLARE_INTERRUPT_HANDLER_RAW - Declare raw interrupt handler function
* @func: Function name of the entry point
* @returns: Returns a value back to asm caller
*/
#define DECLARE_INTERRUPT_HANDLER_RAW(func) \
__visible long func(struct pt_regs *regs)

/**
* DEFINE_INTERRUPT_HANDLER_RAW - Define raw interrupt handler function
* @func: Function name of the entry point
* @returns: Returns a value back to asm caller
*
* @func is called from ASM entry code.
*
* This is a plain function which does no tracing, reconciling, etc.
* The macro is written so it acts as function definition. Append the
* body with a pair of curly brackets.
*/
#define DEFINE_INTERRUPT_HANDLER_RAW(func) \
static __always_inline long ___##func(struct pt_regs *regs); \
\
__visible noinstr long func(struct pt_regs *regs) \
{ \
long ret; \
\
ret = ___##func (regs); \
\
return ret; \
} \
\
static __always_inline long ___##func(struct pt_regs *regs)

/**
* DECLARE_INTERRUPT_HANDLER - Declare synchronous interrupt handler function
* @func: Function name of the entry point
*/
#define DECLARE_INTERRUPT_HANDLER(func) \
__visible void func(struct pt_regs *regs)

/**
* DEFINE_INTERRUPT_HANDLER - Define synchronous interrupt handler function
* @func: Function name of the entry point
*
* @func is called from ASM entry code.
*
* The macro is written so it acts as function definition. Append the
* body with a pair of curly brackets.
*/
#define DEFINE_INTERRUPT_HANDLER(func) \
static __always_inline void ___##func(struct pt_regs *regs); \
\
__visible noinstr void func(struct pt_regs *regs) \
{ \
___##func (regs); \
} \
\
static __always_inline void ___##func(struct pt_regs *regs)

/**
* DECLARE_INTERRUPT_HANDLER_RET - Declare synchronous interrupt handler function
* @func: Function name of the entry point
* @returns: Returns a value back to asm caller
*/
#define DECLARE_INTERRUPT_HANDLER_RET(func) \
__visible long func(struct pt_regs *regs)

/**
* DEFINE_INTERRUPT_HANDLER_RET - Define synchronous interrupt handler function
* @func: Function name of the entry point
* @returns: Returns a value back to asm caller
*
* @func is called from ASM entry code.
*
* The macro is written so it acts as function definition. Append the
* body with a pair of curly brackets.
*/
#define DEFINE_INTERRUPT_HANDLER_RET(func) \
static __always_inline long ___##func(struct pt_regs *regs); \
\
__visible noinstr long func(struct pt_regs *regs) \
{ \
long ret; \
\
ret = ___##func (regs); \
\
return ret; \
} \
\
static __always_inline long ___##func(struct pt_regs *regs)

/**
* DECLARE_INTERRUPT_HANDLER_ASYNC - Declare asynchronous interrupt handler function
* @func: Function name of the entry point
*/
#define DECLARE_INTERRUPT_HANDLER_ASYNC(func) \
__visible void func(struct pt_regs *regs)

/**
* DEFINE_INTERRUPT_HANDLER_ASYNC - Define asynchronous interrupt handler function
* @func: Function name of the entry point
*
* @func is called from ASM entry code.
*
* The macro is written so it acts as function definition. Append the
* body with a pair of curly brackets.
*/
#define DEFINE_INTERRUPT_HANDLER_ASYNC(func) \
static __always_inline void ___##func(struct pt_regs *regs); \
\
__visible noinstr void func(struct pt_regs *regs) \
{ \
___##func (regs); \
} \
\
static __always_inline void ___##func(struct pt_regs *regs)

/**
* DECLARE_INTERRUPT_HANDLER_NMI - Declare NMI interrupt handler function
* @func: Function name of the entry point
* @returns: Returns a value back to asm caller
*/
#define DECLARE_INTERRUPT_HANDLER_NMI(func) \
__visible long func(struct pt_regs *regs)

/**
* DEFINE_INTERRUPT_HANDLER_NMI - Define NMI interrupt handler function
* @func: Function name of the entry point
* @returns: Returns a value back to asm caller
*
* @func is called from ASM entry code.
*
* The macro is written so it acts as function definition. Append the
* body with a pair of curly brackets.
*/
#define DEFINE_INTERRUPT_HANDLER_NMI(func) \
static __always_inline long ___##func(struct pt_regs *regs); \
\
__visible noinstr long func(struct pt_regs *regs) \
{ \
long ret; \
\
ret = ___##func (regs); \
\
return ret; \
} \
\
static __always_inline long ___##func(struct pt_regs *regs)


/* Interrupt handlers */
DECLARE_INTERRUPT_HANDLER_NMI(machine_check_early);
DECLARE_INTERRUPT_HANDLER_NMI(hmi_exception_realmode);
DECLARE_INTERRUPT_HANDLER(SMIException);
DECLARE_INTERRUPT_HANDLER(handle_hmi_exception);
DECLARE_INTERRUPT_HANDLER(instruction_breakpoint_exception);
DECLARE_INTERRUPT_HANDLER(RunModeException);
DECLARE_INTERRUPT_HANDLER(single_step_exception);
DECLARE_INTERRUPT_HANDLER(program_check_exception);
DECLARE_INTERRUPT_HANDLER(alignment_exception);
DECLARE_INTERRUPT_HANDLER(StackOverflow);
DECLARE_INTERRUPT_HANDLER(stack_overflow_exception);
DECLARE_INTERRUPT_HANDLER(kernel_fp_unavailable_exception);
DECLARE_INTERRUPT_HANDLER(altivec_unavailable_exception);
DECLARE_INTERRUPT_HANDLER(vsx_unavailable_exception);
DECLARE_INTERRUPT_HANDLER(fp_unavailable_tm);
DECLARE_INTERRUPT_HANDLER(altivec_unavailable_tm);
DECLARE_INTERRUPT_HANDLER(vsx_unavailable_tm);
DECLARE_INTERRUPT_HANDLER(facility_unavailable_exception);
DECLARE_INTERRUPT_HANDLER_ASYNC(TAUException);
DECLARE_INTERRUPT_HANDLER(altivec_assist_exception);
DECLARE_INTERRUPT_HANDLER(unrecoverable_exception);
DECLARE_INTERRUPT_HANDLER(kernel_bad_stack);
DECLARE_INTERRUPT_HANDLER_NMI(system_reset_exception);
#ifdef CONFIG_PPC_BOOK3S_64
DECLARE_INTERRUPT_HANDLER_ASYNC(machine_check_exception);
#else
DECLARE_INTERRUPT_HANDLER_NMI(machine_check_exception);
#endif
DECLARE_INTERRUPT_HANDLER(emulation_assist_interrupt);
DECLARE_INTERRUPT_HANDLER_RAW(do_slb_fault);
DECLARE_INTERRUPT_HANDLER(do_bad_slb_fault);
DECLARE_INTERRUPT_HANDLER_RET(do_hash_fault);
DECLARE_INTERRUPT_HANDLER_RET(do_page_fault);
DECLARE_INTERRUPT_HANDLER(do_bad_page_fault);

DECLARE_INTERRUPT_HANDLER_ASYNC(timer_interrupt);
DECLARE_INTERRUPT_HANDLER_ASYNC(performance_monitor_exception);
DECLARE_INTERRUPT_HANDLER(WatchdogException);
DECLARE_INTERRUPT_HANDLER(unknown_exception);
DECLARE_INTERRUPT_HANDLER_ASYNC(unknown_async_exception);

void replay_system_reset(void);
void replay_soft_interrupts(void);

#endif /* _ASM_POWERPC_INTERRUPT_H */
@@ -131,6 +131,8 @@ DECLARE_PER_CPU(u64, decrementers_next_tb);
/* Convert timebase ticks to nanoseconds */
unsigned long long tb_to_ns(unsigned long long tb_ticks);

void timer_broadcast_interrupt(void);

/* SPLPAR */
void accumulate_stolen_time(void);

@@ -12,14 +12,14 @@
#include <linux/hardirq.h>

#include <asm/dbell.h>
#include <asm/interrupt.h>
#include <asm/irq_regs.h>
#include <asm/kvm_ppc.h>
#include <asm/trace.h>

#ifdef CONFIG_SMP

void doorbell_exception(struct pt_regs *regs)
DEFINE_INTERRUPT_HANDLER_ASYNC(doorbell_exception)
{
#ifdef CONFIG_SMP
struct pt_regs *old_regs = set_irq_regs(regs);

irq_enter();
@@ -37,11 +37,7 @@ void doorbell_exception(struct pt_regs *regs)
trace_doorbell_exit(regs);
irq_exit();
set_irq_regs(old_regs);
}
#else /* CONFIG_SMP */
void doorbell_exception(struct pt_regs *regs)
{
printk(KERN_WARNING "Received doorbell on non-smp system\n");
}
#endif /* CONFIG_SMP */

}
@@ -1922,7 +1922,7 @@ EXC_COMMON_BEGIN(doorbell_super_common)
#ifdef CONFIG_PPC_DOORBELL
bl doorbell_exception
#else
bl unknown_exception
bl unknown_async_exception
#endif
b interrupt_return

@@ -2135,8 +2135,7 @@ EXC_COMMON_BEGIN(h_data_storage_common)
GEN_COMMON h_data_storage
addi r3,r1,STACK_FRAME_OVERHEAD
BEGIN_MMU_FTR_SECTION
li r4,SIGSEGV
bl bad_page_fault
bl do_bad_page_fault
MMU_FTR_SECTION_ELSE
bl unknown_exception
ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_TYPE_RADIX)
@@ -2309,7 +2308,7 @@ EXC_COMMON_BEGIN(h_doorbell_common)
#ifdef CONFIG_PPC_DOORBELL
bl doorbell_exception
#else
bl unknown_exception
bl unknown_async_exception
#endif
b interrupt_return

@@ -239,8 +239,8 @@ __secondary_hold_acknowledge:

/* System reset */
/* core99 pmac starts the seconary here by changing the vector, and
putting it back to what it was (unknown_exception) when done. */
EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
putting it back to what it was (unknown_async_exception) when done. */
EXCEPTION(0x100, Reset, unknown_async_exception, EXC_XFER_STD)

/* Machine check */
/*
@@ -653,7 +653,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
#endif

#ifndef CONFIG_TAU_INT
#define TAUException unknown_exception
#define TAUException unknown_async_exception
#endif

EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_STD)
@@ -54,6 +54,7 @@
#include <linux/pgtable.h>

#include <linux/uaccess.h>
#include <asm/interrupt.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/cache.h>
@@ -710,7 +711,7 @@ void __do_irq(struct pt_regs *regs)
irq_exit();
}

void do_IRQ(struct pt_regs *regs)
DEFINE_INTERRUPT_HANDLER_ASYNC(do_IRQ)
{
struct pt_regs *old_regs = set_irq_regs(regs);
void *cursp, *irqsp, *sirqsp;
@@ -18,6 +18,7 @@
#include <linux/extable.h>
#include <linux/ftrace.h>

#include <asm/interrupt.h>
#include <asm/machdep.h>
#include <asm/mce.h>
#include <asm/nmi.h>
@@ -588,7 +589,7 @@ EXPORT_SYMBOL_GPL(machine_check_print_event_info);
*
* regs->nip and regs->msr contains srr0 and ssr1.
*/
long notrace machine_check_early(struct pt_regs *regs)
DEFINE_INTERRUPT_HANDLER_NMI(machine_check_early)
{
long handled = 0;
u8 ftrace_enabled = this_cpu_get_ftrace_enabled();
@@ -722,7 +723,7 @@ long hmi_handle_debugtrig(struct pt_regs *regs)
/*
* Return values:
*/
long hmi_exception_realmode(struct pt_regs *regs)
DEFINE_INTERRUPT_HANDLER_NMI(hmi_exception_realmode)
{
int ret;

0 comments on commit 36805b0

Please sign in to comment.