summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Kossifidis <[email protected]>2019-02-17 09:00:20 +0200
committerAnup Patel <[email protected]>2019-02-18 09:21:58 +0530
commit918c1354b75c74b62f67c4e929551d643f035443 (patch)
treea4dae8b766d17ae3d3dc38564ac7d9dba18cdf20
parent51e543511a7425da1a5378e149de0b45928c7111 (diff)
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 <[email protected]>
-rw-r--r--lib/sbi_ipi.c47
1 files 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 <[email protected]>
+ * Nick Kossifidis <[email protected]
*/
#include <sbi/riscv_asm.h>
@@ -18,28 +19,48 @@
#include <sbi/sbi_timer.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,
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;
}