xref: /freebsd/sys/riscv/riscv/sbi.c (revision 6ec8bf9f)
1ff33210cSMitchell Horne /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3ff33210cSMitchell Horne  *
4ff33210cSMitchell Horne  * Copyright (c) 2019 Mitchell Horne <mhorne@FreeBSD.org>
5c55272fdSJessica Clarke  * Copyright (c) 2021 Jessica Clarke <jrtc27@FreeBSD.org>
6ff33210cSMitchell Horne  *
7ff33210cSMitchell Horne  * Redistribution and use in source and binary forms, with or without
8ff33210cSMitchell Horne  * modification, are permitted provided that the following conditions
9ff33210cSMitchell Horne  * are met:
10ff33210cSMitchell Horne  * 1. Redistributions of source code must retain the above copyright
11ff33210cSMitchell Horne  *    notice, this list of conditions and the following disclaimer.
12ff33210cSMitchell Horne  * 2. Redistributions in binary form must reproduce the above copyright
13ff33210cSMitchell Horne  *    notice, this list of conditions and the following disclaimer in the
14ff33210cSMitchell Horne  *    documentation and/or other materials provided with the distribution.
15ff33210cSMitchell Horne  *
16ff33210cSMitchell Horne  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17ff33210cSMitchell Horne  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ff33210cSMitchell Horne  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ff33210cSMitchell Horne  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20ff33210cSMitchell Horne  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ff33210cSMitchell Horne  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ff33210cSMitchell Horne  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ff33210cSMitchell Horne  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ff33210cSMitchell Horne  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ff33210cSMitchell Horne  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ff33210cSMitchell Horne  * SUCH DAMAGE.
27ff33210cSMitchell Horne  */
28ff33210cSMitchell Horne 
29ff33210cSMitchell Horne #include <sys/param.h>
30ff33210cSMitchell Horne #include <sys/systm.h>
31c55272fdSJessica Clarke #include <sys/bus.h>
32e28d8a5bSJessica Clarke #include <sys/eventhandler.h>
33c55272fdSJessica Clarke #include <sys/kernel.h>
346ec8bf9fSJessica Clarke #include <sys/malloc.h>
35c55272fdSJessica Clarke #include <sys/module.h>
36e28d8a5bSJessica Clarke #include <sys/reboot.h>
37ff33210cSMitchell Horne 
38ff33210cSMitchell Horne #include <machine/md_var.h>
39ff33210cSMitchell Horne #include <machine/sbi.h>
40ff33210cSMitchell Horne 
41a1092942SMitchell Horne /* SBI Implementation-Specific Definitions */
42a1092942SMitchell Horne #define	OPENSBI_VERSION_MAJOR_OFFSET	16
43a1092942SMitchell Horne #define	OPENSBI_VERSION_MINOR_MASK	0xFFFF
44a1092942SMitchell Horne 
45c55272fdSJessica Clarke struct sbi_softc {
46c55272fdSJessica Clarke 	device_t		dev;
47c55272fdSJessica Clarke };
48c55272fdSJessica Clarke 
496ec8bf9fSJessica Clarke struct sbi_devinfo {
506ec8bf9fSJessica Clarke 	struct resource_list	rl;
516ec8bf9fSJessica Clarke };
526ec8bf9fSJessica Clarke 
53c55272fdSJessica Clarke static struct sbi_softc *sbi_softc = NULL;
54c55272fdSJessica Clarke 
55c55272fdSJessica Clarke static u_long sbi_spec_version;
56c55272fdSJessica Clarke static u_long sbi_impl_id;
57c55272fdSJessica Clarke static u_long sbi_impl_version;
58ff33210cSMitchell Horne 
5989f34929SMitchell Horne static bool has_time_extension = false;
6089f34929SMitchell Horne static bool has_ipi_extension = false;
6189f34929SMitchell Horne static bool has_rfnc_extension = false;
629bae4ce6SDanjel Qyteza static bool has_srst_extension = false;
6389f34929SMitchell Horne 
64ff33210cSMitchell Horne static struct sbi_ret
sbi_get_spec_version(void)65ff33210cSMitchell Horne sbi_get_spec_version(void)
66ff33210cSMitchell Horne {
67ff33210cSMitchell Horne 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_SPEC_VERSION));
68ff33210cSMitchell Horne }
69ff33210cSMitchell Horne 
70ff33210cSMitchell Horne static struct sbi_ret
sbi_get_impl_id(void)71ff33210cSMitchell Horne sbi_get_impl_id(void)
72ff33210cSMitchell Horne {
73ff33210cSMitchell Horne 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_ID));
74ff33210cSMitchell Horne }
75ff33210cSMitchell Horne 
76ff33210cSMitchell Horne static struct sbi_ret
sbi_get_impl_version(void)77ff33210cSMitchell Horne sbi_get_impl_version(void)
78ff33210cSMitchell Horne {
79ff33210cSMitchell Horne 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_VERSION));
80ff33210cSMitchell Horne }
81ff33210cSMitchell Horne 
82ff33210cSMitchell Horne static struct sbi_ret
sbi_get_mvendorid(void)83ff33210cSMitchell Horne sbi_get_mvendorid(void)
84ff33210cSMitchell Horne {
85ff33210cSMitchell Horne 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MVENDORID));
86ff33210cSMitchell Horne }
87ff33210cSMitchell Horne 
88ff33210cSMitchell Horne static struct sbi_ret
sbi_get_marchid(void)89ff33210cSMitchell Horne sbi_get_marchid(void)
90ff33210cSMitchell Horne {
91ff33210cSMitchell Horne 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MARCHID));
92ff33210cSMitchell Horne }
93ff33210cSMitchell Horne 
94ff33210cSMitchell Horne static struct sbi_ret
sbi_get_mimpid(void)95ff33210cSMitchell Horne sbi_get_mimpid(void)
96ff33210cSMitchell Horne {
97ff33210cSMitchell Horne 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MIMPID));
98ff33210cSMitchell Horne }
99ff33210cSMitchell Horne 
100e28d8a5bSJessica Clarke static void
sbi_shutdown_final(void * dummy __unused,int howto)101e28d8a5bSJessica Clarke sbi_shutdown_final(void *dummy __unused, int howto)
102e28d8a5bSJessica Clarke {
103e28d8a5bSJessica Clarke 	if ((howto & RB_POWEROFF) != 0)
1049bae4ce6SDanjel Qyteza 		sbi_system_reset(SBI_SRST_TYPE_SHUTDOWN, SBI_SRST_REASON_NONE);
1059bae4ce6SDanjel Qyteza }
1069bae4ce6SDanjel Qyteza 
1079bae4ce6SDanjel Qyteza void
sbi_system_reset(u_long reset_type,u_long reset_reason)1089bae4ce6SDanjel Qyteza sbi_system_reset(u_long reset_type, u_long reset_reason)
1099bae4ce6SDanjel Qyteza {
1109bae4ce6SDanjel Qyteza 	/* Use the SRST extension, if available. */
1119bae4ce6SDanjel Qyteza 	if (has_srst_extension) {
1129bae4ce6SDanjel Qyteza 		(void)SBI_CALL2(SBI_EXT_ID_SRST, SBI_SRST_SYSTEM_RESET,
1139bae4ce6SDanjel Qyteza 		    reset_type, reset_reason);
1149bae4ce6SDanjel Qyteza 	}
1159bae4ce6SDanjel Qyteza 	(void)SBI_CALL0(SBI_SHUTDOWN, 0);
116e28d8a5bSJessica Clarke }
117e28d8a5bSJessica Clarke 
118ff33210cSMitchell Horne void
sbi_print_version(void)119a1092942SMitchell Horne sbi_print_version(void)
120a1092942SMitchell Horne {
121a1092942SMitchell Horne 	u_int major;
122a1092942SMitchell Horne 	u_int minor;
123a1092942SMitchell Horne 
124a1092942SMitchell Horne 	/* For legacy SBI implementations. */
125a1092942SMitchell Horne 	if (sbi_spec_version == 0) {
126a1092942SMitchell Horne 		printf("SBI: Unknown (Legacy) Implementation\n");
127a1092942SMitchell Horne 		printf("SBI Specification Version: 0.1\n");
128a1092942SMitchell Horne 		return;
129a1092942SMitchell Horne 	}
130a1092942SMitchell Horne 
131a1092942SMitchell Horne 	switch (sbi_impl_id) {
132a1092942SMitchell Horne 	case (SBI_IMPL_ID_BBL):
1337c7b8f57SMitchell Horne 		printf("SBI: Berkely Boot Loader %lu\n", sbi_impl_version);
134a1092942SMitchell Horne 		break;
13525de8fb6SMitchell Horne 	case (SBI_IMPL_ID_XVISOR):
136a6405133SMitchell Horne 		printf("SBI: eXtensible Versatile hypervISOR %lu\n",
137a6405133SMitchell Horne 		    sbi_impl_version);
13825de8fb6SMitchell Horne 		break;
13925de8fb6SMitchell Horne 	case (SBI_IMPL_ID_KVM):
140a6405133SMitchell Horne 		printf("SBI: Kernel-based Virtual Machine %lu\n",
141a6405133SMitchell Horne 		    sbi_impl_version);
14225de8fb6SMitchell Horne 		break;
14325de8fb6SMitchell Horne 	case (SBI_IMPL_ID_RUSTSBI):
14425de8fb6SMitchell Horne 		printf("SBI: RustSBI %lu\n", sbi_impl_version);
14525de8fb6SMitchell Horne 		break;
14625de8fb6SMitchell Horne 	case (SBI_IMPL_ID_DIOSIX):
14725de8fb6SMitchell Horne 		printf("SBI: Diosix %lu\n", sbi_impl_version);
14825de8fb6SMitchell Horne 		break;
149a1092942SMitchell Horne 	case (SBI_IMPL_ID_OPENSBI):
150a1092942SMitchell Horne 		major = sbi_impl_version >> OPENSBI_VERSION_MAJOR_OFFSET;
151a1092942SMitchell Horne 		minor = sbi_impl_version & OPENSBI_VERSION_MINOR_MASK;
152a1092942SMitchell Horne 		printf("SBI: OpenSBI v%u.%u\n", major, minor);
153a1092942SMitchell Horne 		break;
154a1092942SMitchell Horne 	default:
1557c7b8f57SMitchell Horne 		printf("SBI: Unrecognized Implementation: %lu\n", sbi_impl_id);
156a1092942SMitchell Horne 		break;
157a1092942SMitchell Horne 	}
158a1092942SMitchell Horne 
159a1092942SMitchell Horne 	major = (sbi_spec_version & SBI_SPEC_VERS_MAJOR_MASK) >>
160a1092942SMitchell Horne 	    SBI_SPEC_VERS_MAJOR_OFFSET;
161a1092942SMitchell Horne 	minor = (sbi_spec_version & SBI_SPEC_VERS_MINOR_MASK);
162a1092942SMitchell Horne 	printf("SBI Specification Version: %u.%u\n", major, minor);
163a1092942SMitchell Horne }
164a1092942SMitchell Horne 
16589f34929SMitchell Horne void
sbi_set_timer(uint64_t val)16689f34929SMitchell Horne sbi_set_timer(uint64_t val)
16789f34929SMitchell Horne {
168a56881d3SJohn Baldwin 	struct sbi_ret ret __diagused;
16989f34929SMitchell Horne 
17089f34929SMitchell Horne 	/* Use the TIME legacy replacement extension, if available. */
17189f34929SMitchell Horne 	if (has_time_extension) {
17289f34929SMitchell Horne 		ret = SBI_CALL1(SBI_EXT_ID_TIME, SBI_TIME_SET_TIMER, val);
17389f34929SMitchell Horne 		MPASS(ret.error == SBI_SUCCESS);
17489f34929SMitchell Horne 	} else {
17589f34929SMitchell Horne 		(void)SBI_CALL1(SBI_SET_TIMER, 0, val);
17689f34929SMitchell Horne 	}
17789f34929SMitchell Horne }
17889f34929SMitchell Horne 
17989f34929SMitchell Horne void
sbi_send_ipi(const u_long * hart_mask)18089f34929SMitchell Horne sbi_send_ipi(const u_long *hart_mask)
18189f34929SMitchell Horne {
182a56881d3SJohn Baldwin 	struct sbi_ret ret __diagused;
18389f34929SMitchell Horne 
18489f34929SMitchell Horne 	/* Use the IPI legacy replacement extension, if available. */
18589f34929SMitchell Horne 	if (has_ipi_extension) {
18689f34929SMitchell Horne 		ret = SBI_CALL2(SBI_EXT_ID_IPI, SBI_IPI_SEND_IPI,
18789f34929SMitchell Horne 		    *hart_mask, 0);
18889f34929SMitchell Horne 		MPASS(ret.error == SBI_SUCCESS);
18989f34929SMitchell Horne 	} else {
19089f34929SMitchell Horne 		(void)SBI_CALL1(SBI_SEND_IPI, 0, (uint64_t)hart_mask);
19189f34929SMitchell Horne 	}
19289f34929SMitchell Horne }
19389f34929SMitchell Horne 
19489f34929SMitchell Horne void
sbi_remote_fence_i(const u_long * hart_mask)19589f34929SMitchell Horne sbi_remote_fence_i(const u_long *hart_mask)
19689f34929SMitchell Horne {
197a56881d3SJohn Baldwin 	struct sbi_ret ret __diagused;
19889f34929SMitchell Horne 
19989f34929SMitchell Horne 	/* Use the RFENCE legacy replacement extension, if available. */
20089f34929SMitchell Horne 	if (has_rfnc_extension) {
20189f34929SMitchell Horne 		ret = SBI_CALL2(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_FENCE_I,
20289f34929SMitchell Horne 		    *hart_mask, 0);
20389f34929SMitchell Horne 		MPASS(ret.error == SBI_SUCCESS);
20489f34929SMitchell Horne 	} else {
20589f34929SMitchell Horne 		(void)SBI_CALL1(SBI_REMOTE_FENCE_I, 0, (uint64_t)hart_mask);
20689f34929SMitchell Horne 	}
20789f34929SMitchell Horne }
20889f34929SMitchell Horne 
20989f34929SMitchell Horne void
sbi_remote_sfence_vma(const u_long * hart_mask,u_long start,u_long size)21089f34929SMitchell Horne sbi_remote_sfence_vma(const u_long *hart_mask, u_long start, u_long size)
21189f34929SMitchell Horne {
212a56881d3SJohn Baldwin 	struct sbi_ret ret __diagused;
21389f34929SMitchell Horne 
21489f34929SMitchell Horne 	/* Use the RFENCE legacy replacement extension, if available. */
21589f34929SMitchell Horne 	if (has_rfnc_extension) {
21689f34929SMitchell Horne 		ret = SBI_CALL4(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_SFENCE_VMA,
21789f34929SMitchell Horne 		    *hart_mask, 0, start, size);
21889f34929SMitchell Horne 		MPASS(ret.error == SBI_SUCCESS);
21989f34929SMitchell Horne 	} else {
22089f34929SMitchell Horne 		(void)SBI_CALL3(SBI_REMOTE_SFENCE_VMA, 0, (uint64_t)hart_mask,
22189f34929SMitchell Horne 		    start, size);
22289f34929SMitchell Horne 	}
22389f34929SMitchell Horne }
22489f34929SMitchell Horne 
22589f34929SMitchell Horne void
sbi_remote_sfence_vma_asid(const u_long * hart_mask,u_long start,u_long size,u_long asid)22689f34929SMitchell Horne sbi_remote_sfence_vma_asid(const u_long *hart_mask, u_long start, u_long size,
22789f34929SMitchell Horne     u_long asid)
22889f34929SMitchell Horne {
229a56881d3SJohn Baldwin 	struct sbi_ret ret __diagused;
23089f34929SMitchell Horne 
23189f34929SMitchell Horne 	/* Use the RFENCE legacy replacement extension, if available. */
23289f34929SMitchell Horne 	if (has_rfnc_extension) {
233a6405133SMitchell Horne 		ret = SBI_CALL5(SBI_EXT_ID_RFNC,
234a6405133SMitchell Horne 		    SBI_RFNC_REMOTE_SFENCE_VMA_ASID, *hart_mask, 0, start,
235a6405133SMitchell Horne 		    size, asid);
23689f34929SMitchell Horne 		MPASS(ret.error == SBI_SUCCESS);
23789f34929SMitchell Horne 	} else {
23889f34929SMitchell Horne 		(void)SBI_CALL4(SBI_REMOTE_SFENCE_VMA_ASID, 0,
23989f34929SMitchell Horne 		    (uint64_t)hart_mask, start, size, asid);
24089f34929SMitchell Horne 	}
24189f34929SMitchell Horne }
24289f34929SMitchell Horne 
243bfe918faSMitchell Horne int
sbi_hsm_hart_start(u_long hart,u_long start_addr,u_long priv)244bfe918faSMitchell Horne sbi_hsm_hart_start(u_long hart, u_long start_addr, u_long priv)
245bfe918faSMitchell Horne {
246bfe918faSMitchell Horne 	struct sbi_ret ret;
247bfe918faSMitchell Horne 
248a6405133SMitchell Horne 	ret = SBI_CALL3(SBI_EXT_ID_HSM, SBI_HSM_HART_START, hart, start_addr,
249a6405133SMitchell Horne 	    priv);
250bfe918faSMitchell Horne 	return (ret.error != 0 ? (int)ret.error : 0);
251bfe918faSMitchell Horne }
252bfe918faSMitchell Horne 
253bfe918faSMitchell Horne void
sbi_hsm_hart_stop(void)254bfe918faSMitchell Horne sbi_hsm_hart_stop(void)
255bfe918faSMitchell Horne {
256bfe918faSMitchell Horne 	(void)SBI_CALL0(SBI_EXT_ID_HSM, SBI_HSM_HART_STOP);
257bfe918faSMitchell Horne }
258bfe918faSMitchell Horne 
259bfe918faSMitchell Horne int
sbi_hsm_hart_status(u_long hart)260bfe918faSMitchell Horne sbi_hsm_hart_status(u_long hart)
261bfe918faSMitchell Horne {
262bfe918faSMitchell Horne 	struct sbi_ret ret;
263bfe918faSMitchell Horne 
264bfe918faSMitchell Horne 	ret = SBI_CALL1(SBI_EXT_ID_HSM, SBI_HSM_HART_STATUS, hart);
265bfe918faSMitchell Horne 
266bfe918faSMitchell Horne 	return (ret.error != 0 ? (int)ret.error : (int)ret.value);
267bfe918faSMitchell Horne }
268bfe918faSMitchell Horne 
269a1092942SMitchell Horne void
sbi_init(void)270ff33210cSMitchell Horne sbi_init(void)
271ff33210cSMitchell Horne {
272ff33210cSMitchell Horne 	struct sbi_ret sret;
273ff33210cSMitchell Horne 
274ff33210cSMitchell Horne 	/*
275ff33210cSMitchell Horne 	 * Get the spec version. For legacy SBI implementations this will
276ff33210cSMitchell Horne 	 * return an error, otherwise it is guaranteed to succeed.
277ff33210cSMitchell Horne 	 */
278ff33210cSMitchell Horne 	sret = sbi_get_spec_version();
279ff33210cSMitchell Horne 	if (sret.error != 0) {
280ff33210cSMitchell Horne 		/* We are running a legacy SBI implementation. */
281ff33210cSMitchell Horne 		sbi_spec_version = 0;
282ff33210cSMitchell Horne 		return;
283ff33210cSMitchell Horne 	}
284ff33210cSMitchell Horne 
285ff33210cSMitchell Horne 	/* Set the SBI implementation info. */
286ff33210cSMitchell Horne 	sbi_spec_version = sret.value;
287ff33210cSMitchell Horne 	sbi_impl_id = sbi_get_impl_id().value;
288ff33210cSMitchell Horne 	sbi_impl_version = sbi_get_impl_version().value;
289ff33210cSMitchell Horne 
290ff33210cSMitchell Horne 	/* Set the hardware implementation info. */
291ff33210cSMitchell Horne 	mvendorid = sbi_get_mvendorid().value;
292ff33210cSMitchell Horne 	marchid = sbi_get_marchid().value;
293ff33210cSMitchell Horne 	mimpid = sbi_get_mimpid().value;
294ff33210cSMitchell Horne 
29589f34929SMitchell Horne 	/* Probe for legacy replacement extensions. */
29689f34929SMitchell Horne 	if (sbi_probe_extension(SBI_EXT_ID_TIME) != 0)
29789f34929SMitchell Horne 		has_time_extension = true;
29889f34929SMitchell Horne 	if (sbi_probe_extension(SBI_EXT_ID_IPI) != 0)
29989f34929SMitchell Horne 		has_ipi_extension = true;
30089f34929SMitchell Horne 	if (sbi_probe_extension(SBI_EXT_ID_RFNC) != 0)
30189f34929SMitchell Horne 		has_rfnc_extension = true;
3029bae4ce6SDanjel Qyteza 	if (sbi_probe_extension(SBI_EXT_ID_SRST) != 0)
3039bae4ce6SDanjel Qyteza 		has_srst_extension = true;
30489f34929SMitchell Horne 
305ff33210cSMitchell Horne 	/*
30689f34929SMitchell Horne 	 * Probe for legacy extensions. We still rely on many of them to be
30789f34929SMitchell Horne 	 * implemented, but this is not guaranteed by the spec.
308ff33210cSMitchell Horne 	 */
30989f34929SMitchell Horne 	KASSERT(has_time_extension || sbi_probe_extension(SBI_SET_TIMER) != 0,
310ff33210cSMitchell Horne 	    ("SBI doesn't implement sbi_set_timer()"));
311ff33210cSMitchell Horne 	KASSERT(sbi_probe_extension(SBI_CONSOLE_PUTCHAR) != 0,
312ff33210cSMitchell Horne 	    ("SBI doesn't implement sbi_console_putchar()"));
313ff33210cSMitchell Horne 	KASSERT(sbi_probe_extension(SBI_CONSOLE_GETCHAR) != 0,
314ff33210cSMitchell Horne 	    ("SBI doesn't implement sbi_console_getchar()"));
31589f34929SMitchell Horne 	KASSERT(has_ipi_extension || sbi_probe_extension(SBI_SEND_IPI) != 0,
316ff33210cSMitchell Horne 	    ("SBI doesn't implement sbi_send_ipi()"));
31789f34929SMitchell Horne 	KASSERT(has_rfnc_extension ||
31889f34929SMitchell Horne 	    sbi_probe_extension(SBI_REMOTE_FENCE_I) != 0,
319ff33210cSMitchell Horne 	    ("SBI doesn't implement sbi_remote_fence_i()"));
32089f34929SMitchell Horne 	KASSERT(has_rfnc_extension ||
32189f34929SMitchell Horne 	    sbi_probe_extension(SBI_REMOTE_SFENCE_VMA) != 0,
322ff33210cSMitchell Horne 	    ("SBI doesn't implement sbi_remote_sfence_vma()"));
32389f34929SMitchell Horne 	KASSERT(has_rfnc_extension ||
32489f34929SMitchell Horne 	    sbi_probe_extension(SBI_REMOTE_SFENCE_VMA_ASID) != 0,
325ff33210cSMitchell Horne 	    ("SBI doesn't implement sbi_remote_sfence_vma_asid()"));
3269bae4ce6SDanjel Qyteza 	KASSERT(has_srst_extension || sbi_probe_extension(SBI_SHUTDOWN) != 0,
3279bae4ce6SDanjel Qyteza 	    ("SBI doesn't implement a shutdown or reset extension"));
328ff33210cSMitchell Horne }
329e28d8a5bSJessica Clarke 
330e28d8a5bSJessica Clarke static void
sbi_identify(driver_t * driver,device_t parent)331c55272fdSJessica Clarke sbi_identify(driver_t *driver, device_t parent)
332e28d8a5bSJessica Clarke {
333c55272fdSJessica Clarke 	device_t dev;
334c55272fdSJessica Clarke 
335c55272fdSJessica Clarke 	if (device_find_child(parent, "sbi", -1) != NULL)
336c55272fdSJessica Clarke 		return;
337c55272fdSJessica Clarke 
338c55272fdSJessica Clarke 	dev = BUS_ADD_CHILD(parent, 0, "sbi", -1);
339c55272fdSJessica Clarke 	if (dev == NULL)
340c55272fdSJessica Clarke 		device_printf(parent, "Can't add sbi child\n");
341e28d8a5bSJessica Clarke }
342e28d8a5bSJessica Clarke 
343c55272fdSJessica Clarke static int
sbi_probe(device_t dev)344c55272fdSJessica Clarke sbi_probe(device_t dev)
345c55272fdSJessica Clarke {
346c55272fdSJessica Clarke 	device_set_desc(dev, "RISC-V Supervisor Binary Interface");
347c55272fdSJessica Clarke 
348c55272fdSJessica Clarke 	return (BUS_PROBE_NOWILDCARD);
349c55272fdSJessica Clarke }
350c55272fdSJessica Clarke 
351c55272fdSJessica Clarke static int
sbi_attach(device_t dev)352c55272fdSJessica Clarke sbi_attach(device_t dev)
353c55272fdSJessica Clarke {
354c55272fdSJessica Clarke 	struct sbi_softc *sc;
3556ec8bf9fSJessica Clarke #ifdef SMP
3566ec8bf9fSJessica Clarke 	device_t child;
3576ec8bf9fSJessica Clarke 	struct sbi_devinfo *di;
3586ec8bf9fSJessica Clarke #endif
359c55272fdSJessica Clarke 
360c55272fdSJessica Clarke 	if (sbi_softc != NULL)
361c55272fdSJessica Clarke 		return (ENXIO);
362c55272fdSJessica Clarke 
363c55272fdSJessica Clarke 	sc = device_get_softc(dev);
364c55272fdSJessica Clarke 	sc->dev = dev;
365c55272fdSJessica Clarke 	sbi_softc = sc;
366c55272fdSJessica Clarke 
367c55272fdSJessica Clarke 	EVENTHANDLER_REGISTER(shutdown_final, sbi_shutdown_final, NULL,
368c55272fdSJessica Clarke 	    SHUTDOWN_PRI_LAST);
369c55272fdSJessica Clarke 
3706ec8bf9fSJessica Clarke #ifdef SMP
3716ec8bf9fSJessica Clarke 	di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO);
3726ec8bf9fSJessica Clarke 	resource_list_init(&di->rl);
3736ec8bf9fSJessica Clarke 	child = device_add_child(dev, "sbi_ipi", -1);
3746ec8bf9fSJessica Clarke 	if (child == NULL) {
3756ec8bf9fSJessica Clarke 		device_printf(dev, "Could not add sbi_ipi child\n");
3766ec8bf9fSJessica Clarke 		return (ENXIO);
3776ec8bf9fSJessica Clarke 	}
3786ec8bf9fSJessica Clarke 
3796ec8bf9fSJessica Clarke 	device_set_ivars(child, di);
3806ec8bf9fSJessica Clarke #endif
3816ec8bf9fSJessica Clarke 
382c55272fdSJessica Clarke 	return (0);
383c55272fdSJessica Clarke }
384c55272fdSJessica Clarke 
3856ec8bf9fSJessica Clarke static struct resource_list *
sbi_get_resource_list(device_t bus,device_t child)3866ec8bf9fSJessica Clarke sbi_get_resource_list(device_t bus, device_t child)
3876ec8bf9fSJessica Clarke {
3886ec8bf9fSJessica Clarke 	struct sbi_devinfo *di;
3896ec8bf9fSJessica Clarke 
3906ec8bf9fSJessica Clarke 	di = device_get_ivars(child);
3916ec8bf9fSJessica Clarke 	KASSERT(di != NULL, ("%s: No devinfo", __func__));
3926ec8bf9fSJessica Clarke 
3936ec8bf9fSJessica Clarke 	return (&di->rl);
3946ec8bf9fSJessica Clarke }
3956ec8bf9fSJessica Clarke 
396c55272fdSJessica Clarke static device_method_t sbi_methods[] = {
397c55272fdSJessica Clarke 	/* Device interface */
398c55272fdSJessica Clarke 	DEVMETHOD(device_identify,	sbi_identify),
399c55272fdSJessica Clarke 	DEVMETHOD(device_probe,		sbi_probe),
400c55272fdSJessica Clarke 	DEVMETHOD(device_attach,	sbi_attach),
401c55272fdSJessica Clarke 
4026ec8bf9fSJessica Clarke 	/* Bus interface */
4036ec8bf9fSJessica Clarke 	DEVMETHOD(bus_alloc_resource,	bus_generic_rl_alloc_resource),
4046ec8bf9fSJessica Clarke 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
4056ec8bf9fSJessica Clarke 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
4066ec8bf9fSJessica Clarke 	DEVMETHOD(bus_release_resource,	bus_generic_rl_release_resource),
4076ec8bf9fSJessica Clarke 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
4086ec8bf9fSJessica Clarke 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
4096ec8bf9fSJessica Clarke 	DEVMETHOD(bus_get_resource_list, sbi_get_resource_list),
4106ec8bf9fSJessica Clarke 	DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
4116ec8bf9fSJessica Clarke 	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
4126ec8bf9fSJessica Clarke 
413c55272fdSJessica Clarke 	DEVMETHOD_END
414c55272fdSJessica Clarke };
415c55272fdSJessica Clarke 
416c55272fdSJessica Clarke DEFINE_CLASS_0(sbi, sbi_driver, sbi_methods, sizeof(struct sbi_softc));
417c55272fdSJessica Clarke EARLY_DRIVER_MODULE(sbi, nexus, sbi_driver, 0, 0,
418c55272fdSJessica Clarke     BUS_PASS_CPU + BUS_PASS_ORDER_FIRST);
419