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_shutdown(void)110 void sbi_shutdown(void)
111 {
112 sbi_ecall(SBI_EXT_SRST, 0, 0, 0, 0, 0, 0, 0);
113 puts("SBI shutdown failed!\n");
114 }
115
sbi_hart_start(unsigned long hartid,unsigned long entry,unsigned long sp)116 struct sbiret sbi_hart_start(unsigned long hartid, unsigned long entry, unsigned long sp)
117 {
118 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, entry, sp, 0, 0, 0);
119 }
120
sbi_hart_stop(void)121 struct sbiret sbi_hart_stop(void)
122 {
123 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0);
124 }
125
sbi_hart_get_status(unsigned long hartid)126 struct sbiret sbi_hart_get_status(unsigned long hartid)
127 {
128 return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS, hartid, 0, 0, 0, 0, 0);
129 }
130
sbi_send_ipi(unsigned long hart_mask,unsigned long hart_mask_base)131 struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base)
132 {
133 return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0);
134 }
135
sbi_send_ipi_cpu(int cpu)136 struct sbiret sbi_send_ipi_cpu(int cpu)
137 {
138 return sbi_send_ipi(1UL, cpus[cpu].hartid);
139 }
140
sbi_send_ipi_broadcast(void)141 struct sbiret sbi_send_ipi_broadcast(void)
142 {
143 return sbi_send_ipi(0, -1UL);
144 }
145
sbi_send_ipi_cpumask(const cpumask_t * mask)146 struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask)
147 {
148 struct sbiret ret;
149 cpumask_t tmp;
150
151 if (cpumask_full(mask))
152 return sbi_send_ipi_broadcast();
153
154 cpumask_copy(&tmp, mask);
155
156 while (!cpumask_empty(&tmp)) {
157 unsigned long base = ULONG_MAX;
158 unsigned long mask = 0;
159 int cpu;
160
161 for_each_cpu(cpu, &tmp) {
162 if (base > cpus[cpu].hartid)
163 base = cpus[cpu].hartid;
164 }
165
166 for_each_cpu(cpu, &tmp) {
167 if (cpus[cpu].hartid < base + BITS_PER_LONG) {
168 mask |= 1UL << (cpus[cpu].hartid - base);
169 cpumask_clear_cpu(cpu, &tmp);
170 }
171 }
172
173 ret = sbi_send_ipi(mask, base);
174 if (ret.error)
175 break;
176 }
177
178 return ret;
179 }
180
sbi_set_timer(unsigned long stime_value)181 struct sbiret sbi_set_timer(unsigned long stime_value)
182 {
183 return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0);
184 }
185
sbi_get_imp_version(void)186 struct sbiret sbi_get_imp_version(void)
187 {
188 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_VERSION, 0, 0, 0, 0, 0, 0);
189 }
190
sbi_get_imp_id(void)191 struct sbiret sbi_get_imp_id(void)
192 {
193 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_ID, 0, 0, 0, 0, 0, 0);
194 }
195
__sbi_get_imp_version(void)196 unsigned long __sbi_get_imp_version(void)
197 {
198 struct sbiret ret;
199
200 ret = sbi_get_imp_version();
201 assert(!ret.error);
202
203 return ret.value;
204 }
205
__sbi_get_imp_id(void)206 unsigned long __sbi_get_imp_id(void)
207 {
208 struct sbiret ret;
209
210 ret = sbi_get_imp_id();
211 assert(!ret.error);
212
213 return ret.value;
214 }
215
sbi_get_spec_version(void)216 struct sbiret sbi_get_spec_version(void)
217 {
218 return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0);
219 }
220
sbi_probe(int ext)221 long sbi_probe(int ext)
222 {
223 struct sbiret ret;
224
225 ret = sbi_get_spec_version();
226 assert(!ret.error && (ret.value & SBI_SPEC_VERSION_MASK) >= sbi_mk_version(0, 2));
227
228 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0);
229 assert(!ret.error);
230
231 return ret.value;
232 }
233