13320648eSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0-only
2b9dcd9e4SAtish Patra /*
3b9dcd9e4SAtish Patra * SBI initialilization and all extension implementation.
4b9dcd9e4SAtish Patra *
5b9dcd9e4SAtish Patra * Copyright (c) 2020 Western Digital Corporation or its affiliates.
6b9dcd9e4SAtish Patra */
73320648eSChristoph Hellwig
812f4a665SGeert Uytterhoeven #include <linux/bits.h>
93320648eSChristoph Hellwig #include <linux/init.h>
103320648eSChristoph Hellwig #include <linux/pm.h>
11b579dfe7SAnup Patel #include <linux/reboot.h>
123320648eSChristoph Hellwig #include <asm/sbi.h>
131ef46c23SAtish Patra #include <asm/smp.h>
14*53a38f8fSAlexandre Ghiti #include <asm/tlbflush.h>
153320648eSChristoph Hellwig
16b9dcd9e4SAtish Patra /* default SBI version is 0.1 */
17de31ea4aSJisheng Zhang unsigned long sbi_spec_version __ro_after_init = SBI_SPEC_VERSION_DEFAULT;
18b9dcd9e4SAtish Patra EXPORT_SYMBOL(sbi_spec_version);
19b9dcd9e4SAtish Patra
20de31ea4aSJisheng Zhang static void (*__sbi_set_timer)(uint64_t stime) __ro_after_init;
21832f15f4SAnup Patel static void (*__sbi_send_ipi)(unsigned int cpu) __ro_after_init;
2226fb751cSAtish Patra static int (*__sbi_rfence)(int fid, const struct cpumask *cpu_mask,
23efca1398SAtish Patra unsigned long start, unsigned long size,
24de31ea4aSJisheng Zhang unsigned long arg4, unsigned long arg5) __ro_after_init;
25efca1398SAtish Patra
sbi_ecall(int ext,int fid,unsigned long arg0,unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5)26b9dcd9e4SAtish Patra struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
27b9dcd9e4SAtish Patra unsigned long arg1, unsigned long arg2,
28b9dcd9e4SAtish Patra unsigned long arg3, unsigned long arg4,
29b9dcd9e4SAtish Patra unsigned long arg5)
30b9dcd9e4SAtish Patra {
31b9dcd9e4SAtish Patra struct sbiret ret;
32b9dcd9e4SAtish Patra
33b9dcd9e4SAtish Patra register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
34b9dcd9e4SAtish Patra register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
35b9dcd9e4SAtish Patra register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
36b9dcd9e4SAtish Patra register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
37b9dcd9e4SAtish Patra register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
38b9dcd9e4SAtish Patra register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
39b9dcd9e4SAtish Patra register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
40b9dcd9e4SAtish Patra register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
41b9dcd9e4SAtish Patra asm volatile ("ecall"
42b9dcd9e4SAtish Patra : "+r" (a0), "+r" (a1)
43b9dcd9e4SAtish Patra : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
44b9dcd9e4SAtish Patra : "memory");
45b9dcd9e4SAtish Patra ret.error = a0;
46b9dcd9e4SAtish Patra ret.value = a1;
47b9dcd9e4SAtish Patra
48b9dcd9e4SAtish Patra return ret;
49b9dcd9e4SAtish Patra }
50b9dcd9e4SAtish Patra EXPORT_SYMBOL(sbi_ecall);
51b9dcd9e4SAtish Patra
sbi_err_map_linux_errno(int err)52f90b43ceSAtish Patra int sbi_err_map_linux_errno(int err)
53b9dcd9e4SAtish Patra {
54b9dcd9e4SAtish Patra switch (err) {
55b9dcd9e4SAtish Patra case SBI_SUCCESS:
56b9dcd9e4SAtish Patra return 0;
57b9dcd9e4SAtish Patra case SBI_ERR_DENIED:
58b9dcd9e4SAtish Patra return -EPERM;
59b9dcd9e4SAtish Patra case SBI_ERR_INVALID_PARAM:
60b9dcd9e4SAtish Patra return -EINVAL;
61b9dcd9e4SAtish Patra case SBI_ERR_INVALID_ADDRESS:
62b9dcd9e4SAtish Patra return -EFAULT;
63b9dcd9e4SAtish Patra case SBI_ERR_NOT_SUPPORTED:
64b9dcd9e4SAtish Patra case SBI_ERR_FAILURE:
65b9dcd9e4SAtish Patra default:
66b9dcd9e4SAtish Patra return -ENOTSUPP;
67b9dcd9e4SAtish Patra };
68b9dcd9e4SAtish Patra }
69f90b43ceSAtish Patra EXPORT_SYMBOL(sbi_err_map_linux_errno);
70b9dcd9e4SAtish Patra
71efca1398SAtish Patra #ifdef CONFIG_RISCV_SBI_V01
__sbi_v01_cpumask_to_hartmask(const struct cpumask * cpu_mask)7226fb751cSAtish Patra static unsigned long __sbi_v01_cpumask_to_hartmask(const struct cpumask *cpu_mask)
7326fb751cSAtish Patra {
7426fb751cSAtish Patra unsigned long cpuid, hartid;
7526fb751cSAtish Patra unsigned long hmask = 0;
7626fb751cSAtish Patra
7726fb751cSAtish Patra /*
7826fb751cSAtish Patra * There is no maximum hartid concept in RISC-V and NR_CPUS must not be
7926fb751cSAtish Patra * associated with hartid. As SBI v0.1 is only kept for backward compatibility
8026fb751cSAtish Patra * and will be removed in the future, there is no point in supporting hartid
8126fb751cSAtish Patra * greater than BITS_PER_LONG (32 for RV32 and 64 for RV64). Ideally, SBI v0.2
8226fb751cSAtish Patra * should be used for platforms with hartid greater than BITS_PER_LONG.
8326fb751cSAtish Patra */
8426fb751cSAtish Patra for_each_cpu(cpuid, cpu_mask) {
8526fb751cSAtish Patra hartid = cpuid_to_hartid_map(cpuid);
8626fb751cSAtish Patra if (hartid >= BITS_PER_LONG) {
8726fb751cSAtish Patra pr_warn("Unable to send any request to hartid > BITS_PER_LONG for SBI v0.1\n");
8826fb751cSAtish Patra break;
8926fb751cSAtish Patra }
9012f4a665SGeert Uytterhoeven hmask |= BIT(hartid);
9126fb751cSAtish Patra }
9226fb751cSAtish Patra
9326fb751cSAtish Patra return hmask;
9426fb751cSAtish Patra }
9526fb751cSAtish Patra
96b9dcd9e4SAtish Patra /**
97b9dcd9e4SAtish Patra * sbi_console_putchar() - Writes given character to the console device.
98b9dcd9e4SAtish Patra * @ch: The data to be written to the console.
99b9dcd9e4SAtish Patra *
100b9dcd9e4SAtish Patra * Return: None
101b9dcd9e4SAtish Patra */
sbi_console_putchar(int ch)102b9dcd9e4SAtish Patra void sbi_console_putchar(int ch)
103b9dcd9e4SAtish Patra {
104b9dcd9e4SAtish Patra sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0);
105b9dcd9e4SAtish Patra }
106b9dcd9e4SAtish Patra EXPORT_SYMBOL(sbi_console_putchar);
107b9dcd9e4SAtish Patra
108b9dcd9e4SAtish Patra /**
109b9dcd9e4SAtish Patra * sbi_console_getchar() - Reads a byte from console device.
110b9dcd9e4SAtish Patra *
111b9dcd9e4SAtish Patra * Returns the value read from console.
112b9dcd9e4SAtish Patra */
sbi_console_getchar(void)113b9dcd9e4SAtish Patra int sbi_console_getchar(void)
114b9dcd9e4SAtish Patra {
115b9dcd9e4SAtish Patra struct sbiret ret;
116b9dcd9e4SAtish Patra
117b9dcd9e4SAtish Patra ret = sbi_ecall(SBI_EXT_0_1_CONSOLE_GETCHAR, 0, 0, 0, 0, 0, 0, 0);
118b9dcd9e4SAtish Patra
119b9dcd9e4SAtish Patra return ret.error;
120b9dcd9e4SAtish Patra }
121b9dcd9e4SAtish Patra EXPORT_SYMBOL(sbi_console_getchar);
122b9dcd9e4SAtish Patra
123b9dcd9e4SAtish Patra /**
124b9dcd9e4SAtish Patra * sbi_shutdown() - Remove all the harts from executing supervisor code.
125b9dcd9e4SAtish Patra *
126b9dcd9e4SAtish Patra * Return: None
127b9dcd9e4SAtish Patra */
sbi_shutdown(void)128b9dcd9e4SAtish Patra void sbi_shutdown(void)
129b9dcd9e4SAtish Patra {
130b9dcd9e4SAtish Patra sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0);
131b9dcd9e4SAtish Patra }
13272df61d9SKefeng Wang EXPORT_SYMBOL(sbi_shutdown);
133b9dcd9e4SAtish Patra
134b9dcd9e4SAtish Patra /**
13556a6c37fSNanyong Sun * __sbi_set_timer_v01() - Program the timer for next timer event.
136efca1398SAtish Patra * @stime_value: The value after which next timer event should fire.
137efca1398SAtish Patra *
138efca1398SAtish Patra * Return: None
139efca1398SAtish Patra */
__sbi_set_timer_v01(uint64_t stime_value)140efca1398SAtish Patra static void __sbi_set_timer_v01(uint64_t stime_value)
141efca1398SAtish Patra {
142efca1398SAtish Patra #if __riscv_xlen == 32
143efca1398SAtish Patra sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value,
144efca1398SAtish Patra stime_value >> 32, 0, 0, 0, 0);
145efca1398SAtish Patra #else
146efca1398SAtish Patra sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value, 0, 0, 0, 0, 0);
147efca1398SAtish Patra #endif
148efca1398SAtish Patra }
149efca1398SAtish Patra
__sbi_send_ipi_v01(unsigned int cpu)150832f15f4SAnup Patel static void __sbi_send_ipi_v01(unsigned int cpu)
151efca1398SAtish Patra {
152832f15f4SAnup Patel unsigned long hart_mask =
153832f15f4SAnup Patel __sbi_v01_cpumask_to_hartmask(cpumask_of(cpu));
15426fb751cSAtish Patra sbi_ecall(SBI_EXT_0_1_SEND_IPI, 0, (unsigned long)(&hart_mask),
155efca1398SAtish Patra 0, 0, 0, 0, 0);
156efca1398SAtish Patra }
157efca1398SAtish Patra
__sbi_rfence_v01(int fid,const struct cpumask * cpu_mask,unsigned long start,unsigned long size,unsigned long arg4,unsigned long arg5)15826fb751cSAtish Patra static int __sbi_rfence_v01(int fid, const struct cpumask *cpu_mask,
159efca1398SAtish Patra unsigned long start, unsigned long size,
160efca1398SAtish Patra unsigned long arg4, unsigned long arg5)
161efca1398SAtish Patra {
162efca1398SAtish Patra int result = 0;
16326fb751cSAtish Patra unsigned long hart_mask;
16426fb751cSAtish Patra
1652b35d5b7SGeert Uytterhoeven if (!cpu_mask || cpumask_empty(cpu_mask))
16626fb751cSAtish Patra cpu_mask = cpu_online_mask;
16726fb751cSAtish Patra hart_mask = __sbi_v01_cpumask_to_hartmask(cpu_mask);
168efca1398SAtish Patra
169efca1398SAtish Patra /* v0.2 function IDs are equivalent to v0.1 extension IDs */
170efca1398SAtish Patra switch (fid) {
171efca1398SAtish Patra case SBI_EXT_RFENCE_REMOTE_FENCE_I:
172efca1398SAtish Patra sbi_ecall(SBI_EXT_0_1_REMOTE_FENCE_I, 0,
17326fb751cSAtish Patra (unsigned long)&hart_mask, 0, 0, 0, 0, 0);
174efca1398SAtish Patra break;
175efca1398SAtish Patra case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
176efca1398SAtish Patra sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA, 0,
17726fb751cSAtish Patra (unsigned long)&hart_mask, start, size,
178efca1398SAtish Patra 0, 0, 0);
179efca1398SAtish Patra break;
180efca1398SAtish Patra case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
181efca1398SAtish Patra sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID, 0,
18226fb751cSAtish Patra (unsigned long)&hart_mask, start, size,
183efca1398SAtish Patra arg4, 0, 0);
184efca1398SAtish Patra break;
185efca1398SAtish Patra default:
186efca1398SAtish Patra pr_err("SBI call [%d]not supported in SBI v0.1\n", fid);
187efca1398SAtish Patra result = -EINVAL;
188efca1398SAtish Patra }
189efca1398SAtish Patra
190efca1398SAtish Patra return result;
191efca1398SAtish Patra }
1927d0ce3b2SKefeng Wang
sbi_set_power_off(void)1937d0ce3b2SKefeng Wang static void sbi_set_power_off(void)
1947d0ce3b2SKefeng Wang {
1957d0ce3b2SKefeng Wang pm_power_off = sbi_shutdown;
1967d0ce3b2SKefeng Wang }
197efca1398SAtish Patra #else
__sbi_set_timer_v01(uint64_t stime_value)198efca1398SAtish Patra static void __sbi_set_timer_v01(uint64_t stime_value)
199efca1398SAtish Patra {
200efca1398SAtish Patra pr_warn("Timer extension is not available in SBI v%lu.%lu\n",
201efca1398SAtish Patra sbi_major_version(), sbi_minor_version());
202efca1398SAtish Patra }
203efca1398SAtish Patra
__sbi_send_ipi_v01(unsigned int cpu)204832f15f4SAnup Patel static void __sbi_send_ipi_v01(unsigned int cpu)
205efca1398SAtish Patra {
206efca1398SAtish Patra pr_warn("IPI extension is not available in SBI v%lu.%lu\n",
207efca1398SAtish Patra sbi_major_version(), sbi_minor_version());
208efca1398SAtish Patra }
209efca1398SAtish Patra
__sbi_rfence_v01(int fid,const struct cpumask * cpu_mask,unsigned long start,unsigned long size,unsigned long arg4,unsigned long arg5)21026fb751cSAtish Patra static int __sbi_rfence_v01(int fid, const struct cpumask *cpu_mask,
211efca1398SAtish Patra unsigned long start, unsigned long size,
212efca1398SAtish Patra unsigned long arg4, unsigned long arg5)
213efca1398SAtish Patra {
214efca1398SAtish Patra pr_warn("remote fence extension is not available in SBI v%lu.%lu\n",
215efca1398SAtish Patra sbi_major_version(), sbi_minor_version());
216efca1398SAtish Patra
217efca1398SAtish Patra return 0;
218efca1398SAtish Patra }
2197d0ce3b2SKefeng Wang
sbi_set_power_off(void)2207d0ce3b2SKefeng Wang static void sbi_set_power_off(void) {}
221efca1398SAtish Patra #endif /* CONFIG_RISCV_SBI_V01 */
222efca1398SAtish Patra
__sbi_set_timer_v02(uint64_t stime_value)2231ef46c23SAtish Patra static void __sbi_set_timer_v02(uint64_t stime_value)
2241ef46c23SAtish Patra {
2251ef46c23SAtish Patra #if __riscv_xlen == 32
2261ef46c23SAtish Patra sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value,
2271ef46c23SAtish Patra stime_value >> 32, 0, 0, 0, 0);
2281ef46c23SAtish Patra #else
2291ef46c23SAtish Patra sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0,
2301ef46c23SAtish Patra 0, 0, 0, 0);
2311ef46c23SAtish Patra #endif
2321ef46c23SAtish Patra }
2331ef46c23SAtish Patra
__sbi_send_ipi_v02(unsigned int cpu)234832f15f4SAnup Patel static void __sbi_send_ipi_v02(unsigned int cpu)
2351ef46c23SAtish Patra {
2361ef46c23SAtish Patra int result;
237832f15f4SAnup Patel struct sbiret ret = {0};
2381ef46c23SAtish Patra
2391ef46c23SAtish Patra ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
240832f15f4SAnup Patel 1UL, cpuid_to_hartid_map(cpu), 0, 0, 0, 0);
241832f15f4SAnup Patel if (ret.error) {
2421ef46c23SAtish Patra result = sbi_err_map_linux_errno(ret.error);
243832f15f4SAnup Patel pr_err("%s: hbase = [%lu] failed (error [%d])\n",
244832f15f4SAnup Patel __func__, cpuid_to_hartid_map(cpu), result);
245832f15f4SAnup Patel }
2461ef46c23SAtish Patra }
2471ef46c23SAtish Patra
__sbi_rfence_v02_call(unsigned long fid,unsigned long hmask,unsigned long hbase,unsigned long start,unsigned long size,unsigned long arg4,unsigned long arg5)24826fb751cSAtish Patra static int __sbi_rfence_v02_call(unsigned long fid, unsigned long hmask,
2491ef46c23SAtish Patra unsigned long hbase, unsigned long start,
2501ef46c23SAtish Patra unsigned long size, unsigned long arg4,
2511ef46c23SAtish Patra unsigned long arg5)
2521ef46c23SAtish Patra {
2531ef46c23SAtish Patra struct sbiret ret = {0};
2541ef46c23SAtish Patra int ext = SBI_EXT_RFENCE;
2551ef46c23SAtish Patra int result = 0;
2561ef46c23SAtish Patra
2571ef46c23SAtish Patra switch (fid) {
2581ef46c23SAtish Patra case SBI_EXT_RFENCE_REMOTE_FENCE_I:
25926fb751cSAtish Patra ret = sbi_ecall(ext, fid, hmask, hbase, 0, 0, 0, 0);
2601ef46c23SAtish Patra break;
2611ef46c23SAtish Patra case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
26226fb751cSAtish Patra ret = sbi_ecall(ext, fid, hmask, hbase, start,
2631ef46c23SAtish Patra size, 0, 0);
2641ef46c23SAtish Patra break;
2651ef46c23SAtish Patra case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
26626fb751cSAtish Patra ret = sbi_ecall(ext, fid, hmask, hbase, start,
2671ef46c23SAtish Patra size, arg4, 0);
2681ef46c23SAtish Patra break;
2691ef46c23SAtish Patra
2701ef46c23SAtish Patra case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
27126fb751cSAtish Patra ret = sbi_ecall(ext, fid, hmask, hbase, start,
2721ef46c23SAtish Patra size, 0, 0);
2731ef46c23SAtish Patra break;
2741ef46c23SAtish Patra case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
27526fb751cSAtish Patra ret = sbi_ecall(ext, fid, hmask, hbase, start,
2761ef46c23SAtish Patra size, arg4, 0);
2771ef46c23SAtish Patra break;
2781ef46c23SAtish Patra case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
27926fb751cSAtish Patra ret = sbi_ecall(ext, fid, hmask, hbase, start,
2801ef46c23SAtish Patra size, 0, 0);
2811ef46c23SAtish Patra break;
2821ef46c23SAtish Patra case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
28326fb751cSAtish Patra ret = sbi_ecall(ext, fid, hmask, hbase, start,
2841ef46c23SAtish Patra size, arg4, 0);
2851ef46c23SAtish Patra break;
2861ef46c23SAtish Patra default:
2871ef46c23SAtish Patra pr_err("unknown function ID [%lu] for SBI extension [%d]\n",
2881ef46c23SAtish Patra fid, ext);
2891ef46c23SAtish Patra result = -EINVAL;
2901ef46c23SAtish Patra }
2911ef46c23SAtish Patra
2921ef46c23SAtish Patra if (ret.error) {
2931ef46c23SAtish Patra result = sbi_err_map_linux_errno(ret.error);
2941ef46c23SAtish Patra pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n",
29526fb751cSAtish Patra __func__, hbase, hmask, result);
2961ef46c23SAtish Patra }
2971ef46c23SAtish Patra
2981ef46c23SAtish Patra return result;
2991ef46c23SAtish Patra }
3001ef46c23SAtish Patra
__sbi_rfence_v02(int fid,const struct cpumask * cpu_mask,unsigned long start,unsigned long size,unsigned long arg4,unsigned long arg5)30126fb751cSAtish Patra static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask,
3021ef46c23SAtish Patra unsigned long start, unsigned long size,
3031ef46c23SAtish Patra unsigned long arg4, unsigned long arg5)
3041ef46c23SAtish Patra {
3055feef64fSGeert Uytterhoeven unsigned long hartid, cpuid, hmask = 0, hbase = 0, htop = 0;
3061ef46c23SAtish Patra int result;
3071ef46c23SAtish Patra
3082b35d5b7SGeert Uytterhoeven if (!cpu_mask || cpumask_empty(cpu_mask))
30926fb751cSAtish Patra cpu_mask = cpu_online_mask;
3101ef46c23SAtish Patra
31126fb751cSAtish Patra for_each_cpu(cpuid, cpu_mask) {
31226fb751cSAtish Patra hartid = cpuid_to_hartid_map(cpuid);
3135feef64fSGeert Uytterhoeven if (hmask) {
3145feef64fSGeert Uytterhoeven if (hartid + BITS_PER_LONG <= htop ||
3155feef64fSGeert Uytterhoeven hbase + BITS_PER_LONG <= hartid) {
3165feef64fSGeert Uytterhoeven result = __sbi_rfence_v02_call(fid, hmask,
3175feef64fSGeert Uytterhoeven hbase, start, size, arg4, arg5);
3181ef46c23SAtish Patra if (result)
3191ef46c23SAtish Patra return result;
32026fb751cSAtish Patra hmask = 0;
3215feef64fSGeert Uytterhoeven } else if (hartid < hbase) {
3225feef64fSGeert Uytterhoeven /* shift the mask to fit lower hartid */
3235feef64fSGeert Uytterhoeven hmask <<= hbase - hartid;
3241ef46c23SAtish Patra hbase = hartid;
3255feef64fSGeert Uytterhoeven }
3265feef64fSGeert Uytterhoeven }
3275feef64fSGeert Uytterhoeven if (!hmask) {
3285feef64fSGeert Uytterhoeven hbase = hartid;
3295feef64fSGeert Uytterhoeven htop = hartid;
3305feef64fSGeert Uytterhoeven } else if (hartid > htop) {
3315feef64fSGeert Uytterhoeven htop = hartid;
3325feef64fSGeert Uytterhoeven }
33312f4a665SGeert Uytterhoeven hmask |= BIT(hartid - hbase);
3341ef46c23SAtish Patra }
3351ef46c23SAtish Patra
33626fb751cSAtish Patra if (hmask) {
33726fb751cSAtish Patra result = __sbi_rfence_v02_call(fid, hmask, hbase,
3381ef46c23SAtish Patra start, size, arg4, arg5);
3391ef46c23SAtish Patra if (result)
3401ef46c23SAtish Patra return result;
3411ef46c23SAtish Patra }
3421ef46c23SAtish Patra
3431ef46c23SAtish Patra return 0;
3441ef46c23SAtish Patra }
3451ef46c23SAtish Patra
346efca1398SAtish Patra /**
347efca1398SAtish Patra * sbi_set_timer() - Program the timer for next timer event.
348efca1398SAtish Patra * @stime_value: The value after which next timer event should fire.
349efca1398SAtish Patra *
3504bb87563SAtish Patra * Return: None.
351efca1398SAtish Patra */
sbi_set_timer(uint64_t stime_value)352efca1398SAtish Patra void sbi_set_timer(uint64_t stime_value)
353efca1398SAtish Patra {
354efca1398SAtish Patra __sbi_set_timer(stime_value);
355efca1398SAtish Patra }
356b9dcd9e4SAtish Patra
357b9dcd9e4SAtish Patra /**
358b9dcd9e4SAtish Patra * sbi_send_ipi() - Send an IPI to any hart.
359832f15f4SAnup Patel * @cpu: Logical id of the target CPU.
360b9dcd9e4SAtish Patra */
sbi_send_ipi(unsigned int cpu)361832f15f4SAnup Patel void sbi_send_ipi(unsigned int cpu)
362b9dcd9e4SAtish Patra {
363832f15f4SAnup Patel __sbi_send_ipi(cpu);
364b9dcd9e4SAtish Patra }
365b9dcd9e4SAtish Patra EXPORT_SYMBOL(sbi_send_ipi);
366b9dcd9e4SAtish Patra
367b9dcd9e4SAtish Patra /**
368b9dcd9e4SAtish Patra * sbi_remote_fence_i() - Execute FENCE.I instruction on given remote harts.
36926fb751cSAtish Patra * @cpu_mask: A cpu mask containing all the target harts.
370b9dcd9e4SAtish Patra *
3714bb87563SAtish Patra * Return: 0 on success, appropriate linux error code otherwise.
372b9dcd9e4SAtish Patra */
sbi_remote_fence_i(const struct cpumask * cpu_mask)37326fb751cSAtish Patra int sbi_remote_fence_i(const struct cpumask *cpu_mask)
374b9dcd9e4SAtish Patra {
3754bb87563SAtish Patra return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_FENCE_I,
37626fb751cSAtish Patra cpu_mask, 0, 0, 0, 0);
377b9dcd9e4SAtish Patra }
378b9dcd9e4SAtish Patra EXPORT_SYMBOL(sbi_remote_fence_i);
379b9dcd9e4SAtish Patra
380b9dcd9e4SAtish Patra /**
381b9dcd9e4SAtish Patra * sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given
382*53a38f8fSAlexandre Ghiti * remote harts for a virtual address range belonging to a specific ASID or not.
383b9dcd9e4SAtish Patra *
38426fb751cSAtish Patra * @cpu_mask: A cpu mask containing all the target harts.
385b9dcd9e4SAtish Patra * @start: Start of the virtual address
386b9dcd9e4SAtish Patra * @size: Total size of the virtual address range.
387*53a38f8fSAlexandre Ghiti * @asid: The value of address space identifier (ASID), or FLUSH_TLB_NO_ASID
388*53a38f8fSAlexandre Ghiti * for flushing all address spaces.
389b9dcd9e4SAtish Patra *
3904bb87563SAtish Patra * Return: 0 on success, appropriate linux error code otherwise.
391b9dcd9e4SAtish Patra */
sbi_remote_sfence_vma_asid(const struct cpumask * cpu_mask,unsigned long start,unsigned long size,unsigned long asid)39226fb751cSAtish Patra int sbi_remote_sfence_vma_asid(const struct cpumask *cpu_mask,
393b9dcd9e4SAtish Patra unsigned long start,
394b9dcd9e4SAtish Patra unsigned long size,
395b9dcd9e4SAtish Patra unsigned long asid)
396b9dcd9e4SAtish Patra {
397*53a38f8fSAlexandre Ghiti if (asid == FLUSH_TLB_NO_ASID)
398*53a38f8fSAlexandre Ghiti return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
399*53a38f8fSAlexandre Ghiti cpu_mask, start, size, 0, 0);
400*53a38f8fSAlexandre Ghiti else
4014bb87563SAtish Patra return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
40226fb751cSAtish Patra cpu_mask, start, size, asid, 0);
403b9dcd9e4SAtish Patra }
404b9dcd9e4SAtish Patra EXPORT_SYMBOL(sbi_remote_sfence_vma_asid);
405b9dcd9e4SAtish Patra
406b9dcd9e4SAtish Patra /**
4071ef46c23SAtish Patra * sbi_remote_hfence_gvma() - Execute HFENCE.GVMA instructions on given remote
4081ef46c23SAtish Patra * harts for the specified guest physical address range.
40926fb751cSAtish Patra * @cpu_mask: A cpu mask containing all the target harts.
4101ef46c23SAtish Patra * @start: Start of the guest physical address
4111ef46c23SAtish Patra * @size: Total size of the guest physical address range.
4121ef46c23SAtish Patra *
4131ef46c23SAtish Patra * Return: None
4141ef46c23SAtish Patra */
sbi_remote_hfence_gvma(const struct cpumask * cpu_mask,unsigned long start,unsigned long size)41526fb751cSAtish Patra int sbi_remote_hfence_gvma(const struct cpumask *cpu_mask,
4161ef46c23SAtish Patra unsigned long start,
4171ef46c23SAtish Patra unsigned long size)
4181ef46c23SAtish Patra {
4191ef46c23SAtish Patra return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA,
42026fb751cSAtish Patra cpu_mask, start, size, 0, 0);
4211ef46c23SAtish Patra }
4221ef46c23SAtish Patra EXPORT_SYMBOL_GPL(sbi_remote_hfence_gvma);
4231ef46c23SAtish Patra
4241ef46c23SAtish Patra /**
4251ef46c23SAtish Patra * sbi_remote_hfence_gvma_vmid() - Execute HFENCE.GVMA instructions on given
4261ef46c23SAtish Patra * remote harts for a guest physical address range belonging to a specific VMID.
4271ef46c23SAtish Patra *
42826fb751cSAtish Patra * @cpu_mask: A cpu mask containing all the target harts.
4291ef46c23SAtish Patra * @start: Start of the guest physical address
4301ef46c23SAtish Patra * @size: Total size of the guest physical address range.
4311ef46c23SAtish Patra * @vmid: The value of guest ID (VMID).
4321ef46c23SAtish Patra *
4331ef46c23SAtish Patra * Return: 0 if success, Error otherwise.
4341ef46c23SAtish Patra */
sbi_remote_hfence_gvma_vmid(const struct cpumask * cpu_mask,unsigned long start,unsigned long size,unsigned long vmid)43526fb751cSAtish Patra int sbi_remote_hfence_gvma_vmid(const struct cpumask *cpu_mask,
4361ef46c23SAtish Patra unsigned long start,
4371ef46c23SAtish Patra unsigned long size,
4381ef46c23SAtish Patra unsigned long vmid)
4391ef46c23SAtish Patra {
4401ef46c23SAtish Patra return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID,
44126fb751cSAtish Patra cpu_mask, start, size, vmid, 0);
4421ef46c23SAtish Patra }
4431ef46c23SAtish Patra EXPORT_SYMBOL(sbi_remote_hfence_gvma_vmid);
4441ef46c23SAtish Patra
4451ef46c23SAtish Patra /**
4461ef46c23SAtish Patra * sbi_remote_hfence_vvma() - Execute HFENCE.VVMA instructions on given remote
4471ef46c23SAtish Patra * harts for the current guest virtual address range.
44826fb751cSAtish Patra * @cpu_mask: A cpu mask containing all the target harts.
4491ef46c23SAtish Patra * @start: Start of the current guest virtual address
4501ef46c23SAtish Patra * @size: Total size of the current guest virtual address range.
4511ef46c23SAtish Patra *
4521ef46c23SAtish Patra * Return: None
4531ef46c23SAtish Patra */
sbi_remote_hfence_vvma(const struct cpumask * cpu_mask,unsigned long start,unsigned long size)45426fb751cSAtish Patra int sbi_remote_hfence_vvma(const struct cpumask *cpu_mask,
4551ef46c23SAtish Patra unsigned long start,
4561ef46c23SAtish Patra unsigned long size)
4571ef46c23SAtish Patra {
4581ef46c23SAtish Patra return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA,
45926fb751cSAtish Patra cpu_mask, start, size, 0, 0);
4601ef46c23SAtish Patra }
4611ef46c23SAtish Patra EXPORT_SYMBOL(sbi_remote_hfence_vvma);
4621ef46c23SAtish Patra
4631ef46c23SAtish Patra /**
4641ef46c23SAtish Patra * sbi_remote_hfence_vvma_asid() - Execute HFENCE.VVMA instructions on given
4651ef46c23SAtish Patra * remote harts for current guest virtual address range belonging to a specific
4661ef46c23SAtish Patra * ASID.
4671ef46c23SAtish Patra *
46826fb751cSAtish Patra * @cpu_mask: A cpu mask containing all the target harts.
4691ef46c23SAtish Patra * @start: Start of the current guest virtual address
4701ef46c23SAtish Patra * @size: Total size of the current guest virtual address range.
4711ef46c23SAtish Patra * @asid: The value of address space identifier (ASID).
4721ef46c23SAtish Patra *
4731ef46c23SAtish Patra * Return: None
4741ef46c23SAtish Patra */
sbi_remote_hfence_vvma_asid(const struct cpumask * cpu_mask,unsigned long start,unsigned long size,unsigned long asid)47526fb751cSAtish Patra int sbi_remote_hfence_vvma_asid(const struct cpumask *cpu_mask,
4761ef46c23SAtish Patra unsigned long start,
4771ef46c23SAtish Patra unsigned long size,
4781ef46c23SAtish Patra unsigned long asid)
4791ef46c23SAtish Patra {
4801ef46c23SAtish Patra return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID,
48126fb751cSAtish Patra cpu_mask, start, size, asid, 0);
4821ef46c23SAtish Patra }
4831ef46c23SAtish Patra EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid);
4841ef46c23SAtish Patra
sbi_srst_reset(unsigned long type,unsigned long reason)485b579dfe7SAnup Patel static void sbi_srst_reset(unsigned long type, unsigned long reason)
486b579dfe7SAnup Patel {
487b579dfe7SAnup Patel sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason,
488b579dfe7SAnup Patel 0, 0, 0, 0);
489b579dfe7SAnup Patel pr_warn("%s: type=0x%lx reason=0x%lx failed\n",
490b579dfe7SAnup Patel __func__, type, reason);
491b579dfe7SAnup Patel }
492b579dfe7SAnup Patel
sbi_srst_reboot(struct notifier_block * this,unsigned long mode,void * cmd)493b579dfe7SAnup Patel static int sbi_srst_reboot(struct notifier_block *this,
494b579dfe7SAnup Patel unsigned long mode, void *cmd)
495b579dfe7SAnup Patel {
496b579dfe7SAnup Patel sbi_srst_reset((mode == REBOOT_WARM || mode == REBOOT_SOFT) ?
497b579dfe7SAnup Patel SBI_SRST_RESET_TYPE_WARM_REBOOT :
498b579dfe7SAnup Patel SBI_SRST_RESET_TYPE_COLD_REBOOT,
499b579dfe7SAnup Patel SBI_SRST_RESET_REASON_NONE);
500b579dfe7SAnup Patel return NOTIFY_DONE;
501b579dfe7SAnup Patel }
502b579dfe7SAnup Patel
503b579dfe7SAnup Patel static struct notifier_block sbi_srst_reboot_nb;
504b579dfe7SAnup Patel
sbi_srst_power_off(void)505b579dfe7SAnup Patel static void sbi_srst_power_off(void)
506b579dfe7SAnup Patel {
507b579dfe7SAnup Patel sbi_srst_reset(SBI_SRST_RESET_TYPE_SHUTDOWN,
508b579dfe7SAnup Patel SBI_SRST_RESET_REASON_NONE);
509b579dfe7SAnup Patel }
510b579dfe7SAnup Patel
5111ef46c23SAtish Patra /**
512b9dcd9e4SAtish Patra * sbi_probe_extension() - Check if an SBI extension ID is supported or not.
513b9dcd9e4SAtish Patra * @extid: The extension ID to be probed.
514b9dcd9e4SAtish Patra *
51541cad828SAndrew Jones * Return: 1 or an extension specific nonzero value if yes, 0 otherwise.
516b9dcd9e4SAtish Patra */
sbi_probe_extension(int extid)51741cad828SAndrew Jones long sbi_probe_extension(int extid)
518b9dcd9e4SAtish Patra {
519b9dcd9e4SAtish Patra struct sbiret ret;
520b9dcd9e4SAtish Patra
521b9dcd9e4SAtish Patra ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid,
522b9dcd9e4SAtish Patra 0, 0, 0, 0, 0);
523b9dcd9e4SAtish Patra if (!ret.error)
524b9dcd9e4SAtish Patra return ret.value;
525b9dcd9e4SAtish Patra
52641cad828SAndrew Jones return 0;
527b9dcd9e4SAtish Patra }
528b9dcd9e4SAtish Patra EXPORT_SYMBOL(sbi_probe_extension);
529b9dcd9e4SAtish Patra
__sbi_base_ecall(int fid)530b9dcd9e4SAtish Patra static long __sbi_base_ecall(int fid)
531b9dcd9e4SAtish Patra {
532b9dcd9e4SAtish Patra struct sbiret ret;
533b9dcd9e4SAtish Patra
534b9dcd9e4SAtish Patra ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0);
535b9dcd9e4SAtish Patra if (!ret.error)
536b9dcd9e4SAtish Patra return ret.value;
537b9dcd9e4SAtish Patra else
538b9dcd9e4SAtish Patra return sbi_err_map_linux_errno(ret.error);
539b9dcd9e4SAtish Patra }
540b9dcd9e4SAtish Patra
sbi_get_spec_version(void)541b9dcd9e4SAtish Patra static inline long sbi_get_spec_version(void)
542b9dcd9e4SAtish Patra {
543b9dcd9e4SAtish Patra return __sbi_base_ecall(SBI_EXT_BASE_GET_SPEC_VERSION);
544b9dcd9e4SAtish Patra }
545b9dcd9e4SAtish Patra
sbi_get_firmware_id(void)546b9dcd9e4SAtish Patra static inline long sbi_get_firmware_id(void)
547b9dcd9e4SAtish Patra {
548b9dcd9e4SAtish Patra return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_ID);
549b9dcd9e4SAtish Patra }
550b9dcd9e4SAtish Patra
sbi_get_firmware_version(void)551b9dcd9e4SAtish Patra static inline long sbi_get_firmware_version(void)
552b9dcd9e4SAtish Patra {
553b9dcd9e4SAtish Patra return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION);
554b9dcd9e4SAtish Patra }
555b9dcd9e4SAtish Patra
sbi_get_mvendorid(void)556183787c6SVincent Chen long sbi_get_mvendorid(void)
557183787c6SVincent Chen {
558183787c6SVincent Chen return __sbi_base_ecall(SBI_EXT_BASE_GET_MVENDORID);
559183787c6SVincent Chen }
560a1a44e22SAnup Patel EXPORT_SYMBOL_GPL(sbi_get_mvendorid);
561183787c6SVincent Chen
sbi_get_marchid(void)562183787c6SVincent Chen long sbi_get_marchid(void)
563183787c6SVincent Chen {
564183787c6SVincent Chen return __sbi_base_ecall(SBI_EXT_BASE_GET_MARCHID);
565183787c6SVincent Chen }
566a1a44e22SAnup Patel EXPORT_SYMBOL_GPL(sbi_get_marchid);
567183787c6SVincent Chen
sbi_get_mimpid(void)568183787c6SVincent Chen long sbi_get_mimpid(void)
569183787c6SVincent Chen {
570183787c6SVincent Chen return __sbi_base_ecall(SBI_EXT_BASE_GET_MIMPID);
571183787c6SVincent Chen }
572a1a44e22SAnup Patel EXPORT_SYMBOL_GPL(sbi_get_mimpid);
573183787c6SVincent Chen
sbi_init(void)574641e8cd2SKefeng Wang void __init sbi_init(void)
5753320648eSChristoph Hellwig {
576b9dcd9e4SAtish Patra int ret;
577b9dcd9e4SAtish Patra
5787d0ce3b2SKefeng Wang sbi_set_power_off();
579b9dcd9e4SAtish Patra ret = sbi_get_spec_version();
580b9dcd9e4SAtish Patra if (ret > 0)
581b9dcd9e4SAtish Patra sbi_spec_version = ret;
582b9dcd9e4SAtish Patra
583b9dcd9e4SAtish Patra pr_info("SBI specification v%lu.%lu detected\n",
584b9dcd9e4SAtish Patra sbi_major_version(), sbi_minor_version());
585efca1398SAtish Patra
586efca1398SAtish Patra if (!sbi_spec_is_0_1()) {
587b9dcd9e4SAtish Patra pr_info("SBI implementation ID=0x%lx Version=0x%lx\n",
588b9dcd9e4SAtish Patra sbi_get_firmware_id(), sbi_get_firmware_version());
58941cad828SAndrew Jones if (sbi_probe_extension(SBI_EXT_TIME)) {
5901ef46c23SAtish Patra __sbi_set_timer = __sbi_set_timer_v02;
591f35bb4b8SAnup Patel pr_info("SBI TIME extension detected\n");
5921ef46c23SAtish Patra } else {
5931ef46c23SAtish Patra __sbi_set_timer = __sbi_set_timer_v01;
594efca1398SAtish Patra }
59541cad828SAndrew Jones if (sbi_probe_extension(SBI_EXT_IPI)) {
5961ef46c23SAtish Patra __sbi_send_ipi = __sbi_send_ipi_v02;
597f35bb4b8SAnup Patel pr_info("SBI IPI extension detected\n");
5981ef46c23SAtish Patra } else {
5991ef46c23SAtish Patra __sbi_send_ipi = __sbi_send_ipi_v01;
6001ef46c23SAtish Patra }
60141cad828SAndrew Jones if (sbi_probe_extension(SBI_EXT_RFENCE)) {
6021ef46c23SAtish Patra __sbi_rfence = __sbi_rfence_v02;
603f35bb4b8SAnup Patel pr_info("SBI RFENCE extension detected\n");
6041ef46c23SAtish Patra } else {
6051ef46c23SAtish Patra __sbi_rfence = __sbi_rfence_v01;
6061ef46c23SAtish Patra }
607b579dfe7SAnup Patel if ((sbi_spec_version >= sbi_mk_version(0, 3)) &&
60841cad828SAndrew Jones sbi_probe_extension(SBI_EXT_SRST)) {
609b579dfe7SAnup Patel pr_info("SBI SRST extension detected\n");
610b579dfe7SAnup Patel pm_power_off = sbi_srst_power_off;
611b579dfe7SAnup Patel sbi_srst_reboot_nb.notifier_call = sbi_srst_reboot;
612b579dfe7SAnup Patel sbi_srst_reboot_nb.priority = 192;
613b579dfe7SAnup Patel register_restart_handler(&sbi_srst_reboot_nb);
614b579dfe7SAnup Patel }
6151ef46c23SAtish Patra } else {
616efca1398SAtish Patra __sbi_set_timer = __sbi_set_timer_v01;
617efca1398SAtish Patra __sbi_send_ipi = __sbi_send_ipi_v01;
618efca1398SAtish Patra __sbi_rfence = __sbi_rfence_v01;
6191ef46c23SAtish Patra }
6203320648eSChristoph Hellwig }
621