Index: usr.sbin/bhyve/pci_nvme.c =================================================================== --- usr.sbin/bhyve/pci_nvme.c +++ usr.sbin/bhyve/pci_nvme.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -129,6 +130,12 @@ #define NVME_DOORBELL_OFFSET offsetof(struct nvme_registers, doorbell) +#define TIMEVAL_DIFF_MILLISECONDS(now, from) \ + ((now.tv_sec - from.tv_sec) * 1000 + (now.tv_usec - from.tv_usec) / 1000) + +#define TIMEVAL_MILLISECONDS(now) \ + (now.tv_sec * 1000 + now.tv_usec / 1000) + enum nvme_controller_register_offsets { NVME_CR_CAP_LOW = 0x00, NVME_CR_CAP_HI = 0x04, @@ -159,6 +166,8 @@ #define NVME_CQ_INTEN 0x01 #define NVME_CQ_INTCOAL 0x02 +#define NVME_FEAT_TIMESTAMP_TIMESTAMP_ORIGIN_SHIFT (1) + struct nvme_completion_queue { struct nvme_completion *qbase; pthread_mutex_t mtx; @@ -242,12 +251,32 @@ struct nvme_completion *); struct nvme_feature_obj { - uint32_t cdw11; + void *data; nvme_feature_cb set; nvme_feature_cb get; bool namespace_specific; }; +/* Timestamp - Data Structure for Get Features */ +union nvme_feature_timestamp_data { + struct { + uint64_t timestamp : 48; + uint64_t synch : 1; + uint64_t origin : 3; + uint64_t reserved1 : 12; + }; + uint64_t all; +}; + +/* feature timestamp */ +static struct timestamp_data { + uint64_t ts_set_data; + uint64_t ts_set_time; +} ts_data = { + .ts_set_data = 0, + .ts_set_time = 0, +}; + #define NVME_FID_MAX (NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION + 1) struct pci_nvme_aer { @@ -303,6 +332,8 @@ STAILQ_HEAD(, pci_nvme_aer) aer_list; uint32_t aer_count; + + struct timeval power_on_time; }; @@ -359,6 +390,14 @@ struct nvme_feature_obj *, struct nvme_command *, struct nvme_completion *); +static void nvme_feature_timestamp_get(struct pci_nvme_softc *, + struct nvme_feature_obj *, + struct nvme_command *, + struct nvme_completion *); +static void nvme_feature_timestamp_set(struct pci_nvme_softc *, + struct nvme_feature_obj *, + struct nvme_command *, + struct nvme_completion *); static __inline void cpywithpad(char *dst, size_t dst_size, const char *src, char pad) @@ -487,7 +526,8 @@ (4 << NVME_CTRLR_DATA_CQES_MIN_SHIFT); cd->nn = 1; /* number of namespaces */ - cd->oncs = 0; + cd->oncs = 1 << NVME_CTRLR_DATA_ONCS_TIMESTAMP_SHIFT; + switch (sc->dataset_management) { case NVME_DATASET_MANAGEMENT_AUTO: if (sc->nvstore.deallocate) @@ -503,6 +543,8 @@ cd->fna = 0x03; cd->power_state[0].mp = 10; + + gettimeofday(&sc->power_on_time, NULL); } /* @@ -627,6 +669,9 @@ nvme_feature_invalid_cb; sc->feat[NVME_FEAT_PREDICTABLE_LATENCY_MODE_WINDOW].get = nvme_feature_invalid_cb; + sc->feat[NVME_FEAT_TIMESTAMP].set = nvme_feature_timestamp_set; + sc->feat[NVME_FEAT_TIMESTAMP].get = nvme_feature_timestamp_get; + sc->feat[NVME_FEAT_TIMESTAMP].data = &ts_data; } static void @@ -1376,6 +1421,50 @@ sc->num_q_is_set = true; } +static void +nvme_feature_timestamp_set(struct pci_nvme_softc *sc, + struct nvme_feature_obj *feat, + struct nvme_command *command, + struct nvme_completion *compl) +{ + struct timeval now; + struct timestamp_data *data = (struct timestamp_data *)feat->data; + + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, (uint8_t*)&data->ts_set_data, + sizeof(data->ts_set_data), NVME_COPY_FROM_PRP); + + DPRINTF("%s: value: %lu", __func__, data->ts_set_data); + data->ts_set_data &= 0xFFFFFFFFFFFF; + + gettimeofday(&now, NULL); + data->ts_set_time = TIMEVAL_MILLISECONDS(now); +} + +static void +nvme_feature_timestamp_get(struct pci_nvme_softc *sc, + struct nvme_feature_obj *feat, + struct nvme_command *command, + struct nvme_completion *compl) +{ + union nvme_feature_timestamp_data ts; + struct timeval now; + uint64_t elapsed; + struct timestamp_data *data = (struct timestamp_data *)feat->data;; + + gettimeofday(&now, NULL); + elapsed = (TIMEVAL_MILLISECONDS(now) + data->ts_set_time) & 0xFFFFFFFFFFFF; + + DPRINTF("%s: elapsed: %lu", __func__, elapsed); + + ts.origin = data->ts_set_time == 0 ? 0x00 : 0x01; + ts.timestamp = elapsed + data->ts_set_time; + + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, (uint8_t*)&ts.all, + sizeof(ts.all), NVME_COPY_TO_PRP); +} + static int nvme_opc_set_features(struct pci_nvme_softc *sc, struct nvme_command *command, struct nvme_completion *compl) @@ -1406,9 +1495,6 @@ if (feat->set) feat->set(sc, feat, command, compl); - if (compl->status == NVME_SC_SUCCESS) - feat->cdw11 = command->cdw11; - return (0); } @@ -1435,10 +1521,6 @@ feat->get(sc, feat, command, compl); } - if (compl->status == NVME_SC_SUCCESS) { - compl->cdw0 = feat->cdw11; - } - return (0); }