forked from Mirrors/opensbi
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:
@@ -9,7 +9,10 @@
|
|||||||
|
|
||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
#include <sbi/riscv_barrier.h>
|
#include <sbi/riscv_barrier.h>
|
||||||
|
#include <sbi/riscv_atomic.h>
|
||||||
#include <sbi/sbi_hart.h>
|
#include <sbi/sbi_hart.h>
|
||||||
|
#include <sbi/sbi_bitops.h>
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
#include <sbi/sbi_ipi.h>
|
#include <sbi/sbi_ipi.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_timer.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) {
|
for (i = 0, m = mask; m; i++, m >>= 1) {
|
||||||
if ((m & 1) && (i != hartid) && !sbi_platform_hart_disabled(plat, hartid)) {
|
if ((m & 1) && (i != hartid) && !sbi_platform_hart_disabled(plat, hartid)) {
|
||||||
oth = sbi_hart_id_to_scratch(scratch, i);
|
oth = sbi_hart_id_to_scratch(scratch, i);
|
||||||
oth->ipi_type = event;
|
atomic_raw_set_bit(event, &oth->ipi_type);
|
||||||
mb();
|
mb();
|
||||||
sbi_platform_ipi_inject(plat, i, hartid);
|
sbi_platform_ipi_inject(plat, i, hartid);
|
||||||
if (event != SBI_IPI_EVENT_SOFT)
|
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)
|
void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid)
|
||||||
{
|
{
|
||||||
struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
volatile unsigned long ipi_type;
|
||||||
|
unsigned int ipi_event;
|
||||||
|
|
||||||
sbi_platform_ipi_clear(plat, hartid);
|
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:
|
case SBI_IPI_EVENT_SOFT:
|
||||||
csr_set(mip, MIP_SSIP);
|
csr_set(mip, MIP_SSIP);
|
||||||
break;
|
break;
|
||||||
@@ -65,7 +75,8 @@ void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
sbi_hart_hang();
|
sbi_hart_hang();
|
||||||
break;
|
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)
|
int sbi_ipi_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||||
|
Reference in New Issue
Block a user