From c257e5b4ad48f97b8d6e57d694c760e6314083a3 Mon Sep 17 00:00:00 2001 From: Wenbo Wang Date: Thu, 27 Oct 2016 14:34:32 +0800 Subject: [PATCH] nvme: add quirk to delay checking device readiness (#56) --- include/spdk/pci_ids.h | 1 + lib/nvme/nvme_ctrlr.c | 19 +++++++++++++++++++ lib/nvme/nvme_internal.h | 9 +++++++++ lib/nvme/nvme_quirks.c | 1 + 4 files changed, 30 insertions(+) diff --git a/include/spdk/pci_ids.h b/include/spdk/pci_ids.h index 9de31cdce..26883c547 100644 --- a/include/spdk/pci_ids.h +++ b/include/spdk/pci_ids.h @@ -46,6 +46,7 @@ extern "C" { #define SPDK_PCI_ANY_ID 0xffff #define SPDK_PCI_VID_INTEL 0x8086 +#define SPDK_PCI_VID_MEMBLAZE 0x1c5f /** * PCI class code for NVMe devices. diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index a6d54d0b9..95974e5d8 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -731,6 +731,17 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr) uint32_t ready_timeout_in_ms; int rc; + /* + * May need to avoid accessing any register on the target controller + * for a while. Return early without touching the FSM. + * Check sleep_timeout_tsc > 0 for unit test. + */ + if ((ctrlr->sleep_timeout_tsc > 0) && + (spdk_get_ticks() <= ctrlr->sleep_timeout_tsc)) { + return 0; + } + ctrlr->sleep_timeout_tsc = 0; + if (nvme_ctrlr_get_cc(ctrlr, &cc) || nvme_ctrlr_get_csts(ctrlr, &csts)) { SPDK_TRACELOG(SPDK_TRACE_NVME, "get registers failed\n"); @@ -766,6 +777,14 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr) return -EIO; } nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_DISABLE_WAIT_FOR_READY_0, ready_timeout_in_ms); + + /* + * Wait 2 secsonds before accessing PCI registers. + * Not using sleep() to avoid blocking other controller's initialization. + */ + if (ctrlr->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY) { + ctrlr->sleep_timeout_tsc = spdk_get_ticks() + 2 * spdk_get_ticks_hz(); + } return 0; } else { if (csts.bits.rdy == 1) { diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index e6bf206c3..31b8e97bd 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -70,6 +70,12 @@ */ #define NVME_INTEL_QUIRK_WRITE_LATENCY 0x2 +/* + * The controller needs a delay before starts checking the device + * readiness, which is done by reading the NVME_CSTS_RDY bit. + */ +#define NVME_QUIRK_DELAY_BEFORE_CHK_RDY 0x4 + #define NVME_MAX_ASYNC_EVENTS (8) #define NVME_MIN_TIMEOUT_PERIOD (5) @@ -390,6 +396,9 @@ struct spdk_nvme_ctrlr { struct spdk_pci_addr pci_addr; uint64_t quirks; + + /* Extra sleep time during controller initialization */ + uint64_t sleep_timeout_tsc; }; struct nvme_driver { diff --git a/lib/nvme/nvme_quirks.c b/lib/nvme/nvme_quirks.c index 4c1c1621f..7b6d05000 100644 --- a/lib/nvme/nvme_quirks.c +++ b/lib/nvme/nvme_quirks.c @@ -45,6 +45,7 @@ static const struct nvme_quirk nvme_quirks[] = { {{SPDK_PCI_VID_INTEL, 0x0953, SPDK_PCI_VID_INTEL, 0x3705}, NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY }, {{SPDK_PCI_VID_INTEL, 0x0953, SPDK_PCI_VID_INTEL, 0x3709}, NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY }, {{SPDK_PCI_VID_INTEL, 0x0953, SPDK_PCI_VID_INTEL, 0x370a}, NVME_INTEL_QUIRK_READ_LATENCY | NVME_INTEL_QUIRK_WRITE_LATENCY }, + {{SPDK_PCI_VID_MEMBLAZE, 0x0540, SPDK_PCI_ANY_ID, SPDK_PCI_ANY_ID}, NVME_QUIRK_DELAY_BEFORE_CHK_RDY }, {{0x0000, 0x0000, 0x0000, 0x0000}, 0 } };