xref: /OK3568_Linux_fs/kernel/arch/riscv/kernel/sbi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * SBI initialilization and all extension implementation.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/pm.h>
10*4882a593Smuzhiyun #include <asm/sbi.h>
11*4882a593Smuzhiyun #include <asm/smp.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun /* default SBI version is 0.1 */
14*4882a593Smuzhiyun unsigned long sbi_spec_version = SBI_SPEC_VERSION_DEFAULT;
15*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_spec_version);
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun static void (*__sbi_set_timer)(uint64_t stime);
18*4882a593Smuzhiyun static int (*__sbi_send_ipi)(const unsigned long *hart_mask);
19*4882a593Smuzhiyun static int (*__sbi_rfence)(int fid, const unsigned long *hart_mask,
20*4882a593Smuzhiyun 			   unsigned long start, unsigned long size,
21*4882a593Smuzhiyun 			   unsigned long arg4, unsigned long arg5);
22*4882a593Smuzhiyun 
sbi_ecall(int ext,int fid,unsigned long arg0,unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5)23*4882a593Smuzhiyun struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
24*4882a593Smuzhiyun 			unsigned long arg1, unsigned long arg2,
25*4882a593Smuzhiyun 			unsigned long arg3, unsigned long arg4,
26*4882a593Smuzhiyun 			unsigned long arg5)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	struct sbiret ret;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
31*4882a593Smuzhiyun 	register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
32*4882a593Smuzhiyun 	register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
33*4882a593Smuzhiyun 	register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
34*4882a593Smuzhiyun 	register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
35*4882a593Smuzhiyun 	register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
36*4882a593Smuzhiyun 	register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
37*4882a593Smuzhiyun 	register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
38*4882a593Smuzhiyun 	asm volatile ("ecall"
39*4882a593Smuzhiyun 		      : "+r" (a0), "+r" (a1)
40*4882a593Smuzhiyun 		      : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
41*4882a593Smuzhiyun 		      : "memory");
42*4882a593Smuzhiyun 	ret.error = a0;
43*4882a593Smuzhiyun 	ret.value = a1;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	return ret;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_ecall);
48*4882a593Smuzhiyun 
sbi_err_map_linux_errno(int err)49*4882a593Smuzhiyun int sbi_err_map_linux_errno(int err)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	switch (err) {
52*4882a593Smuzhiyun 	case SBI_SUCCESS:
53*4882a593Smuzhiyun 		return 0;
54*4882a593Smuzhiyun 	case SBI_ERR_DENIED:
55*4882a593Smuzhiyun 		return -EPERM;
56*4882a593Smuzhiyun 	case SBI_ERR_INVALID_PARAM:
57*4882a593Smuzhiyun 		return -EINVAL;
58*4882a593Smuzhiyun 	case SBI_ERR_INVALID_ADDRESS:
59*4882a593Smuzhiyun 		return -EFAULT;
60*4882a593Smuzhiyun 	case SBI_ERR_NOT_SUPPORTED:
61*4882a593Smuzhiyun 	case SBI_ERR_FAILURE:
62*4882a593Smuzhiyun 	default:
63*4882a593Smuzhiyun 		return -ENOTSUPP;
64*4882a593Smuzhiyun 	};
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_err_map_linux_errno);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #ifdef CONFIG_RISCV_SBI_V01
69*4882a593Smuzhiyun /**
70*4882a593Smuzhiyun  * sbi_console_putchar() - Writes given character to the console device.
71*4882a593Smuzhiyun  * @ch: The data to be written to the console.
72*4882a593Smuzhiyun  *
73*4882a593Smuzhiyun  * Return: None
74*4882a593Smuzhiyun  */
sbi_console_putchar(int ch)75*4882a593Smuzhiyun void sbi_console_putchar(int ch)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_console_putchar);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /**
82*4882a593Smuzhiyun  * sbi_console_getchar() - Reads a byte from console device.
83*4882a593Smuzhiyun  *
84*4882a593Smuzhiyun  * Returns the value read from console.
85*4882a593Smuzhiyun  */
sbi_console_getchar(void)86*4882a593Smuzhiyun int sbi_console_getchar(void)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct sbiret ret;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	ret = sbi_ecall(SBI_EXT_0_1_CONSOLE_GETCHAR, 0, 0, 0, 0, 0, 0, 0);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	return ret.error;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_console_getchar);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun /**
97*4882a593Smuzhiyun  * sbi_shutdown() - Remove all the harts from executing supervisor code.
98*4882a593Smuzhiyun  *
99*4882a593Smuzhiyun  * Return: None
100*4882a593Smuzhiyun  */
sbi_shutdown(void)101*4882a593Smuzhiyun void sbi_shutdown(void)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_shutdown);
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun /**
108*4882a593Smuzhiyun  * sbi_clear_ipi() - Clear any pending IPIs for the calling hart.
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * Return: None
111*4882a593Smuzhiyun  */
sbi_clear_ipi(void)112*4882a593Smuzhiyun void sbi_clear_ipi(void)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	sbi_ecall(SBI_EXT_0_1_CLEAR_IPI, 0, 0, 0, 0, 0, 0, 0);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_clear_ipi);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun /**
119*4882a593Smuzhiyun  * sbi_set_timer_v01() - Program the timer for next timer event.
120*4882a593Smuzhiyun  * @stime_value: The value after which next timer event should fire.
121*4882a593Smuzhiyun  *
122*4882a593Smuzhiyun  * Return: None
123*4882a593Smuzhiyun  */
__sbi_set_timer_v01(uint64_t stime_value)124*4882a593Smuzhiyun static void __sbi_set_timer_v01(uint64_t stime_value)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun #if __riscv_xlen == 32
127*4882a593Smuzhiyun 	sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value,
128*4882a593Smuzhiyun 		  stime_value >> 32, 0, 0, 0, 0);
129*4882a593Smuzhiyun #else
130*4882a593Smuzhiyun 	sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value, 0, 0, 0, 0, 0);
131*4882a593Smuzhiyun #endif
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
__sbi_send_ipi_v01(const unsigned long * hart_mask)134*4882a593Smuzhiyun static int __sbi_send_ipi_v01(const unsigned long *hart_mask)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	sbi_ecall(SBI_EXT_0_1_SEND_IPI, 0, (unsigned long)hart_mask,
137*4882a593Smuzhiyun 		  0, 0, 0, 0, 0);
138*4882a593Smuzhiyun 	return 0;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
__sbi_rfence_v01(int fid,const unsigned long * hart_mask,unsigned long start,unsigned long size,unsigned long arg4,unsigned long arg5)141*4882a593Smuzhiyun static int __sbi_rfence_v01(int fid, const unsigned long *hart_mask,
142*4882a593Smuzhiyun 			    unsigned long start, unsigned long size,
143*4882a593Smuzhiyun 			    unsigned long arg4, unsigned long arg5)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	int result = 0;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* v0.2 function IDs are equivalent to v0.1 extension IDs */
148*4882a593Smuzhiyun 	switch (fid) {
149*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_FENCE_I:
150*4882a593Smuzhiyun 		sbi_ecall(SBI_EXT_0_1_REMOTE_FENCE_I, 0,
151*4882a593Smuzhiyun 			  (unsigned long)hart_mask, 0, 0, 0, 0, 0);
152*4882a593Smuzhiyun 		break;
153*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
154*4882a593Smuzhiyun 		sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA, 0,
155*4882a593Smuzhiyun 			  (unsigned long)hart_mask, start, size,
156*4882a593Smuzhiyun 			  0, 0, 0);
157*4882a593Smuzhiyun 		break;
158*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
159*4882a593Smuzhiyun 		sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID, 0,
160*4882a593Smuzhiyun 			  (unsigned long)hart_mask, start, size,
161*4882a593Smuzhiyun 			  arg4, 0, 0);
162*4882a593Smuzhiyun 		break;
163*4882a593Smuzhiyun 	default:
164*4882a593Smuzhiyun 		pr_err("SBI call [%d]not supported in SBI v0.1\n", fid);
165*4882a593Smuzhiyun 		result = -EINVAL;
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	return result;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
sbi_set_power_off(void)171*4882a593Smuzhiyun static void sbi_set_power_off(void)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	pm_power_off = sbi_shutdown;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun #else
__sbi_set_timer_v01(uint64_t stime_value)176*4882a593Smuzhiyun static void __sbi_set_timer_v01(uint64_t stime_value)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	pr_warn("Timer extension is not available in SBI v%lu.%lu\n",
179*4882a593Smuzhiyun 		sbi_major_version(), sbi_minor_version());
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
__sbi_send_ipi_v01(const unsigned long * hart_mask)182*4882a593Smuzhiyun static int __sbi_send_ipi_v01(const unsigned long *hart_mask)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	pr_warn("IPI extension is not available in SBI v%lu.%lu\n",
185*4882a593Smuzhiyun 		sbi_major_version(), sbi_minor_version());
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	return 0;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
__sbi_rfence_v01(int fid,const unsigned long * hart_mask,unsigned long start,unsigned long size,unsigned long arg4,unsigned long arg5)190*4882a593Smuzhiyun static int __sbi_rfence_v01(int fid, const unsigned long *hart_mask,
191*4882a593Smuzhiyun 			    unsigned long start, unsigned long size,
192*4882a593Smuzhiyun 			    unsigned long arg4, unsigned long arg5)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	pr_warn("remote fence extension is not available in SBI v%lu.%lu\n",
195*4882a593Smuzhiyun 		sbi_major_version(), sbi_minor_version());
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return 0;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
sbi_set_power_off(void)200*4882a593Smuzhiyun static void sbi_set_power_off(void) {}
201*4882a593Smuzhiyun #endif /* CONFIG_RISCV_SBI_V01 */
202*4882a593Smuzhiyun 
__sbi_set_timer_v02(uint64_t stime_value)203*4882a593Smuzhiyun static void __sbi_set_timer_v02(uint64_t stime_value)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun #if __riscv_xlen == 32
206*4882a593Smuzhiyun 	sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value,
207*4882a593Smuzhiyun 		  stime_value >> 32, 0, 0, 0, 0);
208*4882a593Smuzhiyun #else
209*4882a593Smuzhiyun 	sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0,
210*4882a593Smuzhiyun 		  0, 0, 0, 0);
211*4882a593Smuzhiyun #endif
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
__sbi_send_ipi_v02(const unsigned long * hart_mask)214*4882a593Smuzhiyun static int __sbi_send_ipi_v02(const unsigned long *hart_mask)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	unsigned long hartid, hmask_val, hbase;
217*4882a593Smuzhiyun 	struct cpumask tmask;
218*4882a593Smuzhiyun 	struct sbiret ret = {0};
219*4882a593Smuzhiyun 	int result;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	if (!hart_mask || !(*hart_mask)) {
222*4882a593Smuzhiyun 		riscv_cpuid_to_hartid_mask(cpu_online_mask, &tmask);
223*4882a593Smuzhiyun 		hart_mask = cpumask_bits(&tmask);
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	hmask_val = 0;
227*4882a593Smuzhiyun 	hbase = 0;
228*4882a593Smuzhiyun 	for_each_set_bit(hartid, hart_mask, NR_CPUS) {
229*4882a593Smuzhiyun 		if (hmask_val && ((hbase + BITS_PER_LONG) <= hartid)) {
230*4882a593Smuzhiyun 			ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
231*4882a593Smuzhiyun 					hmask_val, hbase, 0, 0, 0, 0);
232*4882a593Smuzhiyun 			if (ret.error)
233*4882a593Smuzhiyun 				goto ecall_failed;
234*4882a593Smuzhiyun 			hmask_val = 0;
235*4882a593Smuzhiyun 			hbase = 0;
236*4882a593Smuzhiyun 		}
237*4882a593Smuzhiyun 		if (!hmask_val)
238*4882a593Smuzhiyun 			hbase = hartid;
239*4882a593Smuzhiyun 		hmask_val |= 1UL << (hartid - hbase);
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (hmask_val) {
243*4882a593Smuzhiyun 		ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
244*4882a593Smuzhiyun 				hmask_val, hbase, 0, 0, 0, 0);
245*4882a593Smuzhiyun 		if (ret.error)
246*4882a593Smuzhiyun 			goto ecall_failed;
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	return 0;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun ecall_failed:
252*4882a593Smuzhiyun 	result = sbi_err_map_linux_errno(ret.error);
253*4882a593Smuzhiyun 	pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n",
254*4882a593Smuzhiyun 	       __func__, hbase, hmask_val, result);
255*4882a593Smuzhiyun 	return result;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
__sbi_rfence_v02_call(unsigned long fid,unsigned long hmask_val,unsigned long hbase,unsigned long start,unsigned long size,unsigned long arg4,unsigned long arg5)258*4882a593Smuzhiyun static int __sbi_rfence_v02_call(unsigned long fid, unsigned long hmask_val,
259*4882a593Smuzhiyun 				 unsigned long hbase, unsigned long start,
260*4882a593Smuzhiyun 				 unsigned long size, unsigned long arg4,
261*4882a593Smuzhiyun 				 unsigned long arg5)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	struct sbiret ret = {0};
264*4882a593Smuzhiyun 	int ext = SBI_EXT_RFENCE;
265*4882a593Smuzhiyun 	int result = 0;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	switch (fid) {
268*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_FENCE_I:
269*4882a593Smuzhiyun 		ret = sbi_ecall(ext, fid, hmask_val, hbase, 0, 0, 0, 0);
270*4882a593Smuzhiyun 		break;
271*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
272*4882a593Smuzhiyun 		ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
273*4882a593Smuzhiyun 				size, 0, 0);
274*4882a593Smuzhiyun 		break;
275*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
276*4882a593Smuzhiyun 		ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
277*4882a593Smuzhiyun 				size, arg4, 0);
278*4882a593Smuzhiyun 		break;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
281*4882a593Smuzhiyun 		ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
282*4882a593Smuzhiyun 				size, 0, 0);
283*4882a593Smuzhiyun 		break;
284*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
285*4882a593Smuzhiyun 		ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
286*4882a593Smuzhiyun 				size, arg4, 0);
287*4882a593Smuzhiyun 		break;
288*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
289*4882a593Smuzhiyun 		ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
290*4882a593Smuzhiyun 				size, 0, 0);
291*4882a593Smuzhiyun 		break;
292*4882a593Smuzhiyun 	case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
293*4882a593Smuzhiyun 		ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
294*4882a593Smuzhiyun 				size, arg4, 0);
295*4882a593Smuzhiyun 		break;
296*4882a593Smuzhiyun 	default:
297*4882a593Smuzhiyun 		pr_err("unknown function ID [%lu] for SBI extension [%d]\n",
298*4882a593Smuzhiyun 		       fid, ext);
299*4882a593Smuzhiyun 		result = -EINVAL;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (ret.error) {
303*4882a593Smuzhiyun 		result = sbi_err_map_linux_errno(ret.error);
304*4882a593Smuzhiyun 		pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n",
305*4882a593Smuzhiyun 		       __func__, hbase, hmask_val, result);
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return result;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
__sbi_rfence_v02(int fid,const unsigned long * hart_mask,unsigned long start,unsigned long size,unsigned long arg4,unsigned long arg5)311*4882a593Smuzhiyun static int __sbi_rfence_v02(int fid, const unsigned long *hart_mask,
312*4882a593Smuzhiyun 			    unsigned long start, unsigned long size,
313*4882a593Smuzhiyun 			    unsigned long arg4, unsigned long arg5)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	unsigned long hmask_val, hartid, hbase;
316*4882a593Smuzhiyun 	struct cpumask tmask;
317*4882a593Smuzhiyun 	int result;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	if (!hart_mask || !(*hart_mask)) {
320*4882a593Smuzhiyun 		riscv_cpuid_to_hartid_mask(cpu_online_mask, &tmask);
321*4882a593Smuzhiyun 		hart_mask = cpumask_bits(&tmask);
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	hmask_val = 0;
325*4882a593Smuzhiyun 	hbase = 0;
326*4882a593Smuzhiyun 	for_each_set_bit(hartid, hart_mask, NR_CPUS) {
327*4882a593Smuzhiyun 		if (hmask_val && ((hbase + BITS_PER_LONG) <= hartid)) {
328*4882a593Smuzhiyun 			result = __sbi_rfence_v02_call(fid, hmask_val, hbase,
329*4882a593Smuzhiyun 						       start, size, arg4, arg5);
330*4882a593Smuzhiyun 			if (result)
331*4882a593Smuzhiyun 				return result;
332*4882a593Smuzhiyun 			hmask_val = 0;
333*4882a593Smuzhiyun 			hbase = 0;
334*4882a593Smuzhiyun 		}
335*4882a593Smuzhiyun 		if (!hmask_val)
336*4882a593Smuzhiyun 			hbase = hartid;
337*4882a593Smuzhiyun 		hmask_val |= 1UL << (hartid - hbase);
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	if (hmask_val) {
341*4882a593Smuzhiyun 		result = __sbi_rfence_v02_call(fid, hmask_val, hbase,
342*4882a593Smuzhiyun 					       start, size, arg4, arg5);
343*4882a593Smuzhiyun 		if (result)
344*4882a593Smuzhiyun 			return result;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun /**
351*4882a593Smuzhiyun  * sbi_set_timer() - Program the timer for next timer event.
352*4882a593Smuzhiyun  * @stime_value: The value after which next timer event should fire.
353*4882a593Smuzhiyun  *
354*4882a593Smuzhiyun  * Return: None
355*4882a593Smuzhiyun  */
sbi_set_timer(uint64_t stime_value)356*4882a593Smuzhiyun void sbi_set_timer(uint64_t stime_value)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	__sbi_set_timer(stime_value);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun /**
362*4882a593Smuzhiyun  * sbi_send_ipi() - Send an IPI to any hart.
363*4882a593Smuzhiyun  * @hart_mask: A cpu mask containing all the target harts.
364*4882a593Smuzhiyun  *
365*4882a593Smuzhiyun  * Return: None
366*4882a593Smuzhiyun  */
sbi_send_ipi(const unsigned long * hart_mask)367*4882a593Smuzhiyun void sbi_send_ipi(const unsigned long *hart_mask)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun 	__sbi_send_ipi(hart_mask);
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_send_ipi);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun /**
374*4882a593Smuzhiyun  * sbi_remote_fence_i() - Execute FENCE.I instruction on given remote harts.
375*4882a593Smuzhiyun  * @hart_mask: A cpu mask containing all the target harts.
376*4882a593Smuzhiyun  *
377*4882a593Smuzhiyun  * Return: None
378*4882a593Smuzhiyun  */
sbi_remote_fence_i(const unsigned long * hart_mask)379*4882a593Smuzhiyun void sbi_remote_fence_i(const unsigned long *hart_mask)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	__sbi_rfence(SBI_EXT_RFENCE_REMOTE_FENCE_I,
382*4882a593Smuzhiyun 		     hart_mask, 0, 0, 0, 0);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_remote_fence_i);
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun /**
387*4882a593Smuzhiyun  * sbi_remote_sfence_vma() - Execute SFENCE.VMA instructions on given remote
388*4882a593Smuzhiyun  *			     harts for the specified virtual address range.
389*4882a593Smuzhiyun  * @hart_mask: A cpu mask containing all the target harts.
390*4882a593Smuzhiyun  * @start: Start of the virtual address
391*4882a593Smuzhiyun  * @size: Total size of the virtual address range.
392*4882a593Smuzhiyun  *
393*4882a593Smuzhiyun  * Return: None
394*4882a593Smuzhiyun  */
sbi_remote_sfence_vma(const unsigned long * hart_mask,unsigned long start,unsigned long size)395*4882a593Smuzhiyun void sbi_remote_sfence_vma(const unsigned long *hart_mask,
396*4882a593Smuzhiyun 			   unsigned long start,
397*4882a593Smuzhiyun 			   unsigned long size)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	__sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
400*4882a593Smuzhiyun 		     hart_mask, start, size, 0, 0);
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_remote_sfence_vma);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun /**
405*4882a593Smuzhiyun  * sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given
406*4882a593Smuzhiyun  * remote harts for a virtual address range belonging to a specific ASID.
407*4882a593Smuzhiyun  *
408*4882a593Smuzhiyun  * @hart_mask: A cpu mask containing all the target harts.
409*4882a593Smuzhiyun  * @start: Start of the virtual address
410*4882a593Smuzhiyun  * @size: Total size of the virtual address range.
411*4882a593Smuzhiyun  * @asid: The value of address space identifier (ASID).
412*4882a593Smuzhiyun  *
413*4882a593Smuzhiyun  * Return: None
414*4882a593Smuzhiyun  */
sbi_remote_sfence_vma_asid(const unsigned long * hart_mask,unsigned long start,unsigned long size,unsigned long asid)415*4882a593Smuzhiyun void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
416*4882a593Smuzhiyun 				unsigned long start,
417*4882a593Smuzhiyun 				unsigned long size,
418*4882a593Smuzhiyun 				unsigned long asid)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	__sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
421*4882a593Smuzhiyun 		     hart_mask, start, size, asid, 0);
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_remote_sfence_vma_asid);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun /**
426*4882a593Smuzhiyun  * sbi_remote_hfence_gvma() - Execute HFENCE.GVMA instructions on given remote
427*4882a593Smuzhiyun  *			   harts for the specified guest physical address range.
428*4882a593Smuzhiyun  * @hart_mask: A cpu mask containing all the target harts.
429*4882a593Smuzhiyun  * @start: Start of the guest physical address
430*4882a593Smuzhiyun  * @size: Total size of the guest physical address range.
431*4882a593Smuzhiyun  *
432*4882a593Smuzhiyun  * Return: None
433*4882a593Smuzhiyun  */
sbi_remote_hfence_gvma(const unsigned long * hart_mask,unsigned long start,unsigned long size)434*4882a593Smuzhiyun int sbi_remote_hfence_gvma(const unsigned long *hart_mask,
435*4882a593Smuzhiyun 			   unsigned long start,
436*4882a593Smuzhiyun 			   unsigned long size)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA,
439*4882a593Smuzhiyun 			    hart_mask, start, size, 0, 0);
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sbi_remote_hfence_gvma);
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun /**
444*4882a593Smuzhiyun  * sbi_remote_hfence_gvma_vmid() - Execute HFENCE.GVMA instructions on given
445*4882a593Smuzhiyun  * remote harts for a guest physical address range belonging to a specific VMID.
446*4882a593Smuzhiyun  *
447*4882a593Smuzhiyun  * @hart_mask: A cpu mask containing all the target harts.
448*4882a593Smuzhiyun  * @start: Start of the guest physical address
449*4882a593Smuzhiyun  * @size: Total size of the guest physical address range.
450*4882a593Smuzhiyun  * @vmid: The value of guest ID (VMID).
451*4882a593Smuzhiyun  *
452*4882a593Smuzhiyun  * Return: 0 if success, Error otherwise.
453*4882a593Smuzhiyun  */
sbi_remote_hfence_gvma_vmid(const unsigned long * hart_mask,unsigned long start,unsigned long size,unsigned long vmid)454*4882a593Smuzhiyun int sbi_remote_hfence_gvma_vmid(const unsigned long *hart_mask,
455*4882a593Smuzhiyun 				unsigned long start,
456*4882a593Smuzhiyun 				unsigned long size,
457*4882a593Smuzhiyun 				unsigned long vmid)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun 	return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID,
460*4882a593Smuzhiyun 			    hart_mask, start, size, vmid, 0);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_remote_hfence_gvma_vmid);
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun /**
465*4882a593Smuzhiyun  * sbi_remote_hfence_vvma() - Execute HFENCE.VVMA instructions on given remote
466*4882a593Smuzhiyun  *			     harts for the current guest virtual address range.
467*4882a593Smuzhiyun  * @hart_mask: A cpu mask containing all the target harts.
468*4882a593Smuzhiyun  * @start: Start of the current guest virtual address
469*4882a593Smuzhiyun  * @size: Total size of the current guest virtual address range.
470*4882a593Smuzhiyun  *
471*4882a593Smuzhiyun  * Return: None
472*4882a593Smuzhiyun  */
sbi_remote_hfence_vvma(const unsigned long * hart_mask,unsigned long start,unsigned long size)473*4882a593Smuzhiyun int sbi_remote_hfence_vvma(const unsigned long *hart_mask,
474*4882a593Smuzhiyun 			   unsigned long start,
475*4882a593Smuzhiyun 			   unsigned long size)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA,
478*4882a593Smuzhiyun 			    hart_mask, start, size, 0, 0);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_remote_hfence_vvma);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun /**
483*4882a593Smuzhiyun  * sbi_remote_hfence_vvma_asid() - Execute HFENCE.VVMA instructions on given
484*4882a593Smuzhiyun  * remote harts for current guest virtual address range belonging to a specific
485*4882a593Smuzhiyun  * ASID.
486*4882a593Smuzhiyun  *
487*4882a593Smuzhiyun  * @hart_mask: A cpu mask containing all the target harts.
488*4882a593Smuzhiyun  * @start: Start of the current guest virtual address
489*4882a593Smuzhiyun  * @size: Total size of the current guest virtual address range.
490*4882a593Smuzhiyun  * @asid: The value of address space identifier (ASID).
491*4882a593Smuzhiyun  *
492*4882a593Smuzhiyun  * Return: None
493*4882a593Smuzhiyun  */
sbi_remote_hfence_vvma_asid(const unsigned long * hart_mask,unsigned long start,unsigned long size,unsigned long asid)494*4882a593Smuzhiyun int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,
495*4882a593Smuzhiyun 				unsigned long start,
496*4882a593Smuzhiyun 				unsigned long size,
497*4882a593Smuzhiyun 				unsigned long asid)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun 	return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID,
500*4882a593Smuzhiyun 			    hart_mask, start, size, asid, 0);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun /**
505*4882a593Smuzhiyun  * sbi_probe_extension() - Check if an SBI extension ID is supported or not.
506*4882a593Smuzhiyun  * @extid: The extension ID to be probed.
507*4882a593Smuzhiyun  *
508*4882a593Smuzhiyun  * Return: Extension specific nonzero value f yes, -ENOTSUPP otherwise.
509*4882a593Smuzhiyun  */
sbi_probe_extension(int extid)510*4882a593Smuzhiyun int sbi_probe_extension(int extid)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	struct sbiret ret;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid,
515*4882a593Smuzhiyun 			0, 0, 0, 0, 0);
516*4882a593Smuzhiyun 	if (!ret.error)
517*4882a593Smuzhiyun 		if (ret.value)
518*4882a593Smuzhiyun 			return ret.value;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	return -ENOTSUPP;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun EXPORT_SYMBOL(sbi_probe_extension);
523*4882a593Smuzhiyun 
__sbi_base_ecall(int fid)524*4882a593Smuzhiyun static long __sbi_base_ecall(int fid)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	struct sbiret ret;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0);
529*4882a593Smuzhiyun 	if (!ret.error)
530*4882a593Smuzhiyun 		return ret.value;
531*4882a593Smuzhiyun 	else
532*4882a593Smuzhiyun 		return sbi_err_map_linux_errno(ret.error);
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
sbi_get_spec_version(void)535*4882a593Smuzhiyun static inline long sbi_get_spec_version(void)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	return __sbi_base_ecall(SBI_EXT_BASE_GET_SPEC_VERSION);
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
sbi_get_firmware_id(void)540*4882a593Smuzhiyun static inline long sbi_get_firmware_id(void)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun 	return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_ID);
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun 
sbi_get_firmware_version(void)545*4882a593Smuzhiyun static inline long sbi_get_firmware_version(void)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION);
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
sbi_send_cpumask_ipi(const struct cpumask * target)550*4882a593Smuzhiyun static void sbi_send_cpumask_ipi(const struct cpumask *target)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun 	struct cpumask hartid_mask;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	riscv_cpuid_to_hartid_mask(target, &hartid_mask);
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	sbi_send_ipi(cpumask_bits(&hartid_mask));
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun static struct riscv_ipi_ops sbi_ipi_ops = {
560*4882a593Smuzhiyun 	.ipi_inject = sbi_send_cpumask_ipi
561*4882a593Smuzhiyun };
562*4882a593Smuzhiyun 
sbi_init(void)563*4882a593Smuzhiyun int __init sbi_init(void)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun 	int ret;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	sbi_set_power_off();
568*4882a593Smuzhiyun 	ret = sbi_get_spec_version();
569*4882a593Smuzhiyun 	if (ret > 0)
570*4882a593Smuzhiyun 		sbi_spec_version = ret;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	pr_info("SBI specification v%lu.%lu detected\n",
573*4882a593Smuzhiyun 		sbi_major_version(), sbi_minor_version());
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	if (!sbi_spec_is_0_1()) {
576*4882a593Smuzhiyun 		pr_info("SBI implementation ID=0x%lx Version=0x%lx\n",
577*4882a593Smuzhiyun 			sbi_get_firmware_id(), sbi_get_firmware_version());
578*4882a593Smuzhiyun 		if (sbi_probe_extension(SBI_EXT_TIME) > 0) {
579*4882a593Smuzhiyun 			__sbi_set_timer = __sbi_set_timer_v02;
580*4882a593Smuzhiyun 			pr_info("SBI v0.2 TIME extension detected\n");
581*4882a593Smuzhiyun 		} else {
582*4882a593Smuzhiyun 			__sbi_set_timer = __sbi_set_timer_v01;
583*4882a593Smuzhiyun 		}
584*4882a593Smuzhiyun 		if (sbi_probe_extension(SBI_EXT_IPI) > 0) {
585*4882a593Smuzhiyun 			__sbi_send_ipi	= __sbi_send_ipi_v02;
586*4882a593Smuzhiyun 			pr_info("SBI v0.2 IPI extension detected\n");
587*4882a593Smuzhiyun 		} else {
588*4882a593Smuzhiyun 			__sbi_send_ipi	= __sbi_send_ipi_v01;
589*4882a593Smuzhiyun 		}
590*4882a593Smuzhiyun 		if (sbi_probe_extension(SBI_EXT_RFENCE) > 0) {
591*4882a593Smuzhiyun 			__sbi_rfence	= __sbi_rfence_v02;
592*4882a593Smuzhiyun 			pr_info("SBI v0.2 RFENCE extension detected\n");
593*4882a593Smuzhiyun 		} else {
594*4882a593Smuzhiyun 			__sbi_rfence	= __sbi_rfence_v01;
595*4882a593Smuzhiyun 		}
596*4882a593Smuzhiyun 	} else {
597*4882a593Smuzhiyun 		__sbi_set_timer = __sbi_set_timer_v01;
598*4882a593Smuzhiyun 		__sbi_send_ipi	= __sbi_send_ipi_v01;
599*4882a593Smuzhiyun 		__sbi_rfence	= __sbi_rfence_v01;
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	riscv_set_ipi_ops(&sbi_ipi_ops);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	return 0;
605*4882a593Smuzhiyun }
606