summaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew.r.wilcox@intel.com>2013-06-24 17:47:34 +0200
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2013-06-24 17:54:20 +0200
commite9539f47525ecee05c9f22c3565885f3e9492c52 (patch)
tree5de495060ebbad25fc7de7180cb381a3c7e85f98 /drivers/block
parentNVMe: Disk IO statistics (diff)
downloadlinux-e9539f47525ecee05c9f22c3565885f3e9492c52.tar.xz
linux-e9539f47525ecee05c9f22c3565885f3e9492c52.zip
NVMe: Return correct value from interrupt handler
The interrupt handler currently reports whether it found any new completion queue entries. If the completion queue is primarily being processed by a method other than the interrupt handler, it may return IRQ_NONE so often that Linux thinks that the interrupt is being falsely triggered. To solve this problem, report whether any completion queue entries have been seen since the last interrupt was received for this queue. Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/nvme-core.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 4e71b075d3b4..88a95747494c 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -79,7 +79,8 @@ struct nvme_queue {
u16 sq_head;
u16 sq_tail;
u16 cq_head;
- u16 cq_phase;
+ u8 cq_phase;
+ u8 cqe_seen;
unsigned long cmdid_data[];
};
@@ -756,7 +757,7 @@ static void nvme_make_request(struct request_queue *q, struct bio *bio)
put_nvmeq(nvmeq);
}
-static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq)
+static int nvme_process_cq(struct nvme_queue *nvmeq)
{
u16 head, phase;
@@ -786,13 +787,14 @@ static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq)
* a big problem.
*/
if (head == nvmeq->cq_head && phase == nvmeq->cq_phase)
- return IRQ_NONE;
+ return 0;
writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride));
nvmeq->cq_head = head;
nvmeq->cq_phase = phase;
- return IRQ_HANDLED;
+ nvmeq->cqe_seen = 1;
+ return 1;
}
static irqreturn_t nvme_irq(int irq, void *data)
@@ -800,7 +802,9 @@ static irqreturn_t nvme_irq(int irq, void *data)
irqreturn_t result;
struct nvme_queue *nvmeq = data;
spin_lock(&nvmeq->q_lock);
- result = nvme_process_cq(nvmeq);
+ nvme_process_cq(nvmeq);
+ result = nvmeq->cqe_seen ? IRQ_HANDLED : IRQ_NONE;
+ nvmeq->cqe_seen = 0;
spin_unlock(&nvmeq->q_lock);
return result;
}