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_cpumask(const cpumask_t *mask) 66 { 67 struct sbiret ret; 68 cpumask_t tmp; 69 70 if (cpumask_full(mask)) 71 return sbi_send_ipi(0, -1UL); 72 73 cpumask_copy(&tmp, mask); 74 75 while (!cpumask_empty(&tmp)) { 76 unsigned long base = ULONG_MAX; 77 unsigned long mask = 0; 78 int cpu; 79 80 for_each_cpu(cpu, &tmp) { 81 if (base > cpus[cpu].hartid) 82 base = cpus[cpu].hartid; 83 } 84 85 for_each_cpu(cpu, &tmp) { 86 if (cpus[cpu].hartid < base + BITS_PER_LONG) { 87 mask |= 1UL << (cpus[cpu].hartid - base); 88 cpumask_clear_cpu(cpu, &tmp); 89 } 90 } 91 92 ret = sbi_send_ipi(mask, base); 93 if (ret.error) 94 break; 95 } 96 97 return ret; 98 } 99 100 struct sbiret sbi_set_timer(unsigned long stime_value) 101 { 102 return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0); 103 } 104 105 long sbi_probe(int ext) 106 { 107 struct sbiret ret; 108 109 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0); 110 assert(!ret.error && ret.value >= 2); 111 112 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0); 113 assert(!ret.error); 114 115 return ret.value; 116 } 117