1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <libcflat.h> 3 #include <cpumask.h> 4 #include <limits.h> 5 #include <asm/io.h> 6 #include <asm/sbi.h> 7 #include <asm/setup.h> 8 9 struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, 10 unsigned long arg1, unsigned long arg2, 11 unsigned long arg3, unsigned long arg4, 12 unsigned long arg5) 13 { 14 register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); 15 register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); 16 register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); 17 register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3); 18 register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4); 19 register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5); 20 register uintptr_t a6 asm ("a6") = (uintptr_t)(fid); 21 register uintptr_t a7 asm ("a7") = (uintptr_t)(ext); 22 struct sbiret ret; 23 24 asm volatile ( 25 "ecall" 26 : "+r" (a0), "+r" (a1) 27 : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7) 28 : "memory"); 29 ret.error = a0; 30 ret.value = a1; 31 32 return ret; 33 } 34 35 struct sbiret sbi_sse_read_attrs_raw(unsigned long event_id, unsigned long base_attr_id, 36 unsigned long attr_count, unsigned long phys_lo, 37 unsigned long phys_hi) 38 { 39 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_READ_ATTRS, event_id, base_attr_id, attr_count, 40 phys_lo, phys_hi, 0); 41 } 42 43 struct sbiret sbi_sse_read_attrs(unsigned long event_id, unsigned long base_attr_id, 44 unsigned long attr_count, unsigned long *values) 45 { 46 phys_addr_t p = virt_to_phys(values); 47 48 return sbi_sse_read_attrs_raw(event_id, base_attr_id, attr_count, lower_32_bits(p), 49 upper_32_bits(p)); 50 } 51 52 struct sbiret sbi_sse_write_attrs_raw(unsigned long event_id, unsigned long base_attr_id, 53 unsigned long attr_count, unsigned long phys_lo, 54 unsigned long phys_hi) 55 { 56 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_WRITE_ATTRS, event_id, base_attr_id, attr_count, 57 phys_lo, phys_hi, 0); 58 } 59 60 struct sbiret sbi_sse_write_attrs(unsigned long event_id, unsigned long base_attr_id, 61 unsigned long attr_count, unsigned long *values) 62 { 63 phys_addr_t p = virt_to_phys(values); 64 65 return sbi_sse_write_attrs_raw(event_id, base_attr_id, attr_count, lower_32_bits(p), 66 upper_32_bits(p)); 67 } 68 69 struct sbiret sbi_sse_register_raw(unsigned long event_id, unsigned long entry_pc, 70 unsigned long entry_arg) 71 { 72 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_REGISTER, event_id, entry_pc, entry_arg, 0, 0, 0); 73 } 74 75 struct sbiret sbi_sse_register(unsigned long event_id, struct sbi_sse_handler_arg *arg) 76 { 77 return sbi_sse_register_raw(event_id, (unsigned long)sbi_sse_entry, (unsigned long)arg); 78 } 79 80 struct sbiret sbi_sse_unregister(unsigned long event_id) 81 { 82 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_UNREGISTER, event_id, 0, 0, 0, 0, 0); 83 } 84 85 struct sbiret sbi_sse_enable(unsigned long event_id) 86 { 87 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_ENABLE, event_id, 0, 0, 0, 0, 0); 88 } 89 90 struct sbiret sbi_sse_disable(unsigned long event_id) 91 { 92 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_DISABLE, event_id, 0, 0, 0, 0, 0); 93 } 94 95 struct sbiret sbi_sse_hart_mask(void) 96 { 97 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_HART_MASK, 0, 0, 0, 0, 0, 0); 98 } 99 100 struct sbiret sbi_sse_hart_unmask(void) 101 { 102 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_HART_UNMASK, 0, 0, 0, 0, 0, 0); 103 } 104 105 struct sbiret sbi_sse_inject(unsigned long event_id, unsigned long hart_id) 106 { 107 return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_INJECT, event_id, hart_id, 0, 0, 0, 0); 108 } 109 110 void sbi_shutdown(void) 111 { 112 sbi_ecall(SBI_EXT_SRST, 0, 0, 0, 0, 0, 0, 0); 113 puts("SBI shutdown failed!\n"); 114 } 115 116 struct sbiret sbi_hart_start(unsigned long hartid, unsigned long entry, unsigned long sp) 117 { 118 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, entry, sp, 0, 0, 0); 119 } 120 121 struct sbiret sbi_hart_stop(void) 122 { 123 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0); 124 } 125 126 struct sbiret sbi_hart_get_status(unsigned long hartid) 127 { 128 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS, hartid, 0, 0, 0, 0, 0); 129 } 130 131 struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base) 132 { 133 return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0); 134 } 135 136 struct sbiret sbi_send_ipi_cpu(int cpu) 137 { 138 return sbi_send_ipi(1UL, cpus[cpu].hartid); 139 } 140 141 struct sbiret sbi_send_ipi_broadcast(void) 142 { 143 return sbi_send_ipi(0, -1UL); 144 } 145 146 struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask) 147 { 148 struct sbiret ret; 149 cpumask_t tmp; 150 151 if (cpumask_full(mask)) 152 return sbi_send_ipi_broadcast(); 153 154 cpumask_copy(&tmp, mask); 155 156 while (!cpumask_empty(&tmp)) { 157 unsigned long base = ULONG_MAX; 158 unsigned long mask = 0; 159 int cpu; 160 161 for_each_cpu(cpu, &tmp) { 162 if (base > cpus[cpu].hartid) 163 base = cpus[cpu].hartid; 164 } 165 166 for_each_cpu(cpu, &tmp) { 167 if (cpus[cpu].hartid < base + BITS_PER_LONG) { 168 mask |= 1UL << (cpus[cpu].hartid - base); 169 cpumask_clear_cpu(cpu, &tmp); 170 } 171 } 172 173 ret = sbi_send_ipi(mask, base); 174 if (ret.error) 175 break; 176 } 177 178 return ret; 179 } 180 181 struct sbiret sbi_set_timer(unsigned long stime_value) 182 { 183 return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0); 184 } 185 186 struct sbiret sbi_get_imp_version(void) 187 { 188 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_VERSION, 0, 0, 0, 0, 0, 0); 189 } 190 191 struct sbiret sbi_get_imp_id(void) 192 { 193 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_ID, 0, 0, 0, 0, 0, 0); 194 } 195 196 unsigned long __sbi_get_imp_version(void) 197 { 198 struct sbiret ret; 199 200 ret = sbi_get_imp_version(); 201 assert(!ret.error); 202 203 return ret.value; 204 } 205 206 unsigned long __sbi_get_imp_id(void) 207 { 208 struct sbiret ret; 209 210 ret = sbi_get_imp_id(); 211 assert(!ret.error); 212 213 return ret.value; 214 } 215 216 struct sbiret sbi_get_spec_version(void) 217 { 218 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0); 219 } 220 221 long sbi_probe(int ext) 222 { 223 struct sbiret ret; 224 225 ret = sbi_get_spec_version(); 226 assert(!ret.error && (ret.value & SBI_SPEC_VERSION_MASK) >= sbi_mk_version(0, 2)); 227 228 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0); 229 assert(!ret.error); 230 231 return ret.value; 232 } 233