19ccb00e4SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only 29ccb00e4SAndrew Jones #include <libcflat.h> 3*25475fa5SAndrew Jones #include <cpumask.h> 4*25475fa5SAndrew Jones #include <limits.h> 59ccb00e4SAndrew Jones #include <asm/sbi.h> 6*25475fa5SAndrew Jones #include <asm/setup.h> 79ccb00e4SAndrew Jones 89ccb00e4SAndrew Jones struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, 99ccb00e4SAndrew Jones unsigned long arg1, unsigned long arg2, 109ccb00e4SAndrew Jones unsigned long arg3, unsigned long arg4, 119ccb00e4SAndrew Jones unsigned long arg5) 129ccb00e4SAndrew Jones { 139ccb00e4SAndrew Jones register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); 149ccb00e4SAndrew Jones register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); 159ccb00e4SAndrew Jones register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); 169ccb00e4SAndrew Jones register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3); 179ccb00e4SAndrew Jones register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4); 189ccb00e4SAndrew Jones register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5); 199ccb00e4SAndrew Jones register uintptr_t a6 asm ("a6") = (uintptr_t)(fid); 209ccb00e4SAndrew Jones register uintptr_t a7 asm ("a7") = (uintptr_t)(ext); 219ccb00e4SAndrew Jones struct sbiret ret; 229ccb00e4SAndrew Jones 239ccb00e4SAndrew Jones asm volatile ( 249ccb00e4SAndrew Jones "ecall" 259ccb00e4SAndrew Jones : "+r" (a0), "+r" (a1) 269ccb00e4SAndrew Jones : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7) 279ccb00e4SAndrew Jones : "memory"); 289ccb00e4SAndrew Jones ret.error = a0; 299ccb00e4SAndrew Jones ret.value = a1; 309ccb00e4SAndrew Jones 319ccb00e4SAndrew Jones return ret; 329ccb00e4SAndrew Jones } 339ccb00e4SAndrew Jones 349ccb00e4SAndrew Jones void sbi_shutdown(void) 359ccb00e4SAndrew Jones { 369ccb00e4SAndrew Jones sbi_ecall(SBI_EXT_SRST, 0, 0, 0, 0, 0, 0, 0); 379ccb00e4SAndrew Jones puts("SBI shutdown failed!\n"); 389ccb00e4SAndrew Jones } 399c92b28eSAndrew Jones 409c92b28eSAndrew Jones struct sbiret sbi_hart_start(unsigned long hartid, unsigned long entry, unsigned long sp) 419c92b28eSAndrew Jones { 429c92b28eSAndrew Jones return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, entry, sp, 0, 0, 0); 439c92b28eSAndrew Jones } 447040d2a9SJames Raphael Tiovalen 456489b8b0SJames Raphael Tiovalen struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base) 466489b8b0SJames Raphael Tiovalen { 476489b8b0SJames Raphael Tiovalen return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0); 486489b8b0SJames Raphael Tiovalen } 496489b8b0SJames Raphael Tiovalen 50*25475fa5SAndrew Jones struct sbiret sbi_send_ipi_cpu(int cpu) 51*25475fa5SAndrew Jones { 52*25475fa5SAndrew Jones return sbi_send_ipi(1UL, cpus[cpu].hartid); 53*25475fa5SAndrew Jones } 54*25475fa5SAndrew Jones 55*25475fa5SAndrew Jones struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask) 56*25475fa5SAndrew Jones { 57*25475fa5SAndrew Jones struct sbiret ret; 58*25475fa5SAndrew Jones cpumask_t tmp; 59*25475fa5SAndrew Jones 60*25475fa5SAndrew Jones if (cpumask_full(mask)) 61*25475fa5SAndrew Jones return sbi_send_ipi(0, -1UL); 62*25475fa5SAndrew Jones 63*25475fa5SAndrew Jones cpumask_copy(&tmp, mask); 64*25475fa5SAndrew Jones 65*25475fa5SAndrew Jones while (!cpumask_empty(&tmp)) { 66*25475fa5SAndrew Jones unsigned long base = ULONG_MAX; 67*25475fa5SAndrew Jones unsigned long mask = 0; 68*25475fa5SAndrew Jones int cpu; 69*25475fa5SAndrew Jones 70*25475fa5SAndrew Jones for_each_cpu(cpu, &tmp) { 71*25475fa5SAndrew Jones if (base > cpus[cpu].hartid) 72*25475fa5SAndrew Jones base = cpus[cpu].hartid; 73*25475fa5SAndrew Jones } 74*25475fa5SAndrew Jones 75*25475fa5SAndrew Jones for_each_cpu(cpu, &tmp) { 76*25475fa5SAndrew Jones if (cpus[cpu].hartid < base + BITS_PER_LONG) { 77*25475fa5SAndrew Jones mask |= 1UL << (cpus[cpu].hartid - base); 78*25475fa5SAndrew Jones cpumask_clear_cpu(cpu, &tmp); 79*25475fa5SAndrew Jones } 80*25475fa5SAndrew Jones } 81*25475fa5SAndrew Jones 82*25475fa5SAndrew Jones ret = sbi_send_ipi(mask, base); 83*25475fa5SAndrew Jones if (ret.error) 84*25475fa5SAndrew Jones break; 85*25475fa5SAndrew Jones } 86*25475fa5SAndrew Jones 87*25475fa5SAndrew Jones return ret; 88*25475fa5SAndrew Jones } 89*25475fa5SAndrew Jones 909340e4b7SAndrew Jones struct sbiret sbi_set_timer(unsigned long stime_value) 919340e4b7SAndrew Jones { 929340e4b7SAndrew Jones return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0); 939340e4b7SAndrew Jones } 949340e4b7SAndrew Jones 957040d2a9SJames Raphael Tiovalen long sbi_probe(int ext) 967040d2a9SJames Raphael Tiovalen { 977040d2a9SJames Raphael Tiovalen struct sbiret ret; 987040d2a9SJames Raphael Tiovalen 997040d2a9SJames Raphael Tiovalen ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0); 1007040d2a9SJames Raphael Tiovalen assert(!ret.error && ret.value >= 2); 1017040d2a9SJames Raphael Tiovalen 1027040d2a9SJames Raphael Tiovalen ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0); 1037040d2a9SJames Raphael Tiovalen assert(!ret.error); 1047040d2a9SJames Raphael Tiovalen 1057040d2a9SJames Raphael Tiovalen return ret.value; 1067040d2a9SJames Raphael Tiovalen } 107