RISC-V: self-contained IPI handling routine

Currently, the IPI handling routine riscv_software_interrupt() does
not take any argument and also does not perform irq_enter()/irq_exit().

This patch makes IPI handling routine more self-contained by:
1. Passing "pt_regs *" argument
2. Explicitly doing irq_enter()/irq_exit()
3. Explicitly save/restore "pt_regs *" using set_irq_regs()

With above changes, IPI handling routine does not depend on caller
function to perform irq_enter()/irq_exit() and save/restore of
"pt_regs *" hence its more self-contained. This also enables us
to call IPI handling routine from IRQCHIP drivers.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com>
Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
This commit is contained in:
Anup Patel 2020-06-01 14:45:38 +05:30 committed by Palmer Dabbelt
parent e8c7ef7d58
commit 5cf998ba8c
No known key found for this signature in database
GPG Key ID: 2E1319F35FBB1889
4 changed files with 22 additions and 9 deletions

View File

@ -13,7 +13,6 @@
#define NR_IRQS 0 #define NR_IRQS 0
void riscv_timer_interrupt(void); void riscv_timer_interrupt(void);
void riscv_software_interrupt(void);
#include <asm-generic/irq.h> #include <asm-generic/irq.h>

View File

@ -28,6 +28,9 @@ void show_ipi_stats(struct seq_file *p, int prec);
/* SMP initialization hook for setup_arch */ /* SMP initialization hook for setup_arch */
void __init setup_smp(void); void __init setup_smp(void);
/* Called from C code, this handles an IPI. */
void handle_IPI(struct pt_regs *regs);
/* Hook for the generic smp_call_function_many() routine. */ /* Hook for the generic smp_call_function_many() routine. */
void arch_send_call_function_ipi_mask(struct cpumask *mask); void arch_send_call_function_ipi_mask(struct cpumask *mask);

View File

@ -19,12 +19,15 @@ int arch_show_interrupts(struct seq_file *p, int prec)
asmlinkage __visible void __irq_entry do_IRQ(struct pt_regs *regs) asmlinkage __visible void __irq_entry do_IRQ(struct pt_regs *regs)
{ {
struct pt_regs *old_regs = set_irq_regs(regs); struct pt_regs *old_regs;
irq_enter();
switch (regs->cause & ~CAUSE_IRQ_FLAG) { switch (regs->cause & ~CAUSE_IRQ_FLAG) {
case RV_IRQ_TIMER: case RV_IRQ_TIMER:
old_regs = set_irq_regs(regs);
irq_enter();
riscv_timer_interrupt(); riscv_timer_interrupt();
irq_exit();
set_irq_regs(old_regs);
break; break;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
case RV_IRQ_SOFT: case RV_IRQ_SOFT:
@ -32,19 +35,20 @@ asmlinkage __visible void __irq_entry do_IRQ(struct pt_regs *regs)
* We only use software interrupts to pass IPIs, so if a non-SMP * We only use software interrupts to pass IPIs, so if a non-SMP
* system gets one, then we don't know what to do. * system gets one, then we don't know what to do.
*/ */
riscv_software_interrupt(); handle_IPI(regs);
break; break;
#endif #endif
case RV_IRQ_EXT: case RV_IRQ_EXT:
old_regs = set_irq_regs(regs);
irq_enter();
handle_arch_irq(regs); handle_arch_irq(regs);
irq_exit();
set_irq_regs(old_regs);
break; break;
default: default:
pr_alert("unexpected interrupt cause 0x%lx", regs->cause); pr_alert("unexpected interrupt cause 0x%lx", regs->cause);
BUG(); BUG();
} }
irq_exit();
set_irq_regs(old_regs);
} }
void __init init_IRQ(void) void __init init_IRQ(void)

View File

@ -123,11 +123,14 @@ static inline void clear_ipi(void)
clint_clear_ipi(cpuid_to_hartid_map(smp_processor_id())); clint_clear_ipi(cpuid_to_hartid_map(smp_processor_id()));
} }
void riscv_software_interrupt(void) void handle_IPI(struct pt_regs *regs)
{ {
struct pt_regs *old_regs = set_irq_regs(regs);
unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
unsigned long *stats = ipi_data[smp_processor_id()].stats; unsigned long *stats = ipi_data[smp_processor_id()].stats;
irq_enter();
clear_ipi(); clear_ipi();
while (true) { while (true) {
@ -138,7 +141,7 @@ void riscv_software_interrupt(void)
ops = xchg(pending_ipis, 0); ops = xchg(pending_ipis, 0);
if (ops == 0) if (ops == 0)
return; goto done;
if (ops & (1 << IPI_RESCHEDULE)) { if (ops & (1 << IPI_RESCHEDULE)) {
stats[IPI_RESCHEDULE]++; stats[IPI_RESCHEDULE]++;
@ -160,6 +163,10 @@ void riscv_software_interrupt(void)
/* Order data access and bit testing. */ /* Order data access and bit testing. */
mb(); mb();
} }
done:
irq_exit();
set_irq_regs(old_regs);
} }
static const char * const ipi_names[] = { static const char * const ipi_names[] = {