RISC-V IPI Call: Code walkthrough
void smp_call_function_many(const struct cpumask *mask,
smp_call_func_t func, void *info, bool wait)
{
smp_call_function_many_cond(mask, func, info, wait * SCF_WAIT, NULL);
}
EXPORT_SYMBOL(smp_call_function_many);
void send_call_function_single_ipi(int cpu)
{
struct rq *rq = cpu_rq(cpu);
if (!set_nr_if_polling(rq->idle))
arch_send_call_function_single_ipi(cpu);
else
trace_sched_wake_idle_without_ipi(cpu);
}
arch/riscv/kernel/smp.c
void arch_send_call_function_single_ipi(int cpu)
{
send_ipi_single(cpu, IPI_CALL_FUNC);
}
static void send_ipi_single(int cpu, enum ipi_message_type op)
{
smp_mb__before_atomic();
set_bit(op, &ipi_data[cpu].bits);
smp_mb__after_atomic();
if (ipi_ops && ipi_ops->ipi_inject)
ipi_ops->ipi_inject(cpumask_of(cpu));
else
pr_warn("SMP: IPI inject method not available\n");
}
static const struct riscv_ipi_ops sbi_ipi_ops = {
.ipi_inject = sbi_send_cpumask_ipi
};
static void sbi_send_cpumask_ipi(const struct cpumask *target)
{
sbi_send_ipi(target);
}
int sbi_send_ipi(const struct cpumask *cpu_mask)
{
return __sbi_send_ipi(cpu_mask);
}
arch/riscv/kernel/sbi.c
void __init sbi_init(void)
{
...
if (!sbi_spec_is_0_1()) {
pr_info("SBI implementation ID=0x%lx Version=0x%lx\n",
sbi_get_firmware_id(), sbi_get_firmware_version());
if (sbi_probe_extension(SBI_EXT_TIME)) {
__sbi_set_timer = __sbi_set_timer_v02;
pr_info("SBI TIME extension detected\n");
} else {
__sbi_set_timer = __sbi_set_timer_v01;
}
if (sbi_probe_extension(SBI_EXT_IPI)) {
__sbi_send_ipi = __sbi_send_ipi_v02;
pr_info("SBI IPI extension detected\n");
} else {
__sbi_send_ipi = __sbi_send_ipi_v01;
}
arch/riscv/kernel/sbi.c
static int __sbi_send_ipi_v01(const struct cpumask *cpu_mask)
{
pr_warn("IPI extension is not available in SBI v%lu.%lu\n",
sbi_major_version(), sbi_minor_version());
return 0;
}
static int __sbi_send_ipi_v02(const struct cpumask *cpu_mask)
{
...
if (hmask) {
ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
hmask, hbase, 0, 0, 0, 0);
if (ret.error)
goto ecall_failed;
}
return 0;
ecall_failed:
result = sbi_err_map_linux_errno(ret.error);
pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n",
__func__, hbase, hmask, result);
return result;
}
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
unsigned long arg5)
{
struct sbiret ret;
register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
asm volatile ("ecall"
: "+r" (a0), "+r" (a1)
: "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
: "memory");
ret.error = a0;
ret.value = a1;
return ret;
}
EXPORT_SYMBOL(sbi_ecall);
ffffffff80006a20 <sbi_ecall>:
ffffffff80006a20: 1101 add sp,sp,-32
ffffffff80006a22: ec22 sd s0,24(sp)
ffffffff80006a24: 832a mv t1,a0
ffffffff80006a26: 1000 add s0,sp,32
ffffffff80006a28: 8e2e mv t3,a1
ffffffff80006a2a: 8532 mv a0,a2
ffffffff80006a2c: 85b6 mv a1,a3
ffffffff80006a2e: 863a mv a2,a4
ffffffff80006a30: 86be mv a3,a5
ffffffff80006a32: 8742 mv a4,a6
ffffffff80006a34: 87c6 mv a5,a7
ffffffff80006a36: 8872 mv a6,t3
ffffffff80006a38: 889a mv a7,t1
ffffffff80006a3a: 00000073 ecall
ffffffff80006a3e: 6462 ld s0,24(sp)
ffffffff80006a40: 6105 add sp,sp,32
ffffffff80006a42: 8082 ret
'RISC-V' 카테고리의 다른 글
Useful material for RISC-V (0) | 2024.05.28 |
---|---|
[RISC-V] system call return (s mode -> u mode) (0) | 2024.02.29 |
[RISC-V]: Interrupt handling - code walkthrough (0) | 2024.01.29 |
[RISC-V]: Interrupt handling workflow in Linux kernel (0) | 2024.01.29 |