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 | |
| 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>
| -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 | ||
