From nobody Wed Dec 17 21:50:08 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1559574397; cv=none; d=zoho.com; s=zohoarc; b=IE863+JcStYLaX89NVOGCrBazLMrAYnJc51k8n9/u6wDxO2/8ee4/UacelT89q2WmSh4jryfCvyjq+myULjZ0Hvt3vYC1tOFFL60aDgLb2E+g523LZIznGEaD2dLFbfiqgECVrCxVe3Ii9HTuoRzlszCLhFyU1qZ5Cnwf86NtfU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1559574397; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=5xgnmiac41lFgQdf4Zijge7mj22Uj4m0sXUaosKRpf4=; b=fdRGU4rr3Y8DO+ESv6tQXh/uokMTuwN/ERqGyOz+UmwOBEjZ53j18LkMgpyB+16YF8l0Jab+xYubFcgEL8pAJst/5VUdRxhYiPmw/OdfO9+S3HZr0vjJ+SHDVGf30pkc6lU4BZmsHOhGqxG2/jc2PTwoMCLSdOgudjcNQgZsVLs= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 155957439731680.36526758180162; Mon, 3 Jun 2019 08:06:37 -0700 (PDT) Received: from localhost ([127.0.0.1]:36313 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hXoXc-0002IL-3c for importer@patchew.org; Mon, 03 Jun 2019 11:06:28 -0400 Received: from eggs.gnu.org ([209.51.188.92]:39786) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hXoUw-0000gc-VA for qemu-devel@nongnu.org; Mon, 03 Jun 2019 11:03:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hXoUv-0007s6-B5 for qemu-devel@nongnu.org; Mon, 03 Jun 2019 11:03:42 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48496) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hXoUq-0007jW-Kq; Mon, 03 Jun 2019 11:03:36 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 35D783107B2E; Mon, 3 Jun 2019 15:03:31 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-129.ams2.redhat.com [10.36.116.129]) by smtp.corp.redhat.com (Postfix) with ESMTP id C209767279; Mon, 3 Jun 2019 15:03:28 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Mon, 3 Jun 2019 17:02:14 +0200 Message-Id: <20190603150233.6614-10-kwolf@redhat.com> In-Reply-To: <20190603150233.6614-1-kwolf@redhat.com> References: <20190603150233.6614-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.47]); Mon, 03 Jun 2019 15:03:31 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 09/28] nvme: add Get/Set Feature Timestamp support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" From: Kenneth Heitke Signed-off-by: Kenneth Heitke Reviewed-by: Klaus Birkelund Jensen Signed-off-by: Kevin Wolf --- hw/block/nvme.h | 2 + include/block/nvme.h | 2 + hw/block/nvme.c | 106 +++++++++++++++++++++++++++++++++++++++++- hw/block/trace-events | 2 + 4 files changed, 110 insertions(+), 2 deletions(-) diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 56c9d4b4b1..557194ee19 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -79,6 +79,8 @@ typedef struct NvmeCtrl { uint32_t cmbloc; uint8_t *cmbuf; uint64_t irq_status; + uint64_t host_timestamp; /* Timestamp sent by the h= ost */ + uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ =20 char *serial; NvmeNamespace *namespaces; diff --git a/include/block/nvme.h b/include/block/nvme.h index 849a6f3fa3..3ec8efcc43 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -581,6 +581,7 @@ enum NvmeIdCtrlOncs { NVME_ONCS_WRITE_ZEROS =3D 1 << 3, NVME_ONCS_FEATURES =3D 1 << 4, NVME_ONCS_RESRVATIONS =3D 1 << 5, + NVME_ONCS_TIMESTAMP =3D 1 << 6, }; =20 #define NVME_CTRL_SQES_MIN(sqes) ((sqes) & 0xf) @@ -622,6 +623,7 @@ enum NvmeFeatureIds { NVME_INTERRUPT_VECTOR_CONF =3D 0x9, NVME_WRITE_ATOMICITY =3D 0xa, NVME_ASYNCHRONOUS_EVENT_CONF =3D 0xb, + NVME_TIMESTAMP =3D 0xe, NVME_SOFTWARE_PROGRESS_MARKER =3D 0x80 }; =20 diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 63a5b58849..ea409da76e 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -219,6 +219,30 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVe= ctor *iov, uint64_t prp1, return NVME_INVALID_FIELD | NVME_DNR; } =20 +static uint16_t nvme_dma_write_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + uint64_t prp1, uint64_t prp2) +{ + QEMUSGList qsg; + QEMUIOVector iov; + uint16_t status =3D NVME_SUCCESS; + + if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) { + return NVME_INVALID_FIELD | NVME_DNR; + } + if (qsg.nsg > 0) { + if (dma_buf_write(ptr, len, &qsg)) { + status =3D NVME_INVALID_FIELD | NVME_DNR; + } + qemu_sglist_destroy(&qsg); + } else { + if (qemu_iovec_to_buf(&iov, 0, ptr, len) !=3D len) { + status =3D NVME_INVALID_FIELD | NVME_DNR; + } + qemu_iovec_destroy(&iov); + } + return status; +} + static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len, uint64_t prp1, uint64_t prp2) { @@ -678,7 +702,6 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeI= dentify *c) return ret; } =20 - static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) { NvmeIdentify *c =3D (NvmeIdentify *)cmd; @@ -696,6 +719,57 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cm= d) } } =20 +static inline void nvme_set_timestamp(NvmeCtrl *n, uint64_t ts) +{ + trace_nvme_setfeat_timestamp(ts); + + n->host_timestamp =3D le64_to_cpu(ts); + n->timestamp_set_qemu_clock_ms =3D qemu_clock_get_ms(QEMU_CLOCK_REALTI= ME); +} + +static inline uint64_t nvme_get_timestamp(const NvmeCtrl *n) +{ + uint64_t current_time =3D qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + uint64_t elapsed_time =3D current_time - n->timestamp_set_qemu_clock_m= s; + + union nvme_timestamp { + struct { + uint64_t timestamp:48; + uint64_t sync:1; + uint64_t origin:3; + uint64_t rsvd1:12; + }; + uint64_t all; + }; + + union nvme_timestamp ts; + ts.all =3D 0; + + /* + * If the sum of the Timestamp value set by the host and the elapsed + * time exceeds 2^48, the value returned should be reduced modulo 2^48. + */ + ts.timestamp =3D (n->host_timestamp + elapsed_time) & 0xffffffffffff; + + /* If the host timestamp is non-zero, set the timestamp origin */ + ts.origin =3D n->host_timestamp ? 0x01 : 0x00; + + trace_nvme_getfeat_timestamp(ts.all); + + return cpu_to_le64(ts.all); +} + +static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd) +{ + uint64_t prp1 =3D le64_to_cpu(cmd->prp1); + uint64_t prp2 =3D le64_to_cpu(cmd->prp2); + + uint64_t timestamp =3D nvme_get_timestamp(n); + + return nvme_dma_read_prp(n, (uint8_t *)×tamp, + sizeof(timestamp), prp1, prp2); +} + static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *r= eq) { uint32_t dw10 =3D le32_to_cpu(cmd->cdw10); @@ -710,6 +784,9 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *= cmd, NvmeRequest *req) result =3D cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) = << 16)); trace_nvme_getfeat_numq(result); break; + case NVME_TIMESTAMP: + return nvme_get_feature_timestamp(n, cmd); + break; default: trace_nvme_err_invalid_getfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; @@ -719,6 +796,24 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd = *cmd, NvmeRequest *req) return NVME_SUCCESS; } =20 +static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd) +{ + uint16_t ret; + uint64_t timestamp; + uint64_t prp1 =3D le64_to_cpu(cmd->prp1); + uint64_t prp2 =3D le64_to_cpu(cmd->prp2); + + ret =3D nvme_dma_write_prp(n, (uint8_t *)×tamp, + sizeof(timestamp), prp1, prp2); + if (ret !=3D NVME_SUCCESS) { + return ret; + } + + nvme_set_timestamp(n, timestamp); + + return NVME_SUCCESS; +} + static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *r= eq) { uint32_t dw10 =3D le32_to_cpu(cmd->cdw10); @@ -735,6 +830,11 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd = *cmd, NvmeRequest *req) req->cqe.result =3D cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); break; + + case NVME_TIMESTAMP: + return nvme_set_feature_timestamp(n, cmd); + break; + default: trace_nvme_err_invalid_setfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; @@ -907,6 +1007,8 @@ static int nvme_start_ctrl(NvmeCtrl *n) nvme_init_sq(&n->admin_sq, n, n->bar.asq, 0, 0, NVME_AQA_ASQS(n->bar.aqa) + 1); =20 + nvme_set_timestamp(n, 0ULL); + return 0; } =20 @@ -1270,7 +1372,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **= errp) id->sqes =3D (0x6 << 4) | 0x6; id->cqes =3D (0x4 << 4) | 0x4; id->nn =3D cpu_to_le32(n->num_namespaces); - id->oncs =3D cpu_to_le16(NVME_ONCS_WRITE_ZEROS); + id->oncs =3D cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP); id->psd[0].mp =3D cpu_to_le16(0x9c4); id->psd[0].enlat =3D cpu_to_le32(0x10); id->psd[0].exlat =3D cpu_to_le32(0x4); diff --git a/hw/block/trace-events b/hw/block/trace-events index b92039a573..97a17838ed 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -46,6 +46,8 @@ nvme_identify_nslist(uint16_t ns) "identify namespace lis= t, nsid=3D%"PRIu16"" nvme_getfeat_vwcache(const char* result) "get feature volatile write cache= , result=3D%s" nvme_getfeat_numq(int result) "get feature number of queues, result=3D%d" nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested c= q_count=3D%d sq_count=3D%d, responding with cq_count=3D%d sq_count=3D%d" +nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp =3D 0x%"PRIx64"" +nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp =3D 0x%"PRIx64"" nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrup= t mask set, data=3D0x%"PRIx64", new_mask=3D0x%"PRIx64"" nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrup= t mask clr, data=3D0x%"PRIx64", new_mask=3D0x%"PRIx64"" nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=3D0x%"P= RIx64"" --=20 2.20.1