diff options
Diffstat (limited to 'sys/arch/arm64/dev')
-rw-r--r-- | sys/arch/arm64/dev/aplns.c | 77 | ||||
-rw-r--r-- | sys/arch/arm64/dev/rtkit.c | 293 | ||||
-rw-r--r-- | sys/arch/arm64/dev/rtkit.h | 3 |
3 files changed, 364 insertions, 9 deletions
diff --git a/sys/arch/arm64/dev/aplns.c b/sys/arch/arm64/dev/aplns.c index 11c16805e36..846df28ab2e 100644 --- a/sys/arch/arm64/dev/aplns.c +++ b/sys/arch/arm64/dev/aplns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aplns.c,v 1.6 2021/12/09 11:38:27 kettenis Exp $ */ +/* $OpenBSD: aplns.c,v 1.7 2021/12/19 23:47:24 kettenis Exp $ */ /* * Copyright (c) 2014, 2021 David Gwynne <dlg@openbsd.org> * @@ -40,7 +40,20 @@ #include <dev/ic/nvmereg.h> #include <dev/ic/nvmevar.h> +#include <arm64/dev/rtkit.h> + +#define ANS_CPU_CTRL 0x0044 +#define ANS_CPU_CTRL_RUN (1 << 4) + +#define ANS_MAX_PEND_CMDS_CTRL 0x01210 +#define ANS_MAX_QUEUE_DEPTH 64 +#define ANS_BOOT_STATUS 0x01300 +#define ANS_BOOT_STATUS_OK 0xde71ce55 #define ANS_MODESEL_REG 0x01304 +#define ANS_UNKNOWN_CTRL 0x24008 +#define ANS_PRP_NULL_CHECK (1 << 11) +#define ANS_LINEAR_SQ_CTRL 0x24908 +#define ANS_LINEAR_SQ_CTRL_EN (1 << 0) #define ANS_LINEAR_ASQ_DB 0x2490c #define ANS_LINEAR_IOSQ_DB 0x24910 @@ -100,7 +113,10 @@ aplns_attach(struct device *parent, struct device *self, void *aux) struct nvme_ans_softc { struct nvme_softc asc_nvme; + bus_space_tag_t asc_iot; + bus_space_handle_t asc_ioh; + struct mbox_channel *asc_mbox; struct nvme_dmamem *asc_nvmmu; }; @@ -156,13 +172,25 @@ nvme_ans_attach(struct device *parent, struct device *self, void *aux) struct nvme_ans_softc *asc = (struct nvme_ans_softc *)self; struct nvme_softc *sc = &asc->asc_nvme; struct fdt_attach_args *faa = aux; + uint32_t ctrl, status; - printf(": "); + if (faa->fa_nreg < 2) { + printf(": no registers\n"); + return; + } - if (bus_space_map(faa->fa_iot, - faa->fa_reg[0].addr, faa->fa_reg[0].size, - 0, &sc->sc_ioh) != 0) { - printf("unable to map registers\n"); + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh) != 0) { + printf(": can't map registers\n"); + return; + } + + asc->asc_iot = faa->fa_iot; + if (bus_space_map(asc->asc_iot, faa->fa_reg[1].addr, + faa->fa_reg[1].size, 0, &asc->asc_ioh)) { + bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); + printf(": can't map registers\n"); return; } @@ -171,12 +199,42 @@ nvme_ans_attach(struct device *parent, struct device *self, void *aux) sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, nvme_intr, sc, sc->sc_dev.dv_xname); if (sc->sc_ih == NULL) { - printf("unable to establish interrupt\n"); + printf(": can't establish interrupt\n"); goto unmap; } + asc->asc_mbox = mbox_channel(faa->fa_node, NULL, NULL); + if (asc->asc_mbox == NULL) { + printf(": can't map mailbox channel\n"); + goto disestablish; + } + + ctrl = bus_space_read_4(asc->asc_iot, asc->asc_ioh, ANS_CPU_CTRL); + bus_space_write_4(asc->asc_iot, asc->asc_ioh, ANS_CPU_CTRL, + ctrl | ANS_CPU_CTRL_RUN); + + status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_BOOT_STATUS); + if (status != ANS_BOOT_STATUS_OK) + rtkit_init(asc->asc_mbox); + + status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_BOOT_STATUS); + if (status != ANS_BOOT_STATUS_OK) { + printf(": firmware not ready\n"); + goto disestablish; + } + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, ANS_LINEAR_SQ_CTRL, + ANS_LINEAR_SQ_CTRL_EN); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, ANS_MAX_PEND_CMDS_CTRL, + (ANS_MAX_QUEUE_DEPTH << 16) | ANS_MAX_QUEUE_DEPTH); + + ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_UNKNOWN_CTRL); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, ANS_UNKNOWN_CTRL, + ctrl & ~ANS_PRP_NULL_CHECK); + + printf(": "); + sc->sc_dmat = faa->fa_dmat; - sc->sc_iot = faa->fa_iot; sc->sc_ios = faa->fa_reg[0].size; sc->sc_ops = &nvme_ans_ops; sc->sc_openings = 1; @@ -193,7 +251,8 @@ disestablish: sc->sc_ih = NULL; unmap: - bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); + bus_space_unmap(asc->asc_iot, asc->asc_ioh, faa->fa_reg[1].size); + bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); sc->sc_ios = 0; } diff --git a/sys/arch/arm64/dev/rtkit.c b/sys/arch/arm64/dev/rtkit.c new file mode 100644 index 00000000000..d8b1f76f980 --- /dev/null +++ b/sys/arch/arm64/dev/rtkit.c @@ -0,0 +1,293 @@ +/* $OpenBSD: rtkit.c,v 1.1 2021/12/19 23:47:24 kettenis Exp $ */ +/* + * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_misc.h> +#include <dev/ofw/fdt.h> + +#include <arm64/dev/aplmbox.h> + +#define RTKIT_EP_MGMT 0 +#define RTKIT_EP_CRASHLOG 1 +#define RTKIT_EP_SYSLOG 2 +#define RTKIT_EP_DEBUG 3 +#define RTKIT_EP_IOREPORT 4 + +#define RTKIT_MGMT_TYPE(x) (((x) >> 52) & 0xff) +#define RTKIT_MGMT_TYPE_SHIFT 52 + +#define RTKIT_MGMT_PWR_STATE(x) (((x) >> 0) & 0xff) +#define RTKIT_MGMT_PWR_STATE_ON 0x20 + +#define RTKIT_MGMT_HELLO 1 +#define RTKIT_MGMT_HELLO_ACK 2 +#define RTKIT_MGMT_STARTEP 5 +#define RTKIT_MGMT_IOP_PWR_STATE 6 +#define RTKIT_MGMT_IOP_PWR_STATE_ACK 7 +#define RTKIT_MGMT_EPMAP 8 + +#define RTKIT_MGMT_HELLO_MINVER(x) (((x) >> 0) & 0xffff) +#define RTKIT_MGMT_HELLO_MINVER_SHIFT 0 +#define RTKIT_MGMT_HELLO_MAXVER(x) (((x) >> 16) & 0xffff) +#define RTKIT_MGMT_HELLO_MAXVER_SHIFT 16 + +#define RTKIT_MGMT_STARTEP_EP_SHIFT 32 +#define RTKIT_MGMT_STARTEP_START (1ULL << 1) + +#define RTKIT_MGMT_EPMAP_LAST (1ULL << 51) +#define RTKIT_MGMT_EPMAP_BASE(x) (((x) >> 32) & 0x7) +#define RTKIT_MGMT_EPMAP_BASE_SHIFT 32 +#define RTKIT_MGMT_EPMAP_BITMAP(x) (((x) >> 0) & 0xffffffff) +#define RTKIT_MGMT_EPMAP_MORE (1ULL << 0) + +#define RTKIT_BUFFER_REQUEST 1 +#define RTKIT_BUFFER_ADDR(x) (((x) >> 0) & 0xfffffffffff) +#define RTKIT_BUFFER_SIZE(x) (((x) >> 44) & 0xff) +#define RTKIT_BUFFER_SIZE_SHIFT 44 + +/* Versions we support. */ +#define RTKIT_MINVER 11 +#define RTKIT_MAXVER 12 + +struct rtkit_state { + struct mbox_channel *mc; + int pwrstate; + uint64_t epmap; +}; + +int +rtkit_recv(struct mbox_channel *mc, struct aplmbox_msg *msg) +{ + int error, timo; + + for (timo = 0; timo < 10000; timo++) { + error = mbox_recv(mc, msg, sizeof(*msg)); + if (error == 0) + break; + delay(10); + } + + return error; +} + +int +rtkit_send(struct mbox_channel *mc, uint32_t endpoint, + uint64_t type, uint64_t data) +{ + struct aplmbox_msg msg; + + msg.data0 = (type << RTKIT_MGMT_TYPE_SHIFT) | data; + msg.data1 = endpoint; + return mbox_send(mc, &msg, sizeof(msg)); +} + +int +rtkit_start_ep(struct rtkit_state *state, uint64_t ep) +{ + struct mbox_channel *mc = state->mc; + uint64_t reply; + + if ((state->epmap & (1ULL << ep)) == 0) + return EINVAL; + + reply = (ep << RTKIT_MGMT_STARTEP_EP_SHIFT); + reply |= RTKIT_MGMT_STARTEP_START; + return rtkit_send(mc, RTKIT_EP_MGMT, RTKIT_MGMT_STARTEP, reply); +} + +int +rtkit_handle_mgmt(struct rtkit_state *state, struct aplmbox_msg *msg) +{ + struct mbox_channel *mc = state->mc; + uint64_t minver, maxver, ver; + uint64_t base, bitmap, reply; + int error; + uint8_t ep; + + switch (RTKIT_MGMT_TYPE(msg->data0)) { + case RTKIT_MGMT_HELLO: + minver = RTKIT_MGMT_HELLO_MINVER(msg->data0); + maxver = RTKIT_MGMT_HELLO_MAXVER(msg->data0); + if (minver > RTKIT_MAXVER) { + printf("unsupported minimum firmware version %lld\n", + minver); + return EINVAL; + } + if (maxver < RTKIT_MINVER) { + printf("unsupported maximum firmware version %lld\n", + maxver); + return EINVAL; + } + ver = min(RTKIT_MAXVER, maxver); + error = rtkit_send(mc, RTKIT_EP_MGMT, RTKIT_MGMT_HELLO_ACK, + (ver << RTKIT_MGMT_HELLO_MINVER_SHIFT) | + (ver << RTKIT_MGMT_HELLO_MAXVER_SHIFT)); + if (error) + return error; + break; + + case RTKIT_MGMT_IOP_PWR_STATE_ACK: + state->pwrstate = RTKIT_MGMT_PWR_STATE(msg->data0); + break; + + case RTKIT_MGMT_EPMAP: + base = RTKIT_MGMT_EPMAP_BASE(msg->data0); + bitmap = RTKIT_MGMT_EPMAP_BITMAP(msg->data0); + state->epmap |= (bitmap << (base * 32)); + reply = (base << RTKIT_MGMT_EPMAP_BASE_SHIFT); + if (msg->data0 & RTKIT_MGMT_EPMAP_LAST) + reply |= RTKIT_MGMT_EPMAP_LAST; + else + reply |= RTKIT_MGMT_EPMAP_MORE; + error = rtkit_send(state->mc, RTKIT_EP_MGMT, + RTKIT_MGMT_EPMAP, reply); + if (error) + return error; + if (msg->data0 & RTKIT_MGMT_EPMAP_LAST) { + for (ep = 1; ep < 32; ep++) { + if ((state->epmap & (1ULL << ep)) == 0) + continue; + + switch (ep) { + case RTKIT_EP_CRASHLOG: + case RTKIT_EP_DEBUG: + case RTKIT_EP_IOREPORT: + error = rtkit_start_ep(state, ep); + if (error) + return error; + break; + } + } + } + break; + default: + printf("unhandle management event 0x%016lld\n", msg->data0); + return EIO; + } + + return 0; +} + +int +rtkit_handle_crashlog(struct rtkit_state *state, struct aplmbox_msg *msg) +{ + struct mbox_channel *mc = state->mc; + bus_addr_t addr; + bus_size_t size; + int error; + + switch (RTKIT_MGMT_TYPE(msg->data0)) { + case RTKIT_BUFFER_REQUEST: + addr = RTKIT_BUFFER_ADDR(msg->data0); + size = RTKIT_BUFFER_SIZE(msg->data0); + if (addr) + break; + + error = rtkit_send(mc, RTKIT_EP_CRASHLOG, RTKIT_BUFFER_REQUEST, + size << RTKIT_BUFFER_SIZE_SHIFT | addr); + if (error) + return error; + break; + default: + printf("unhandle crashlog event 0x%016llx\n", msg->data0); + return EIO; + } + + return 0; +} + +int +rtkit_handle_ioreport(struct rtkit_state *state, struct aplmbox_msg *msg) +{ + struct mbox_channel *mc = state->mc; + bus_addr_t addr; + bus_size_t size; + int error; + + switch (RTKIT_MGMT_TYPE(msg->data0)) { + case RTKIT_BUFFER_REQUEST: + addr = RTKIT_BUFFER_ADDR(msg->data0); + size = RTKIT_BUFFER_SIZE(msg->data0); + if (addr) + break; + + error = rtkit_send(mc, RTKIT_EP_IOREPORT, RTKIT_BUFFER_REQUEST, + size << RTKIT_BUFFER_SIZE_SHIFT | addr); + if (error) + return error; + break; + default: + printf("unhandle ioreport event 0x%016llx\n", msg->data0); + return EIO; + } + + return 0; +} + +int +rtkit_init(struct mbox_channel *mc) +{ + struct rtkit_state state; + struct aplmbox_msg msg; + int error; + + memset(&state, 0, sizeof(state)); + state.mc = mc; + + /* Wake up! */ + error = rtkit_send(state.mc, RTKIT_EP_MGMT, RTKIT_MGMT_IOP_PWR_STATE, + RTKIT_MGMT_PWR_STATE_ON); + if (error) + return error; + + while (state.pwrstate != RTKIT_MGMT_PWR_STATE_ON) { + error = rtkit_recv(state.mc, &msg); + if (error) + return error; + + switch (msg.data1) { + case RTKIT_EP_MGMT: + error = rtkit_handle_mgmt(&state, &msg); + if (error) + return error; + break; + case RTKIT_EP_CRASHLOG: + error = rtkit_handle_crashlog(&state, &msg); + if (error) + return error; + break; + case RTKIT_EP_IOREPORT: + error = rtkit_handle_ioreport(&state, &msg); + if (error) + return error; + break; + default: + printf("unhandled endpoint %d\n", msg.data1); + return EIO; + } + } + + return 0; +} diff --git a/sys/arch/arm64/dev/rtkit.h b/sys/arch/arm64/dev/rtkit.h new file mode 100644 index 00000000000..c8df0b6f32d --- /dev/null +++ b/sys/arch/arm64/dev/rtkit.h @@ -0,0 +1,3 @@ +/* public domain */ + +int rtkit_init(struct mbox_channel *); |