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_hart_stop(void) 46 { 47 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0); 48 } 49 50 struct sbiret sbi_hart_get_status(unsigned long hartid) 51 { 52 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS, hartid, 0, 0, 0, 0, 0); 53 } 54 55 struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base) 56 { 57 return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0); 58 } 59 60 struct sbiret sbi_send_ipi_cpu(int cpu) 61 { 62 return sbi_send_ipi(1UL, cpus[cpu].hartid); 63 } 64 65 struct sbiret sbi_send_ipi_broadcast(void) 66 { 67 return sbi_send_ipi(0, -1UL); 68 } 69 70 struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask) 71 { 72 struct sbiret ret; 73 cpumask_t tmp; 74 75 if (cpumask_full(mask)) 76 return sbi_send_ipi_broadcast(); 77 78 cpumask_copy(&tmp, mask); 79 80 while (!cpumask_empty(&tmp)) { 81 unsigned long base = ULONG_MAX; 82 unsigned long mask = 0; 83 int cpu; 84 85 for_each_cpu(cpu, &tmp) { 86 if (base > cpus[cpu].hartid) 87 base = cpus[cpu].hartid; 88 } 89 90 for_each_cpu(cpu, &tmp) { 91 if (cpus[cpu].hartid < base + BITS_PER_LONG) { 92 mask |= 1UL << (cpus[cpu].hartid - base); 93 cpumask_clear_cpu(cpu, &tmp); 94 } 95 } 96 97 ret = sbi_send_ipi(mask, base); 98 if (ret.error) 99 break; 100 } 101 102 return ret; 103 } 104 105 struct sbiret sbi_set_timer(unsigned long stime_value) 106 { 107 return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0); 108 } 109 110 struct sbiret sbi_get_spec_version(void) 111 { 112 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0); 113 } 114 115 long sbi_probe(int ext) 116 { 117 struct sbiret ret; 118 119 ret = sbi_get_spec_version(); 120 assert(!ret.error && (ret.value & SBI_SPEC_VERSION_MASK) >= sbi_mk_version(0, 2)); 121 122 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0); 123 assert(!ret.error); 124 125 return ret.value; 126 } 127