xref: /openbsd-src/sys/arch/arm64/dev/rtkit.c (revision 44aabc179b474a8312765241465fb752139a1bb1)
1*44aabc17Skettenis /*	$OpenBSD: rtkit.c,v 1.17 2024/10/29 21:19:25 kettenis Exp $	*/
20b0ff99eSkettenis /*
30b0ff99eSkettenis  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
40b0ff99eSkettenis  *
50b0ff99eSkettenis  * Permission to use, copy, modify, and distribute this software for any
60b0ff99eSkettenis  * purpose with or without fee is hereby granted, provided that the above
70b0ff99eSkettenis  * copyright notice and this permission notice appear in all copies.
80b0ff99eSkettenis  *
90b0ff99eSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
100b0ff99eSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110b0ff99eSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
120b0ff99eSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
130b0ff99eSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
140b0ff99eSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
150b0ff99eSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160b0ff99eSkettenis  */
170b0ff99eSkettenis 
180b0ff99eSkettenis #include <sys/param.h>
190b0ff99eSkettenis #include <sys/systm.h>
200b0ff99eSkettenis #include <sys/device.h>
210b0ff99eSkettenis #include <sys/malloc.h>
222f2026fdSkettenis #include <sys/task.h>
230b0ff99eSkettenis 
240b0ff99eSkettenis #include <machine/bus.h>
250b0ff99eSkettenis #include <machine/fdt.h>
260b0ff99eSkettenis 
27b9886d31Skettenis #include <uvm/uvm_extern.h>
28b9886d31Skettenis 
290b0ff99eSkettenis #include <dev/ofw/openfirm.h>
300b0ff99eSkettenis #include <dev/ofw/ofw_misc.h>
310b0ff99eSkettenis #include <dev/ofw/fdt.h>
320b0ff99eSkettenis 
330b0ff99eSkettenis #include <arm64/dev/aplmbox.h>
34d80548acSkettenis #include <arm64/dev/rtkit.h>
350b0ff99eSkettenis 
360b0ff99eSkettenis #define RTKIT_EP_MGMT			0
370b0ff99eSkettenis #define RTKIT_EP_CRASHLOG		1
380b0ff99eSkettenis #define RTKIT_EP_SYSLOG			2
390b0ff99eSkettenis #define RTKIT_EP_DEBUG			3
400b0ff99eSkettenis #define RTKIT_EP_IOREPORT		4
412ed3dc7bSkettenis #define RTKIT_EP_OSLOG			8
422ed3dc7bSkettenis #define RTKIT_EP_UNKNOWN		10
430b0ff99eSkettenis 
440b0ff99eSkettenis #define RTKIT_MGMT_TYPE(x)		(((x) >> 52) & 0xff)
450b0ff99eSkettenis #define RTKIT_MGMT_TYPE_SHIFT		52
460b0ff99eSkettenis 
47c1a14ff8Skettenis #define RTKIT_MGMT_PWR_STATE(x)		(((x) >> 0) & 0xffff)
480b0ff99eSkettenis 
490b0ff99eSkettenis #define RTKIT_MGMT_HELLO		1
500b0ff99eSkettenis #define RTKIT_MGMT_HELLO_ACK		2
510b0ff99eSkettenis #define RTKIT_MGMT_STARTEP		5
520b0ff99eSkettenis #define RTKIT_MGMT_IOP_PWR_STATE	6
530b0ff99eSkettenis #define RTKIT_MGMT_IOP_PWR_STATE_ACK	7
540b0ff99eSkettenis #define RTKIT_MGMT_EPMAP		8
55c1a14ff8Skettenis #define RTKIT_MGMT_AP_PWR_STATE		11
560b0ff99eSkettenis 
570b0ff99eSkettenis #define RTKIT_MGMT_HELLO_MINVER(x)	(((x) >> 0) & 0xffff)
580b0ff99eSkettenis #define RTKIT_MGMT_HELLO_MINVER_SHIFT	0
590b0ff99eSkettenis #define RTKIT_MGMT_HELLO_MAXVER(x)	(((x) >> 16) & 0xffff)
600b0ff99eSkettenis #define RTKIT_MGMT_HELLO_MAXVER_SHIFT	16
610b0ff99eSkettenis 
620b0ff99eSkettenis #define RTKIT_MGMT_STARTEP_EP_SHIFT	32
630b0ff99eSkettenis #define RTKIT_MGMT_STARTEP_START	(1ULL << 1)
640b0ff99eSkettenis 
650b0ff99eSkettenis #define RTKIT_MGMT_EPMAP_LAST		(1ULL << 51)
660b0ff99eSkettenis #define RTKIT_MGMT_EPMAP_BASE(x)	(((x) >> 32) & 0x7)
670b0ff99eSkettenis #define RTKIT_MGMT_EPMAP_BASE_SHIFT	32
680b0ff99eSkettenis #define RTKIT_MGMT_EPMAP_BITMAP(x)	(((x) >> 0) & 0xffffffff)
690b0ff99eSkettenis #define RTKIT_MGMT_EPMAP_MORE		(1ULL << 0)
700b0ff99eSkettenis 
710b0ff99eSkettenis #define RTKIT_BUFFER_REQUEST		1
720b0ff99eSkettenis #define RTKIT_BUFFER_ADDR(x)		(((x) >> 0) & 0xfffffffffff)
730b0ff99eSkettenis #define RTKIT_BUFFER_SIZE(x)		(((x) >> 44) & 0xff)
740b0ff99eSkettenis #define RTKIT_BUFFER_SIZE_SHIFT		44
750b0ff99eSkettenis 
76c1a14ff8Skettenis #define RTKIT_SYSLOG_LOG		5
77b9886d31Skettenis #define RTKIT_SYSLOG_LOG_IDX(x)		(((x) >> 0) & 0xff)
78c1a14ff8Skettenis #define RTKIT_SYSLOG_INIT		8
79b9886d31Skettenis #define RTKIT_SYSLOG_INIT_N_ENTRIES(x)	(((x) >> 0) & 0xff)
80b9886d31Skettenis #define RTKIT_SYSLOG_INIT_MSG_SIZE(x)	(((x) >> 24) & 0xff)
81c1a14ff8Skettenis 
822ec5c635Skettenis #define RTKIT_IOREPORT_UNKNOWN1		8
832ec5c635Skettenis #define RTKIT_IOREPORT_UNKNOWN2		12
842ec5c635Skettenis 
852ed3dc7bSkettenis #define RTKIT_OSLOG_TYPE(x)		(((x) >> 56) & 0xff)
864359fbd8Skettenis #define RTKIT_OSLOG_TYPE_SHIFT		(56 - RTKIT_MGMT_TYPE_SHIFT)
874359fbd8Skettenis #define RTKIT_OSLOG_BUFFER_REQUEST	1
884359fbd8Skettenis #define RTKIT_OSLOG_BUFFER_ADDR(x)	(((x) >> 0) & 0xfffffffff)
894359fbd8Skettenis #define RTKIT_OSLOG_BUFFER_SIZE(x)	(((x) >> 36) & 0xfffff)
904359fbd8Skettenis #define RTKIT_OSLOG_BUFFER_SIZE_SHIFT	36
914359fbd8Skettenis #define RTKIT_OSLOG_UNKNOWN1		3
924359fbd8Skettenis #define RTKIT_OSLOG_UNKNOWN2		4
934359fbd8Skettenis #define RTKIT_OSLOG_UNKNOWN3		5
942ed3dc7bSkettenis 
950b0ff99eSkettenis /* Versions we support. */
960b0ff99eSkettenis #define RTKIT_MINVER			11
970b0ff99eSkettenis #define RTKIT_MAXVER			12
980b0ff99eSkettenis 
99ea87a8bfSkettenis struct rtkit_dmamem {
100ea87a8bfSkettenis 	bus_dmamap_t		rdm_map;
101ea87a8bfSkettenis 	bus_dma_segment_t	rdm_seg;
102ea87a8bfSkettenis 	size_t			rdm_size;
103b9886d31Skettenis 	caddr_t			rdm_kva;
104ea87a8bfSkettenis };
105ea87a8bfSkettenis 
1060b0ff99eSkettenis struct rtkit_state {
1070b0ff99eSkettenis 	struct mbox_channel	*mc;
1082ec5c635Skettenis 	struct rtkit		*rk;
109b9886d31Skettenis 	int			flags;
110b9886d31Skettenis 	char			*crashlog;
1112f2026fdSkettenis 	bus_addr_t		crashlog_addr;
1122f2026fdSkettenis 	bus_size_t		crashlog_size;
1132f2026fdSkettenis 	struct task		crashlog_task;
114b9886d31Skettenis 	char			*ioreport;
1152f2026fdSkettenis 	bus_addr_t		ioreport_addr;
1162f2026fdSkettenis 	bus_size_t		ioreport_size;
1172f2026fdSkettenis 	struct task		ioreport_task;
118b9886d31Skettenis 	char			*oslog;
1192f2026fdSkettenis 	bus_addr_t		oslog_addr;
1202f2026fdSkettenis 	bus_size_t		oslog_size;
1212f2026fdSkettenis 	struct task		oslog_task;
122b9886d31Skettenis 	char			*syslog;
1232f2026fdSkettenis 	bus_addr_t		syslog_addr;
1242f2026fdSkettenis 	bus_size_t		syslog_size;
1252f2026fdSkettenis 	struct task		syslog_task;
126b9886d31Skettenis 	uint8_t			syslog_n_entries;
127b9886d31Skettenis 	uint8_t			syslog_msg_size;
128b9886d31Skettenis 	char			*syslog_msg;
129c1a14ff8Skettenis 	uint16_t		iop_pwrstate;
130c1a14ff8Skettenis 	uint16_t		ap_pwrstate;
1310b0ff99eSkettenis 	uint64_t		epmap;
132d80548acSkettenis 	void			(*callback[32])(void *, uint64_t);
133d80548acSkettenis 	void			*arg[32];
134ea87a8bfSkettenis 	struct rtkit_dmamem	dmamem[32];
135ea87a8bfSkettenis 	int			ndmamem;
1360b0ff99eSkettenis };
1370b0ff99eSkettenis 
1380b0ff99eSkettenis int
1390b0ff99eSkettenis rtkit_recv(struct mbox_channel *mc, struct aplmbox_msg *msg)
1400b0ff99eSkettenis {
141fb1acad1Skettenis 	return mbox_recv(mc, msg, sizeof(*msg));
1420b0ff99eSkettenis }
1430b0ff99eSkettenis 
1440b0ff99eSkettenis int
1451760008aSkettenis rtkit_send(struct rtkit_state *state, uint32_t endpoint,
1460b0ff99eSkettenis     uint64_t type, uint64_t data)
1470b0ff99eSkettenis {
1480b0ff99eSkettenis 	struct aplmbox_msg msg;
1490b0ff99eSkettenis 
1500b0ff99eSkettenis 	msg.data0 = (type << RTKIT_MGMT_TYPE_SHIFT) | data;
1510b0ff99eSkettenis 	msg.data1 = endpoint;
1521760008aSkettenis 
1531760008aSkettenis 	if (state->flags & RK_DEBUG) {
1541760008aSkettenis 		printf("%s: 0x%016llx 0x%02x\n", __func__,
1551760008aSkettenis 		    msg.data0, msg.data1);
1561760008aSkettenis 	}
1571760008aSkettenis 
1581760008aSkettenis 	return mbox_send(state->mc, &msg, sizeof(msg));
1590b0ff99eSkettenis }
1600b0ff99eSkettenis 
1612ec5c635Skettenis bus_addr_t
162b9886d31Skettenis rtkit_alloc(struct rtkit_state *state, bus_size_t size, caddr_t *kvap)
1632ec5c635Skettenis {
164ea87a8bfSkettenis 	struct rtkit *rk = state->rk;
1652ec5c635Skettenis 	bus_dma_segment_t seg;
166f1e4522dSkettenis 	bus_dmamap_t map;
167b9886d31Skettenis 	caddr_t kva;
1682ec5c635Skettenis 	int nsegs;
1692ec5c635Skettenis 
170ea87a8bfSkettenis 	if (state->ndmamem >= nitems(state->dmamem))
171b9886d31Skettenis 		return (bus_addr_t)-1;
172ea87a8bfSkettenis 
1732ec5c635Skettenis 	if (bus_dmamem_alloc(rk->rk_dmat, size, 16384, 0,
1742ec5c635Skettenis 	    &seg, 1, &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO))
1752ec5c635Skettenis 		return (bus_addr_t)-1;
1762ec5c635Skettenis 
177b9886d31Skettenis 	if (bus_dmamem_map(rk->rk_dmat, &seg, 1, size,
178b9886d31Skettenis 	    &kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
179b9886d31Skettenis 		bus_dmamem_free(rk->rk_dmat, &seg, 1);
180b9886d31Skettenis 		return (bus_addr_t)-1;
181b9886d31Skettenis 	}
182b9886d31Skettenis 
183f1e4522dSkettenis 	if (bus_dmamap_create(rk->rk_dmat, size, 1, size, 0,
184f1e4522dSkettenis 	    BUS_DMA_WAITOK, &map)) {
185b9886d31Skettenis 		bus_dmamem_unmap(rk->rk_dmat, kva, size);
186f1e4522dSkettenis 		bus_dmamem_free(rk->rk_dmat, &seg, 1);
187f1e4522dSkettenis 		return (bus_addr_t)-1;
188f1e4522dSkettenis 	}
189f1e4522dSkettenis 
190f1e4522dSkettenis 	if (bus_dmamap_load_raw(rk->rk_dmat, map, &seg, 1, size,
191f1e4522dSkettenis 	    BUS_DMA_WAITOK)) {
192f1e4522dSkettenis 		bus_dmamap_destroy(rk->rk_dmat, map);
193b9886d31Skettenis 		bus_dmamem_unmap(rk->rk_dmat, kva, size);
194f1e4522dSkettenis 		bus_dmamem_free(rk->rk_dmat, &seg, 1);
195f1e4522dSkettenis 		return (bus_addr_t)-1;
196f1e4522dSkettenis 	}
197f1e4522dSkettenis 
198ea87a8bfSkettenis 	if (rk->rk_map) {
199ea87a8bfSkettenis 		if (rk->rk_map(rk->rk_cookie, seg.ds_addr, seg.ds_len)) {
200ea87a8bfSkettenis 			bus_dmamap_unload(rk->rk_dmat, map);
201ea87a8bfSkettenis 			bus_dmamap_destroy(rk->rk_dmat, map);
202b9886d31Skettenis 			bus_dmamem_unmap(rk->rk_dmat, kva, size);
203ea87a8bfSkettenis 			bus_dmamem_free(rk->rk_dmat, &seg, 1);
204ea87a8bfSkettenis 			return (bus_addr_t)-1;
205ea87a8bfSkettenis 		}
206ea87a8bfSkettenis 	}
207ea87a8bfSkettenis 
208ea87a8bfSkettenis 	state->dmamem[state->ndmamem].rdm_map = map;
209ea87a8bfSkettenis 	state->dmamem[state->ndmamem].rdm_seg = seg;
210ea87a8bfSkettenis 	state->dmamem[state->ndmamem].rdm_size = size;
211b9886d31Skettenis 	state->dmamem[state->ndmamem].rdm_kva = kva;
212ea87a8bfSkettenis 	state->ndmamem++;
213ea87a8bfSkettenis 
214b9886d31Skettenis 	*kvap = kva;
215b9886d31Skettenis 	return map->dm_segs[0].ds_addr;
2162ec5c635Skettenis }
2172ec5c635Skettenis 
2180b0ff99eSkettenis int
219d80548acSkettenis rtkit_start(struct rtkit_state *state, uint32_t endpoint)
2200b0ff99eSkettenis {
2210b0ff99eSkettenis 	uint64_t reply;
2220b0ff99eSkettenis 
223d80548acSkettenis 	reply = ((uint64_t)endpoint << RTKIT_MGMT_STARTEP_EP_SHIFT);
2240b0ff99eSkettenis 	reply |= RTKIT_MGMT_STARTEP_START;
2251760008aSkettenis 	return rtkit_send(state, RTKIT_EP_MGMT, RTKIT_MGMT_STARTEP, reply);
2260b0ff99eSkettenis }
2270b0ff99eSkettenis 
2280b0ff99eSkettenis int
2290b0ff99eSkettenis rtkit_handle_mgmt(struct rtkit_state *state, struct aplmbox_msg *msg)
2300b0ff99eSkettenis {
2310b0ff99eSkettenis 	uint64_t minver, maxver, ver;
2320b0ff99eSkettenis 	uint64_t base, bitmap, reply;
233d80548acSkettenis 	uint32_t endpoint;
2340b0ff99eSkettenis 	int error;
2350b0ff99eSkettenis 
2360b0ff99eSkettenis 	switch (RTKIT_MGMT_TYPE(msg->data0)) {
2370b0ff99eSkettenis 	case RTKIT_MGMT_HELLO:
2380b0ff99eSkettenis 		minver = RTKIT_MGMT_HELLO_MINVER(msg->data0);
2390b0ff99eSkettenis 		maxver = RTKIT_MGMT_HELLO_MAXVER(msg->data0);
2400b0ff99eSkettenis 		if (minver > RTKIT_MAXVER) {
2412ec5c635Skettenis 			printf("%s: unsupported minimum firmware version %lld\n",
2422ec5c635Skettenis 			    __func__, minver);
2430b0ff99eSkettenis 			return EINVAL;
2440b0ff99eSkettenis 		}
2450b0ff99eSkettenis 		if (maxver < RTKIT_MINVER) {
2462ec5c635Skettenis 			printf("%s: unsupported maximum firmware version %lld\n",
2472ec5c635Skettenis 			    __func__, maxver);
2480b0ff99eSkettenis 			return EINVAL;
2490b0ff99eSkettenis 		}
2500b0ff99eSkettenis 		ver = min(RTKIT_MAXVER, maxver);
2511760008aSkettenis 		error = rtkit_send(state, RTKIT_EP_MGMT, RTKIT_MGMT_HELLO_ACK,
2520b0ff99eSkettenis 		    (ver << RTKIT_MGMT_HELLO_MINVER_SHIFT) |
2530b0ff99eSkettenis 		    (ver << RTKIT_MGMT_HELLO_MAXVER_SHIFT));
2540b0ff99eSkettenis 		if (error)
2550b0ff99eSkettenis 			return error;
2560b0ff99eSkettenis 		break;
2570b0ff99eSkettenis 	case RTKIT_MGMT_IOP_PWR_STATE_ACK:
258c1a14ff8Skettenis 		state->iop_pwrstate = RTKIT_MGMT_PWR_STATE(msg->data0);
2592f2026fdSkettenis 		wakeup(&state->iop_pwrstate);
2600b0ff99eSkettenis 		break;
261c1a14ff8Skettenis 	case RTKIT_MGMT_AP_PWR_STATE:
262c1a14ff8Skettenis 		state->ap_pwrstate = RTKIT_MGMT_PWR_STATE(msg->data0);
2632f2026fdSkettenis 		wakeup(&state->ap_pwrstate);
264c1a14ff8Skettenis 		break;
2650b0ff99eSkettenis 	case RTKIT_MGMT_EPMAP:
2660b0ff99eSkettenis 		base = RTKIT_MGMT_EPMAP_BASE(msg->data0);
2670b0ff99eSkettenis 		bitmap = RTKIT_MGMT_EPMAP_BITMAP(msg->data0);
2680b0ff99eSkettenis 		state->epmap |= (bitmap << (base * 32));
2690b0ff99eSkettenis 		reply = (base << RTKIT_MGMT_EPMAP_BASE_SHIFT);
2700b0ff99eSkettenis 		if (msg->data0 & RTKIT_MGMT_EPMAP_LAST)
2710b0ff99eSkettenis 			reply |= RTKIT_MGMT_EPMAP_LAST;
2720b0ff99eSkettenis 		else
2730b0ff99eSkettenis 			reply |= RTKIT_MGMT_EPMAP_MORE;
2741760008aSkettenis 		error = rtkit_send(state, RTKIT_EP_MGMT,
2750b0ff99eSkettenis 		    RTKIT_MGMT_EPMAP, reply);
2760b0ff99eSkettenis 		if (error)
2770b0ff99eSkettenis 			return error;
2780b0ff99eSkettenis 		if (msg->data0 & RTKIT_MGMT_EPMAP_LAST) {
279d80548acSkettenis 			for (endpoint = 1; endpoint < 32; endpoint++) {
280d80548acSkettenis 				if ((state->epmap & (1ULL << endpoint)) == 0)
2810b0ff99eSkettenis 					continue;
2820b0ff99eSkettenis 
283d80548acSkettenis 				switch (endpoint) {
2840b0ff99eSkettenis 				case RTKIT_EP_CRASHLOG:
2852ec5c635Skettenis 				case RTKIT_EP_SYSLOG:
2860b0ff99eSkettenis 				case RTKIT_EP_DEBUG:
2870b0ff99eSkettenis 				case RTKIT_EP_IOREPORT:
2882ed3dc7bSkettenis 				case RTKIT_EP_OSLOG:
289d80548acSkettenis 					error = rtkit_start(state, endpoint);
2900b0ff99eSkettenis 					if (error)
2910b0ff99eSkettenis 						return error;
2920b0ff99eSkettenis 					break;
2932ed3dc7bSkettenis 				case RTKIT_EP_UNKNOWN:
2942ed3dc7bSkettenis 					break;
2952ec5c635Skettenis 				default:
2962ec5c635Skettenis 					printf("%s: skipping endpoint %d\n",
2972ec5c635Skettenis 					    __func__, endpoint);
2982ec5c635Skettenis 					break;
2990b0ff99eSkettenis 				}
3000b0ff99eSkettenis 			}
3010b0ff99eSkettenis 		}
3020b0ff99eSkettenis 		break;
3030b0ff99eSkettenis 	default:
3042ec5c635Skettenis 		printf("%s: unhandled management event 0x%016lld\n",
3052ec5c635Skettenis 		    __func__, msg->data0);
3064359fbd8Skettenis 		break;
3070b0ff99eSkettenis 	}
3080b0ff99eSkettenis 
3090b0ff99eSkettenis 	return 0;
3100b0ff99eSkettenis }
3110b0ff99eSkettenis 
312b9886d31Skettenis struct rtkit_crashlog_header {
313b9886d31Skettenis 	uint32_t	fourcc;
314b9886d31Skettenis 	uint32_t	version;
315b9886d31Skettenis 	uint32_t	size;
316b9886d31Skettenis 	uint32_t	flags;
317b9886d31Skettenis 	uint8_t		unknown[16];
318b9886d31Skettenis };
319b9886d31Skettenis 
320b9886d31Skettenis struct rtkit_crashlog_mbx {
321b9886d31Skettenis 	uint64_t	msg1;
322b9886d31Skettenis 	uint64_t	msg0;
323b9886d31Skettenis 	uint32_t	timestamp;
324b9886d31Skettenis 	uint8_t		unknown[4];
325b9886d31Skettenis };
326b9886d31Skettenis 
327b9886d31Skettenis struct rtkit_crashlog_rg8 {
328b9886d31Skettenis 	uint64_t	unknown0;
329b9886d31Skettenis 	uint64_t	reg[31];
330b9886d31Skettenis 	uint64_t	sp;
331b9886d31Skettenis 	uint64_t	pc;
332b9886d31Skettenis 	uint64_t	psr;
333b9886d31Skettenis 	uint64_t	cpacr;
334b9886d31Skettenis 	uint64_t	fpsr;
335b9886d31Skettenis 	uint64_t	fpcr;
336b9886d31Skettenis 	uint64_t	fpreg[64];
337b9886d31Skettenis 	uint64_t	far;
338b9886d31Skettenis 	uint64_t	unknown1;
339b9886d31Skettenis 	uint64_t	esr;
340b9886d31Skettenis 	uint64_t	unknown2;
341b9886d31Skettenis };
342b9886d31Skettenis 
343b9886d31Skettenis #define RTKIT_FOURCC(s)	((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])
344b9886d31Skettenis 
345b9886d31Skettenis void
346b9886d31Skettenis rtkit_crashlog_dump_str(char *buf, size_t size)
347b9886d31Skettenis {
348b9886d31Skettenis 	char *end = buf + size - 1;
349b9886d31Skettenis 	char *newl;
350b9886d31Skettenis 	uint32_t idx;
351b9886d31Skettenis 
352b9886d31Skettenis 	if (size < 5)
353b9886d31Skettenis 		return;
354b9886d31Skettenis 
355b9886d31Skettenis 	idx = lemtoh32((uint32_t *)buf);
356b9886d31Skettenis 	buf += sizeof(uint32_t);
357b9886d31Skettenis 
358b9886d31Skettenis 	*end = 0;
359b9886d31Skettenis 	while (buf < end) {
360b9886d31Skettenis 		if (*buf == 0)
361b9886d31Skettenis 			return;
362b9886d31Skettenis 		newl = memchr(buf, '\n', buf - end);
363b9886d31Skettenis 		if (newl)
364b9886d31Skettenis 			*newl = 0;
365b9886d31Skettenis 		printf("RTKit Cstr %x: %s\n", idx, buf);
366b9886d31Skettenis 		if (!newl)
367b9886d31Skettenis 			return;
368b9886d31Skettenis 		buf = newl + 1;
369b9886d31Skettenis 	}
370b9886d31Skettenis }
371b9886d31Skettenis 
372b9886d31Skettenis void
373b9886d31Skettenis rtkit_crashlog_dump_ver(char *buf, size_t size)
374b9886d31Skettenis {
375b9886d31Skettenis 	char *end = buf + size - 1;
376b9886d31Skettenis 
377b9886d31Skettenis 	if (size < 17)
378b9886d31Skettenis 		return;
379b9886d31Skettenis 
380b9886d31Skettenis 	buf += 16;
381b9886d31Skettenis 
382b9886d31Skettenis 	*end = 0;
383b9886d31Skettenis 	printf("RTKit Cver %s\n", buf);
384b9886d31Skettenis }
385b9886d31Skettenis 
386b9886d31Skettenis void
387b9886d31Skettenis rtkit_crashlog_dump_mbx(char *buf, size_t size)
388b9886d31Skettenis {
389b9886d31Skettenis 	struct rtkit_crashlog_mbx mbx;
390b9886d31Skettenis 	char *end = buf + size;
391b9886d31Skettenis 
392b9886d31Skettenis 	buf += 28;
393b9886d31Skettenis 	size -= 28;
394b9886d31Skettenis 
395b9886d31Skettenis 	while (buf + sizeof(mbx) <= end) {
396b9886d31Skettenis 		memcpy(&mbx, buf, sizeof(mbx));
397b9886d31Skettenis 		printf("RTKit Cmbx: 0x%016llx 0x%016llx @0x%08x\n",
398b9886d31Skettenis 		    mbx.msg0, mbx.msg1, mbx.timestamp);
399b9886d31Skettenis 		buf += sizeof(mbx);
400b9886d31Skettenis 	}
401b9886d31Skettenis }
402b9886d31Skettenis 
403b9886d31Skettenis void
404b9886d31Skettenis rtkit_crashlog_dump_rg8(char *buf, size_t size)
405b9886d31Skettenis {
406b9886d31Skettenis 	struct rtkit_crashlog_rg8 rg8;
407b9886d31Skettenis 	int i;
408b9886d31Skettenis 
409b9886d31Skettenis 	if (size < sizeof(rg8))
410b9886d31Skettenis 		return;
411b9886d31Skettenis 
412b9886d31Skettenis 	memcpy(&rg8, buf, sizeof(rg8));
413b9886d31Skettenis 	printf("RTKit Crg8: psr %016llx\n", rg8.psr);
414b9886d31Skettenis 	printf("RTKit Crg8: pc  %016llx\n", rg8.pc);
415b9886d31Skettenis 	printf("RTKit Crg8: esr %016llx\n", rg8.esr);
416b9886d31Skettenis 	printf("RTKit Crg8: far %016llx\n", rg8.far);
417b9886d31Skettenis 	printf("RTKit Crg8: sp  %016llx\n", rg8.sp);
418b9886d31Skettenis 	for (i = 0; i < nitems(rg8.reg); i++)
419b9886d31Skettenis 		printf("RTKit Crg8: reg[%d] %016llx\n", i, rg8.reg[i]);
420b9886d31Skettenis }
421b9886d31Skettenis 
422b9886d31Skettenis void
423b9886d31Skettenis rtkit_crashlog_dump(char *buf, size_t size)
424b9886d31Skettenis {
425b9886d31Skettenis 	struct rtkit_crashlog_header hdr;
426b9886d31Skettenis 	size_t off;
427b9886d31Skettenis 
428b9886d31Skettenis 	if (size < sizeof(hdr))
429b9886d31Skettenis 		return;
430b9886d31Skettenis 
431b9886d31Skettenis 	memcpy(&hdr, buf, sizeof(hdr));
432b9886d31Skettenis 	if (letoh32(hdr.fourcc) != RTKIT_FOURCC("CLHE")) {
433b9886d31Skettenis 		printf("RTKit: Invalid header\n");
434b9886d31Skettenis 		return;
435b9886d31Skettenis 	}
436b9886d31Skettenis 
437b9886d31Skettenis 	if (letoh32(hdr.size) > size) {
438b9886d31Skettenis 		printf("RTKit: Invalid header size\n");
439b9886d31Skettenis 		return;
440b9886d31Skettenis 	}
441b9886d31Skettenis 
442b9886d31Skettenis 	off = sizeof(hdr);
443b9886d31Skettenis 	while (off < letoh32(hdr.size)) {
444b9886d31Skettenis 		uint32_t fourcc, size;
445b9886d31Skettenis 
446b9886d31Skettenis 		fourcc = lemtoh32((uint32_t *)(buf + off));
447b9886d31Skettenis 		size = lemtoh32((uint32_t *)(buf + off + 12));
448b9886d31Skettenis 		if (fourcc == RTKIT_FOURCC("CLHE"))
449b9886d31Skettenis 			break;
450b9886d31Skettenis 		if (fourcc == RTKIT_FOURCC("Cstr"))
451b9886d31Skettenis 			rtkit_crashlog_dump_str(buf + off + 16, size - 16);
452b9886d31Skettenis 		if (fourcc == RTKIT_FOURCC("Cver"))
453b9886d31Skettenis 			rtkit_crashlog_dump_ver(buf + off + 16, size - 16);
454b9886d31Skettenis 		if (fourcc == RTKIT_FOURCC("Cmbx"))
455b9886d31Skettenis 			rtkit_crashlog_dump_mbx(buf + off + 16, size - 16);
456b9886d31Skettenis 		if (fourcc == RTKIT_FOURCC("Crg8"))
457b9886d31Skettenis 			rtkit_crashlog_dump_rg8(buf + off + 16, size - 16);
458b9886d31Skettenis 		off += size;
459b9886d31Skettenis 	}
460b9886d31Skettenis }
461b9886d31Skettenis 
4622f2026fdSkettenis void
4632f2026fdSkettenis rtkit_handle_crashlog_buffer(void *arg)
4642f2026fdSkettenis {
4652f2026fdSkettenis 	struct rtkit_state *state = arg;
4662f2026fdSkettenis 	struct rtkit *rk = state->rk;
4672f2026fdSkettenis 	bus_addr_t addr = state->crashlog_addr;
4682f2026fdSkettenis 	bus_size_t size = state->crashlog_size;
4692f2026fdSkettenis 
4702f2026fdSkettenis 	if (addr) {
4712f2026fdSkettenis 		paddr_t pa = addr;
4722f2026fdSkettenis 		vaddr_t va;
4732f2026fdSkettenis 
4742f2026fdSkettenis 		if (rk && rk->rk_logmap) {
4752f2026fdSkettenis 			pa = rk->rk_logmap(rk->rk_cookie, addr);
4762f2026fdSkettenis 			if (pa == (paddr_t)-1)
4772f2026fdSkettenis 				return;
4782f2026fdSkettenis 		}
4792f2026fdSkettenis 
4802f2026fdSkettenis 		state->crashlog = km_alloc(size * PAGE_SIZE,
4812f2026fdSkettenis 		    &kv_any, &kp_none, &kd_waitok);
4822f2026fdSkettenis 		va = (vaddr_t)state->crashlog;
4832f2026fdSkettenis 
4842f2026fdSkettenis 		while (size-- > 0) {
4852f2026fdSkettenis 			pmap_kenter_cache(va, pa, PROT_READ,
4862f2026fdSkettenis 			    PMAP_CACHE_CI);
4872f2026fdSkettenis 			va += PAGE_SIZE;
4882f2026fdSkettenis 			pa += PAGE_SIZE;
4892f2026fdSkettenis 		}
4902f2026fdSkettenis 		return;
4912f2026fdSkettenis 	}
4922f2026fdSkettenis 
4932f2026fdSkettenis 	if (rk) {
4942f2026fdSkettenis 		addr = rtkit_alloc(state, size << PAGE_SHIFT,
4952f2026fdSkettenis 		    &state->crashlog);
4962f2026fdSkettenis 		if (addr == (bus_addr_t)-1)
4972f2026fdSkettenis 			return;
4982f2026fdSkettenis 	}
4992f2026fdSkettenis 
5001760008aSkettenis 	rtkit_send(state, RTKIT_EP_CRASHLOG, RTKIT_BUFFER_REQUEST,
5012f2026fdSkettenis 	    (size << RTKIT_BUFFER_SIZE_SHIFT) | addr);
5022f2026fdSkettenis }
5032f2026fdSkettenis 
5040b0ff99eSkettenis int
5050b0ff99eSkettenis rtkit_handle_crashlog(struct rtkit_state *state, struct aplmbox_msg *msg)
5060b0ff99eSkettenis {
5070b0ff99eSkettenis 	bus_addr_t addr;
5080b0ff99eSkettenis 	bus_size_t size;
5090b0ff99eSkettenis 
5100b0ff99eSkettenis 	switch (RTKIT_MGMT_TYPE(msg->data0)) {
5110b0ff99eSkettenis 	case RTKIT_BUFFER_REQUEST:
5120b0ff99eSkettenis 		addr = RTKIT_BUFFER_ADDR(msg->data0);
5130b0ff99eSkettenis 		size = RTKIT_BUFFER_SIZE(msg->data0);
514b9886d31Skettenis 
515b9886d31Skettenis 		if (state->crashlog) {
516b9886d31Skettenis 			char *buf;
517b9886d31Skettenis 
518b9886d31Skettenis 			printf("\nRTKit crashed:\n");
519b9886d31Skettenis 
520b9886d31Skettenis 			buf = malloc(size * PAGE_SIZE, M_TEMP, M_NOWAIT);
521b9886d31Skettenis 			if (buf) {
522b9886d31Skettenis 				memcpy(buf, state->crashlog, size * PAGE_SIZE);
523b9886d31Skettenis 				rtkit_crashlog_dump(buf, size * PAGE_SIZE);
524b9886d31Skettenis 			}
5250b0ff99eSkettenis 			break;
526b9886d31Skettenis 		}
527b9886d31Skettenis 
5282f2026fdSkettenis 		state->crashlog_addr = addr;
5292f2026fdSkettenis 		state->crashlog_size = size;
5302f2026fdSkettenis 		if (cold)
5312f2026fdSkettenis 			rtkit_handle_crashlog_buffer(state);
5322f2026fdSkettenis 		else
5332f2026fdSkettenis 			task_add(systq, &state->crashlog_task);
5340b0ff99eSkettenis 		break;
5350b0ff99eSkettenis 	default:
5362ec5c635Skettenis 		printf("%s: unhandled crashlog event 0x%016llx\n",
5372ec5c635Skettenis 		    __func__, msg->data0);
5384359fbd8Skettenis 		break;
5390b0ff99eSkettenis 	}
5400b0ff99eSkettenis 
5410b0ff99eSkettenis 	return 0;
5420b0ff99eSkettenis }
5430b0ff99eSkettenis 
544b9886d31Skettenis void
545b9886d31Skettenis rtkit_handle_syslog_log(struct rtkit_state *state, struct aplmbox_msg *msg)
546b9886d31Skettenis {
547b9886d31Skettenis 	char context[24];
548b9886d31Skettenis 	size_t syslog_msg_size;
549b9886d31Skettenis 	char *syslog_msg;
550b9886d31Skettenis 	int idx, pos;
551b9886d31Skettenis 
552b9886d31Skettenis 	if ((state->flags & RK_SYSLOG) == 0)
553b9886d31Skettenis 		return;
554b9886d31Skettenis 
5552f2026fdSkettenis 	if (state->syslog_msg == NULL)
5562f2026fdSkettenis 		return;
557b9886d31Skettenis 	idx = RTKIT_SYSLOG_LOG_IDX(msg->data0);
558b9886d31Skettenis 	if (idx > state->syslog_n_entries)
559b9886d31Skettenis 		return;
560b9886d31Skettenis 
561b9886d31Skettenis 	syslog_msg_size = state->syslog_msg_size + 32;
562b9886d31Skettenis 	syslog_msg = state->syslog + (idx * syslog_msg_size + 8);
563b9886d31Skettenis 	memcpy(context, syslog_msg, sizeof(context));
564b9886d31Skettenis 	context[sizeof(context) - 1] = 0;
565b9886d31Skettenis 
566b9886d31Skettenis 	syslog_msg += sizeof(context);
567b9886d31Skettenis 	memcpy(state->syslog_msg, syslog_msg, state->syslog_msg_size);
568b9886d31Skettenis 	state->syslog_msg[state->syslog_msg_size - 1] = 0;
569b9886d31Skettenis 
570b9886d31Skettenis 	pos = strlen(state->syslog_msg) - 1;
571b9886d31Skettenis 	while (pos >= 0) {
572b9886d31Skettenis 		if (state->syslog_msg[pos] != ' ' &&
573b9886d31Skettenis 		    state->syslog_msg[pos] != '\n' &&
574b9886d31Skettenis 		    state->syslog_msg[pos] != '\r')
575b9886d31Skettenis 			break;
576b9886d31Skettenis 		state->syslog_msg[pos--] = 0;
577b9886d31Skettenis 	}
578b9886d31Skettenis 
579b9886d31Skettenis 	printf("RTKit syslog %d: %s:%s\n", idx, context, state->syslog_msg);
580b9886d31Skettenis }
581b9886d31Skettenis 
5822f2026fdSkettenis void
5832f2026fdSkettenis rtkit_handle_syslog_buffer(void *arg)
5842f2026fdSkettenis {
5852f2026fdSkettenis 	struct rtkit_state *state = arg;
5862f2026fdSkettenis 	struct rtkit *rk = state->rk;
5872f2026fdSkettenis 	bus_addr_t addr = state->syslog_addr;
5882f2026fdSkettenis 	bus_size_t size = state->syslog_size;
5892f2026fdSkettenis 
5902f2026fdSkettenis 	if (rk) {
5912f2026fdSkettenis 		addr = rtkit_alloc(state, size << PAGE_SHIFT,
5922f2026fdSkettenis 		    &state->syslog);
5932f2026fdSkettenis 		if (addr == (bus_addr_t)-1)
5942f2026fdSkettenis 			return;
5952f2026fdSkettenis 	}
5962f2026fdSkettenis 
5971760008aSkettenis 	rtkit_send(state, RTKIT_EP_SYSLOG, RTKIT_BUFFER_REQUEST,
5982f2026fdSkettenis 	    (size << RTKIT_BUFFER_SIZE_SHIFT) | addr);
5992f2026fdSkettenis }
6002f2026fdSkettenis 
6010b0ff99eSkettenis int
602c1a14ff8Skettenis rtkit_handle_syslog(struct rtkit_state *state, struct aplmbox_msg *msg)
603c1a14ff8Skettenis {
604c1a14ff8Skettenis 	bus_addr_t addr;
605c1a14ff8Skettenis 	bus_size_t size;
606c1a14ff8Skettenis 	int error;
607c1a14ff8Skettenis 
608c1a14ff8Skettenis 	switch (RTKIT_MGMT_TYPE(msg->data0)) {
609c1a14ff8Skettenis 	case RTKIT_BUFFER_REQUEST:
610c1a14ff8Skettenis 		addr = RTKIT_BUFFER_ADDR(msg->data0);
611c1a14ff8Skettenis 		size = RTKIT_BUFFER_SIZE(msg->data0);
612c1a14ff8Skettenis 		if (addr)
613c1a14ff8Skettenis 			break;
614c1a14ff8Skettenis 
6152f2026fdSkettenis 		state->syslog_addr = addr;
6162f2026fdSkettenis 		state->syslog_size = size;
6172f2026fdSkettenis 		if (cold)
6182f2026fdSkettenis 			rtkit_handle_syslog_buffer(state);
6192f2026fdSkettenis 		else
6202f2026fdSkettenis 			task_add(systq, &state->syslog_task);
621c1a14ff8Skettenis 		break;
622c1a14ff8Skettenis 	case RTKIT_SYSLOG_INIT:
623b9886d31Skettenis 		state->syslog_n_entries =
624b9886d31Skettenis 		    RTKIT_SYSLOG_INIT_N_ENTRIES(msg->data0);
625b9886d31Skettenis 		state->syslog_msg_size =
626b9886d31Skettenis 		    RTKIT_SYSLOG_INIT_MSG_SIZE(msg->data0);
627b9886d31Skettenis 		state->syslog_msg = malloc(state->syslog_msg_size,
6282f2026fdSkettenis 		    M_DEVBUF, M_NOWAIT);
629c1a14ff8Skettenis 		break;
630c1a14ff8Skettenis 	case RTKIT_SYSLOG_LOG:
631b9886d31Skettenis 		rtkit_handle_syslog_log(state, msg);
6321760008aSkettenis 		error = rtkit_send(state, RTKIT_EP_SYSLOG,
633c1a14ff8Skettenis 		    RTKIT_MGMT_TYPE(msg->data0), msg->data0);
634c1a14ff8Skettenis 		if (error)
635c1a14ff8Skettenis 			return error;
636c1a14ff8Skettenis 		break;
637c1a14ff8Skettenis 	default:
638c1a14ff8Skettenis 		printf("%s: unhandled syslog event 0x%016llx\n",
639c1a14ff8Skettenis 		    __func__, msg->data0);
6404359fbd8Skettenis 		break;
641c1a14ff8Skettenis 	}
642c1a14ff8Skettenis 
643c1a14ff8Skettenis 	return 0;
644c1a14ff8Skettenis }
645c1a14ff8Skettenis 
6462f2026fdSkettenis void
6472f2026fdSkettenis rtkit_handle_ioreport_buffer(void *arg)
6482f2026fdSkettenis {
6492f2026fdSkettenis 	struct rtkit_state *state = arg;
6502f2026fdSkettenis 	struct rtkit *rk = state->rk;
6512f2026fdSkettenis 	bus_addr_t addr = state->ioreport_addr;
6522f2026fdSkettenis 	bus_size_t size = state->ioreport_size;
6532f2026fdSkettenis 
6542f2026fdSkettenis 	if (rk) {
6552f2026fdSkettenis 		addr = rtkit_alloc(state, size << PAGE_SHIFT,
6562f2026fdSkettenis 		    &state->ioreport);
6572f2026fdSkettenis 		if (addr == (bus_addr_t)-1)
6582f2026fdSkettenis 			return;
6592f2026fdSkettenis 	}
6602f2026fdSkettenis 
6611760008aSkettenis 	rtkit_send(state, RTKIT_EP_IOREPORT, RTKIT_BUFFER_REQUEST,
6622f2026fdSkettenis 	    (size << RTKIT_BUFFER_SIZE_SHIFT) | addr);
6632f2026fdSkettenis }
6642f2026fdSkettenis 
665c1a14ff8Skettenis int
6660b0ff99eSkettenis rtkit_handle_ioreport(struct rtkit_state *state, struct aplmbox_msg *msg)
6670b0ff99eSkettenis {
6680b0ff99eSkettenis 	bus_addr_t addr;
6690b0ff99eSkettenis 	bus_size_t size;
6700b0ff99eSkettenis 	int error;
6710b0ff99eSkettenis 
6720b0ff99eSkettenis 	switch (RTKIT_MGMT_TYPE(msg->data0)) {
6730b0ff99eSkettenis 	case RTKIT_BUFFER_REQUEST:
6740b0ff99eSkettenis 		addr = RTKIT_BUFFER_ADDR(msg->data0);
6750b0ff99eSkettenis 		size = RTKIT_BUFFER_SIZE(msg->data0);
6760b0ff99eSkettenis 		if (addr)
6770b0ff99eSkettenis 			break;
6780b0ff99eSkettenis 
6792f2026fdSkettenis 		state->ioreport_addr = addr;
6802f2026fdSkettenis 		state->ioreport_size = size;
6812f2026fdSkettenis 		if (cold)
6822f2026fdSkettenis 			rtkit_handle_ioreport_buffer(state);
6832f2026fdSkettenis 		else
6842f2026fdSkettenis 			task_add(systq, &state->ioreport_task);
6852ec5c635Skettenis 		break;
6862ec5c635Skettenis 	case RTKIT_IOREPORT_UNKNOWN1:
6872ec5c635Skettenis 	case RTKIT_IOREPORT_UNKNOWN2:
6882ec5c635Skettenis 		/* These unknown events have to be acked to make progress. */
6891760008aSkettenis 		error = rtkit_send(state, RTKIT_EP_IOREPORT,
6902ec5c635Skettenis 		    RTKIT_MGMT_TYPE(msg->data0), msg->data0);
6910b0ff99eSkettenis 		if (error)
6920b0ff99eSkettenis 			return error;
6930b0ff99eSkettenis 		break;
6940b0ff99eSkettenis 	default:
6952ec5c635Skettenis 		printf("%s: unhandled ioreport event 0x%016llx\n",
6962ec5c635Skettenis 		    __func__, msg->data0);
6974359fbd8Skettenis 		break;
6980b0ff99eSkettenis 	}
6990b0ff99eSkettenis 
7000b0ff99eSkettenis 	return 0;
7010b0ff99eSkettenis }
7020b0ff99eSkettenis 
7032f2026fdSkettenis void
7042f2026fdSkettenis rtkit_handle_oslog_buffer(void *arg)
7052f2026fdSkettenis {
7062f2026fdSkettenis 	struct rtkit_state *state = arg;
7072f2026fdSkettenis 	struct rtkit *rk = state->rk;
7082f2026fdSkettenis 	bus_addr_t addr = state->oslog_addr;
7092f2026fdSkettenis 	bus_size_t size = state->oslog_size;
7102f2026fdSkettenis 
7112f2026fdSkettenis 	if (rk) {
7122f2026fdSkettenis 		addr = rtkit_alloc(state, size, &state->oslog);
7132f2026fdSkettenis 		if (addr == (bus_addr_t)-1)
7142f2026fdSkettenis 			return;
7152f2026fdSkettenis 	}
7162f2026fdSkettenis 
7171760008aSkettenis 	rtkit_send(state, RTKIT_EP_OSLOG,
7182f2026fdSkettenis 	    (RTKIT_OSLOG_BUFFER_REQUEST << RTKIT_OSLOG_TYPE_SHIFT),
7192f2026fdSkettenis 	    (size << RTKIT_OSLOG_BUFFER_SIZE_SHIFT) | (addr >> PAGE_SHIFT));
7202f2026fdSkettenis }
7212f2026fdSkettenis 
7220b0ff99eSkettenis int
7232ed3dc7bSkettenis rtkit_handle_oslog(struct rtkit_state *state, struct aplmbox_msg *msg)
7242ed3dc7bSkettenis {
7254359fbd8Skettenis 	bus_addr_t addr;
7264359fbd8Skettenis 	bus_size_t size;
7272ed3dc7bSkettenis 
7282ed3dc7bSkettenis 	switch (RTKIT_OSLOG_TYPE(msg->data0)) {
7294359fbd8Skettenis 	case RTKIT_OSLOG_BUFFER_REQUEST:
7304359fbd8Skettenis 		addr = RTKIT_OSLOG_BUFFER_ADDR(msg->data0) << PAGE_SHIFT;
7314359fbd8Skettenis 		size = RTKIT_OSLOG_BUFFER_SIZE(msg->data0);
7324359fbd8Skettenis 		if (addr)
7334359fbd8Skettenis 			break;
7344359fbd8Skettenis 
7352f2026fdSkettenis 		state->oslog_addr = addr;
7362f2026fdSkettenis 		state->oslog_size = size;
7372f2026fdSkettenis 		if (cold)
7382f2026fdSkettenis 			rtkit_handle_oslog_buffer(state);
7392f2026fdSkettenis 		else
7402f2026fdSkettenis 			task_add(systq, &state->oslog_task);
7412ed3dc7bSkettenis 		break;
7424359fbd8Skettenis 	case RTKIT_OSLOG_UNKNOWN1:
7434359fbd8Skettenis 	case RTKIT_OSLOG_UNKNOWN2:
7444359fbd8Skettenis 	case RTKIT_OSLOG_UNKNOWN3:
7454359fbd8Skettenis 		break;
7462ed3dc7bSkettenis 	default:
7472ed3dc7bSkettenis 		printf("%s: unhandled oslog event 0x%016llx\n",
7482ed3dc7bSkettenis 		    __func__, msg->data0);
7494359fbd8Skettenis 		break;
7502ed3dc7bSkettenis 	}
7512ed3dc7bSkettenis 
7522ed3dc7bSkettenis 	return 0;
7532ed3dc7bSkettenis }
7542ed3dc7bSkettenis 
7552ed3dc7bSkettenis int
756d80548acSkettenis rtkit_poll(struct rtkit_state *state)
7570b0ff99eSkettenis {
758d80548acSkettenis 	struct mbox_channel *mc = state->mc;
7590b0ff99eSkettenis 	struct aplmbox_msg msg;
760d80548acSkettenis 	void (*callback)(void *, uint64_t);
761d80548acSkettenis 	void *arg;
762d80548acSkettenis 	uint32_t endpoint;
7630b0ff99eSkettenis 	int error;
7640b0ff99eSkettenis 
765d80548acSkettenis 	error = rtkit_recv(mc, &msg);
7660b0ff99eSkettenis 	if (error)
7670b0ff99eSkettenis 		return error;
7680b0ff99eSkettenis 
7691760008aSkettenis 	if (state->flags & RK_DEBUG) {
7701760008aSkettenis 		printf("%s: 0x%016llx 0x%02x\n", __func__,
7711760008aSkettenis 		    msg.data0, msg.data1);
7721760008aSkettenis 	}
7731760008aSkettenis 
774d80548acSkettenis 	endpoint = msg.data1;
775d80548acSkettenis 	switch (endpoint) {
7760b0ff99eSkettenis 	case RTKIT_EP_MGMT:
777d80548acSkettenis 		error = rtkit_handle_mgmt(state, &msg);
7780b0ff99eSkettenis 		if (error)
7790b0ff99eSkettenis 			return error;
7800b0ff99eSkettenis 		break;
7810b0ff99eSkettenis 	case RTKIT_EP_CRASHLOG:
782d80548acSkettenis 		error = rtkit_handle_crashlog(state, &msg);
7830b0ff99eSkettenis 		if (error)
7840b0ff99eSkettenis 			return error;
7850b0ff99eSkettenis 		break;
786c1a14ff8Skettenis 	case RTKIT_EP_SYSLOG:
787c1a14ff8Skettenis 		error = rtkit_handle_syslog(state, &msg);
788c1a14ff8Skettenis 		if (error)
789c1a14ff8Skettenis 			return error;
790c1a14ff8Skettenis 		break;
7910b0ff99eSkettenis 	case RTKIT_EP_IOREPORT:
792d80548acSkettenis 		error = rtkit_handle_ioreport(state, &msg);
7930b0ff99eSkettenis 		if (error)
7940b0ff99eSkettenis 			return error;
7950b0ff99eSkettenis 		break;
7962ed3dc7bSkettenis 	case RTKIT_EP_OSLOG:
7972ed3dc7bSkettenis 		error = rtkit_handle_oslog(state, &msg);
7982ed3dc7bSkettenis 		if (error)
7992ed3dc7bSkettenis 			return error;
8002ed3dc7bSkettenis 		break;
8010b0ff99eSkettenis 	default:
802d80548acSkettenis 		if (endpoint >= 32 && endpoint < 64 &&
803d80548acSkettenis 		    state->callback[endpoint - 32]) {
804d80548acSkettenis 			callback = state->callback[endpoint - 32];
805d80548acSkettenis 			arg = state->arg[endpoint - 32];
806d80548acSkettenis 			callback(arg, msg.data0);
807d80548acSkettenis 			break;
808d80548acSkettenis 		}
809d80548acSkettenis 
8102ec5c635Skettenis 		printf("%s: unhandled endpoint %d\n", __func__, msg.data1);
8114359fbd8Skettenis 		break;
8120b0ff99eSkettenis 	}
8130b0ff99eSkettenis 
8140b0ff99eSkettenis 	return 0;
8150b0ff99eSkettenis }
816d80548acSkettenis 
817d80548acSkettenis void
818d80548acSkettenis rtkit_rx_callback(void *cookie)
819d80548acSkettenis {
820d80548acSkettenis 	rtkit_poll(cookie);
821d80548acSkettenis }
822d80548acSkettenis 
823d80548acSkettenis struct rtkit_state *
8243b6109e0Skettenis rtkit_init(int node, const char *name, int flags, struct rtkit *rk)
825d80548acSkettenis {
826d80548acSkettenis 	struct rtkit_state *state;
827d80548acSkettenis 	struct mbox_client client;
828d80548acSkettenis 
829d80548acSkettenis 	state = malloc(sizeof(*state), M_DEVBUF, M_WAITOK | M_ZERO);
830d80548acSkettenis 	client.mc_rx_callback = rtkit_rx_callback;
831d80548acSkettenis 	client.mc_rx_arg = state;
8323b6109e0Skettenis 	if (flags & RK_WAKEUP)
833527291f8Sjsg 		client.mc_flags = MC_WAKEUP;
834527291f8Sjsg 	else
835527291f8Sjsg 		client.mc_flags = 0;
8363b6109e0Skettenis 
837d80548acSkettenis 	state->mc = mbox_channel(node, name, &client);
838d80548acSkettenis 	if (state->mc == NULL) {
839d80548acSkettenis 		free(state, M_DEVBUF, sizeof(*state));
840d80548acSkettenis 		return NULL;
841d80548acSkettenis 	}
8422ec5c635Skettenis 	state->rk = rk;
843b9886d31Skettenis 	state->flags = flags;
844d80548acSkettenis 
845c1a14ff8Skettenis 	state->iop_pwrstate = RTKIT_MGMT_PWR_STATE_SLEEP;
846c1a14ff8Skettenis 	state->ap_pwrstate = RTKIT_MGMT_PWR_STATE_QUIESCED;
847c1a14ff8Skettenis 
8482f2026fdSkettenis 	task_set(&state->crashlog_task, rtkit_handle_crashlog_buffer, state);
8492f2026fdSkettenis 	task_set(&state->syslog_task, rtkit_handle_syslog_buffer, state);
8502f2026fdSkettenis 	task_set(&state->ioreport_task, rtkit_handle_ioreport_buffer, state);
8512f2026fdSkettenis 	task_set(&state->oslog_task, rtkit_handle_oslog_buffer, state);
8522f2026fdSkettenis 
853d80548acSkettenis 	return state;
854d80548acSkettenis }
855d80548acSkettenis 
856d80548acSkettenis int
857d80548acSkettenis rtkit_boot(struct rtkit_state *state)
858d80548acSkettenis {
859*44aabc17Skettenis 	int error;
860*44aabc17Skettenis 
861d80548acSkettenis 	/* Wake up! */
862*44aabc17Skettenis 	error = rtkit_set_iop_pwrstate(state, RTKIT_MGMT_PWR_STATE_INIT);
863*44aabc17Skettenis 	if (error)
864*44aabc17Skettenis 		return error;
865*44aabc17Skettenis 
866*44aabc17Skettenis 	return rtkit_set_ap_pwrstate(state, RTKIT_MGMT_PWR_STATE_ON);
867c1a14ff8Skettenis }
868c1a14ff8Skettenis 
86919c18994Skettenis void
87019c18994Skettenis rtkit_shutdown(struct rtkit_state *state)
87119c18994Skettenis {
872ea87a8bfSkettenis 	struct rtkit *rk = state->rk;
873ea87a8bfSkettenis 	int i;
87419c18994Skettenis 
87519c18994Skettenis 	rtkit_set_ap_pwrstate(state, RTKIT_MGMT_PWR_STATE_QUIESCED);
876fb1acad1Skettenis 	rtkit_set_iop_pwrstate(state, RTKIT_MGMT_PWR_STATE_SLEEP);
87719c18994Skettenis 
87819c18994Skettenis 	KASSERT(state->iop_pwrstate == RTKIT_MGMT_PWR_STATE_SLEEP);
87919c18994Skettenis 	KASSERT(state->ap_pwrstate == RTKIT_MGMT_PWR_STATE_QUIESCED);
88019c18994Skettenis 	state->epmap = 0;
881ea87a8bfSkettenis 
882b9886d31Skettenis 	state->crashlog = NULL;
883b9886d31Skettenis 	state->ioreport = NULL;
884b9886d31Skettenis 	state->oslog = NULL;
885b9886d31Skettenis 	state->syslog = NULL;
886b9886d31Skettenis 
887ea87a8bfSkettenis 	/* Clean up our memory allocations. */
888ea87a8bfSkettenis 	for (i = 0; i < state->ndmamem; i++) {
889ea87a8bfSkettenis 		if (rk->rk_unmap) {
890ea87a8bfSkettenis 			rk->rk_unmap(rk->rk_cookie,
891ea87a8bfSkettenis 			    state->dmamem[i].rdm_seg.ds_addr,
892ea87a8bfSkettenis 			    state->dmamem[i].rdm_seg.ds_len);
893ea87a8bfSkettenis 		}
894ea87a8bfSkettenis 		bus_dmamap_unload(rk->rk_dmat, state->dmamem[i].rdm_map);
895ea87a8bfSkettenis 		bus_dmamap_destroy(rk->rk_dmat, state->dmamem[i].rdm_map);
896b9886d31Skettenis 		bus_dmamem_unmap(rk->rk_dmat, state->dmamem[i].rdm_kva,
897b9886d31Skettenis 		    state->dmamem[i].rdm_size);
898ea87a8bfSkettenis 		bus_dmamem_free(rk->rk_dmat, &state->dmamem[i].rdm_seg, 1);
899ea87a8bfSkettenis 	}
900ea87a8bfSkettenis 	state->ndmamem = 0;
90119c18994Skettenis }
90219c18994Skettenis 
903c1a14ff8Skettenis int
904c1a14ff8Skettenis rtkit_set_ap_pwrstate(struct rtkit_state *state, uint16_t pwrstate)
905c1a14ff8Skettenis {
906fb1acad1Skettenis 	int error, timo;
907c1a14ff8Skettenis 
908c1a14ff8Skettenis 	if (state->ap_pwrstate == pwrstate)
909c1a14ff8Skettenis 		return 0;
910c1a14ff8Skettenis 
9111760008aSkettenis 	error = rtkit_send(state, RTKIT_EP_MGMT, RTKIT_MGMT_AP_PWR_STATE,
912c1a14ff8Skettenis 	    pwrstate);
913c1a14ff8Skettenis 	if (error)
914c1a14ff8Skettenis 		return error;
915c1a14ff8Skettenis 
9162f2026fdSkettenis 	if (cold) {
917fb1acad1Skettenis 		for (timo = 0; timo < 100000; timo++) {
918fb1acad1Skettenis 			error = rtkit_poll(state);
919fb1acad1Skettenis 			if (error == EWOULDBLOCK) {
920fb1acad1Skettenis 				delay(10);
921fb1acad1Skettenis 				continue;
922fb1acad1Skettenis 			}
9234359fbd8Skettenis 			if (error)
9244359fbd8Skettenis 				return error;
925d80548acSkettenis 
926fb1acad1Skettenis 			if (state->ap_pwrstate == pwrstate)
9272f2026fdSkettenis 				return 0;
9282f2026fdSkettenis 		}
929fb1acad1Skettenis 	}
930fb1acad1Skettenis 
9312f2026fdSkettenis 	while (state->ap_pwrstate != pwrstate) {
9322f2026fdSkettenis 		error = tsleep_nsec(&state->ap_pwrstate, PWAIT, "appwr",
9332f2026fdSkettenis 		    SEC_TO_NSEC(1));
9342f2026fdSkettenis 		if (error)
935fb1acad1Skettenis 			return error;
936fb1acad1Skettenis 	}
937fb1acad1Skettenis 
9382f2026fdSkettenis 	return 0;
9392f2026fdSkettenis }
9402f2026fdSkettenis 
941fb1acad1Skettenis int
942fb1acad1Skettenis rtkit_set_iop_pwrstate(struct rtkit_state *state, uint16_t pwrstate)
943fb1acad1Skettenis {
944fb1acad1Skettenis 	int error, timo;
945fb1acad1Skettenis 
9462f2026fdSkettenis 	if (state->iop_pwrstate == (pwrstate & 0xff))
947d80548acSkettenis 		return 0;
948fb1acad1Skettenis 
9491760008aSkettenis 	error = rtkit_send(state, RTKIT_EP_MGMT, RTKIT_MGMT_IOP_PWR_STATE,
950fb1acad1Skettenis 	    pwrstate);
951fb1acad1Skettenis 	if (error)
952fb1acad1Skettenis 		return error;
953fb1acad1Skettenis 
9542f2026fdSkettenis 	if (cold) {
955fb1acad1Skettenis 		for (timo = 0; timo < 100000; timo++) {
956fb1acad1Skettenis 			error = rtkit_poll(state);
957fb1acad1Skettenis 			if (error == EWOULDBLOCK) {
958fb1acad1Skettenis 				delay(10);
959fb1acad1Skettenis 				continue;
960fb1acad1Skettenis 			}
9614359fbd8Skettenis 			if (error)
9624359fbd8Skettenis 				return error;
963fb1acad1Skettenis 
964b9886d31Skettenis 			if (state->iop_pwrstate == (pwrstate & 0xff))
9652f2026fdSkettenis 				return 0;
9662f2026fdSkettenis 		}
967fb1acad1Skettenis 	}
968fb1acad1Skettenis 
9692f2026fdSkettenis 	while (state->iop_pwrstate != (pwrstate & 0xff)) {
9702f2026fdSkettenis 		error = tsleep_nsec(&state->iop_pwrstate, PWAIT, "ioppwr",
9712f2026fdSkettenis 		    SEC_TO_NSEC(1));
9722f2026fdSkettenis 		if (error)
973fb1acad1Skettenis 			return error;
974d80548acSkettenis 	}
975d80548acSkettenis 
9762f2026fdSkettenis 	return 0;
9772f2026fdSkettenis }
9782f2026fdSkettenis 
979d80548acSkettenis int
980d80548acSkettenis rtkit_start_endpoint(struct rtkit_state *state, uint32_t endpoint,
981d80548acSkettenis     void (*callback)(void *, uint64_t), void *arg)
982d80548acSkettenis {
983d80548acSkettenis 	if (endpoint < 32 || endpoint >= 64)
984d80548acSkettenis 		return EINVAL;
985d80548acSkettenis 
986d80548acSkettenis 	if ((state->epmap & (1ULL << endpoint)) == 0)
987d80548acSkettenis 		return EINVAL;
988d80548acSkettenis 
989d80548acSkettenis 	state->callback[endpoint - 32] = callback;
990d80548acSkettenis 	state->arg[endpoint - 32] = arg;
991d80548acSkettenis 	return rtkit_start(state, endpoint);
992d80548acSkettenis }
993d80548acSkettenis 
994d80548acSkettenis int
995d80548acSkettenis rtkit_send_endpoint(struct rtkit_state *state, uint32_t endpoint,
996d80548acSkettenis     uint64_t data)
997d80548acSkettenis {
9981760008aSkettenis 	return rtkit_send(state, endpoint, 0, data);
999d80548acSkettenis }
1000