lib: Fix ipi type update

IPIs are updated in scratch space by source hart.
However, different harts or same hart may want to
send different IPIs before previous IPI was read
by the target hart. Currently, previous IPI type
is overwritten in that case.

Use atomic bit set/clear operations to update IPIs.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
This commit is contained in:
Atish Patra
2019-01-20 23:24:26 -08:00
committed by Anup Patel
parent 312b6bf32f
commit b9c517f559

View File

@@ -9,7 +9,10 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_atomic.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_timer.h>
@@ -30,7 +33,7 @@ int sbi_ipi_send_many(struct sbi_scratch *scratch,
for (i = 0, m = mask; m; i++, m >>= 1) {
if ((m & 1) && (i != hartid) && !sbi_platform_hart_disabled(plat, hartid)) {
oth = sbi_hart_id_to_scratch(scratch, i);
oth->ipi_type = event;
atomic_raw_set_bit(event, &oth->ipi_type);
mb();
sbi_platform_ipi_inject(plat, i, hartid);
if (event != SBI_IPI_EVENT_SOFT)
@@ -49,9 +52,16 @@ void sbi_ipi_clear_smode(struct sbi_scratch *scratch, u32 hartid)
void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid)
{
struct sbi_platform *plat = sbi_platform_ptr(scratch);
volatile unsigned long ipi_type;
unsigned int ipi_event;
sbi_platform_ipi_clear(plat, hartid);
switch (scratch->ipi_type) {
do {
ipi_type = scratch->ipi_type;
rmb();
ipi_event = __ffs(ipi_type);
switch (ipi_event) {
case SBI_IPI_EVENT_SOFT:
csr_set(mip, MIP_SSIP);
break;
@@ -65,7 +75,8 @@ void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
break;
};
scratch->ipi_type = 0;
ipi_type = atomic_raw_clear_bit(ipi_event, &scratch->ipi_type);
} while(ipi_type > 0);
}
int sbi_ipi_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)