diff options
author | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2013-05-04 06:43:16 -0400 |
---|---|---|
committer | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2013-05-08 09:53:49 -0400 |
commit | ba47e3865e8023e79b670793a41508222b5f0322 (patch) | |
tree | d222ea337ee683ce0a544a818d85721a71d125c9 /drivers | |
parent | 78f8d2577bd79ce9d62f4d9e6d3b895bd1dd1d1d (diff) |
NVMe: Wait for device to acknowledge shutdown
A recent update to the specification makes it clear that the host
is expected to wait for the device to acknowledge the Enable bit
transitioning to 0 as well as waiting for the device to acknowledge a
transition to 1.
Reported-by: Khosrow Panah <Khosrow.Panah@idt.com>
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Reviewed-by: Keith Busch <keith.busch@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/nvme-core.c | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index a232dfc1cd4a..2b1b5a74dc72 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c | |||
@@ -1108,15 +1108,57 @@ static struct nvme_queue *nvme_create_queue(struct nvme_dev *dev, int qid, | |||
1108 | return ERR_PTR(result); | 1108 | return ERR_PTR(result); |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | static int nvme_wait_ready(struct nvme_dev *dev, u64 cap, bool enabled) | ||
1112 | { | ||
1113 | unsigned long timeout; | ||
1114 | u32 bit = enabled ? NVME_CSTS_RDY : 0; | ||
1115 | |||
1116 | timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies; | ||
1117 | |||
1118 | while ((readl(&dev->bar->csts) & NVME_CSTS_RDY) != bit) { | ||
1119 | msleep(100); | ||
1120 | if (fatal_signal_pending(current)) | ||
1121 | return -EINTR; | ||
1122 | if (time_after(jiffies, timeout)) { | ||
1123 | dev_err(&dev->pci_dev->dev, | ||
1124 | "Device not ready; aborting initialisation\n"); | ||
1125 | return -ENODEV; | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | /* | ||
1133 | * If the device has been passed off to us in an enabled state, just clear | ||
1134 | * the enabled bit. The spec says we should set the 'shutdown notification | ||
1135 | * bits', but doing so may cause the device to complete commands to the | ||
1136 | * admin queue ... and we don't know what memory that might be pointing at! | ||
1137 | */ | ||
1138 | static int nvme_disable_ctrl(struct nvme_dev *dev, u64 cap) | ||
1139 | { | ||
1140 | writel(0, &dev->bar->cc); | ||
1141 | return nvme_wait_ready(dev, cap, false); | ||
1142 | } | ||
1143 | |||
1144 | static int nvme_enable_ctrl(struct nvme_dev *dev, u64 cap) | ||
1145 | { | ||
1146 | return nvme_wait_ready(dev, cap, true); | ||
1147 | } | ||
1148 | |||
1111 | static int nvme_configure_admin_queue(struct nvme_dev *dev) | 1149 | static int nvme_configure_admin_queue(struct nvme_dev *dev) |
1112 | { | 1150 | { |
1113 | int result = 0; | 1151 | int result; |
1114 | u32 aqa; | 1152 | u32 aqa; |
1115 | u64 cap; | 1153 | u64 cap = readq(&dev->bar->cap); |
1116 | unsigned long timeout; | ||
1117 | struct nvme_queue *nvmeq; | 1154 | struct nvme_queue *nvmeq; |
1118 | 1155 | ||
1119 | dev->dbs = ((void __iomem *)dev->bar) + 4096; | 1156 | dev->dbs = ((void __iomem *)dev->bar) + 4096; |
1157 | dev->db_stride = NVME_CAP_STRIDE(cap); | ||
1158 | |||
1159 | result = nvme_disable_ctrl(dev, cap); | ||
1160 | if (result < 0) | ||
1161 | return result; | ||
1120 | 1162 | ||
1121 | nvmeq = nvme_alloc_queue(dev, 0, 64, 0); | 1163 | nvmeq = nvme_alloc_queue(dev, 0, 64, 0); |
1122 | if (!nvmeq) | 1164 | if (!nvmeq) |
@@ -1130,27 +1172,12 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) | |||
1130 | dev->ctrl_config |= NVME_CC_ARB_RR | NVME_CC_SHN_NONE; | 1172 | dev->ctrl_config |= NVME_CC_ARB_RR | NVME_CC_SHN_NONE; |
1131 | dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES; | 1173 | dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES; |
1132 | 1174 | ||
1133 | writel(0, &dev->bar->cc); | ||
1134 | writel(aqa, &dev->bar->aqa); | 1175 | writel(aqa, &dev->bar->aqa); |
1135 | writeq(nvmeq->sq_dma_addr, &dev->bar->asq); | 1176 | writeq(nvmeq->sq_dma_addr, &dev->bar->asq); |
1136 | writeq(nvmeq->cq_dma_addr, &dev->bar->acq); | 1177 | writeq(nvmeq->cq_dma_addr, &dev->bar->acq); |
1137 | writel(dev->ctrl_config, &dev->bar->cc); | 1178 | writel(dev->ctrl_config, &dev->bar->cc); |
1138 | 1179 | ||
1139 | cap = readq(&dev->bar->cap); | 1180 | result = nvme_enable_ctrl(dev, cap); |
1140 | timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies; | ||
1141 | dev->db_stride = NVME_CAP_STRIDE(cap); | ||
1142 | |||
1143 | while (!result && !(readl(&dev->bar->csts) & NVME_CSTS_RDY)) { | ||
1144 | msleep(100); | ||
1145 | if (fatal_signal_pending(current)) | ||
1146 | result = -EINTR; | ||
1147 | if (time_after(jiffies, timeout)) { | ||
1148 | dev_err(&dev->pci_dev->dev, | ||
1149 | "Device not ready; aborting initialisation\n"); | ||
1150 | result = -ENODEV; | ||
1151 | } | ||
1152 | } | ||
1153 | |||
1154 | if (result) | 1181 | if (result) |
1155 | goto free_q; | 1182 | goto free_q; |
1156 | 1183 | ||