summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjimharris <jimharris@FreeBSD.org>2013-08-13 21:47:08 +0000
committerjimharris <jimharris@FreeBSD.org>2013-08-13 21:47:08 +0000
commit3f846da35adcf59806a7022f25cc733b0feaa4a3 (patch)
tree5f492f298073eecaa0f7076f533d93c510e4ecc8
parente3e0bd874e439a7ced10380adec12fa4ca4ec23e (diff)
downloadFreeBSD-src-3f846da35adcf59806a7022f25cc733b0feaa4a3.zip
FreeBSD-src-3f846da35adcf59806a7022f25cc733b0feaa4a3.tar.gz
Send a shutdown notification in the driver unload path, to ensure
notification gets sent in cases where system shuts down with driver unloaded. Sponsored by: Intel Reviewed by: carl MFC after: 3 days
-rw-r--r--sys/dev/nvme/nvme.c18
-rw-r--r--sys/dev/nvme/nvme.h25
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c35
-rw-r--r--sys/dev/nvme/nvme_private.h1
4 files changed, 51 insertions, 28 deletions
diff --git a/sys/dev/nvme/nvme.c b/sys/dev/nvme/nvme.c
index eacd0cc..2e598e8 100644
--- a/sys/dev/nvme/nvme.c
+++ b/sys/dev/nvme/nvme.c
@@ -157,30 +157,14 @@ nvme_shutdown(void)
{
device_t *devlist;
struct nvme_controller *ctrlr;
- union cc_register cc;
- union csts_register csts;
int dev, devcount;
if (devclass_get_devices(nvme_devclass, &devlist, &devcount))
return;
for (dev = 0; dev < devcount; dev++) {
- /*
- * Only notify controller of shutdown when a real shutdown is
- * in process, not when a module unload occurs. It seems at
- * least some controllers (Chatham at least) don't let you
- * re-enable the controller after shutdown notification has
- * been received.
- */
ctrlr = DEVICE2SOFTC(devlist[dev]);
- cc.raw = nvme_mmio_read_4(ctrlr, cc);
- cc.bits.shn = NVME_SHN_NORMAL;
- nvme_mmio_write_4(ctrlr, cc, cc.raw);
- csts.raw = nvme_mmio_read_4(ctrlr, csts);
- while (csts.bits.shst != NVME_SHST_COMPLETE) {
- DELAY(5);
- csts.raw = nvme_mmio_read_4(ctrlr, csts);
- }
+ nvme_ctrlr_shutdown(ctrlr);
}
free(devlist, M_TEMP);
diff --git a/sys/dev/nvme/nvme.h b/sys/dev/nvme/nvme.h
index 9df75da..f904933 100644
--- a/sys/dev/nvme/nvme.h
+++ b/sys/dev/nvme/nvme.h
@@ -170,27 +170,30 @@ struct nvme_registers
union cap_lo_register cap_lo;
union cap_hi_register cap_hi;
- uint32_t vs; /* version */
- uint32_t intms; /* interrupt mask set */
- uint32_t intmc; /* interrupt mask clear */
+ uint32_t vs; /* version */
+ uint32_t intms; /* interrupt mask set */
+ uint32_t intmc; /* interrupt mask clear */
/** controller configuration */
union cc_register cc;
- uint32_t reserved1;
- uint32_t csts; /* controller status */
- uint32_t reserved2;
+ uint32_t reserved1;
+
+ /** controller status */
+ union csts_register csts;
+
+ uint32_t reserved2;
/** admin queue attributes */
union aqa_register aqa;
- uint64_t asq; /* admin submission queue base addr */
- uint64_t acq; /* admin completion queue base addr */
- uint32_t reserved3[0x3f2];
+ uint64_t asq; /* admin submission queue base addr */
+ uint64_t acq; /* admin completion queue base addr */
+ uint32_t reserved3[0x3f2];
struct {
- uint32_t sq_tdbl; /* submission queue tail doorbell */
- uint32_t cq_hdbl; /* completion queue head doorbell */
+ uint32_t sq_tdbl; /* submission queue tail doorbell */
+ uint32_t cq_hdbl; /* completion queue head doorbell */
} doorbell[1] __packed;
} __packed;
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 1338f15..4845782 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -1117,6 +1117,21 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
{
int i;
+ /*
+ * Notify the controller of a shutdown, even though this is due to
+ * a driver unload, not a system shutdown (this path is not invoked
+ * during shutdown). This ensures the controller receives a
+ * shutdown notification in case the system is shutdown before
+ * reloading the driver.
+ *
+ * Chatham does not let you re-enable the controller after shutdown
+ * notification has been received, so do not send it in this case.
+ * This is OK because Chatham does not depend on the shutdown
+ * notification anyways.
+ */
+ if (pci_get_devid(ctrlr->dev) != CHATHAM_PCI_ID)
+ nvme_ctrlr_shutdown(ctrlr);
+
nvme_ctrlr_disable(ctrlr);
taskqueue_free(ctrlr->taskqueue);
@@ -1163,6 +1178,26 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
}
void
+nvme_ctrlr_shutdown(struct nvme_controller *ctrlr)
+{
+ union cc_register cc;
+ union csts_register csts;
+ int ticks = 0;
+
+ cc.raw = nvme_mmio_read_4(ctrlr, cc);
+ cc.bits.shn = NVME_SHN_NORMAL;
+ nvme_mmio_write_4(ctrlr, cc, cc.raw);
+ csts.raw = nvme_mmio_read_4(ctrlr, csts);
+ while ((csts.bits.shst != NVME_SHST_COMPLETE) && (ticks++ < 5*hz)) {
+ pause("nvme shn", 1);
+ csts.raw = nvme_mmio_read_4(ctrlr, csts);
+ }
+ if (csts.bits.shst != NVME_SHST_COMPLETE)
+ nvme_printf(ctrlr, "did not complete shutdown within 5 seconds "
+ "of notification\n");
+}
+
+void
nvme_ctrlr_submit_admin_request(struct nvme_controller *ctrlr,
struct nvme_request *req)
{
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index 10643f2..f0f4453 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -433,6 +433,7 @@ void nvme_completion_poll_cb(void *arg, const struct nvme_completion *cpl);
int nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev);
void nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev);
+void nvme_ctrlr_shutdown(struct nvme_controller *ctrlr);
int nvme_ctrlr_hw_reset(struct nvme_controller *ctrlr);
void nvme_ctrlr_reset(struct nvme_controller *ctrlr);
/* ctrlr defined as void * to allow use with config_intrhook. */
OpenPOWER on IntegriCloud