This patch fixes the IPI(inner processor interrupt) missing issue. It
failed because it used hartid_mask to iterate for_each_cpu(), however the
cpu_mask and hartid_mask may not be always the same. It will never send the
IPI to hartid 4 because it will be skipped in for_each_cpu loop in my case.
We can reproduce this case in Qemu sifive_u machine by this command.
qemu-system-riscv64 -nographic -smp 5 -m 1G -M sifive_u -kernel \
arch/riscv/boot/loader
It will hang in csd_lock_wait(csd) because the csd_unlock(csd) is not
called. It is not called because hartid 4 doesn't receive the IPI to
release this lock. The caller hart doesn't send the IPI to hartid 4 is
because of hartid 4 is skipped in for_each_cpu(). It will be skipped is
because "(cpu) < nr_cpu_ids" is not true. The hartid is 4 and nr_cpu_ids
is 4. Therefore it should use cpumask in for_each_cpu() instead of
hartid_mask.
/* Send a message to all CPUs in the map */
arch_send_call_function_ipi_mask(cfd->cpumask_ipi);
if (wait) {
for_each_cpu(cpu, cfd->cpumask) {
call_single_data_t *csd;
csd = per_cpu_ptr(cfd->csd, cpu);
csd_lock_wait(csd);
}
}
for ((cpu) = -1; \
(cpu) = cpumask_next((cpu), (mask)), \
(cpu) < nr_cpu_ids;)
It could boot to login console after this patch applied.
Fixes: b2d36b5668f6 ("riscv: provide native clint access for M-mode")
Signed-off-by: Greentime Hu <greentime.hu@sifive.com>
Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
40 lines
983 B
C
40 lines
983 B
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_RISCV_CLINT_H
|
|
#define _ASM_RISCV_CLINT_H 1
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/smp.h>
|
|
|
|
#ifdef CONFIG_RISCV_M_MODE
|
|
extern u32 __iomem *clint_ipi_base;
|
|
|
|
void clint_init_boot_cpu(void);
|
|
|
|
static inline void clint_send_ipi_single(unsigned long hartid)
|
|
{
|
|
writel(1, clint_ipi_base + hartid);
|
|
}
|
|
|
|
static inline void clint_send_ipi_mask(const struct cpumask *mask)
|
|
{
|
|
int cpu;
|
|
|
|
for_each_cpu(cpu, mask)
|
|
clint_send_ipi_single(cpuid_to_hartid_map(cpu));
|
|
}
|
|
|
|
static inline void clint_clear_ipi(unsigned long hartid)
|
|
{
|
|
writel(0, clint_ipi_base + hartid);
|
|
}
|
|
#else /* CONFIG_RISCV_M_MODE */
|
|
#define clint_init_boot_cpu() do { } while (0)
|
|
|
|
/* stubs to for code is only reachable under IS_ENABLED(CONFIG_RISCV_M_MODE): */
|
|
void clint_send_ipi_single(unsigned long hartid);
|
|
void clint_send_ipi_mask(const struct cpumask *hartid_mask);
|
|
void clint_clear_ipi(unsigned long hartid);
|
|
#endif /* CONFIG_RISCV_M_MODE */
|
|
|
|
#endif /* _ASM_RISCV_CLINT_H */
|