summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2022-11-09 18:17:01 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2022-11-09 18:17:01 +0000
commitc7dcf9689fea0f47e018b5a56a7823bf9b173026 (patch)
treeca7e4db206db0b3670e6b26a16cb6069bce340ec /sys
parentdae3ba08dc165904352edb7877d1423f4e3b99b2 (diff)
Add suspend/resume support to aplns(4).
ok dlg@, patrick@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm64/dev/aplns.c123
-rw-r--r--sys/arch/arm64/dev/rtkit.c22
-rw-r--r--sys/arch/arm64/dev/rtkit.h1
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 <dlg@openbsd.org>
*
@@ -32,6 +32,7 @@
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_misc.h>
#include <dev/ofw/ofw_power.h>
+#include <dev/ofw/ofw_clock.h>
#include <dev/ofw/fdt.h>
#include <scsi/scsi_all.h>
@@ -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;
@@ -268,6 +251,84 @@ unmap:
}
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)
{
struct nvme_ans_softc *asc = cookie;
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 <kettenis@openbsd.org>
*
@@ -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,