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 struct sbiret sbi_fwft_set_raw(unsigned long feature, unsigned long value, unsigned long flags) 111 { 112 return sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_SET, feature, value, flags, 0, 0, 0); 113 } 114 115 struct sbiret sbi_fwft_set(uint32_t feature, unsigned long value, unsigned long flags) 116 { 117 return sbi_fwft_set_raw(feature, value, flags); 118 } 119 120 struct sbiret sbi_fwft_get_raw(unsigned long feature) 121 { 122 return sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_GET, feature, 0, 0, 0, 0, 0); 123 } 124 125 struct sbiret sbi_fwft_get(uint32_t feature) 126 { 127 return sbi_fwft_get_raw(feature); 128 } 129 130 void sbi_shutdown(bool passed) 131 { 132 sbi_ecall(SBI_EXT_SRST, 0, 0, !passed, 0, 0, 0, 0); 133 puts("SBI shutdown failed!\n"); 134 } 135 136 struct sbiret sbi_hart_start(unsigned long hartid, unsigned long entry, unsigned long sp) 137 { 138 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, entry, sp, 0, 0, 0); 139 } 140 141 struct sbiret sbi_hart_stop(void) 142 { 143 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0); 144 } 145 146 struct sbiret sbi_hart_get_status(unsigned long hartid) 147 { 148 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS, hartid, 0, 0, 0, 0, 0); 149 } 150 151 struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base) 152 { 153 return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0); 154 } 155 156 struct sbiret sbi_send_ipi_cpu(int cpu) 157 { 158 return sbi_send_ipi(1UL, cpus[cpu].hartid); 159 } 160 161 struct sbiret sbi_send_ipi_broadcast(void) 162 { 163 return sbi_send_ipi(0, -1UL); 164 } 165 166 struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask) 167 { 168 struct sbiret ret; 169 cpumask_t tmp; 170 171 if (cpumask_full(mask)) 172 return sbi_send_ipi_broadcast(); 173 174 cpumask_copy(&tmp, mask); 175 176 while (!cpumask_empty(&tmp)) { 177 unsigned long base = ULONG_MAX; 178 unsigned long mask = 0; 179 int cpu; 180 181 for_each_cpu(cpu, &tmp) { 182 if (base > cpus[cpu].hartid) 183 base = cpus[cpu].hartid; 184 } 185 186 for_each_cpu(cpu, &tmp) { 187 if (cpus[cpu].hartid < base + BITS_PER_LONG) { 188 mask |= 1UL << (cpus[cpu].hartid - base); 189 cpumask_clear_cpu(cpu, &tmp); 190 } 191 } 192 193 ret = sbi_send_ipi(mask, base); 194 if (ret.error) 195 break; 196 } 197 198 return ret; 199 } 200 201 struct sbiret sbi_set_timer(unsigned long stime_value) 202 { 203 return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0); 204 } 205 206 struct sbiret sbi_get_imp_version(void) 207 { 208 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_VERSION, 0, 0, 0, 0, 0, 0); 209 } 210 211 struct sbiret sbi_get_imp_id(void) 212 { 213 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_ID, 0, 0, 0, 0, 0, 0); 214 } 215 216 unsigned long __sbi_get_imp_version(void) 217 { 218 struct sbiret ret; 219 220 ret = sbi_get_imp_version(); 221 assert(!ret.error); 222 223 return ret.value; 224 } 225 226 unsigned long __sbi_get_imp_id(void) 227 { 228 struct sbiret ret; 229 230 ret = sbi_get_imp_id(); 231 assert(!ret.error); 232 233 return ret.value; 234 } 235 236 struct sbiret sbi_get_spec_version(void) 237 { 238 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0); 239 } 240 241 long sbi_probe(int ext) 242 { 243 struct sbiret ret; 244 245 ret = sbi_get_spec_version(); 246 assert(!ret.error && (ret.value & SBI_SPEC_VERSION_MASK) >= sbi_mk_version(0, 2)); 247 248 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0); 249 assert(!ret.error); 250 251 return ret.value; 252 } 253