mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 23:41:23 +01:00
lib: Improve delivery of SBI_IPI_EVENT_HALT
When sbi_ipi_send_many gets called with the current hartid included on pmask (or when pmask is NULL), and we send a HALT event, since the for loop works sequentially over all hartids on the mask, we may send a HALT event to the current hart before the loop finishes. So we will halt the current hart before it can deliver a HALT IPI to the rest and some harts will remain active. Make sure we send an IPI to the current hart after we've finished with everybody else. Signed-off-by: Nick Kossifidis <mick@ics.forth.gr>
This commit is contained in:

committed by
Anup Patel

parent
51e543511a
commit
918c1354b7
@@ -5,6 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Anup Patel <anup.patel@wdc.com>
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
* Nick Kossifidis <mick@ics.forth.gr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
@@ -18,28 +19,48 @@
|
|||||||
#include <sbi/sbi_timer.h>
|
#include <sbi/sbi_timer.h>
|
||||||
#include <sbi/sbi_unpriv.h>
|
#include <sbi/sbi_unpriv.h>
|
||||||
|
|
||||||
|
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *remote_scratch = NULL;
|
||||||
|
struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
|
||||||
|
if (sbi_platform_hart_disabled(plat, hartid))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Set IPI type on remote hart's scratch area and
|
||||||
|
* trigger the interrupt
|
||||||
|
*/
|
||||||
|
remote_scratch = sbi_hart_id_to_scratch(scratch, hartid);
|
||||||
|
atomic_raw_set_bit(event, &remote_scratch->ipi_type);
|
||||||
|
mb();
|
||||||
|
sbi_platform_ipi_send(plat, hartid);
|
||||||
|
if (event != SBI_IPI_EVENT_SOFT)
|
||||||
|
sbi_platform_ipi_sync(plat, hartid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_ipi_send_many(struct sbi_scratch *scratch,
|
int sbi_ipi_send_many(struct sbi_scratch *scratch,
|
||||||
ulong *pmask, u32 event)
|
ulong *pmask, u32 event)
|
||||||
{
|
{
|
||||||
ulong i, m;
|
ulong i, m;
|
||||||
struct sbi_scratch *oth;
|
|
||||||
ulong mask = sbi_hart_available_mask();
|
ulong mask = sbi_hart_available_mask();
|
||||||
struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
u32 hartid = sbi_current_hartid();
|
||||||
|
|
||||||
if (pmask)
|
if (pmask)
|
||||||
mask &= load_ulong(pmask, csr_read(CSR_MEPC));
|
mask &= load_ulong(pmask, csr_read(CSR_MEPC));
|
||||||
|
|
||||||
/* send IPIs to everyone */
|
/* send IPIs to every other hart on the set */
|
||||||
for (i = 0, m = mask; m; i++, m >>= 1) {
|
for (i = 0, m = mask; m > 0; m >>= ++i)
|
||||||
if ((m & 1) && !sbi_platform_hart_disabled(plat, i)) {
|
if ((m & 1UL) && (i != hartid))
|
||||||
oth = sbi_hart_id_to_scratch(scratch, i);
|
sbi_ipi_send(scratch, i, event);
|
||||||
atomic_raw_set_bit(event, &oth->ipi_type);
|
|
||||||
mb();
|
/* If the current hart is on the set, send an IPI
|
||||||
sbi_platform_ipi_send(plat, i);
|
* to it as well
|
||||||
if (event != SBI_IPI_EVENT_SOFT)
|
*/
|
||||||
sbi_platform_ipi_sync(plat, i);
|
if (mask & (1UL << hartid))
|
||||||
}
|
sbi_ipi_send(scratch, hartid, event);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user