1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <libcflat.h> 3 #include <cpumask.h> 4 #include <limits.h> 5 #include <asm/sbi.h> 6 #include <asm/setup.h> 7 8 struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, 9 unsigned long arg1, unsigned long arg2, 10 unsigned long arg3, unsigned long arg4, 11 unsigned long arg5) 12 { 13 register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); 14 register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); 15 register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); 16 register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3); 17 register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4); 18 register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5); 19 register uintptr_t a6 asm ("a6") = (uintptr_t)(fid); 20 register uintptr_t a7 asm ("a7") = (uintptr_t)(ext); 21 struct sbiret ret; 22 23 asm volatile ( 24 "ecall" 25 : "+r" (a0), "+r" (a1) 26 : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7) 27 : "memory"); 28 ret.error = a0; 29 ret.value = a1; 30 31 return ret; 32 } 33 34 void sbi_shutdown(void) 35 { 36 sbi_ecall(SBI_EXT_SRST, 0, 0, 0, 0, 0, 0, 0); 37 puts("SBI shutdown failed!\n"); 38 } 39 40 struct sbiret sbi_hart_start(unsigned long hartid, unsigned long entry, unsigned long sp) 41 { 42 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, entry, sp, 0, 0, 0); 43 } 44 45 struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base) 46 { 47 return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0); 48 } 49 50 struct sbiret sbi_send_ipi_cpu(int cpu) 51 { 52 return sbi_send_ipi(1UL, cpus[cpu].hartid); 53 } 54 55 struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask) 56 { 57 struct sbiret ret; 58 cpumask_t tmp; 59 60 if (cpumask_full(mask)) 61 return sbi_send_ipi(0, -1UL); 62 63 cpumask_copy(&tmp, mask); 64 65 while (!cpumask_empty(&tmp)) { 66 unsigned long base = ULONG_MAX; 67 unsigned long mask = 0; 68 int cpu; 69 70 for_each_cpu(cpu, &tmp) { 71 if (base > cpus[cpu].hartid) 72 base = cpus[cpu].hartid; 73 } 74 75 for_each_cpu(cpu, &tmp) { 76 if (cpus[cpu].hartid < base + BITS_PER_LONG) { 77 mask |= 1UL << (cpus[cpu].hartid - base); 78 cpumask_clear_cpu(cpu, &tmp); 79 } 80 } 81 82 ret = sbi_send_ipi(mask, base); 83 if (ret.error) 84 break; 85 } 86 87 return ret; 88 } 89 90 struct sbiret sbi_set_timer(unsigned long stime_value) 91 { 92 return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0); 93 } 94 95 long sbi_probe(int ext) 96 { 97 struct sbiret ret; 98 99 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0); 100 assert(!ret.error && ret.value >= 2); 101 102 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0); 103 assert(!ret.error); 104 105 return ret.value; 106 } 107