diff --git a/libnvme/src/nvme/types.h b/libnvme/src/nvme/types.h index 311bf78b23..452e4df5f9 100644 --- a/libnvme/src/nvme/types.h +++ b/libnvme/src/nvme/types.h @@ -1098,6 +1098,22 @@ enum nvme_psd_ps { NVME_PSD_PS_10_MILLI_WATT = 2, }; +/** + * enum nvme_power_measurement_type - Power measurement types. + * @NVME_PMT_NSS_TOTAL_POWER: NVM subsystem total power + * @NVME_PMT_RSVD_MIN: Reserved minimum value + * @NVME_PMT_RSVD_MAX: Reserved maximum value + * @NVME_PMT_VS_MIN: Vendor Specific minimum value + * @NVME_PMT_VS_MAX: Vendor Specific maximum value + */ +enum nvme_power_measurement_type { + NVME_PMT_NSS_TOTAL_POWER = 0x0, + NVME_PMT_RSVD_MIN = 0x1, + NVME_PMT_RSVD_MAX = 0xb, + NVME_PMT_VS_MIN = 0xc, + NVME_PMT_VS_MAX = 0xf, +}; + /** * nvme_psd_power_scale() - power scale occupies the upper 3 bits * @ps: power scale value @@ -9028,6 +9044,18 @@ enum nvme_features_id { * @NVME_FEAT_RRL_NVMSETID_MASK: * @NVME_FEAT_PLM_NVMSETID_SHIFT: * @NVME_FEAT_PLM_NVMSETID_MASK: + * @NVME_FEAT_POWER_LIMIT_PLV_SHIFT: + * @NVME_FEAT_POWER_LIMIT_PLV_MASK: + * @NVME_FEAT_POWER_LIMIT_PLS_SHIFT: + * @NVME_FEAT_POWER_LIMIT_PLS_MASK: + * @NVME_FEAT_POWER_THRESH_PTV_SHIFT: + * @NVME_FEAT_POWER_THRESH_PTV_MASK: + * @NVME_FEAT_POWER_THRESH_PTS_SHIFT: + * @NVME_FEAT_POWER_THRESH_PTS_MASK: + * @NVME_FEAT_POWER_THRESH_PMTS_SHIFT: + * @NVME_FEAT_POWER_THRESH_PMTS_MASK: + * @NVME_FEAT_POWER_THRESH_EPT_SHIFT: + * @NVME_FEAT_POWER_THRESH_EPT_MASK: **/ enum nvme_feat { NVME_FEAT_ARBITRATION_BURST_SHIFT = 0, @@ -9182,6 +9210,18 @@ enum nvme_feat { NVME_FEAT_SANITIZE_NODRM_MASK = 0x1, NVME_FEAT_RESP_PTPL_SHIFT = 0, NVME_FEAT_RESP_PTPL_MASK = 0x1, + NVME_FEAT_POWER_LIMIT_PLV_SHIFT = 0, + NVME_FEAT_POWER_LIMIT_PLV_MASK = 0xffff, + NVME_FEAT_POWER_LIMIT_PLS_SHIFT = 16, + NVME_FEAT_POWER_LIMIT_PLS_MASK = 0x3, + NVME_FEAT_POWER_THRESH_PTV_SHIFT = 0, + NVME_FEAT_POWER_THRESH_PTV_MASK = 0xffff, + NVME_FEAT_POWER_THRESH_PTS_SHIFT = 16, + NVME_FEAT_POWER_THRESH_PTS_MASK = 0x3, + NVME_FEAT_POWER_THRESH_PMTS_SHIFT = 20, + NVME_FEAT_POWER_THRESH_PMTS_MASK = 0xf, + NVME_FEAT_POWER_THRESH_EPT_SHIFT = 31, + NVME_FEAT_POWER_THRESH_EPT_MASK = 0x1, }; /** diff --git a/libnvme/src/nvme/util.c b/libnvme/src/nvme/util.c index 3e67020431..73215f9cff 100644 --- a/libnvme/src/nvme/util.c +++ b/libnvme/src/nvme/util.c @@ -560,6 +560,7 @@ int nvme_get_feature_length(int fid, __u32 cdw11, enum nvme_data_tfr dir, case NVME_FEAT_FID_RESV_MASK: case NVME_FEAT_FID_RESV_PERSIST: case NVME_FEAT_FID_WRITE_PROTECT: + case NVME_FEAT_FID_POWER_LIMIT: *len = 0; break; case NVME_FEAT_FID_ENH_CTRL_METADATA: diff --git a/libnvme/src/nvme/util.h b/libnvme/src/nvme/util.h index d0f6033db9..0de58ada57 100644 --- a/libnvme/src/nvme/util.h +++ b/libnvme/src/nvme/util.h @@ -288,6 +288,14 @@ static inline void nvme_feature_decode_arbitration(__u32 value, __u8 *ab, #define NVME_FEAT_PM_PS(v) NVME_GET(v, FEAT_PWRMGMT_PS) #define NVME_FEAT_PM_WH(v) NVME_GET(v, FEAT_PWRMGMT_WH) +#define NVME_FEAT_POWER_LIMIT_PLV(v) NVME_GET(v, FEAT_POWER_LIMIT_PLV) +#define NVME_FEAT_POWER_LIMIT_PLS(v) NVME_GET(v, FEAT_POWER_LIMIT_PLS) + +#define NVME_FEAT_POWER_THRESH_PTV(v) NVME_GET(v, FEAT_POWER_THRESH_PTV) +#define NVME_FEAT_POWER_THRESH_PTS(v) NVME_GET(v, FEAT_POWER_THRESH_PTS) +#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) + 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 72d17ca60a..efb6ade9cb 100644 --- a/nvme-print-json.c +++ b/nvme-print-json.c @@ -3997,6 +3997,76 @@ static void json_feature_show_fields_bpwp(struct json_object *r, unsigned int re obj_add_str(r, "Boot Partition 1 Write Protection State", nvme_bpwps_to_string(field)); } +static char *get_power_and_scale(__u16 power, __u8 scale) +{ + char *str; + int ret; + + switch (scale) { + case NVME_PSD_PS_NOT_REPORTED: + /* Not reported for this power state */ + ret = asprintf(&str, "-"); + break; + case NVME_PSD_PS_100_MICRO_WATT: + /* Units of 0.0001W */ + ret = asprintf(&str, "%01u.%04uW", power / 10000, + power % 10000); + break; + case NVME_PSD_PS_10_MILLI_WATT: + /* Units of 0.01W */ + ret = asprintf(&str, "%01u.%02uW", power / 100, power % 100); + break; + default: + ret = asprintf(&str, "reserved"); + break; + } + + if (ret > 0) + return str; + + return NULL; +} + +static void json_feature_show_fields_power_limit(struct json_object *r, + unsigned int result) +{ + __u8 field = NVME_FEAT_POWER_LIMIT_PLS(result); + + _cleanup_free_ char *k = + get_power_and_scale(NVME_FEAT_POWER_LIMIT_PLV(result), field); + + obj_add_str(r, "Power Limit Scale (PLS)", + nvme_feature_power_limit_scale_to_string(field)); + obj_add_uint(r, "Power Limit Value (PLV)", + NVME_FEAT_POWER_LIMIT_PLV(result)); + obj_add_str(r, "Power Limit", k); +} + +static void json_feature_show_fields_power_thresh(struct json_object *r, + unsigned int result) +{ + __u8 field = NVME_FEAT_POWER_THRESH_EPT(result); + + _cleanup_free_ char *k = NULL; + + obj_add_str(r, "Enable Power Threshold (EPT)", + field ? "Enabled" : "Disabled"); + + field = NVME_FEAT_POWER_THRESH_PMTS(result); + obj_add_str(r, "Power Measurement Type Select (PMTS)", + nvme_power_measurement_type_to_string(field)); + + field = NVME_FEAT_POWER_THRESH_PTS(result); + 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); + + k = get_power_and_scale(field, NVME_FEAT_POWER_THRESH_PTS(result)); + obj_add_str(r, "Power Threshold", k); +} + static void json_feature_show(enum nvme_features_id fid, int sel, unsigned int result) { struct json_object *r; @@ -4136,6 +4206,12 @@ static void json_feature_show_fields(enum nvme_features_id fid, unsigned int res case NVME_FEAT_FID_BP_WRITE_PROTECT: json_feature_show_fields_bpwp(r, result); break; + case NVME_FEAT_FID_POWER_LIMIT: + json_feature_show_fields_power_limit(r, result); + break; + case NVME_FEAT_FID_POWER_THRESH: + json_feature_show_fields_power_thresh(r, result); + break; default: break; } diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 09ee8fecee..9baefe9c78 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -3124,10 +3124,8 @@ static void print_psd_workload(__u8 apw) } } -static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale) +static void print_power_and_scale(__u16 power, __u8 scale) { - __u16 power = le16_to_cpu(ctr_power); - switch (scale & 0x3) { case NVME_PSD_PS_NOT_REPORTED: /* Not reported for this power state */ @@ -3147,6 +3145,11 @@ static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale) } } +static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale) +{ + print_power_and_scale(le16_to_cpu(ctr_power), scale); +} + static void print_psd_time(const char *desc, __u8 time, __u8 ts) { int width = 12 + strlen(desc); @@ -5322,6 +5325,33 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, printf("\tBoot Partition 0 Write Protection State (BP0WPS): %s\n", nvme_bpwps_to_string(field)); break; + case NVME_FEAT_FID_POWER_LIMIT: + field = NVME_FEAT_POWER_LIMIT_PLS(result); + printf("\tPower Limit Scale (PLS): %u - %s\n", field, + nvme_feature_power_limit_scale_to_string(field)); + printf("\tPower Limit Value (PLV): %u\n", + NVME_FEAT_POWER_LIMIT_PLV(result)); + printf("\tPower Limit: "); + print_power_and_scale(NVME_FEAT_POWER_LIMIT_PLV(result), field); + printf("\n"); + break; + case NVME_FEAT_FID_POWER_THRESH: + field = NVME_FEAT_POWER_THRESH_EPT(result); + printf("\tEnable Power Threshold (EPT): %u - %s\n", + field, field ? "Enabled" : "Disabled"); + field = NVME_FEAT_POWER_THRESH_PMTS(result); + printf("\tPower Measurement Type Select (PMTS): %u - %s\n", + field, nvme_power_measurement_type_to_string(field)); + field = NVME_FEAT_POWER_THRESH_PTS(result); + printf("\tPower Threshold Scale (PTS): %u - %s\n", field, + nvme_feature_power_limit_scale_to_string(field)); + printf("\tPower Threshold Value (PTV): %u\n", + NVME_FEAT_POWER_THRESH_PTV(result)); + printf("\tPower Threshold: "); + print_power_and_scale(NVME_FEAT_POWER_THRESH_PTV(result), + field); + printf("\n"); + break; default: break; } diff --git a/nvme-print.c b/nvme-print.c index 069fe18cd0..e5ebec2948 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -1495,6 +1495,36 @@ const char *nvme_pls_mode_to_string(__u8 mode) return "Reserved"; } +const char *nvme_feature_power_limit_scale_to_string(__u8 pls) +{ + switch (pls) { + case NVME_PSD_PS_NOT_REPORTED: + return "not reported"; + case NVME_PSD_PS_100_MICRO_WATT: + return "0.0001 W"; + case NVME_PSD_PS_10_MILLI_WATT: + return "0.01 W"; + default: + break; + } + + return "Reserved"; +} + +const char *nvme_power_measurement_type_to_string(__u8 pmt) +{ + switch (pmt) { + case NVME_PMT_NSS_TOTAL_POWER: + return "NVM subsystem total power"; + case NVME_PMT_VS_MIN ... NVME_PMT_VS_MAX: + return "Vendor Specific"; + 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 0f371d8502..227bcd987a 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -341,6 +341,8 @@ const char *nvme_ssi_state_to_string(__u8 state); const char *nvme_time_scale_to_string(__u8 ts); 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); 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/nvme.c b/nvme.c index 4331db36a1..49b55e27e5 100644 --- a/nvme.c +++ b/nvme.c @@ -191,6 +191,7 @@ const char *output_format = "Output format: normal|binary"; const char *timeout = "timeout value, in milliseconds"; const char *verbose = "Increase output verbosity"; const char *dry_run = "show command instead of sending"; +const char *uuid_index = "UUID index"; static const char *app_tag = "app tag for end-to-end PI"; static const char *app_tag_mask = "app tag mask for end-to-end PI"; @@ -237,7 +238,6 @@ static const char *start_block = "64-bit LBA of first block to access"; static const char *storage_tag = "storage tag for end-to-end PI"; static const char *storage_tag_check = "This bit specifies if the Storage Tag field shall be checked as\n" "part of end-to-end data protection processing"; -static const char *uuid_index = "UUID index"; static const char *uuid_index_specify = "specify uuid index"; static const char dash[51] = {[0 ... 49] = '=', '\0'}; static const char space[51] = {[0 ... 49] = ' ', '\0'}; diff --git a/nvme.h b/nvme.h index 054976d1bf..9670959460 100644 --- a/nvme.h +++ b/nvme.h @@ -109,6 +109,7 @@ extern const char *output_format; extern const char *timeout; extern const char *verbose; extern const char *dry_run; +extern const char *uuid_index; extern struct nvme_config nvme_cfg; int validate_output_format(const char *format, nvme_print_flags_t *flags); diff --git a/plugins/feat/feat-nvme.c b/plugins/feat/feat-nvme.c index 17a42803fa..ef8a817f6a 100644 --- a/plugins/feat/feat-nvme.c +++ b/plugins/feat/feat-nvme.c @@ -48,9 +48,11 @@ static const char *timestamp_feat = "timestamp feature"; static const char *temp_thresh_feat = "temperature threshold feature"; 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 int feat_get(struct nvme_transport_handle *hdl, const __u8 fid, - __u32 cdw11, __u8 sel, const char *feat) + __u32 cdw11, __u8 sel, __u8 uidx, const char *feat) { __u64 result; int err; @@ -142,9 +144,10 @@ static int feat_power_mgmt(int argc, char **argv, struct command *acmd, struct p return err; if (argconfig_parse_seen(opts, "ps")) - err = power_mgmt_set(hdl, fid, cfg.ps, cfg.wh, argconfig_parse_seen(opts, "save")); + err = power_mgmt_set(hdl, fid, cfg.ps, cfg.wh, + argconfig_parse_seen(opts, "save")); else - err = feat_get(hdl, fid, 0, cfg.sel, power_mgmt_feat); + err = feat_get(hdl, fid, 0, cfg.sel, 0, power_mgmt_feat); return err; } @@ -240,11 +243,13 @@ static int feat_perfc(int argc, char **argv, struct command *acmd, struct plugin cdw11 = NVME_SET(cfg.attri, FEAT_PERFC_ATTRI) | NVME_SET(cfg.rvspa, FEAT_PERFC_RVSPA); - if (argconfig_parse_seen(opts, "rvspa") || argconfig_parse_seen(opts, "r4karl") || + if (argconfig_parse_seen(opts, "rvspa") || + argconfig_parse_seen(opts, "r4karl") || argconfig_parse_seen(opts, "paid")) - err = perfc_set(hdl, fid, cdw11, &cfg, argconfig_parse_seen(opts, "save")); + err = perfc_set(hdl, fid, cdw11, &cfg, + argconfig_parse_seen(opts, "save")); else - err = feat_get(hdl, fid, cdw11, cfg.sel, perfc_feat); + err = feat_get(hdl, fid, cdw11, cfg.sel, 0, perfc_feat); return err; } @@ -301,10 +306,12 @@ static int feat_hctm(int argc, char **argv, struct command *acmd, struct plugin if (err) return err; - if (argconfig_parse_seen(opts, "tmt1") || argconfig_parse_seen(opts, "tmt2")) - err = hctm_set(hdl, fid, cfg.tmt1, cfg.tmt2, argconfig_parse_seen(opts, "save")); + if (argconfig_parse_seen(opts, "tmt1") || + argconfig_parse_seen(opts, "tmt2")) + err = hctm_set(hdl, fid, cfg.tmt1, cfg.tmt2, + argconfig_parse_seen(opts, "save")); else - err = feat_get(hdl, fid, 0, cfg.sel, hctm_feat); + err = feat_get(hdl, fid, 0, cfg.sel, 0, hctm_feat); return err; } @@ -361,9 +368,10 @@ static int feat_timestamp(int argc, char **argv, struct command *acmd, struct pl return err; if (argconfig_parse_seen(opts, "tstmp")) - err = timestamp_set(hdl, fid, cfg.tstmp, argconfig_parse_seen(opts, "save")); + err = timestamp_set(hdl, fid, cfg.tstmp, + argconfig_parse_seen(opts, "save")); else - err = feat_get(hdl, fid, 0, cfg.sel, timestamp_feat); + err = feat_get(hdl, fid, 0, cfg.sel, 0, timestamp_feat); return err; } @@ -443,11 +451,13 @@ static int feat_temp_thresh(int argc, char **argv, struct command *acmd, struct if (err) return err; - if (argconfig_parse_seen(opts, "tmpth") || argconfig_parse_seen(opts, "tmpthh")) + if (argconfig_parse_seen(opts, "tmpth") || + argconfig_parse_seen(opts, "tmpthh")) err = temp_thresh_set(hdl, fid, opts, &cfg); else err = feat_get(hdl, fid, NVME_SET(cfg.tmpsel, FEAT_TT_TMPSEL) | - NVME_SET(cfg.thsel, FEAT_TT_THSEL), cfg.sel, temp_thresh_feat); + NVME_SET(cfg.thsel, FEAT_TT_THSEL), cfg.sel, 0, + temp_thresh_feat); return err; } @@ -529,7 +539,7 @@ static int feat_arbitration(int argc, char **argv, struct command *acmd, struct return err; if (argc == 2 || argconfig_parse_seen(opts, "sel")) - return feat_get(hdl, fid, 0, cfg.sel, "arbitration feature"); + return feat_get(hdl, fid, 0, cfg.sel, 0, "arbitration feature"); return arbitration_set(hdl, fid, opts, &cfg); } @@ -584,9 +594,160 @@ static int feat_volatile_wc(int argc, char **argv, struct command *acmd, struct return err; if (argconfig_parse_seen(opts, "wce")) - err = volatile_wc_set(hdl, fid, cfg.wce, argconfig_parse_seen(opts, "save")); + err = volatile_wc_set(hdl, fid, cfg.wce, + argconfig_parse_seen(opts, "save")); else - err = feat_get(hdl, fid, 0, cfg.sel, volatile_wc_feat); + err = feat_get(hdl, fid, 0, cfg.sel, 0, volatile_wc_feat); + + return err; +} + +static int power_limit_set(struct nvme_transport_handle *hdl, const __u8 fid, + __u8 plv, __u8 pls, __u8 uidx, bool sv) +{ + __u32 cdw13 = NVME_SET(plv, FEAT_POWER_LIMIT_PLV) | + NVME_SET(pls, FEAT_POWER_LIMIT_PLS); + __u64 result; + int err; + + err = nvme_set_features(hdl, 0, fid, sv, 0, 0, cdw13, 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_limit_feat); + } else { + nvme_show_result("Set %s: 0x%04x (%s)", power_limit_feat, cdw13, + sv ? "Save" : "Not save"); + nvme_feature_show_fields(fid, cdw13, NULL); + } + + nvme_show_finish(); + + return err; +} + +static int feat_power_limit(int argc, char **argv, struct command *acmd, + struct plugin *plugin) +{ + const char *plv = "power limit value"; + const char *pls = "power limit scale"; + const __u8 fid = NVME_FEAT_FID_POWER_LIMIT; + + _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 plv; + __u8 pls; + __u8 uidx; + __u8 sel; + }; + + struct config cfg = { 0 }; + + FEAT_ARGS(opts, + OPT_BYTE("plv", 'p', &cfg.plv, plv), + OPT_BYTE("pls", 'l', &cfg.pls, pls), + OPT_BYTE("uuid-index", 'u', &cfg.uidx, uuid_index)); + + err = parse_and_open(&ctx, &hdl, argc, argv, POWER_LIMIT_DESC, opts); + if (err) + return err; + + if (argconfig_parse_seen(opts, "plv")) + err = power_limit_set(hdl, fid, cfg.plv, cfg.pls, cfg.uidx, + argconfig_parse_seen(opts, "save")); + else + err = feat_get(hdl, fid, 0, cfg.sel, cfg.uidx, + power_limit_feat); + + return err; +} + +static int power_thresh_set(struct nvme_transport_handle *hdl, const __u8 fid, + __u8 ptv, __u8 pts, __u8 pmts, __u8 ept, __u8 uidx, + bool sv) +{ + __u32 cdw11 = NVME_SET(ptv, FEAT_POWER_THRESH_PTV) | + NVME_SET(pmts, FEAT_POWER_THRESH_PMTS) | + NVME_SET(pts, FEAT_POWER_THRESH_PTS) | + NVME_SET(ept, FEAT_POWER_THRESH_EPT); + __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_thresh_feat); + } else { + nvme_show_result("Set %s: 0x%04x (%s)", power_thresh_feat, + cdw11, sv ? "Save" : "Not save"); + nvme_feature_show_fields(fid, cdw11, NULL); + } + + nvme_show_finish(); + + return err; +} + +static int feat_power_thresh(int argc, char **argv, struct command *acmd, + struct plugin *plugin) +{ + const char *ptv = "power threshold value"; + const char *pts = "power threshold scale"; + const char *pmts = "power measurement type select"; + const char *ept = "enable power threshold"; + const __u8 fid = NVME_FEAT_FID_POWER_THRESH; + + _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 ptv; + __u8 pts; + __u8 pmts; + __u8 ept; + __u8 uidx; + __u8 sel; + }; + + struct config cfg = { 0 }; + + FEAT_ARGS(opts, + OPT_BYTE("ptv", 'p', &cfg.ptv, ptv), + OPT_BYTE("pts", 't', &cfg.pts, pts), + OPT_BYTE("pmts", 'm', &cfg.pmts, pmts), + OPT_BYTE("ept", 'e', &cfg.ept, ept), + OPT_BYTE("uuid-index", 'u', &cfg.uidx, uuid_index)); + + err = parse_and_open(&ctx, &hdl, argc, argv, POWER_LIMIT_DESC, opts); + if (err) + return err; + + if (argconfig_parse_seen(opts, "ptv") || + argconfig_parse_seen(opts, "pmts") || + argconfig_parse_seen(opts, "ept")) + err = power_thresh_set(hdl, fid, cfg.ptv, cfg.pts, cfg.pmts, + cfg.ept, cfg.uidx, + argconfig_parse_seen(opts, "save")); + else + err = feat_get(hdl, fid, 0, cfg.sel, cfg.uidx, + power_thresh_feat); return err; } diff --git a/plugins/feat/feat-nvme.h b/plugins/feat/feat-nvme.h index b5ae7b23b5..fcc54002bb 100644 --- a/plugins/feat/feat-nvme.h +++ b/plugins/feat/feat-nvme.h @@ -17,6 +17,8 @@ #define TEMP_THRESH_DESC "Get and set temperature threshold feature" #define ARBITRATION_DESC "Get and set arbitration feature" #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 FEAT_ARGS(n, ...) \ NVME_ARGS(n, ##__VA_ARGS__, OPT_FLAG("save", 's', NULL, save), \ @@ -31,6 +33,8 @@ PLUGIN(NAME("feat", "NVMe feature extensions", FEAT_PLUGIN_VERSION), ENTRY("temp-thresh", TEMP_THRESH_DESC, feat_temp_thresh) ENTRY("arbitration", ARBITRATION_DESC, feat_arbitration) 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) ) ); #endif /* !FEAT_NVME || CMD_HEADER_MULTI_READ */