Skip to content

Commit

Permalink
NVMe: Add pci suspend/resume driver callbacks
Browse files Browse the repository at this point in the history
Used for going in and out of low power states. Resuming reuses the IO
queues from the previous initialization, freeing any allocated queues
that are no longer usable.

Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
  • Loading branch information
Keith Busch authored and Matthew Wilcox committed Sep 3, 2013
1 parent 1894d8f commit cd63894
Showing 1 changed file with 58 additions and 15 deletions.
73 changes: 58 additions & 15 deletions drivers/block/nvme-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,12 @@ static void nvme_make_request(struct request_queue *q, struct bio *bio)
struct nvme_queue *nvmeq = get_nvmeq(ns->dev);
int result = -EBUSY;

if (!nvmeq) {
put_nvmeq(NULL);
bio_endio(bio, -EIO);
return;
}

spin_lock_irq(&nvmeq->q_lock);
if (!nvmeq->q_suspended && bio_list_empty(&nvmeq->sq_cong))
result = nvme_submit_bio_queue(nvmeq, ns, bio);
Expand Down Expand Up @@ -1256,9 +1262,13 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
if (result < 0)
return result;

nvmeq = nvme_alloc_queue(dev, 0, 64, 0);
if (!nvmeq)
return -ENOMEM;
nvmeq = dev->queues[0];
if (!nvmeq) {
nvmeq = nvme_alloc_queue(dev, 0, 64, 0);
if (!nvmeq)
return -ENOMEM;
dev->queues[0] = nvmeq;
}

aqa = nvmeq->q_depth - 1;
aqa |= aqa << 16;
Expand All @@ -1275,21 +1285,16 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)

result = nvme_enable_ctrl(dev, cap);
if (result)
goto free_q;
return result;

result = queue_request_irq(dev, nvmeq, "nvme admin");
if (result)
goto free_q;
return result;

dev->queues[0] = nvmeq;
spin_lock(&nvmeq->q_lock);
nvme_init_queue(nvmeq, 0);
spin_unlock(&nvmeq->q_lock);
return result;

free_q:
nvme_free_queue(nvmeq);
return result;
}

struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
Expand Down Expand Up @@ -1797,6 +1802,21 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
if (result)
goto free_queues;

/* Free previously allocated queues that are no longer usable */
spin_lock(&dev_list_lock);
for (i = dev->queue_count - 1; i > nr_io_queues; i--) {
struct nvme_queue *nvmeq = dev->queues[i];

spin_lock(&nvmeq->q_lock);
nvme_cancel_ios(nvmeq, false);
spin_unlock(&nvmeq->q_lock);

nvme_free_queue(nvmeq);
dev->queue_count--;
dev->queues[i] = NULL;
}
spin_unlock(&dev_list_lock);

cpu = cpumask_first(cpu_online_mask);
for (i = 0; i < nr_io_queues; i++) {
irq_set_affinity_hint(dev->entry[i].vector, get_cpu_mask(cpu));
Expand All @@ -1805,7 +1825,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)

q_depth = min_t(int, NVME_CAP_MQES(readq(&dev->bar->cap)) + 1,
NVME_Q_DEPTH);
for (i = 0; i < nr_io_queues; i++) {
for (i = dev->queue_count - 1; i < nr_io_queues; i++) {
dev->queues[i + 1] = nvme_alloc_queue(dev, i + 1, q_depth, i);
if (!dev->queues[i + 1]) {
result = -ENOMEM;
Expand Down Expand Up @@ -2191,8 +2211,30 @@ static void nvme_remove(struct pci_dev *pdev)
#define nvme_link_reset NULL
#define nvme_slot_reset NULL
#define nvme_error_resume NULL
#define nvme_suspend NULL
#define nvme_resume NULL

static int nvme_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct nvme_dev *ndev = pci_get_drvdata(pdev);

nvme_dev_shutdown(ndev);
return 0;
}

static int nvme_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct nvme_dev *ndev = pci_get_drvdata(pdev);
int ret;

ret = nvme_dev_start(ndev);
/* XXX: should remove gendisks if resume fails */
if (ret)
nvme_free_queues(ndev);
return ret;
}

static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume);

static const struct pci_error_handlers nvme_err_handler = {
.error_detected = nvme_error_detected,
Expand All @@ -2216,8 +2258,9 @@ static struct pci_driver nvme_driver = {
.id_table = nvme_id_table,
.probe = nvme_probe,
.remove = nvme_remove,
.suspend = nvme_suspend,
.resume = nvme_resume,
.driver = {
.pm = &nvme_dev_pm_ops,
},
.err_handler = &nvme_err_handler,
};

Expand Down

0 comments on commit cd63894

Please sign in to comment.