Skip to content

Commit

Permalink
powerpc: interrupt handler wrapper functions
Browse files Browse the repository at this point in the history
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 36805b0
Show file tree
Hide file tree
Showing 21 changed files with 303 additions and 92 deletions.
29 changes: 0 additions & 29 deletions arch/powerpc/include/asm/asm-prototypes.h
Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion arch/powerpc/include/asm/book3s/64/mmu-hash.h
Expand Up @@ -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);
Expand Down
9 changes: 0 additions & 9 deletions arch/powerpc/include/asm/hw_irq.h
Expand Up @@ -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>

Expand Down
203 changes: 203 additions & 0 deletions arch/powerpc/include/asm/interrupt.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 */
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/time.h
Expand Up @@ -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);

Expand Down
12 changes: 4 additions & 8 deletions arch/powerpc/kernel/dbell.c
Expand Up @@ -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();
Expand All @@ -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 */

}
7 changes: 3 additions & 4 deletions arch/powerpc/kernel/exceptions-64s.S
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand Down
6 changes: 3 additions & 3 deletions arch/powerpc/kernel/head_book3s_32.S
Expand Up @@ -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 */
/*
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/kernel/irq.c
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions arch/powerpc/kernel/mce.c
Expand Up @@ -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>
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 36805b0

Please sign in to comment.