Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | // SPDX-License-Identifier: GPL-2.0-only /* * SBI initialilization and all extension implementation. * * Copyright (c) 2020 Western Digital Corporation or its affiliates. * * Taken from Linux arch/riscv/kernel/sbi.c */ #include <errno.h> #include <asm/encoding.h> #include <asm/sbi.h> struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { struct sbiret ret; register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3); register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4); register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5); register uintptr_t a6 asm ("a6") = (uintptr_t)(fid); register uintptr_t a7 asm ("a7") = (uintptr_t)(ext); asm volatile ("ecall" : "+r" (a0), "+r" (a1) : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7) : "memory"); ret.error = a0; ret.value = a1; return ret; } /** * sbi_set_timer() - Program the timer for next timer event. * @stime_value: The value after which next timer event should fire. * * Return: None */ void sbi_set_timer(uint64_t stime_value) { #if __riscv_xlen == 32 sbi_ecall(SBI_EXT_SET_TIMER, SBI_FID_SET_TIMER, stime_value, stime_value >> 32, 0, 0, 0, 0); #else sbi_ecall(SBI_EXT_SET_TIMER, SBI_FID_SET_TIMER, stime_value, 0, 0, 0, 0, 0); #endif } /** * sbi_get_spec_version() - get current SBI specification version * * Return: version id */ long sbi_get_spec_version(void) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0); if (!ret.error) if (ret.value) return ret.value; return -ENOTSUPP; } /** * sbi_get_impl_id() - get SBI implementation ID * * Return: implementation ID */ int sbi_get_impl_id(void) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_ID, 0, 0, 0, 0, 0, 0); if (!ret.error) if (ret.value) return ret.value; return -ENOTSUPP; } /** * sbi_get_impl_version() - get SBI implementation version * * @version: pointer to receive version * Return: 0 on success, -ENOTSUPP otherwise */ int sbi_get_impl_version(long *version) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_VERSION, 0, 0, 0, 0, 0, 0); if (ret.error) return -ENOTSUPP; if (version) *version = ret.value; return 0; } /** * sbi_probe_extension() - Check if an SBI extension ID is supported or not. * @extid: The extension ID to be probed. * * Return: Extension specific nonzero value f yes, -ENOTSUPP otherwise. */ int sbi_probe_extension(int extid) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid, 0, 0, 0, 0, 0); if (!ret.error) if (ret.value) return ret.value; return -ENOTSUPP; } /** * sbi_get_mvendorid() - get machine vendor ID * * @mimpid: on return machine vendor ID * Return: 0 on success */ int sbi_get_mvendorid(long *mvendorid) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_MVENDORID, 0, 0, 0, 0, 0, 0); if (ret.error) return -ENOTSUPP; if (mvendorid) *mvendorid = ret.value; return 0; } /** * sbi_get_marchid() - get machine architecture ID * * @mimpid: on return machine architecture ID * Return: 0 on success */ int sbi_get_marchid(long *marchid) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_MARCHID, 0, 0, 0, 0, 0, 0); if (ret.error) return -ENOTSUPP; if (marchid) *marchid = ret.value; return 0; } /** * sbi_get_mimpid() - get machine implementation ID * * @mimpid: on return machine implementation ID * Return: 0 on success */ int sbi_get_mimpid(long *mimpid) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_MIMPID, 0, 0, 0, 0, 0, 0); if (ret.error) return -ENOTSUPP; if (mimpid) *mimpid = ret.value; return 0; } /** * sbi_srst_reset() - invoke system reset extension * * @type: type of reset * @reason: reason for reset */ void sbi_srst_reset(unsigned long type, unsigned long reason) { sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason, 0, 0, 0, 0); } /** * sbi_dbcn_write_byte() - write byte to debug console * * @ch: byte to be written * Return: SBI error code (SBI_SUCCESS = 0 on success) */ int sbi_dbcn_write_byte(unsigned char ch) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE_BYTE, ch, 0, 0, 0, 0, 0); return ret.error; } #ifdef CONFIG_SBI_V01 /** * sbi_console_putchar() - Writes given character to the console device. * @ch: The data to be written to the console. * * Return: None */ void sbi_console_putchar(int ch) { sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0); } /** * sbi_console_getchar() - Reads a byte from console device. * * Returns the value read from console. */ int sbi_console_getchar(void) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_0_1_CONSOLE_GETCHAR, 0, 0, 0, 0, 0, 0, 0); return ret.error; } /** * sbi_clear_ipi() - Clear any pending IPIs for the calling hart. * * Return: None */ void sbi_clear_ipi(void) { sbi_ecall(SBI_EXT_0_1_CLEAR_IPI, 0, 0, 0, 0, 0, 0, 0); } /** * sbi_shutdown() - Remove all the harts from executing supervisor code. * * Return: None */ void sbi_shutdown(void) { sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0); } /** * sbi_send_ipi() - Send an IPI to any hart. * @hart_mask: A cpu mask containing all the target harts. * * Return: None */ void sbi_send_ipi(const unsigned long *hart_mask) { sbi_ecall(SBI_EXT_SEND_IPI, SBI_FID_SEND_IPI, (unsigned long)hart_mask, 0, 0, 0, 0, 0); } /** * sbi_remote_fence_i() - Execute FENCE.I instruction on given remote harts. * @hart_mask: A cpu mask containing all the target harts. * * Return: None */ void sbi_remote_fence_i(const unsigned long *hart_mask) { sbi_ecall(SBI_EXT_REMOTE_FENCE_I, SBI_FID_REMOTE_FENCE_I, (unsigned long)hart_mask, 0, 0, 0, 0, 0); } /** * sbi_remote_sfence_vma() - Execute SFENCE.VMA instructions on given remote * harts for the specified virtual address range. * @hart_mask: A cpu mask containing all the target harts. * @start: Start of the virtual address * @size: Total size of the virtual address range. * * Return: None */ void sbi_remote_sfence_vma(const unsigned long *hart_mask, unsigned long start, unsigned long size) { sbi_ecall(SBI_EXT_REMOTE_SFENCE_VMA, SBI_FID_REMOTE_SFENCE_VMA, (unsigned long)hart_mask, start, size, 0, 0, 0); } /** * sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given * remote harts for a virtual address range belonging to a specific ASID. * * @hart_mask: A cpu mask containing all the target harts. * @start: Start of the virtual address * @size: Total size of the virtual address range. * @asid: The value of address space identifier (ASID). * * Return: None */ void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, unsigned long start, unsigned long size, unsigned long asid) { sbi_ecall(SBI_EXT_REMOTE_SFENCE_VMA_ASID, SBI_FID_REMOTE_SFENCE_VMA_ASID, (unsigned long)hart_mask, start, size, asid, 0, 0); } #endif /* CONFIG_SBI_V01 */ |