From 5e9aa92eb1a5abbb6e0e3dafdf64ac728e11b6f2 Mon Sep 17 00:00:00 2001 From: Hikaru Nishida Date: Mon, 18 Dec 2017 14:00:43 +0900 Subject: [PATCH] hw/block: Fix pin-based interrupt behaviour of NVMe Pin-based interrupt of NVMe controller did not work properly because using an obsolated function pci_irq_pulse(). To fix this, change to use pci_irq_assert() / pci_irq_deassert() instead of pci_irq_pulse(). Signed-off-by: Hikaru Nishida Reviewed-by: Keith Busch Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 39 ++++++++++++++++++++++++++++++++++----- hw/block/nvme.h | 1 + 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 1ac356d3a5..51a58fefba 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -91,7 +91,19 @@ static uint8_t nvme_sq_empty(NvmeSQueue *sq) return sq->head == sq->tail; } -static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq) +static void nvme_irq_check(NvmeCtrl *n) +{ + if (msix_enabled(&(n->parent_obj))) { + return; + } + if (~n->bar.intms & n->irq_status) { + pci_irq_assert(&n->parent_obj); + } else { + pci_irq_deassert(&n->parent_obj); + } +} + +static void nvme_irq_assert(NvmeCtrl *n, NvmeCQueue *cq) { if (cq->irq_enabled) { if (msix_enabled(&(n->parent_obj))) { @@ -99,13 +111,28 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq) msix_notify(&(n->parent_obj), cq->vector); } else { trace_nvme_irq_pin(); - pci_irq_pulse(&n->parent_obj); + assert(cq->cqid < 64); + n->irq_status |= 1 << cq->cqid; + nvme_irq_check(n); } } else { trace_nvme_irq_masked(); } } +static void nvme_irq_deassert(NvmeCtrl *n, NvmeCQueue *cq) +{ + if (cq->irq_enabled) { + if (msix_enabled(&(n->parent_obj))) { + return; + } else { + assert(cq->cqid < 64); + n->irq_status &= ~(1 << cq->cqid); + nvme_irq_check(n); + } + } +} + static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, uint64_t prp2, uint32_t len, NvmeCtrl *n) { @@ -242,7 +269,7 @@ static void nvme_post_cqes(void *opaque) sizeof(req->cqe)); QTAILQ_INSERT_TAIL(&sq->req_list, req, entry); } - nvme_isr_notify(n, cq); + nvme_irq_assert(n, cq); } static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req) @@ -905,6 +932,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->bar.intmc = n->bar.intms; trace_nvme_mmio_intm_set(data & 0xffffffff, n->bar.intmc); + nvme_irq_check(n); break; case 0x10: /* INTMC */ if (unlikely(msix_enabled(&(n->parent_obj)))) { @@ -917,6 +945,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->bar.intmc = n->bar.intms; trace_nvme_mmio_intm_clr(data & 0xffffffff, n->bar.intmc); + nvme_irq_check(n); break; case 0x14: /* CC */ trace_nvme_mmio_cfg(data & 0xffffffff); @@ -1085,8 +1114,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); } - if (cq->tail != cq->head) { - nvme_isr_notify(n, cq); + if (cq->tail == cq->head) { + nvme_irq_deassert(n, cq); } } else { /* Submission queue doorbell write */ diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 6aab338ff5..7b62dad072 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -775,6 +775,7 @@ typedef struct NvmeCtrl { uint32_t cmbsz; uint32_t cmbloc; uint8_t *cmbuf; + uint64_t irq_status; char *serial; NvmeNamespace *namespaces; -- GitLab