From mboxrd@z Thu Jan 1 00:00:00 1970 From: keith.busch@intel.com (Keith Busch) Date: Mon, 15 Jul 2013 15:02:24 -0600 Subject: [PATCHv5 6/6] NVMe: Handle ioremap failure In-Reply-To: <1373922144-24341-1-git-send-email-keith.busch@intel.com> References: <1373922144-24341-1-git-send-email-keith.busch@intel.com> Message-ID: <1373922144-24341-7-git-send-email-keith.busch@intel.com> Decrement the number of queues required for doorbell remapping until the memory is successfully mapped for that size. Additional checks are done so that we don't call free_irq if it has already been freed. Signed-off-by: Keith Busch --- drivers/block/nvme-core.c | 30 ++++++++++++++++++++++-------- 1 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 9649844..608b0a7 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1741,10 +1741,15 @@ static int set_queue_count(struct nvme_dev *dev, int count) return min(result & 0xffff, result >> 16) + 1; } +static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues) +{ + return 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); +} + static int nvme_setup_io_queues(struct nvme_dev *dev) { struct pci_dev *pdev = dev->pci_dev; - int result, cpu, i, vecs, nr_io_queues, db_bar_size, q_depth; + int result, cpu, i, vecs, nr_io_queues, size, q_depth; nr_io_queues = num_online_cpus(); result = set_queue_count(dev, nr_io_queues); @@ -1753,17 +1758,24 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (result < nr_io_queues) nr_io_queues = result; - /* Deregister the admin queue's interrupt */ - free_irq(dev->entry[0].vector, dev->queues[0]); - - db_bar_size = 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); - if (db_bar_size > 8192) { + size = db_bar_size(dev, nr_io_queues); + if (size > 8192) { iounmap(dev->bar); - dev->bar = ioremap(pci_resource_start(pdev, 0), db_bar_size); + do { + dev->bar = ioremap(pci_resource_start(pdev, 0), size); + if (dev->bar) + break; + if (!--nr_io_queues) + return -ENOMEM; + size = db_bar_size(dev, nr_io_queues); + } while (1); dev->dbs = ((void __iomem *)dev->bar) + 4096; dev->queues[0]->q_db = dev->dbs; } + /* Deregister the admin queue's interrupt */ + free_irq(dev->entry[0].vector, dev->queues[0]); + vecs = nr_io_queues; for (i = 0; i < vecs; i++) dev->entry[i].entry = i; @@ -1801,8 +1813,10 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) nr_io_queues = vecs; result = queue_request_irq(dev, dev->queues[0], "nvme admin"); - if (result) + if (result) { + dev->queues[0]->q_suspended = 1; goto free_queues; + } /* Free previously allocated queues that are no longer usable */ spin_lock(&dev_list_lock); -- 1.7.0.4