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