On Sat, May 27, 2017 at 11:05:42AM +0200, Stefan Fritsch wrote: > On Fri, 26 May 2017, Claudio Jeker wrote: > > > Testing it on my X270. I get: > > nvme0: unable to delete q, disabling > > > > Apart from that it seems to work (eventhough without inteldrm not very > > helpful since I lose the display). > > Thanks for testing. > > We get called twice on suspend, once with DVACT_SUSPEND and once with > DVACT_POWERDOWN. So, here is a patch that does it like in ahci.c an does > everything in the DVACT_POWERDOWN path and nothing in the DVACT_SUSPEND > path. > > ok ? >
Tested on my X270 and this seems to work. > > --- 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,11 @@ nvme_activate(struct nvme_softc *sc, int act) > 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 +1127,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 +1258,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 +1278,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; > -- :wq Claudio