kernel/arch/arm/kernel/smp.c
默认的系统软中断:
enum ipi_msg_type {
IPI_WAKEUP,
IPI_TIMER,
IPI_RESCHEDULE,
IPI_CALL_FUNC,
IPI_CPU_STOP,
IPI_IRQ_WORK,
IPI_COMPLETION,
IPI_CPU_BACKTRACE,
/*
* SGI8-15 can be reserved by secure firmware, and thus may
* not be usable by the kernel. Please keep the above limited
* to at most 8 entries.
*/
};
asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
{
handle_IPI(ipinr, regs);
}
void handle_IPI(int ipinr, struct pt_regs *regs)
{
unsigned int cpu = smp_processor_id();
struct pt_regs *old_regs = set_irq_regs(regs);
if (ipi_types[ipinr].handler) {
printk("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
__inc_irq_stat(cpu, ipi_irqs[ipinr]);
irq_enter();
(*ipi_types[ipinr].handler)();
irq_exit();
} else
pr_debug("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
set_irq_regs(old_regs);
}
/*
* set_ipi_handler:
* Interface provided for a kernel module to specify an IPI handler function.
*/
int set_ipi_handler(int ipinr, void *handler, char *desc)
{
unsigned int cpu = smp_processor_id();
if (ipi_types[ipinr].handler) {
pr_crit("CPU%u: IPI handler 0x%x already registered to %pf\n",
cpu, ipinr, ipi_types[ipinr].handler);
return -1;
}
ipi_types[ipinr].handler = handler;
ipi_types[ipinr].desc = desc;
return 0;
}
EXPORT_SYMBOL(set_ipi_handler);
通过set_ipi_handler 函数注入软件中断回调函数到内部中断ipi_types 中断回调映射表中
int set_ipi_handler(int ipinr, void *handler, char *desc)
static struct ipi ipi_types[NR_IPI] = {
#define S(x, f) [x].desc = IPI_DESC_STR(x), [x].handler = f
S(IPI_WAKEUP, NULL),
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
S(IPI_TIMER, tick_receive_broadcast_local),
#endif
S(IPI_RESCHEDULE, scheduler_ipi),
S(IPI_CALL_FUNC, generic_smp_call_function_interrupt),
S(IPI_CPU_STOP, ipi_cpu_stop),
#ifdef CONFIG_IRQ_WORK
S(IPI_IRQ_WORK, irq_work_run),
#endif
S(IPI_COMPLETION, ipi_complete),
};
/kernel/drivers/remoteproc/zynq_remoteproc.c:
367 }
368
369: ret = set_ipi_handler(local->ipis[0].irq, ipi_kick,
370 "Firmware kick");
371 if (ret) {