diff --git a/libnvme/src/nvme/cmds.c b/libnvme/src/nvme/cmds.c index 71457f5e65..eecc1aaaba 100644 --- a/libnvme/src/nvme/cmds.c +++ b/libnvme/src/nvme/cmds.c @@ -563,6 +563,7 @@ int nvme_get_feature_length(int fid, __u32 cdw11, enum nvme_data_tfr dir, case NVME_FEAT_FID_RESV_PERSIST: case NVME_FEAT_FID_WRITE_PROTECT: case NVME_FEAT_FID_POWER_LIMIT: + case NVME_FEAT_FID_POWER_MEASUREMENT: *len = 0; break; case NVME_FEAT_FID_ENH_CTRL_METADATA: diff --git a/libnvme/src/nvme/types.h b/libnvme/src/nvme/types.h index c6b7662661..b992f6863e 100644 --- a/libnvme/src/nvme/types.h +++ b/libnvme/src/nvme/types.h @@ -1092,6 +1092,16 @@ enum nvme_power_measurement_type { NVME_PMT_VS_MAX = 0xf, }; +/** + * enum nvme_power_measurement_action - Power measurement actions. + * @NVME_PMA_STOP: Stop power measurement + * @NVME_PMA_START: Start power measurement + */ +enum nvme_power_measurement_action { + NVME_PMA_STOP = 0x0, + NVME_PMA_START = 0x1, +}; + /** * nvme_psd_power_scale() - power scale occupies the upper 3 bits * @ps: power scale value @@ -8835,7 +8845,7 @@ enum nvme_cmd_get_log_lid { * @NVME_FEAT_FID_CONF_DEV_PERSONALITY: Configurable Device Personality * @NVME_FEAT_FID_POWER_LIMIT: Power Limit * @NVME_FEAT_FID_POWER_THRESH: Power Threshold - * @NVME_FEAT_FID_POEWR_MEASUREMENT: Power Measurement + * @NVME_FEAT_FID_POWER_MEASUREMENT: Power Measurement * @NVME_FEAT_FID_EMB_MGMT_CTRL_ADDR: Embedded Management Controller Address * @NVME_FEAT_FID_HOST_MGMT_AGENT_ADDR: Host Management Agent Address * @NVME_FEAT_FID_ENH_CTRL_METADATA: Enhanced Controller Metadata @@ -8885,7 +8895,7 @@ enum nvme_features_id { NVME_FEAT_FID_CONF_DEV_PERSONALITY = 0x22, NVME_FEAT_FID_POWER_LIMIT = 0x23, NVME_FEAT_FID_POWER_THRESH = 0x24, - NVME_FEAT_FID_POEWR_MEASUREMENT = 0x25, + NVME_FEAT_FID_POWER_MEASUREMENT = 0x25, NVME_FEAT_FID_EMB_MGMT_CTRL_ADDR = 0x78, NVME_FEAT_FID_HOST_MGMT_AGENT_ADDR = 0x79, NVME_FEAT_FID_ENH_CTRL_METADATA = 0x7d, @@ -9065,6 +9075,12 @@ enum nvme_features_id { * @NVME_FEAT_POWER_THRESH_PMTS_MASK: * @NVME_FEAT_POWER_THRESH_EPT_SHIFT: * @NVME_FEAT_POWER_THRESH_EPT_MASK: + * @NVME_FEAT_POWER_MEAS_ACT_SHIFT: + * @NVME_FEAT_POWER_MEAS_ACT_MASK: + * @NVME_FEAT_POWER_MEAS_PMTS_SHIFT: + * @NVME_FEAT_POWER_MEAS_PMTS_MASK: + * @NVME_FEAT_POWER_MEAS_SMT_SHIFT: + * @NVME_FEAT_POWER_MEAS_SMT_MASK: **/ enum nvme_feat { NVME_FEAT_ARBITRATION_BURST_SHIFT = 0, @@ -9231,6 +9247,12 @@ enum nvme_feat { NVME_FEAT_POWER_THRESH_PMTS_MASK = 0xf, NVME_FEAT_POWER_THRESH_EPT_SHIFT = 31, NVME_FEAT_POWER_THRESH_EPT_MASK = 0x1, + NVME_FEAT_POWER_MEAS_ACT_SHIFT = 0, + NVME_FEAT_POWER_MEAS_ACT_MASK = 0xf, + NVME_FEAT_POWER_MEAS_PMTS_SHIFT = 4, + NVME_FEAT_POWER_MEAS_PMTS_MASK = 0xf, + NVME_FEAT_POWER_MEAS_SMT_SHIFT = 16, + NVME_FEAT_POWER_MEAS_SMT_MASK = 0xffff, }; /** @@ -10514,6 +10536,10 @@ static inline void nvme_feature_decode_arbitration(__u32 value, __u8 *ab, #define NVME_FEAT_POWER_THRESH_PMTS(v) NVME_GET(v, FEAT_POWER_THRESH_PMTS) #define NVME_FEAT_POWER_THRESH_EPT(v) NVME_GET(v, FEAT_POWER_THRESH_EPT) +#define NVME_FEAT_POWER_MEAS_ACT(v) NVME_GET(v, FEAT_POWER_MEAS_ACT) +#define NVME_FEAT_POWER_MEAS_PMTS(v) NVME_GET(v, FEAT_POWER_MEAS_PMTS) +#define NVME_FEAT_POWER_MEAS_SMT(v) NVME_GET(v, FEAT_POWER_MEAS_SMT) + static inline void nvme_feature_decode_power_mgmt(__u32 value, __u8 *ps, __u8 *wh) { diff --git a/nvme-print-json.c b/nvme-print-json.c index d75e19f654..fad8244e44 100644 --- a/nvme-print-json.c +++ b/nvme-print-json.c @@ -4133,10 +4133,12 @@ static void json_feature_show_fields_power_limit(struct json_object *r, static void json_feature_show_fields_power_thresh(struct json_object *r, unsigned int result) { - __u8 field = NVME_FEAT_POWER_THRESH_EPT(result); - + __u8 field; + __u16 ptv; _cleanup_free_ char *k = NULL; + field = NVME_FEAT_POWER_THRESH_EPT(result); + obj_add_str(r, "Enable Power Threshold (EPT)", field ? "Enabled" : "Disabled"); @@ -4148,13 +4150,33 @@ static void json_feature_show_fields_power_thresh(struct json_object *r, obj_add_str(r, "Power Threshold Scale (PTS)", nvme_feature_power_limit_scale_to_string(field)); - field = NVME_FEAT_POWER_THRESH_PTV(result); - obj_add_uint(r, "Power Threshold Value (PTV)", field); + ptv = NVME_FEAT_POWER_THRESH_PTV(result); + + obj_add_uint(r, "Power Threshold Value (PTV)", ptv); - k = get_power_and_scale(field, NVME_FEAT_POWER_THRESH_PTS(result)); + k = get_power_and_scale(ptv, NVME_FEAT_POWER_THRESH_PTS(result)); obj_add_str(r, "Power Threshold", k); } +static void json_feature_show_fields_power_meas(struct json_object *r, + unsigned int result) +{ + __u8 field; + __u16 smt; + + field = NVME_FEAT_POWER_MEAS_ACT(result); + obj_add_str(r, "Action (ACT)", + nvme_power_measurement_action_to_string(field)); + + field = NVME_FEAT_POWER_MEAS_PMTS(result); + obj_add_str(r, "Power Measurement Type Select (PMTS)", + nvme_power_measurement_type_to_string(field)); + + smt = NVME_FEAT_POWER_MEAS_SMT(result); + + obj_add_uint(r, "Stop Measurement Time (SMT)", smt); +} + static void json_feature_show(enum nvme_features_id fid, int sel, unsigned int result) { struct json_object *r; @@ -4300,6 +4322,9 @@ static void json_feature_show_fields(enum nvme_features_id fid, unsigned int res case NVME_FEAT_FID_POWER_THRESH: json_feature_show_fields_power_thresh(r, result); break; + case NVME_FEAT_FID_POWER_MEASUREMENT: + json_feature_show_fields_power_meas(r, result); + break; default: break; } diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 5142f92f51..a5576b7b69 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -5427,6 +5427,16 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, field); printf("\n"); break; + case NVME_FEAT_FID_POWER_MEASUREMENT: + field = NVME_FEAT_POWER_MEAS_ACT(result); + printf("\tAction (ACT): %u - %s\n", field, + nvme_power_measurement_action_to_string(field)); + field = NVME_FEAT_POWER_MEAS_PMTS(result); + printf("\tPower Measurement Type Select (PMTS): %u - %s\n", + field, nvme_power_measurement_type_to_string(field)); + printf("\tStop Measurement Time (SMT): %u\n", + NVME_FEAT_POWER_MEAS_SMT(result)); + break; default: break; } diff --git a/nvme-print.c b/nvme-print.c index b4d9273f2b..5b13ab68ce 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -952,7 +952,7 @@ const char *nvme_feature_to_string(enum nvme_features_id feature) case NVME_FEAT_FID_CONF_DEV_PERSONALITY:return "Configurable Device Personality"; case NVME_FEAT_FID_POWER_LIMIT: return "Power Limit"; case NVME_FEAT_FID_POWER_THRESH: return "Power Threshold"; - case NVME_FEAT_FID_POEWR_MEASUREMENT: return "Power Measurement"; + case NVME_FEAT_FID_POWER_MEASUREMENT: return "Power Measurement"; case NVME_FEAT_FID_EMB_MGMT_CTRL_ADDR: return "Embedded Management Controller Address"; case NVME_FEAT_FID_HOST_MGMT_AGENT_ADDR:return "Host Management Agent Address"; case NVME_FEAT_FID_ENH_CTRL_METADATA: return "Enhanced Controller Metadata"; @@ -1526,6 +1526,21 @@ const char *nvme_power_measurement_type_to_string(__u8 pmt) return "Reserved"; } + +const char *nvme_power_measurement_action_to_string(__u8 act) +{ + switch (act) { + case 0: + return "Stop"; + case 1: + return "Start"; + default: + break; + } + + return "Reserved"; +} + void nvme_feature_show(enum nvme_features_id fid, int sel, unsigned int result) { nvme_print(show_feature, NORMAL, fid, sel, result); diff --git a/nvme-print.h b/nvme-print.h index 3ed2bdc7d8..3d80227e76 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -343,6 +343,7 @@ const char *nvme_pls_mode_to_string(__u8 mode); const char *nvme_bpwps_to_string(__u8 bpwps); const char *nvme_feature_power_limit_scale_to_string(__u8 pls); const char *nvme_power_measurement_type_to_string(__u8 pmt); +const char *nvme_power_measurement_action_to_string(__u8 act); void nvme_dev_full_path(nvme_ns_t n, char *path, size_t len); void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len); diff --git a/plugins/feat/feat-nvme.c b/plugins/feat/feat-nvme.c index 11bb301d89..3d4af81af2 100644 --- a/plugins/feat/feat-nvme.c +++ b/plugins/feat/feat-nvme.c @@ -50,6 +50,7 @@ static const char *arbitration_feat = "arbitration feature"; static const char *volatile_wc_feat = "volatile write cache feature"; static const char *power_limit_feat = "power limit feature"; static const char *power_thresh_feat = "power threshold feature"; +static const char *power_meas_feat = "power measurement feature"; static int feat_get(struct nvme_transport_handle *hdl, const __u8 fid, __u32 cdw11, __u8 sel, __u8 uidx, const char *feat) @@ -753,3 +754,78 @@ static int feat_power_thresh(int argc, char **argv, struct command *acmd, return err; } + +static int power_meas_set(struct nvme_transport_handle *hdl, const __u8 fid, + __u8 action, __u8 pmts, __u16 smt, __u8 uidx, bool sv) +{ + __u32 cdw11 = NVME_SET(action, FEAT_POWER_MEAS_ACT) | + NVME_SET(pmts, FEAT_POWER_MEAS_PMTS) | + NVME_SET(smt, FEAT_POWER_MEAS_SMT); + __u64 result; + int err; + + err = nvme_set_features(hdl, 0, fid, sv, cdw11, 0, 0, uidx, 0, NULL, 0, + &result); + + nvme_show_init(); + + if (err > 0) { + nvme_show_status(err); + } else if (err < 0) { + nvme_show_perror("Set %s", power_meas_feat); + } else { + nvme_show_result("Set %s: 0x%04x (%s)", power_meas_feat, cdw11, + sv ? "Save" : "Not save"); + nvme_feature_show_fields(fid, cdw11, NULL); + } + + nvme_show_finish(); + + return err; +} + +static int feat_power_meas(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *action = "action [0-1]: stop|start"; + const char *pmts = "power measurement type select"; + const char *smt = "stop measurement time"; + const __u8 fid = NVME_FEAT_FID_POWER_MEASUREMENT; + + _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; + + _cleanup_nvme_transport_handle_ struct nvme_transport_handle *hdl = + NULL; + int err; + + struct config { + __u8 act; + __u8 pmts; + __u16 smt; + __u8 uidx; + __u8 sel; + }; + + struct config cfg = { 0 }; + + FEAT_ARGS(opts, + OPT_BYTE("act", 0, &cfg.act, action), + OPT_BYTE("pmts", 0, &cfg.pmts, pmts), + OPT_SHRT("smt", 0, &cfg.smt, smt), + OPT_BYTE("uuid-index", 'u', &cfg.uidx, uuid_index)); + + err = parse_and_open(&ctx, &hdl, argc, argv, POWER_MEAS_DESC, opts); + if (err) + return err; + + if (argconfig_parse_seen(opts, "act") || + argconfig_parse_seen(opts, "pmts") || + argconfig_parse_seen(opts, "smt")) + err = power_meas_set(hdl, fid, cfg.act, cfg.pmts, cfg.smt, + cfg.uidx, + argconfig_parse_seen(opts, "save")); + else + err = feat_get(hdl, fid, 0, cfg.sel, 0, power_meas_feat); + + return err; +} diff --git a/plugins/feat/feat-nvme.h b/plugins/feat/feat-nvme.h index fcc54002bb..b41805d648 100644 --- a/plugins/feat/feat-nvme.h +++ b/plugins/feat/feat-nvme.h @@ -19,6 +19,7 @@ #define VOLATILE_WC_DESC "Get and set volatile write cache feature" #define POWER_LIMIT_DESC "Get and set power limit feature" #define POWER_THRESH_DESC "Get and set power threshold feature" +#define POWER_MEAS_DESC "Get and set power measurement feature" #define FEAT_ARGS(n, ...) \ NVME_ARGS(n, ##__VA_ARGS__, OPT_FLAG("save", 's', NULL, save), \ @@ -35,6 +36,7 @@ PLUGIN(NAME("feat", "NVMe feature extensions", FEAT_PLUGIN_VERSION), ENTRY("volatile-wc", VOLATILE_WC_DESC, feat_volatile_wc) ENTRY("power-limit", POWER_LIMIT_DESC, feat_power_limit) ENTRY("power-thresh", POWER_THRESH_DESC, feat_power_thresh) + ENTRY("power-meas", POWER_MEAS_DESC, feat_power_meas) ) ); #endif /* !FEAT_NVME || CMD_HEADER_MULTI_READ */