From d9860da1c8a2077efd100dcc22dbe3f038fa07a4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 29 Feb 2016 15:59:44 +0100 Subject: [PATCH] nvme: use a work item to submit async event requests Use a dedicated work item to submit async event requests instead of the global kthread. This simplifies the code and reduces the latencies to resubmit a request once an even notification happened. Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Reviewed-by: Sagi Grimberg Reviewed-by: Johannes Thumshirn Signed-off-by: Jens Axboe (cherry picked from commit 9396dec916c052855dbb5b876c13d163df397319) Orabug: 25130845 Signed-off-by: Ashok Vairavan Reviewed-by: Martin K. Petersen --- drivers/nvme/host/pci.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 06c323d2abc5..65b85ae5a4cb 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -109,6 +109,8 @@ struct nvme_dev { struct mutex namespaces_mutex; struct work_struct reset_work; struct work_struct scan_work; + struct work_struct remove_work; + struct work_struct async_work; struct mutex shutdown_lock; bool subsystem; void __iomem *cmb; @@ -290,8 +292,11 @@ static void nvme_complete_async_event(struct nvme_dev *dev, u16 status = le16_to_cpu(cqe->status) >> 1; u32 result = le32_to_cpu(cqe->result); - if (status == NVME_SC_SUCCESS || status == NVME_SC_ABORT_REQ) + if (status == NVME_SC_SUCCESS || status == NVME_SC_ABORT_REQ) { ++dev->ctrl.event_limit; + queue_work(nvme_workq, &dev->async_work); + } + if (status != NVME_SC_SUCCESS) return; @@ -858,15 +863,22 @@ static irqreturn_t nvme_irq_check(int irq, void *data) return IRQ_WAKE_THREAD; } -static void nvme_submit_async_event(struct nvme_dev *dev) +static void nvme_async_event_work(struct work_struct *work) { + struct nvme_dev *dev = container_of(work, struct nvme_dev, async_work); + struct nvme_queue *nvmeq = dev->queues[0]; struct nvme_command c; memset(&c, 0, sizeof(c)); c.common.opcode = nvme_admin_async_event; - c.common.command_id = NVME_AQ_BLKMQ_DEPTH + --dev->ctrl.event_limit; - __nvme_submit_cmd(dev->queues[0], &c); + spin_lock_irq(&nvmeq->q_lock); + while (dev->ctrl.event_limit > 0) { + c.common.command_id = NVME_AQ_BLKMQ_DEPTH + + --dev->ctrl.event_limit; + __nvme_submit_cmd(nvmeq, &c); + } + spin_unlock_irq(&nvmeq->q_lock); } static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id) @@ -1397,9 +1409,6 @@ static int nvme_kthread(void *data) continue; spin_lock_irq(&nvmeq->q_lock); nvme_process_cq(nvmeq); - - while (i == 0 && dev->ctrl.event_limit > 0) - nvme_submit_async_event(dev); spin_unlock_irq(&nvmeq->q_lock); } } @@ -1969,6 +1978,7 @@ static void nvme_reset_work(struct work_struct *work) goto free_tags; dev->ctrl.event_limit = NVME_NR_AEN_COMMANDS; + queue_work(nvme_workq, &dev->async_work); result = nvme_dev_list_add(dev); if (result) @@ -2109,6 +2119,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&dev->node); INIT_WORK(&dev->scan_work, nvme_dev_scan); INIT_WORK(&dev->reset_work, nvme_reset_work); + INIT_WORK(&dev->remove_work, nvme_remove_dead_ctrl_work); + INIT_WORK(&dev->async_work, nvme_async_event_work); mutex_init(&dev->shutdown_lock); init_completion(&dev->ioq_wait); @@ -2158,6 +2170,8 @@ static void nvme_remove(struct pci_dev *pdev) struct nvme_dev *dev = pci_get_drvdata(pdev); pci_set_drvdata(pdev, NULL); + flush_work(&dev->async_work); + flush_work(&dev->reset_work); flush_work(&dev->scan_work); nvme_remove_namespaces(&dev->ctrl); nvme_uninit_ctrl(&dev->ctrl); -- 2.50.1