Add an 'info nvme-queues' HMP command that lists, for every emulated NVMe controller, the admin SQ/CQ and every active I/O SQ/CQ.
For each queue the command prints: - the ring size, head and tail indices; - the associated CQ id (for SQ) or interrupt vector (for CQ); - the queue's PRP1 (DMA base address of the ring); - the BAR0-relative doorbell offset (SQyTDBL / CQyHDBL); - the current CQ phase tag. The doorbell offsets are computed from CAP.DSTRD so they remain correct if the emulation ever exposes a non-zero stride. Useful when debugging the Linux NVMe driver against the QEMU emulation - queue setup, doorbell rings, AERs held in the admin SQ etc. - without attaching gdb to the QEMU process. Example, with the long PRP1 ring address and BAR0-relative doorbell offset replaced by '...'; phase tag column omitted for brevity: (qemu) info nvme-queues /machine/peripheral-anon/device[0] SQ 0 size=32 head=9 tail=9 cqid=0 prp1=... SQTDBL=... CQ 0 size=32 head=8 tail=8 iv=0 prp1=... CQHDBL=... SQ 1 size=1024 head=2 tail=2 cqid=1 prp1=... SQTDBL=... CQ 1 size=1024 head=2 tail=2 iv=1 prp1=... CQHDBL=... Signed-off-by: Mateusz Nowicki <[email protected]> Acked-by: Dr. David Alan Gilbert <[email protected]> Acked-by: Markus Armbruster <[email protected]> --- hmp-commands-info.hx | 15 +++++++++++ hw/nvme/monitor.c | 63 ++++++++++++++++++++++++++++++++++++++++++++ qapi/machine.json | 17 ++++++++++++ 3 files changed, 95 insertions(+) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index b984691c3ce..874c1e19707 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -353,6 +353,21 @@ SRST Show emulated NVMe controllers. ERST + { + .name = "nvme-queues", + .args_type = "", + .params = "", + .help = "show active NVMe queues and their doorbells", + .cmd_info_hrt = qmp_x_query_nvme_queues, + }, + +SRST + ``info nvme-queues`` + Show all active NVMe submission and completion queues, including + head/tail, DMA address of the ring and BAR0-relative doorbell + offset. +ERST + { .name = "usbhost", .args_type = "", diff --git a/hw/nvme/monitor.c b/hw/nvme/monitor.c index 95a67544376..c8161943c08 100644 --- a/hw/nvme/monitor.c +++ b/hw/nvme/monitor.c @@ -74,3 +74,66 @@ HumanReadableText *qmp_x_query_nvme(Error **errp) return human_readable_text_from_str(buf); } + +static void append_sq(GString *buf, NvmeSQueue *sq, unsigned stride) +{ + hwaddr db_off = 0x1000 + 2 * sq->sqid * stride; + + g_string_append_printf(buf, + " SQ %u size=%-5u head=%-5u tail=%-5u cqid=%-3u " + "prp1=0x%016" PRIx64 " SQTDBL=BAR0+0x%03" HWADDR_PRIx "\n", + sq->sqid, sq->size, sq->head, sq->tail, sq->cqid, + sq->dma_addr, db_off); +} + +static void append_cq(GString *buf, NvmeCQueue *cq, unsigned stride) +{ + hwaddr db_off = 0x1000 + (2 * cq->cqid + 1) * stride; + + g_string_append_printf(buf, + " CQ %u size=%-5u head=%-5u tail=%-5u iv=%-5u " + "prp1=0x%016" PRIx64 " CQHDBL=BAR0+0x%03" HWADDR_PRIx + " phaseTag=%u\n", + cq->cqid, cq->size, cq->head, cq->tail, cq->vector, + cq->dma_addr, db_off, cq->phase); +} + +static int collect_queues(Object *obj, void *opaque) +{ + GString *buf = opaque; + NvmeCtrl *n; + unsigned stride; + + if (!object_dynamic_cast(obj, TYPE_NVME)) { + return 0; + } + n = NVME(obj); + stride = 4u << NVME_CAP_DSTRD(ldq_le_p(&n->bar.cap)); + + g_string_append_printf(buf, "%s\n", object_get_canonical_path(obj)); + append_sq(buf, &n->admin_sq, stride); + append_cq(buf, &n->admin_cq, stride); + + for (unsigned i = 1; i <= n->params.max_ioqpairs; i++) { + if (n->sq && n->sq[i]) { + append_sq(buf, n->sq[i], stride); + } + if (n->cq && n->cq[i]) { + append_cq(buf, n->cq[i], stride); + } + } + return 0; +} + +HumanReadableText *qmp_x_query_nvme_queues(Error **errp) +{ + g_autoptr(GString) buf = g_string_new(""); + + object_child_foreach_recursive(object_get_root(), collect_queues, buf); + + if (buf->len == 0) { + g_string_append(buf, "no NVMe controllers\n"); + } + + return human_readable_text_from_str(buf); +} diff --git a/qapi/machine.json b/qapi/machine.json index d4a589e7681..c21b128e0a9 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1789,6 +1789,23 @@ 'returns': 'HumanReadableText', 'features': [ 'unstable' ] } +## +# @x-query-nvme-queues: +# +# Query state of all active SQ/CQ for emulated NVMe controllers. +# +# Features: +# +# @unstable: This command is meant for debugging. +# +# Returns: per-queue state as human-readable text +# +# Since: 11.1 +## +{ 'command': 'x-query-nvme-queues', + 'returns': 'HumanReadableText', + 'features': [ 'unstable' ] } + ## # @SmbiosEntryPointType: # -- 2.53.0
