cbfs: Remove remnants of ext-win-*
[coreboot2.git] / src / arch / riscv / smp.c
blob67dc13b8fcaf0cda66e56caa40cc2432b1a7d599
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/barrier.h>
4 #include <arch/encoding.h>
5 #include <arch/smp/smp.h>
6 #include <arch/smp/atomic.h>
7 #include <console/console.h>
8 #include <mcall.h>
10 // made up value to sync hart state
11 #define HART_SLEEPING 0x1
12 #define HART_AWAKE 0x2
14 void smp_pause(int working_hartid)
16 int hartid = read_csr(mhartid);
18 // pause all harts which are not the working hart
19 if (hartid != working_hartid) {
20 clear_csr(mstatus, MSTATUS_MIE); // disable all interrupts
21 set_msip(hartid, 0); // clear pending interrupts
22 write_csr(mie, MIP_MSIP); // enable only IPI (for smp_resume)
23 barrier();
24 atomic_set(&HLS()->entry.sync_a, HART_SLEEPING); // mark the hart as sleeping.
26 // pause hart
27 do {
28 __asm__ volatile ("wfi"); // wait for interrupt
29 } while ((read_csr(mip) & MIP_MSIP) == 0);
31 atomic_set(&HLS()->entry.sync_a, HART_AWAKE); // mark the hart as awake
32 HLS()->entry.fn(HLS()->entry.arg);
36 // must only be called by the WORKING_HARTID
37 void smp_resume(void (*fn)(void *), void *arg)
39 if (fn == NULL) {
40 printk(BIOS_ERR, "must pass a non-null function pointer\n");
41 return; // we can still boot with one hart
44 int working_hartid = read_csr(mhartid);
46 int hart_count = CONFIG_MAX_CPUS;
47 if (CONFIG(RISCV_GET_HART_COUNT_AT_RUNTIME))
48 hart_count = smp_get_hart_count();
50 // check that all harts are present
52 u32 count_awake_harts = 0;
53 for (int i = 0; i < hart_count; i++) {
54 // The working hart never sleeps. It is a hard working hart.
55 if (i == working_hartid)
56 continue;
58 if (atomic_read(&OTHER_HLS(i)->entry.sync_a) != HART_SLEEPING) {
60 * we assmue here that the time between smp_pause and smp_resume
61 * is enough for all harts to reach the smp_pause state.
62 * But for some reason that was not the case for this hart ...
64 printk(BIOS_ERR, "hart %d did not enter smp_pause\n", i);
65 OTHER_HLS(i)->enabled = 0; // disable hart
66 } else {
67 // hart is in wfi (wait for interrupt) state like it should be.
69 OTHER_HLS(i)->entry.fn = fn;
70 OTHER_HLS(i)->entry.arg = arg;
71 barrier();
72 set_msip(i, 1); // wake up hart
76 printk(BIOS_DEBUG, "waiting for all harts to wake up...\n");
77 // confirm that all harts are wake
78 for (int i = 0; i < hart_count; i++) {
79 // The working hart never sleeps. It is a hard working hart.
80 if (i == working_hartid || !OTHER_HLS(i)->enabled)
81 continue;
83 // wait for hart to publish its waking state
84 while (atomic_read(&OTHER_HLS(i)->entry.sync_a) != HART_AWAKE)
86 count_awake_harts++;
88 printk(BIOS_DEBUG, "all harts up and running...\n");
90 if ((hart_count - 1) != count_awake_harts) { // exclude working hart
92 * Apparently one or more harts did not reach smp_pause before smp_resume has
93 * been called by the working hart. That should not happen and may indicate we
94 * need a timeout of sorts to make sure we get all harts resumed.
96 printk(BIOS_ERR, "some harts were too slow and could not resume\n");
98 fn(arg); // jump to fn with working hart