Skip to content

Commit f376ef8

Browse files
committed
feat: add power-limit command
Add feat_get() uidx parameter also for the command. Signed-off-by: Tokunori Ikegami <[email protected]>
1 parent a57c1b3 commit f376ef8

11 files changed

Lines changed: 192 additions & 20 deletions

File tree

libnvme/src/nvme/types.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9028,6 +9028,10 @@ enum nvme_features_id {
90289028
* @NVME_FEAT_RRL_NVMSETID_MASK:
90299029
* @NVME_FEAT_PLM_NVMSETID_SHIFT:
90309030
* @NVME_FEAT_PLM_NVMSETID_MASK:
9031+
* @NVME_FEAT_POWER_LIMIT_PLV_SHIFT:
9032+
* @NVME_FEAT_POWER_LIMIT_PLV_MASK:
9033+
* @NVME_FEAT_POWER_LIMIT_PLS_SHIFT:
9034+
* @NVME_FEAT_POWER_LIMIT_PLS_MASK:
90319035
**/
90329036
enum nvme_feat {
90339037
NVME_FEAT_ARBITRATION_BURST_SHIFT = 0,
@@ -9182,6 +9186,10 @@ enum nvme_feat {
91829186
NVME_FEAT_SANITIZE_NODRM_MASK = 0x1,
91839187
NVME_FEAT_RESP_PTPL_SHIFT = 0,
91849188
NVME_FEAT_RESP_PTPL_MASK = 0x1,
9189+
NVME_FEAT_POWER_LIMIT_PLV_SHIFT = 0,
9190+
NVME_FEAT_POWER_LIMIT_PLV_MASK = 0xffff,
9191+
NVME_FEAT_POWER_LIMIT_PLS_SHIFT = 16,
9192+
NVME_FEAT_POWER_LIMIT_PLS_MASK = 0x3,
91859193
};
91869194

91879195
/**

libnvme/src/nvme/util.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ int nvme_get_feature_length(int fid, __u32 cdw11, enum nvme_data_tfr dir,
560560
case NVME_FEAT_FID_RESV_MASK:
561561
case NVME_FEAT_FID_RESV_PERSIST:
562562
case NVME_FEAT_FID_WRITE_PROTECT:
563+
case NVME_FEAT_FID_POWER_LIMIT:
563564
*len = 0;
564565
break;
565566
case NVME_FEAT_FID_ENH_CTRL_METADATA:

libnvme/src/nvme/util.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ static inline void nvme_feature_decode_arbitration(__u32 value, __u8 *ab,
288288
#define NVME_FEAT_PM_PS(v) NVME_GET(v, FEAT_PWRMGMT_PS)
289289
#define NVME_FEAT_PM_WH(v) NVME_GET(v, FEAT_PWRMGMT_WH)
290290

291+
#define NVME_FEAT_POWER_LIMIT_PLV(v) NVME_GET(v, FEAT_POWER_LIMIT_PLV)
292+
#define NVME_FEAT_POWER_LIMIT_PLS(v) NVME_GET(v, FEAT_POWER_LIMIT_PLS)
293+
291294
static inline void nvme_feature_decode_power_mgmt(__u32 value, __u8 *ps,
292295
__u8 *wh)
293296
{

nvme-print-json.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3997,6 +3997,51 @@ static void json_feature_show_fields_bpwp(struct json_object *r, unsigned int re
39973997
obj_add_str(r, "Boot Partition 1 Write Protection State", nvme_bpwps_to_string(field));
39983998
}
39993999

4000+
static char *get_power_and_scale(__u16 power, __u8 scale)
4001+
{
4002+
char *str;
4003+
int ret;
4004+
4005+
switch (scale) {
4006+
case NVME_PSD_PS_NOT_REPORTED:
4007+
/* Not reported for this power state */
4008+
ret = asprintf(&str, "-");
4009+
break;
4010+
case NVME_PSD_PS_100_MICRO_WATT:
4011+
/* Units of 0.0001W */
4012+
ret = asprintf(&str, "%01u.%04uW", power / 10000,
4013+
power % 10000);
4014+
break;
4015+
case NVME_PSD_PS_10_MILLI_WATT:
4016+
/* Units of 0.01W */
4017+
ret = asprintf(&str, "%01u.%02uW", power / 100, power % 100);
4018+
break;
4019+
default:
4020+
ret = asprintf(&str, "reserved");
4021+
break;
4022+
}
4023+
4024+
if (ret > 0)
4025+
return str;
4026+
4027+
return NULL;
4028+
}
4029+
4030+
static void json_feature_show_fields_power_limit(struct json_object *r,
4031+
unsigned int result)
4032+
{
4033+
__u8 field = NVME_FEAT_POWER_LIMIT_PLS(result);
4034+
4035+
_cleanup_free_ char *k =
4036+
get_power_and_scale(NVME_FEAT_POWER_LIMIT_PLV(result), field);
4037+
4038+
obj_add_str(r, "Power Limit Scale (PLS)",
4039+
nvme_feature_power_limit_scale_to_string(field));
4040+
obj_add_uint(r, "Power Limit Value (PLV)",
4041+
NVME_FEAT_POWER_LIMIT_PLV(result));
4042+
obj_add_str(r, "Power Limit", k);
4043+
}
4044+
40004045
static void json_feature_show(enum nvme_features_id fid, int sel, unsigned int result)
40014046
{
40024047
struct json_object *r;
@@ -4136,6 +4181,9 @@ static void json_feature_show_fields(enum nvme_features_id fid, unsigned int res
41364181
case NVME_FEAT_FID_BP_WRITE_PROTECT:
41374182
json_feature_show_fields_bpwp(r, result);
41384183
break;
4184+
case NVME_FEAT_FID_POWER_LIMIT:
4185+
json_feature_show_fields_power_limit(r, result);
4186+
break;
41394187
default:
41404188
break;
41414189
}

nvme-print-stdout.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3124,10 +3124,8 @@ static void print_psd_workload(__u8 apw)
31243124
}
31253125
}
31263126

3127-
static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale)
3127+
static void print_power_and_scale(__u16 power, __u8 scale)
31283128
{
3129-
__u16 power = le16_to_cpu(ctr_power);
3130-
31313129
switch (scale & 0x3) {
31323130
case NVME_PSD_PS_NOT_REPORTED:
31333131
/* Not reported for this power state */
@@ -3147,6 +3145,11 @@ static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale)
31473145
}
31483146
}
31493147

3148+
static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale)
3149+
{
3150+
print_power_and_scale(le16_to_cpu(ctr_power), scale);
3151+
}
3152+
31503153
static void print_psd_time(const char *desc, __u8 time, __u8 ts)
31513154
{
31523155
int width = 12 + strlen(desc);
@@ -5322,6 +5325,16 @@ static void stdout_feature_show_fields(enum nvme_features_id fid,
53225325
printf("\tBoot Partition 0 Write Protection State (BP0WPS): %s\n",
53235326
nvme_bpwps_to_string(field));
53245327
break;
5328+
case NVME_FEAT_FID_POWER_LIMIT:
5329+
field = NVME_FEAT_POWER_LIMIT_PLS(result);
5330+
printf("\tPower Limit Scale (PLS): %u - %s\n", field,
5331+
nvme_feature_power_limit_scale_to_string(field));
5332+
printf("\tPower Limit Value (PLV): %u\n",
5333+
NVME_FEAT_POWER_LIMIT_PLV(result));
5334+
printf("\tPower Limit: ");
5335+
print_power_and_scale(NVME_FEAT_POWER_LIMIT_PLV(result), field);
5336+
printf("\n");
5337+
break;
53255338
default:
53265339
break;
53275340
}

nvme-print.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,22 @@ const char *nvme_pls_mode_to_string(__u8 mode)
14951495
return "Reserved";
14961496
}
14971497

1498+
const char *nvme_feature_power_limit_scale_to_string(__u8 pls)
1499+
{
1500+
switch (pls) {
1501+
case NVME_PSD_PS_NOT_REPORTED:
1502+
return "Not reported";
1503+
case NVME_PSD_PS_100_MICRO_WATT:
1504+
return "0.0001 W";
1505+
case NVME_PSD_PS_10_MILLI_WATT:
1506+
return "0.01 W";
1507+
default:
1508+
break;
1509+
}
1510+
1511+
return "Reserved";
1512+
}
1513+
14981514
void nvme_feature_show(enum nvme_features_id fid, int sel, unsigned int result)
14991515
{
15001516
nvme_print(show_feature, NORMAL, fid, sel, result);

nvme-print.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ const char *nvme_ssi_state_to_string(__u8 state);
341341
const char *nvme_time_scale_to_string(__u8 ts);
342342
const char *nvme_pls_mode_to_string(__u8 mode);
343343
const char *nvme_bpwps_to_string(__u8 bpwps);
344+
const char *nvme_feature_power_limit_scale_to_string(__u8 pls);
344345

345346
void nvme_dev_full_path(nvme_ns_t n, char *path, size_t len);
346347
void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len);

nvme.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ const char *output_format = "Output format: normal|binary";
191191
const char *timeout = "timeout value, in milliseconds";
192192
const char *verbose = "Increase output verbosity";
193193
const char *dry_run = "show command instead of sending";
194+
const char *uuid_index = "UUID index";
194195

195196
static const char *app_tag = "app tag for end-to-end PI";
196197
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";
237238
static const char *storage_tag = "storage tag for end-to-end PI";
238239
static const char *storage_tag_check = "This bit specifies if the Storage Tag field shall be checked as\n"
239240
"part of end-to-end data protection processing";
240-
static const char *uuid_index = "UUID index";
241241
static const char *uuid_index_specify = "specify uuid index";
242242
static const char dash[51] = {[0 ... 49] = '=', '\0'};
243243
static const char space[51] = {[0 ... 49] = ' ', '\0'};

nvme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ extern const char *output_format;
109109
extern const char *timeout;
110110
extern const char *verbose;
111111
extern const char *dry_run;
112+
extern const char *uuid_index;
112113
extern struct nvme_config nvme_cfg;
113114

114115
int validate_output_format(const char *format, nvme_print_flags_t *flags);

plugins/feat/feat-nvme.c

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ static const char *timestamp_feat = "timestamp feature";
4848
static const char *temp_thresh_feat = "temperature threshold feature";
4949
static const char *arbitration_feat = "arbitration feature";
5050
static const char *volatile_wc_feat = "volatile write cache feature";
51+
static const char *power_limit_feat = "power limit feature";
5152

5253
static int feat_get(struct nvme_transport_handle *hdl, const __u8 fid,
53-
__u32 cdw11, __u8 sel, const char *feat)
54+
__u32 cdw11, __u8 sel, __u8 uidx, const char *feat)
5455
{
5556
__u64 result;
5657
int err;
@@ -142,9 +143,10 @@ static int feat_power_mgmt(int argc, char **argv, struct command *acmd, struct p
142143
return err;
143144

144145
if (argconfig_parse_seen(opts, "ps"))
145-
err = power_mgmt_set(hdl, fid, cfg.ps, cfg.wh, argconfig_parse_seen(opts, "save"));
146+
err = power_mgmt_set(hdl, fid, cfg.ps, cfg.wh,
147+
argconfig_parse_seen(opts, "save"));
146148
else
147-
err = feat_get(hdl, fid, 0, cfg.sel, power_mgmt_feat);
149+
err = feat_get(hdl, fid, 0, cfg.sel, 0, power_mgmt_feat);
148150

149151
return err;
150152
}
@@ -240,11 +242,13 @@ static int feat_perfc(int argc, char **argv, struct command *acmd, struct plugin
240242

241243
cdw11 = NVME_SET(cfg.attri, FEAT_PERFC_ATTRI) | NVME_SET(cfg.rvspa, FEAT_PERFC_RVSPA);
242244

243-
if (argconfig_parse_seen(opts, "rvspa") || argconfig_parse_seen(opts, "r4karl") ||
245+
if (argconfig_parse_seen(opts, "rvspa") ||
246+
argconfig_parse_seen(opts, "r4karl") ||
244247
argconfig_parse_seen(opts, "paid"))
245-
err = perfc_set(hdl, fid, cdw11, &cfg, argconfig_parse_seen(opts, "save"));
248+
err = perfc_set(hdl, fid, cdw11, &cfg,
249+
argconfig_parse_seen(opts, "save"));
246250
else
247-
err = feat_get(hdl, fid, cdw11, cfg.sel, perfc_feat);
251+
err = feat_get(hdl, fid, cdw11, cfg.sel, 0, perfc_feat);
248252

249253
return err;
250254
}
@@ -301,10 +305,12 @@ static int feat_hctm(int argc, char **argv, struct command *acmd, struct plugin
301305
if (err)
302306
return err;
303307

304-
if (argconfig_parse_seen(opts, "tmt1") || argconfig_parse_seen(opts, "tmt2"))
305-
err = hctm_set(hdl, fid, cfg.tmt1, cfg.tmt2, argconfig_parse_seen(opts, "save"));
308+
if (argconfig_parse_seen(opts, "tmt1") ||
309+
argconfig_parse_seen(opts, "tmt2"))
310+
err = hctm_set(hdl, fid, cfg.tmt1, cfg.tmt2,
311+
argconfig_parse_seen(opts, "save"));
306312
else
307-
err = feat_get(hdl, fid, 0, cfg.sel, hctm_feat);
313+
err = feat_get(hdl, fid, 0, cfg.sel, 0, hctm_feat);
308314

309315
return err;
310316
}
@@ -361,9 +367,10 @@ static int feat_timestamp(int argc, char **argv, struct command *acmd, struct pl
361367
return err;
362368

363369
if (argconfig_parse_seen(opts, "tstmp"))
364-
err = timestamp_set(hdl, fid, cfg.tstmp, argconfig_parse_seen(opts, "save"));
370+
err = timestamp_set(hdl, fid, cfg.tstmp,
371+
argconfig_parse_seen(opts, "save"));
365372
else
366-
err = feat_get(hdl, fid, 0, cfg.sel, timestamp_feat);
373+
err = feat_get(hdl, fid, 0, cfg.sel, 0, timestamp_feat);
367374

368375
return err;
369376
}
@@ -443,11 +450,13 @@ static int feat_temp_thresh(int argc, char **argv, struct command *acmd, struct
443450
if (err)
444451
return err;
445452

446-
if (argconfig_parse_seen(opts, "tmpth") || argconfig_parse_seen(opts, "tmpthh"))
453+
if (argconfig_parse_seen(opts, "tmpth") ||
454+
argconfig_parse_seen(opts, "tmpthh"))
447455
err = temp_thresh_set(hdl, fid, opts, &cfg);
448456
else
449457
err = feat_get(hdl, fid, NVME_SET(cfg.tmpsel, FEAT_TT_TMPSEL) |
450-
NVME_SET(cfg.thsel, FEAT_TT_THSEL), cfg.sel, temp_thresh_feat);
458+
NVME_SET(cfg.thsel, FEAT_TT_THSEL), cfg.sel, 0,
459+
temp_thresh_feat);
451460

452461
return err;
453462
}
@@ -529,7 +538,7 @@ static int feat_arbitration(int argc, char **argv, struct command *acmd, struct
529538
return err;
530539

531540
if (argc == 2 || argconfig_parse_seen(opts, "sel"))
532-
return feat_get(hdl, fid, 0, cfg.sel, "arbitration feature");
541+
return feat_get(hdl, fid, 0, cfg.sel, 0, "arbitration feature");
533542

534543
return arbitration_set(hdl, fid, opts, &cfg);
535544
}
@@ -584,9 +593,79 @@ static int feat_volatile_wc(int argc, char **argv, struct command *acmd, struct
584593
return err;
585594

586595
if (argconfig_parse_seen(opts, "wce"))
587-
err = volatile_wc_set(hdl, fid, cfg.wce, argconfig_parse_seen(opts, "save"));
596+
err = volatile_wc_set(hdl, fid, cfg.wce,
597+
argconfig_parse_seen(opts, "save"));
588598
else
589-
err = feat_get(hdl, fid, 0, cfg.sel, volatile_wc_feat);
599+
err = feat_get(hdl, fid, 0, cfg.sel, 0, volatile_wc_feat);
600+
601+
return err;
602+
}
603+
604+
static int power_limit_set(struct nvme_transport_handle *hdl, const __u8 fid,
605+
__u8 plv, __u8 pls, __u8 uidx, bool sv)
606+
{
607+
__u32 cdw13 = NVME_SET(plv, FEAT_POWER_LIMIT_PLV) |
608+
NVME_SET(pls, FEAT_POWER_LIMIT_PLS);
609+
__u64 result;
610+
int err;
611+
612+
err = nvme_set_features(hdl, 0, fid, sv, 0, 0, cdw13, uidx, 0, NULL, 0,
613+
&result);
614+
615+
nvme_show_init();
616+
617+
if (err > 0) {
618+
nvme_show_status(err);
619+
} else if (err < 0) {
620+
nvme_show_perror("Set %s", power_limit_feat);
621+
} else {
622+
nvme_show_result("Set %s: 0x%04x (%s)", power_limit_feat, cdw13,
623+
sv ? "Save" : "Not save");
624+
nvme_feature_show_fields(fid, cdw13, NULL);
625+
}
626+
627+
nvme_show_finish();
628+
629+
return err;
630+
}
631+
632+
static int feat_power_limit(int argc, char **argv, struct command *acmd,
633+
struct plugin *plugin)
634+
{
635+
const char *plv = "power limit value";
636+
const char *pls = "power limit scale";
637+
const __u8 fid = NVME_FEAT_FID_POWER_LIMIT;
638+
639+
_cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL;
640+
641+
_cleanup_nvme_transport_handle_ struct nvme_transport_handle *hdl =
642+
NULL;
643+
int err;
644+
645+
struct config {
646+
__u8 plv;
647+
__u8 pls;
648+
__u8 uidx;
649+
__u8 sel;
650+
};
651+
652+
struct config cfg = { 0 };
653+
654+
FEAT_ARGS(opts,
655+
OPT_BYTE("plv", 'p', &cfg.plv, plv),
656+
OPT_BYTE("pls", 'l', &cfg.pls, pls),
657+
OPT_BYTE("uuid-index", 'u', &cfg.uidx, uuid_index));
658+
659+
err = parse_and_open(&ctx, &hdl, argc, argv, POWER_LIMIT_DESC, opts);
660+
if (err)
661+
return err;
662+
663+
if (argconfig_parse_seen(opts, "plv"))
664+
err = power_limit_set(hdl, fid, cfg.plv, cfg.pls, cfg.uidx,
665+
argconfig_parse_seen(opts, "save"));
666+
else
667+
err = feat_get(hdl, fid, 0, cfg.sel, cfg.uidx,
668+
power_limit_feat);
590669

591670
return err;
592671
}

0 commit comments

Comments
 (0)