From 918c1354b75c74b62f67c4e929551d643f035443 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 17 Feb 2019 09:00:20 +0200 Subject: [PATCH] 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 --- lib/sbi_ipi.c | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/lib/sbi_ipi.c b/lib/sbi_ipi.c index 0e9fb30a..aeca71c5 100644 --- a/lib/sbi_ipi.c +++ b/lib/sbi_ipi.c @@ -5,6 +5,7 @@ * * Authors: * Anup Patel + * Nick Kossifidis @@ -18,28 +19,48 @@ #include #include +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, ulong *pmask, u32 event) { ulong i, m; - struct sbi_scratch *oth; ulong mask = sbi_hart_available_mask(); - struct sbi_platform *plat = sbi_platform_ptr(scratch); + u32 hartid = sbi_current_hartid(); if (pmask) mask &= load_ulong(pmask, csr_read(CSR_MEPC)); - /* send IPIs to everyone */ - for (i = 0, m = mask; m; i++, m >>= 1) { - if ((m & 1) && !sbi_platform_hart_disabled(plat, i)) { - oth = sbi_hart_id_to_scratch(scratch, i); - atomic_raw_set_bit(event, &oth->ipi_type); - mb(); - sbi_platform_ipi_send(plat, i); - if (event != SBI_IPI_EVENT_SOFT) - sbi_platform_ipi_sync(plat, i); - } - } + /* send IPIs to every other hart on the set */ + for (i = 0, m = mask; m > 0; m >>= ++i) + if ((m & 1UL) && (i != hartid)) + sbi_ipi_send(scratch, i, event); + + /* If the current hart is on the set, send an IPI + * to it as well + */ + if (mask & (1UL << hartid)) + sbi_ipi_send(scratch, hartid, event); + return 0; }