smp.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 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> 9 10 // made up value to sync hart state 11 #define HART_SLEEPING 0x1 12 #define HART_AWAKE 0x2 13 14 void smp_pause(int working_hartid) 15 { 16 int hartid = read_csr(mhartid); 17 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. 25 26 // pause hart 27 do { 28 __asm__ volatile ("wfi"); // wait for interrupt 29 } while ((read_csr(mip) & MIP_MSIP) == 0); 30 31 atomic_set(&HLS()->entry.sync_a, HART_AWAKE); // mark the hart as awake 32 HLS()->entry.fn(HLS()->entry.arg); 33 } 34 } 35 36 // must only be called by the WORKING_HARTID 37 void smp_resume(void (*fn)(void *), void *arg) 38 { 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 42 } 43 44 int working_hartid = read_csr(mhartid); 45 46 int hart_count = CONFIG_MAX_CPUS; 47 if (CONFIG(RISCV_GET_HART_COUNT_AT_RUNTIME)) 48 hart_count = smp_get_hart_count(); 49 50 // check that all harts are present 51 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; 57 58 if (atomic_read(&OTHER_HLS(i)->entry.sync_a) != HART_SLEEPING) { 59 /* 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 ... 63 */ 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. 68 69 OTHER_HLS(i)->entry.fn = fn; 70 OTHER_HLS(i)->entry.arg = arg; 71 barrier(); 72 set_msip(i, 1); // wake up hart 73 } 74 } 75 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; 82 83 // wait for hart to publish its waking state 84 while (atomic_read(&OTHER_HLS(i)->entry.sync_a) != HART_AWAKE) 85 ; 86 count_awake_harts++; 87 } 88 printk(BIOS_DEBUG, "all harts up and running...\n"); 89 90 if ((hart_count - 1) != count_awake_harts) { // exclude working hart 91 /* 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. 95 */ 96 printk(BIOS_ERR, "some harts were too slow and could not resume\n"); 97 } 98 fn(arg); // jump to fn with working hart 99 }