From 19c18994f0851e28fb90ebf5de9fb7853c6c03c5 Mon Sep 17 00:00:00 2001 From: kettenis Date: Wed, 9 Nov 2022 18:17:00 +0000 Subject: [PATCH] Add suspend/resume support to aplns(4). ok dlg@, patrick@ --- sys/arch/arm64/dev/aplns.c | 123 +++++++++++++++++++++++++++---------- sys/arch/arm64/dev/rtkit.c | 22 ++++++- sys/arch/arm64/dev/rtkit.h | 1 + 3 files changed, 114 insertions(+), 32 deletions(-) diff --git a/sys/arch/arm64/dev/aplns.c b/sys/arch/arm64/dev/aplns.c index c59960b76d2..f56c40ba077 100644 --- a/sys/arch/arm64/dev/aplns.c +++ b/sys/arch/arm64/dev/aplns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aplns.c,v 1.12 2022/06/12 16:00:12 kettenis Exp $ */ +/* $OpenBSD: aplns.c,v 1.13 2022/11/09 18:17:00 kettenis Exp $ */ /* * Copyright (c) 2014, 2021 David Gwynne * @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -83,10 +84,8 @@ struct ans_nvmmu_tcb { int aplns_match(struct device *, void *, void *); void aplns_attach(struct device *, struct device *, void *); -const struct cfattach aplns_ca = { - sizeof(struct device), - aplns_match, - aplns_attach +const struct cfattach aplns_ca = { + sizeof(struct device), aplns_match, aplns_attach }; struct cfdriver aplns_cd = { @@ -118,6 +117,7 @@ struct nvme_ans_softc { struct nvme_softc asc_nvme; bus_space_tag_t asc_iot; bus_space_handle_t asc_ioh; + int asc_node; uint32_t asc_sart; struct rtkit asc_rtkit; @@ -127,13 +127,15 @@ struct nvme_ans_softc { int nvme_ans_match(struct device *, void *, void *); void nvme_ans_attach(struct device *, struct device *, void *); +int nvme_ans_activate(struct device *, int act); const struct cfattach nvme_ans_ca = { - sizeof(struct nvme_ans_softc), - nvme_ans_match, - nvme_ans_attach, + sizeof(struct nvme_ans_softc), nvme_ans_match, nvme_ans_attach, NULL, + nvme_ans_activate }; +int nvme_ans_init(struct nvme_ans_softc *sc); +void nvme_ans_shutdown(struct nvme_ans_softc *sc); void nvme_ans_enable(struct nvme_softc *); int nvme_ans_q_alloc(struct nvme_softc *, @@ -178,7 +180,6 @@ 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; if (faa->fa_nreg < 2) { printf(": no registers\n"); @@ -200,8 +201,6 @@ nvme_ans_attach(struct device *parent, struct device *self, void *aux) return; } - power_domain_enable(faa->fa_node); - sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, nvme_intr, sc, sc->sc_dev.dv_xname); if (sc->sc_ih == NULL) { @@ -209,40 +208,24 @@ nvme_ans_attach(struct device *parent, struct device *self, void *aux) goto unmap; } + asc->asc_node = faa->fa_node; asc->asc_sart = OF_getpropint(faa->fa_node, "apple,sart", 0); asc->asc_rtkit.rk_cookie = asc; asc->asc_rtkit.rk_dmat = faa->fa_dmat; asc->asc_rtkit.rk_map = nvme_ans_sart_map; - asc->asc_rtkit_state = rtkit_init(faa->fa_node, NULL, &asc->asc_rtkit); + asc->asc_rtkit_state = + rtkit_init(faa->fa_node, NULL, &asc->asc_rtkit); if (asc->asc_rtkit_state == 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_boot(asc->asc_rtkit_state); - - status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_BOOT_STATUS); - if (status != ANS_BOOT_STATUS_OK) { + if (nvme_ans_init(asc)) { 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; @@ -267,6 +250,84 @@ unmap: sc->sc_ios = 0; } +int +nvme_ans_activate(struct device *self, int act) +{ + struct nvme_ans_softc *asc = (struct nvme_ans_softc *)self; + struct nvme_softc *sc = &asc->asc_nvme; + int rv; + + switch (act) { + case DVACT_POWERDOWN: + rv = nvme_activate(&asc->asc_nvme, act); + nvme_ans_shutdown(asc); + break; + case DVACT_RESUME: + rv = nvme_ans_init(asc); + if (rv) { + printf("%s: firmware not ready\n", DEVNAME(sc)); + goto fail; + } + rv = nvme_activate(&asc->asc_nvme, act); + break; + default: + rv = nvme_activate(&asc->asc_nvme, act); + break; + } + +fail: + return rv; +} + +int +nvme_ans_init(struct nvme_ans_softc *asc) +{ + struct nvme_softc *sc = &asc->asc_nvme; + uint32_t ctrl, status; + + power_domain_enable_all(asc->asc_node); + + 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_boot(asc->asc_rtkit_state); + + status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_BOOT_STATUS); + if (status != ANS_BOOT_STATUS_OK) + return ENXIO; + + 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); + + return 0; +} + +void +nvme_ans_shutdown(struct nvme_ans_softc *asc) +{ + uint32_t ctrl; + + rtkit_shutdown(asc->asc_rtkit_state); + + 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); + + reset_assert_all(asc->asc_node); + reset_deassert_all(asc->asc_node); + + power_domain_disable_all(asc->asc_node); +} + int nvme_ans_sart_map(void *cookie, bus_addr_t addr, bus_size_t size) { diff --git a/sys/arch/arm64/dev/rtkit.c b/sys/arch/arm64/dev/rtkit.c index bb63015f173..c3442456e64 100644 --- a/sys/arch/arm64/dev/rtkit.c +++ b/sys/arch/arm64/dev/rtkit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtkit.c,v 1.6 2022/09/03 19:04:28 kettenis Exp $ */ +/* $OpenBSD: rtkit.c,v 1.7 2022/11/09 18:17:00 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * @@ -472,6 +472,26 @@ rtkit_boot(struct rtkit_state *state) return 0; } + +void +rtkit_shutdown(struct rtkit_state *state) +{ + struct mbox_channel *mc = state->mc; + + if (state->ap_pwrstate != RTKIT_MGMT_PWR_STATE_QUIESCED) + rtkit_set_ap_pwrstate(state, RTKIT_MGMT_PWR_STATE_QUIESCED); + + rtkit_send(mc, RTKIT_EP_MGMT, RTKIT_MGMT_IOP_PWR_STATE, + RTKIT_MGMT_PWR_STATE_SLEEP); + + while (state->iop_pwrstate != RTKIT_MGMT_PWR_STATE_SLEEP) + rtkit_poll(state); + + KASSERT(state->iop_pwrstate == RTKIT_MGMT_PWR_STATE_SLEEP); + KASSERT(state->ap_pwrstate == RTKIT_MGMT_PWR_STATE_QUIESCED); + state->epmap = 0; +} + int rtkit_set_ap_pwrstate(struct rtkit_state *state, uint16_t pwrstate) { diff --git a/sys/arch/arm64/dev/rtkit.h b/sys/arch/arm64/dev/rtkit.h index ddc9c3d7db7..f91e1f9d931 100644 --- a/sys/arch/arm64/dev/rtkit.h +++ b/sys/arch/arm64/dev/rtkit.h @@ -14,6 +14,7 @@ struct rtkit { struct rtkit_state *rtkit_init(int, const char *, struct rtkit *); int rtkit_boot(struct rtkit_state *); +void rtkit_shutdown(struct rtkit_state *); int rtkit_set_ap_pwrstate(struct rtkit_state *, uint16_t); int rtkit_poll(struct rtkit_state *); int rtkit_start_endpoint(struct rtkit_state *, uint32_t, -- 2.20.1