Hi,

the following diff adds the missing bits to make suspend/resuem work with 
nvme. It was done by ehrhardt@ and tested against nvme.c 1.50, but seems 
to apply cleanly.

Unfortunately, I don't have any nvme hardware at the moment in order to 
test it. Is there anyone who could test it?

Cheers,
Stefan

diff --git sys/dev/ic/nvme.c sys/dev/ic/nvme.c
index 3c4b48fd822..e8d4af5059b 100644
--- sys/dev/ic/nvme.c
+++ sys/dev/ic/nvme.c
@@ -45,6 +45,7 @@ int   nvme_ready(struct nvme_softc *, u_int32_t);
 int    nvme_enable(struct nvme_softc *, u_int);
 int    nvme_disable(struct nvme_softc *);
 int    nvme_shutdown(struct nvme_softc *);
+int    nvme_resume(struct nvme_softc *);
 
 void   nvme_dumpregs(struct nvme_softc *);
 int    nvme_identify(struct nvme_softc *, u_int);
@@ -68,6 +69,7 @@ void  nvme_empty_done(struct nvme_softc *, struct nvme_ccb *,
 struct nvme_queue *
        nvme_q_alloc(struct nvme_softc *, u_int16_t, u_int, u_int);
 int    nvme_q_create(struct nvme_softc *, struct nvme_queue *);
+int    nvme_q_reset(struct nvme_softc *, struct nvme_queue *);
 int    nvme_q_delete(struct nvme_softc *, struct nvme_queue *);
 void   nvme_q_submit(struct nvme_softc *,
            struct nvme_queue *, struct nvme_ccb *,
@@ -264,7 +266,6 @@ nvme_attach(struct nvme_softc *sc)
        struct scsibus_attach_args saa;
        u_int64_t cap;
        u_int32_t reg;
-       u_int dstrd;
        u_int mps = PAGE_SHIFT;
 
        mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
@@ -280,7 +281,7 @@ nvme_attach(struct nvme_softc *sc)
        printf(", NVMe %d.%d\n", NVME_VS_MJR(reg), NVME_VS_MNR(reg));
 
        cap = nvme_read8(sc, NVME_CAP);
-       dstrd = NVME_CAP_DSTRD(cap);
+       sc->sc_dstrd = NVME_CAP_DSTRD(cap);
        if (NVME_CAP_MPSMIN(cap) > PAGE_SHIFT) {
                printf("%s: NVMe minimum page size %u "
                    "is greater than CPU page size %u\n", DEVNAME(sc),
@@ -292,6 +293,7 @@ nvme_attach(struct nvme_softc *sc)
 
        sc->sc_rdy_to = NVME_CAP_TO(cap);
        sc->sc_mps = 1 << mps;
+       sc->sc_mps_bits = mps;
        sc->sc_mdts = MAXPHYS;
        sc->sc_max_sgl = 2;
 
@@ -300,7 +302,7 @@ nvme_attach(struct nvme_softc *sc)
                return (1);
        }
 
-       sc->sc_admin_q = nvme_q_alloc(sc, NVME_ADMIN_Q, 128, dstrd);
+       sc->sc_admin_q = nvme_q_alloc(sc, NVME_ADMIN_Q, 128, sc->sc_dstrd);
        if (sc->sc_admin_q == NULL) {
                printf("%s: unable to allocate admin queue\n", DEVNAME(sc));
                return (1);
@@ -330,7 +332,7 @@ nvme_attach(struct nvme_softc *sc)
                goto free_admin_q;
        }
 
-       sc->sc_q = nvme_q_alloc(sc, 1, 128, dstrd);
+       sc->sc_q = nvme_q_alloc(sc, 1, 128, sc->sc_dstrd);
        if (sc->sc_q == NULL) {
                printf("%s: unable to allocate io q\n", DEVNAME(sc));
                goto disable;
@@ -375,6 +377,47 @@ free_admin_q:
 }
 
 int
+nvme_resume(struct nvme_softc *sc)
+{
+       if (nvme_disable(sc) != 0) {
+               printf("%s: unable to disable controller\n", DEVNAME(sc));
+               return (1);
+       }
+
+       if (nvme_q_reset(sc, sc->sc_admin_q) != 0) {
+               printf("%s: unable to reset admin queue\n", DEVNAME(sc));
+               return (1);
+       }
+
+       if (nvme_enable(sc, sc->sc_mps_bits) != 0) {
+               printf("%s: unable to enable controller\n", DEVNAME(sc));
+               return (1);
+       }
+
+       sc->sc_q = nvme_q_alloc(sc, 1, 128, sc->sc_dstrd);
+       if (sc->sc_q == NULL) {
+               printf("%s: unable to allocate io q\n", DEVNAME(sc));
+               goto disable;
+       }
+
+       if (nvme_q_create(sc, sc->sc_q) != 0) {
+               printf("%s: unable to create io q\n", DEVNAME(sc));
+               goto free_q;
+       }
+
+       nvme_write4(sc, NVME_INTMC, 1);
+
+       return (0);
+
+free_q:
+       nvme_q_free(sc, sc->sc_q);
+disable:
+       nvme_disable(sc);
+
+       return (1);
+}
+
+int
 nvme_scsi_probe(struct scsi_link *link)
 {
        struct nvme_softc *sc = link->adapter_softc;
@@ -469,6 +512,15 @@ nvme_activate(struct nvme_softc *sc, int act)
                rv = config_activate_children(&sc->sc_dev, act);
                nvme_shutdown(sc);
                break;
+       case DVACT_SUSPEND:
+               rv = config_activate_children(&sc->sc_dev, act);
+               nvme_shutdown(sc);
+               break;
+       case DVACT_RESUME:
+               rv = nvme_resume(sc);
+               if (rv == 0)
+                       rv = config_activate_children(&sc->sc_dev, act);
+               break;
        default:
                rv = config_activate_children(&sc->sc_dev, act);
                break;
@@ -1079,6 +1131,8 @@ nvme_q_delete(struct nvme_softc *sc, struct nvme_queue *q)
        if (rv != 0)
                goto fail;
 
+       nvme_q_free(sc, q);
+
 fail:
        scsi_io_put(&sc->sc_iopool, ccb);
        return (rv);
@@ -1208,6 +1262,7 @@ nvme_q_alloc(struct nvme_softc *sc, u_int16_t id, u_int 
entries, u_int dstrd)
        mtx_init(&q->q_cq_mtx, IPL_BIO);
        q->q_sqtdbl = NVME_SQTDBL(id, dstrd);
        q->q_cqhdbl = NVME_CQHDBL(id, dstrd);
+
        q->q_id = id;
        q->q_entries = entries;
        q->q_sq_tail = 0;
@@ -1227,6 +1282,25 @@ free:
        return (NULL);
 }
 
+int
+nvme_q_reset(struct nvme_softc *sc, struct nvme_queue *q)
+{
+       memset(NVME_DMA_KVA(q->q_sq_dmamem), 0, NVME_DMA_LEN(q->q_sq_dmamem));
+       memset(NVME_DMA_KVA(q->q_cq_dmamem), 0, NVME_DMA_LEN(q->q_cq_dmamem));
+
+       q->q_sqtdbl = NVME_SQTDBL(q->q_id, sc->sc_dstrd);
+       q->q_cqhdbl = NVME_CQHDBL(q->q_id, sc->sc_dstrd);
+
+       q->q_sq_tail = 0;
+       q->q_cq_head = 0;
+       q->q_cq_phase = NVME_CQE_PHASE;
+
+       nvme_dmamem_sync(sc, q->q_sq_dmamem, BUS_DMASYNC_PREWRITE);
+       nvme_dmamem_sync(sc, q->q_cq_dmamem, BUS_DMASYNC_PREREAD);
+
+       return (0);
+}
+
 void
 nvme_q_free(struct nvme_softc *sc, struct nvme_queue *q)
 {
diff --git sys/dev/ic/nvmevar.h sys/dev/ic/nvmevar.h
index aced9feb6c3..039af0e8671 100644
--- sys/dev/ic/nvmevar.h
+++ sys/dev/ic/nvmevar.h
@@ -76,9 +76,11 @@ struct nvme_softc {
        void                    *sc_ih;
 
        u_int                   sc_rdy_to;
+       u_int                   sc_mps_bits;
        size_t                  sc_mps;
        size_t                  sc_mdts;
        u_int                   sc_max_sgl;
+       u_int                   sc_dstrd;
 
        struct nvm_identify_controller
                                sc_identify;

Reply via email to