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
sbi_ecall(int ext,int fid,unsigned long arg0,unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5)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
sbi_sse_read_attrs_raw(unsigned long event_id,unsigned long base_attr_id,unsigned long attr_count,unsigned long phys_lo,unsigned long phys_hi)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
sbi_sse_read_attrs(unsigned long event_id,unsigned long base_attr_id,unsigned long attr_count,unsigned long * values)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
sbi_sse_write_attrs_raw(unsigned long event_id,unsigned long base_attr_id,unsigned long attr_count,unsigned long phys_lo,unsigned long phys_hi)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
sbi_sse_write_attrs(unsigned long event_id,unsigned long base_attr_id,unsigned long attr_count,unsigned long * values)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
sbi_sse_register_raw(unsigned long event_id,unsigned long entry_pc,unsigned long entry_arg)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
sbi_sse_register(unsigned long event_id,struct sbi_sse_handler_arg * arg)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
sbi_sse_unregister(unsigned long event_id)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
sbi_sse_enable(unsigned long event_id)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
sbi_sse_disable(unsigned long event_id)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
sbi_sse_hart_mask(void)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
sbi_sse_hart_unmask(void)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
sbi_sse_inject(unsigned long event_id,unsigned long hart_id)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
sbi_fwft_set_raw(unsigned long feature,unsigned long value,unsigned long flags)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
sbi_fwft_set(uint32_t feature,unsigned long value,unsigned long flags)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
sbi_fwft_get_raw(unsigned long feature)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
sbi_fwft_get(uint32_t feature)125 struct sbiret sbi_fwft_get(uint32_t feature)
126 {
127 return sbi_fwft_get_raw(feature);
128 }
129
sbi_shutdown(bool passed)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
sbi_hart_start(unsigned long hartid,unsigned long entry,unsigned long sp)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
sbi_hart_stop(void)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
sbi_hart_get_status(unsigned long hartid)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
sbi_send_ipi(unsigned long hart_mask,unsigned long hart_mask_base)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
sbi_send_ipi_cpu(int cpu)156 struct sbiret sbi_send_ipi_cpu(int cpu)
157 {
158 return sbi_send_ipi(1UL, cpus[cpu].hartid);
159 }
160
sbi_send_ipi_broadcast(void)161 struct sbiret sbi_send_ipi_broadcast(void)
162 {
163 return sbi_send_ipi(0, -1UL);
164 }
165
sbi_send_ipi_cpumask(const cpumask_t * mask)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
sbi_set_timer(unsigned long stime_value)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
sbi_get_imp_version(void)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
sbi_get_imp_id(void)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
__sbi_get_imp_version(void)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
__sbi_get_imp_id(void)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
sbi_get_spec_version(void)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
sbi_probe(int ext)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