Skip to content

Commit 3200019

Browse files
committed
Add power-measurement-log command (LID 0x25)
Add power-measurement-log command, including normal, json and binary outputs. Add Operational Lifetime Energy Consumed (OLEC) and Interval Power Measurement (IPM) to smart log output. Signed-off-by: Jim Munn <[email protected]>
1 parent 5263254 commit 3200019

11 files changed

Lines changed: 499 additions & 46 deletions

File tree

libnvme/src/nvme/cmds.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,25 @@ nvme_init_get_log_mgmt_addr_list(struct nvme_passthru_cmd *cmd,
15201520
log, len);
15211521
}
15221522

1523+
/**
1524+
* nvme_init_get_log_power_measurement() - Initialize passthru command for
1525+
* Power Measurement
1526+
* @cmd: Passthru command to use
1527+
* @log: User address to store the log page
1528+
* @len: The allocated length of the log page
1529+
*
1530+
* Initializes the passthru command buffer for the Get Log command with
1531+
* LID value %NVME_LOG_LID_POWER_MEASUREMENT
1532+
*/
1533+
static inline void
1534+
nvme_init_get_log_power_measurement(struct nvme_passthru_cmd *cmd,
1535+
struct nvme_power_meas_log *log, __u32 len)
1536+
{
1537+
nvme_init_get_log(cmd, NVME_NSID_ALL,
1538+
NVME_LOG_LID_POWER_MEASUREMENT, NVME_CSI_NVM,
1539+
log, len);
1540+
}
1541+
15231542
/**
15241543
* nvme_init_get_log_phy_rx_eom() - Initialize passthru command for
15251544
* Physical Interface Receiver Eye Opening Measurement

libnvme/src/nvme/types.h

Lines changed: 147 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3773,7 +3773,26 @@ enum nvme_err_status_field {
37733773
* reached. A value of %0h, indicates that this transition
37743774
* has never occurred or this field is not implemented.
37753775
* @thm_temp2_total_time: Total Time For Thermal Management Temperature 2
3776-
* @rsvd232: Reserved
3776+
* @op_lifetime_energy_consumed: Operational Lifetime Energy Consumed: Contains
3777+
* the cumulative operational energy consumed by the NVM
3778+
* subsystem in watt-hours calculated from all interval
3779+
* power measurements collected from the time of
3780+
* manufacture to the point that this log page is read.
3781+
* This value is rounded up (e.g., two indicates the
3782+
* number of watt-hours consumed is greater than 1 and
3783+
* less than or equal to 2). This field shall not wrap
3784+
* once the value %FFFFFFFFFFFFFFFFh is reached. A value
3785+
* of %0h indicates that the cumulative operational energy
3786+
* consumed is not reported.
3787+
* @interval_power_measurement: Interval Power Measurement: Contains the average
3788+
* of power measurement samples over the most recent one
3789+
* second interval at the time of processing the Get Log
3790+
* Page command. The power in Watts is equal to the
3791+
* Interval Power Measurement Value (bits 15:0) multiplied
3792+
* by the scale indicated in the Interval Power Measurement
3793+
* Scale field (bits 17:16). A value of %0h indicates that
3794+
* the interval power measurement is not reported.
3795+
* @rsvd244: Reserved
37773796
*/
37783797
struct nvme_smart_log {
37793798
__u8 critical_warning;
@@ -3800,7 +3819,9 @@ struct nvme_smart_log {
38003819
__le32 thm_temp2_trans_count;
38013820
__le32 thm_temp1_total_time;
38023821
__le32 thm_temp2_total_time;
3803-
__u8 rsvd232[280];
3822+
__le64 op_lifetime_energy_consumed;
3823+
__le32 interval_power_measurement;
3824+
__u8 rsvd244[268];
38043825
};
38053826

38063827
/**
@@ -4669,6 +4690,23 @@ struct nvme_timestamp {
46694690
__u8 rsvd;
46704691
};
46714692

4693+
/**
4694+
* enum nvme_timestamp_attr - Timestamp Attribute field
4695+
* @NVME_TIMESTAMP_ATTR_SYNC_SHIFT: Shift amount to get the timestamp synch
4696+
* @NVME_TIMESTAMP_ATTR_TO_SHIFT: Shift amount to get the timestamp origin
4697+
* @NVME_TIMESTAMP_ATTR_SYNC_MASK: Mask to get the timestamp synch
4698+
* @NVME_TIMESTAMP_ATTR_TO_MASK: Mask to get the timestamp origin
4699+
*/
4700+
enum nvme_timestamp_attr {
4701+
NVME_TIMESTAMP_ATTR_SYNC_SHIFT = 0,
4702+
NVME_TIMESTAMP_ATTR_TO_SHIFT = 1,
4703+
NVME_TIMESTAMP_ATTR_SYNC_MASK = 0x1,
4704+
NVME_TIMESTAMP_ATTR_TO_MASK = 0x7,
4705+
};
4706+
4707+
#define NVME_TIMESTAMP_ATTR_SYNC(attr) NVME_GET(attr, TIMESTAMP_ATTR_SYNC)
4708+
#define NVME_TIMESTAMP_ATTR_TO(attr) NVME_GET(attr, TIMESTAMP_ATTR_TO)
4709+
46724710
/**
46734711
* struct nvme_time_stamp_change_event - Timestamp Change Event
46744712
* @previous_timestamp: Previous Timestamp
@@ -6102,6 +6140,113 @@ struct nvme_fdp_ruh_status {
61026140
struct nvme_fdp_ruh_status_desc ruhss[];
61036141
};
61046142

6143+
/**
6144+
* enum nvme_pma - Power Measurement Attributes (PMA) field
6145+
* @NVME_PMA_PME_SHIFT: Shift amount to get the power measurement enable
6146+
* @NVME_PMA_NCPDF_SHIFT: Shift amount to get the non-contiguous power data flag
6147+
* @NVME_PMA_EPF_SHIFT: Shift amount to get the estimated power flag
6148+
* @NVME_PMA_MIPWRTS_SHIFT: Shift amount to get the maximum interval power timestamp support
6149+
* @NVME_PMA_PHDO_SHIFT: Shift amount to get the power histogram descriptor overflow
6150+
* @NVME_PMA_PMT_SHIFT: Shift amount to get the power measurement type
6151+
* @NVME_PMA_PME_MASK: Mask to get the power measurement enable
6152+
* @NVME_PMA_NCPDF_MASK: Mask to get the non-contiguous power data flag
6153+
* @NVME_PMA_EPF_MASK: Mask to get the estimated power flag
6154+
* @NVME_PMA_MIPWRTS_MASK: Mask to get the maximum interval power timestamp support
6155+
* @NVME_PMA_PHDO_MASK: Mask to get the power histogram descriptor overflow
6156+
* @NVME_PMA_PMT_MASK: Mask to get the power measurement type
6157+
*/
6158+
enum nvme_pma {
6159+
NVME_PMA_PME_SHIFT = 0,
6160+
NVME_PMA_NCPDF_SHIFT = 1,
6161+
NVME_PMA_EPF_SHIFT = 2,
6162+
NVME_PMA_MIPWRTS_SHIFT = 3,
6163+
NVME_PMA_PHDO_SHIFT = 4,
6164+
NVME_PMA_PMT_SHIFT = 12,
6165+
NVME_PMA_PME_MASK = 0x1,
6166+
NVME_PMA_NCPDF_MASK = 0x1,
6167+
NVME_PMA_EPF_MASK = 0x1,
6168+
NVME_PMA_MIPWRTS_MASK = 0x1,
6169+
NVME_PMA_PHDO_MASK = 0x1,
6170+
NVME_PMA_PMT_MASK = 0xf,
6171+
};
6172+
6173+
/**
6174+
* struct nvme_power_histogram_desc - Power Histogram Descriptor
6175+
* @phbc: Power Histogram Bin Count. Does not wrap after %FFFFFFFFh.
6176+
* Cleared to %0h if PMC is %0h.
6177+
* @phblt: Power Histogram Bin Lower Threshold. Bits 17:16 are PWRS
6178+
* (see &enum nvme_psd_ps), bits 15:0 are PWRV.
6179+
*/
6180+
struct nvme_power_histogram_desc {
6181+
__le32 phbc;
6182+
__le32 phblt;
6183+
};
6184+
6185+
/**
6186+
* struct nvme_power_meas_log - Power Measurement Log Page (Log Identifier 25h)
6187+
* @ver: Version. Shall be cleared to %0h.
6188+
* @pmgn: Power Measurement Generation Number. Incremented each time a
6189+
* Set Features command with Action = %1h (Start Power Measurements)
6190+
* is successfully completed. Rolls over from %FFh to %0h.
6191+
* @pma: Power Measurement Attributes. See &enum nvme_pma.
6192+
* @sze: Size. Indicates the size of this log page in bytes.
6193+
* @pmc: Power Measurement Count. Number of interval power measurements
6194+
* collected. Does not wrap after %FFFFFFFFh. Cleared to %0h when
6195+
* Start Power Measurements succeeds or if no measurement has occurred.
6196+
* @nphd: Number of Power Histogram Descriptors in this log page.
6197+
* @smtr: Stop Measurement Time Remaining. Time remaining in minutes until
6198+
* controller stops collecting interval power measurements.
6199+
* %0h means not specified.
6200+
* @smts: Stop Measurement Timestamp. Timestamp of when interval power
6201+
* measurements stopped being collected. See &struct nvme_timestamp.
6202+
* @phds: Power Histogram Descriptor Size. Size in bytes of each descriptor.
6203+
* @phbs: Power Histogram Bin Size. Size in milliwatts of each bin.
6204+
* Shall be set to 250 milliwatts.
6205+
* @nphds: Number of Power Histogram Descriptors Supported. Maximum number
6206+
* of descriptors that can be reported. If %0h, NPHD shall be
6207+
* cleared to %0h and no descriptors are reported.
6208+
* @vss: Vendor Specific Size. Size in bytes of the Vendor Specific field.
6209+
* @phdoc: Power Histogram Descriptor Overflow Count. Number of interval
6210+
* power measurements greater than the maximum power indicated by
6211+
* the last Power Histogram Descriptor. Does not wrap after %FFFFFFFFh.
6212+
* @rsvd36: Reserved.
6213+
* @aipwr: Average Interval Power. Bits 31:18 are reserved. Bits 17:16
6214+
* contain the Power Scale (PWRS); see &enum nvme_psd_ps. Bits 15:0
6215+
* contain the Power Value (PWRV).
6216+
* @mipwr: Maximum Interval Power. Bits 31:18 are reserved. Bits 17:16
6217+
* contain the Power Scale (PWRS); see &enum nvme_psd_ps. Bits 15:0
6218+
* contain the Power Value (PWRV).
6219+
* @mipwrt: Maximum Interval Power Timestamp. Timestamp of when the maximum
6220+
* interval power was collected. See &struct nvme_timestamp.
6221+
* @ipwrpe: Interval Power Percent Error. Maximum percent error (0-100%).
6222+
* Values 101-254 reserved. 255 indicates not reported.
6223+
* @rsvd57: Reserved.
6224+
* @descs: Power Histogram Descriptors (&struct nvme_power_histogram_desc).
6225+
*/
6226+
struct nvme_power_meas_log {
6227+
__u8 ver;
6228+
__u8 pmgn;
6229+
__le16 pma;
6230+
__le32 sze;
6231+
__le32 pmc;
6232+
__le16 nphd;
6233+
__le16 smtr;
6234+
struct nvme_timestamp smts;
6235+
__le16 phds;
6236+
__le16 phbs;
6237+
__le16 nphds;
6238+
__le16 vss;
6239+
__le32 phdoc;
6240+
__u8 rsvd36[4];
6241+
__le32 aipwr;
6242+
__le32 mipwr;
6243+
struct nvme_timestamp mipwrt;
6244+
__u8 ipwrpe;
6245+
__u8 rsvd57[7];
6246+
struct nvme_power_histogram_desc descs[];
6247+
};
6248+
6249+
61056250
/**
61066251
* struct nvme_lba_status_desc - LBA Status Descriptor Entry
61076252
* @dslba: Descriptor Starting LBA

nvme-builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ COMMAND_LIST(
6767
ENTRY("host-discovery-log", "Retrieve Host Discovery Log, show it", get_host_discovery_log)
6868
ENTRY("ave-discovery-log", "Retrieve AVE Discovery Log, show it", get_ave_discovery_log)
6969
ENTRY("pull-model-ddc-req-log", "Retrieve Pull Model DDC Request Log, show it", get_pull_model_ddc_req_log)
70+
ENTRY("power-measurement-log", "Retrieve Power Measurement Log, show it", get_power_measurement_log)
7071
ENTRY("set-feature", "Set a feature and show the resulting value", set_feature)
7172
ENTRY("set-property", "Set a property and show the resulting value", set_property)
7273
ENTRY("get-property", "Get a property and show the resulting value", get_property)

nvme-cmds.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,33 @@ nvme_get_log_mgmt_addr_list(struct nvme_transport_handle *hdl,
11001100
return nvme_get_log(hdl, &cmd, false, len);
11011101
}
11021102

1103+
/**
1104+
* nvme_get_log_power_measurement() - Retrieve the Power Measurement Log Page
1105+
* @hdl: Transport handle for the controller.
1106+
* @log: Pointer to the buffer (@struct nvme_power_meas_log) where
1107+
* the log page data will be stored.
1108+
* @len: Length of the buffer provided in @log.
1109+
*
1110+
* Submits the Get Log Page command specifically for the Power Measurement Log.
1111+
*
1112+
* It automatically sets the Log Identifier (LID) to
1113+
* NVME_LOG_LID_POWER_MEASUREMENT, Retain Asynchronous Event (RAE) to false,
1114+
* and uses NVME_NSID_ALL.
1115+
*
1116+
* Return: 0 on success, the NVMe command status on error, or a negative
1117+
* errno otherwise.
1118+
*/
1119+
static inline int
1120+
nvme_get_log_power_measurement(struct nvme_transport_handle *hdl,
1121+
struct nvme_power_meas_log *log, __u32 len)
1122+
{
1123+
struct nvme_passthru_cmd cmd;
1124+
1125+
nvme_init_get_log_power_measurement(&cmd, log, len);
1126+
1127+
return nvme_get_log(hdl, &cmd, false, NVME_LOG_PAGE_PDU_SIZE);
1128+
}
1129+
11031130
/**
11041131
* nvme_get_log_phy_rx_eom() - Retrieve the Physical Interface Receiver Eye
11051132
* Opening Measurement Log Page

nvme-print-binary.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,11 @@ static void binary_pull_model_ddc_req_log(struct nvme_pull_model_ddc_req_log *lo
347347
d_raw((unsigned char *)log, le32_to_cpu(log->tpdrpl));
348348
}
349349

350+
static void binary_power_meas_log(struct nvme_power_meas_log *log, __u32 size)
351+
{
352+
d_raw((unsigned char *)log, size);
353+
}
354+
350355
static struct print_ops binary_print_ops = {
351356
/* libnvme types.h print functions */
352357
.ana_log = binary_ana_log,
@@ -421,6 +426,7 @@ static struct print_ops binary_print_ops = {
421426
.host_discovery_log = binary_host_discovery_log,
422427
.ave_discovery_log = binary_ave_discovery_log,
423428
.pull_model_ddc_req_log = binary_pull_model_ddc_req_log,
429+
.power_meas_log = binary_power_meas_log,
424430

425431
/* libnvme tree print functions */
426432
.list_item = NULL,

nvme-print-json.c

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,8 @@ static void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
776776
obj_add_uint(r, "thm_temp2_trans_count", le32_to_cpu(smart->thm_temp2_trans_count));
777777
obj_add_uint(r, "thm_temp1_total_time", le32_to_cpu(smart->thm_temp1_total_time));
778778
obj_add_uint(r, "thm_temp2_total_time", le32_to_cpu(smart->thm_temp2_total_time));
779+
obj_add_uint64(r, "op_lifetime_energy_consumed", le64_to_cpu(smart->op_lifetime_energy_consumed));
780+
obj_add_uint(r, "interval_power_measurement", le32_to_cpu(smart->interval_power_measurement));
779781

780782
json_print(r);
781783
}
@@ -3768,24 +3770,10 @@ static void json_feature_show_fields_host_mem_buf(struct json_object *r, unsigne
37683770

37693771
static void json_timestamp(struct json_object *r, struct nvme_timestamp *ts)
37703772
{
3771-
char buffer[BUF_LEN];
3772-
time_t timestamp = int48_to_long(ts->timestamp) / 1000;
3773-
struct tm *tm = localtime(&timestamp);
3774-
37753773
obj_add_uint64(r, "timestamp", int48_to_long(ts->timestamp));
3776-
3777-
if (!strftime(buffer, sizeof(buffer), "%c %Z", tm))
3778-
sprintf(buffer, "%s", "-");
3779-
3780-
obj_add_str(r, "timestamp string", buffer);
3781-
3782-
obj_add_str(r, "timestamp origin", ts->attr & 2 ?
3783-
"The Timestamp field was initialized with a Timestamp value using a Set Features command." :
3784-
"The Timestamp field was initialized to 0h by a Controller Level Reset.");
3785-
3786-
obj_add_str(r, "synch", ts->attr & 1 ?
3787-
"The controller may have stopped counting during vendor specific intervals after the Timestamp value was initialized." :
3788-
"The controller counted time in milliseconds continuously since the Timestamp value was initialized.");
3774+
obj_add_str(r, "timestamp string", nvme_format_timestamp(ts->timestamp));
3775+
obj_add_str(r, "timestamp origin", nvme_format_timestamp_origin(ts->attr));
3776+
obj_add_str(r, "synch", nvme_format_timestamp_sync(ts->attr));
37893777
}
37903778

37913779
static void json_feature_show_fields_timestamp(struct json_object *r, unsigned char *buf)
@@ -5716,6 +5704,63 @@ static void json_pull_model_ddc_req_log(struct nvme_pull_model_ddc_req_log *log)
57165704
obj_d(r, "osp", (unsigned char *)log->osp, osp_len, 16, 1);
57175705
}
57185706

5707+
static void json_power_meas_log(struct nvme_power_meas_log *log, __u32 size UNUSED)
5708+
{
5709+
struct json_object *r = json_create_object();
5710+
struct json_object *descs;
5711+
struct json_object *smts_obj;
5712+
struct json_object *mipwrt_obj;
5713+
__u16 nphd = le16_to_cpu(log->nphd);
5714+
__u16 pma = le16_to_cpu(log->pma);
5715+
__u8 pmt = NVME_GET(pma, PMA_PMT);
5716+
__u16 i;
5717+
5718+
obj_add_uint(r, "ver", log->ver);
5719+
obj_add_uint(r, "pmgn", log->pmgn);
5720+
obj_add_uint(r, "pma", pma);
5721+
obj_add_uint(r, "pme", NVME_GET(pma, PMA_PME));
5722+
obj_add_uint(r, "ncpdf", NVME_GET(pma, PMA_NCPDF));
5723+
obj_add_uint(r, "epf", NVME_GET(pma, PMA_EPF));
5724+
obj_add_uint(r, "mipwrts", NVME_GET(pma, PMA_MIPWRTS));
5725+
obj_add_uint(r, "phdo", NVME_GET(pma, PMA_PHDO));
5726+
obj_add_uint(r, "pmt", pmt);
5727+
obj_add_str(r, "pmt_str", nvme_power_measurement_type_to_string(pmt));
5728+
obj_add_uint(r, "sze", le32_to_cpu(log->sze));
5729+
obj_add_uint(r, "pmc", le32_to_cpu(log->pmc));
5730+
obj_add_uint(r, "nphd", nphd);
5731+
obj_add_uint(r, "smtr", le16_to_cpu(log->smtr));
5732+
5733+
smts_obj = json_create_object();
5734+
json_timestamp(smts_obj, &log->smts);
5735+
obj_add_obj(r, "smts", smts_obj);
5736+
5737+
obj_add_uint(r, "phds", le16_to_cpu(log->phds));
5738+
obj_add_uint(r, "phbs", le16_to_cpu(log->phbs));
5739+
obj_add_uint(r, "nphds", le16_to_cpu(log->nphds));
5740+
obj_add_uint(r, "vss", le16_to_cpu(log->vss));
5741+
obj_add_uint(r, "phdoc", le32_to_cpu(log->phdoc));
5742+
obj_add_uint(r, "aipwr", le32_to_cpu(log->aipwr));
5743+
obj_add_uint(r, "mipwr", le32_to_cpu(log->mipwr));
5744+
5745+
mipwrt_obj = json_create_object();
5746+
json_timestamp(mipwrt_obj, &log->mipwrt);
5747+
obj_add_obj(r, "mipwrt", mipwrt_obj);
5748+
5749+
obj_add_uint(r, "ipwrpe", log->ipwrpe);
5750+
5751+
descs = json_create_array();
5752+
for (i = 0; i < nphd; i++) {
5753+
struct json_object *desc = json_create_object();
5754+
5755+
obj_add_uint(desc, "phbc", le32_to_cpu(log->descs[i].phbc));
5756+
obj_add_uint(desc, "phblt", le32_to_cpu(log->descs[i].phblt));
5757+
json_object_array_add(descs, desc);
5758+
}
5759+
obj_add_obj(r, "descs", descs);
5760+
5761+
json_print(r);
5762+
}
5763+
57195764
static struct print_ops json_print_ops = {
57205765
/* libnvme types.h print functions */
57215766
.ana_log = json_ana_log,
@@ -5791,6 +5836,7 @@ static struct print_ops json_print_ops = {
57915836
.host_discovery_log = json_host_discovery_log,
57925837
.ave_discovery_log = json_ave_discovery_log,
57935838
.pull_model_ddc_req_log = json_pull_model_ddc_req_log,
5839+
.power_meas_log = json_power_meas_log,
57945840

57955841
/* libnvme tree print functions */
57965842
.list_item = json_list_item,

0 commit comments

Comments
 (0)