Skip to content

Commit b771608

Browse files
ikegami-tigaw
authored andcommitted
feat: add power-limit command
Add feat_get() uidx parameter also for the command. Signed-off-by: Tokunori Ikegami <[email protected]>
1 parent a83dd4d commit b771608

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
@@ -9059,6 +9059,10 @@ enum nvme_features_id {
90599059
* @NVME_FEAT_RRL_NVMSETID_MASK:
90609060
* @NVME_FEAT_PLM_NVMSETID_SHIFT:
90619061
* @NVME_FEAT_PLM_NVMSETID_MASK:
9062+
* @NVME_FEAT_POWER_LIMIT_PLV_SHIFT:
9063+
* @NVME_FEAT_POWER_LIMIT_PLV_MASK:
9064+
* @NVME_FEAT_POWER_LIMIT_PLS_SHIFT:
9065+
* @NVME_FEAT_POWER_LIMIT_PLS_MASK:
90629066
**/
90639067
enum nvme_feat {
90649068
NVME_FEAT_ARBITRATION_BURST_SHIFT = 0,
@@ -9213,6 +9217,10 @@ enum nvme_feat {
92139217
NVME_FEAT_SANITIZE_NODRM_MASK = 0x1,
92149218
NVME_FEAT_RESP_PTPL_SHIFT = 0,
92159219
NVME_FEAT_RESP_PTPL_MASK = 0x1,
9220+
NVME_FEAT_POWER_LIMIT_PLV_SHIFT = 0,
9221+
NVME_FEAT_POWER_LIMIT_PLV_MASK = 0xffff,
9222+
NVME_FEAT_POWER_LIMIT_PLS_SHIFT = 16,
9223+
NVME_FEAT_POWER_LIMIT_PLS_MASK = 0x3,
92169224
};
92179225

92189226
/**

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
@@ -4078,6 +4078,51 @@ static void json_feature_show_fields_bpwp(struct json_object *r, unsigned int re
40784078
obj_add_str(r, "Boot Partition 1 Write Protection State", nvme_bpwps_to_string(field));
40794079
}
40804080

4081+
static char *get_power_and_scale(__u16 power, __u8 scale)
4082+
{
4083+
char *str;
4084+
int ret;
4085+
4086+
switch (scale) {
4087+
case NVME_PSD_PS_NOT_REPORTED:
4088+
/* Not reported for this power state */
4089+
ret = asprintf(&str, "-");
4090+
break;
4091+
case NVME_PSD_PS_100_MICRO_WATT:
4092+
/* Units of 0.0001W */
4093+
ret = asprintf(&str, "%01u.%04uW", power / 10000,
4094+
power % 10000);
4095+
break;
4096+
case NVME_PSD_PS_10_MILLI_WATT:
4097+
/* Units of 0.01W */
4098+
ret = asprintf(&str, "%01u.%02uW", power / 100, power % 100);
4099+
break;
4100+
default:
4101+
ret = asprintf(&str, "reserved");
4102+
break;
4103+
}
4104+
4105+
if (ret > 0)
4106+
return str;
4107+
4108+
return NULL;
4109+
}
4110+
4111+
static void json_feature_show_fields_power_limit(struct json_object *r,
4112+
unsigned int result)
4113+
{
4114+
__u8 field = NVME_FEAT_POWER_LIMIT_PLS(result);
4115+
4116+
_cleanup_free_ char *k =
4117+
get_power_and_scale(NVME_FEAT_POWER_LIMIT_PLV(result), field);
4118+
4119+
obj_add_str(r, "Power Limit Scale (PLS)",
4120+
nvme_feature_power_limit_scale_to_string(field));
4121+
obj_add_uint(r, "Power Limit Value (PLV)",
4122+
NVME_FEAT_POWER_LIMIT_PLV(result));
4123+
obj_add_str(r, "Power Limit", k);
4124+
}
4125+
40814126
static void json_feature_show(enum nvme_features_id fid, int sel, unsigned int result)
40824127
{
40834128
struct json_object *r;
@@ -4217,6 +4262,9 @@ static void json_feature_show_fields(enum nvme_features_id fid, unsigned int res
42174262
case NVME_FEAT_FID_BP_WRITE_PROTECT:
42184263
json_feature_show_fields_bpwp(r, result);
42194264
break;
4265+
case NVME_FEAT_FID_POWER_LIMIT:
4266+
json_feature_show_fields_power_limit(r, result);
4267+
break;
42204268
default:
42214269
break;
42224270
}

nvme-print-stdout.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3186,10 +3186,8 @@ static void print_psd_workload(__u8 apw)
31863186
}
31873187
}
31883188

3189-
static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale)
3189+
static void print_power_and_scale(__u16 power, __u8 scale)
31903190
{
3191-
__u16 power = le16_to_cpu(ctr_power);
3192-
31933191
switch (scale & 0x3) {
31943192
case NVME_PSD_PS_NOT_REPORTED:
31953193
/* Not reported for this power state */
@@ -3209,6 +3207,11 @@ static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale)
32093207
}
32103208
}
32113209

3210+
static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale)
3211+
{
3212+
print_power_and_scale(le16_to_cpu(ctr_power), scale);
3213+
}
3214+
32123215
static void print_psd_time(const char *desc, __u8 time, __u8 ts)
32133216
{
32143217
int width = 12 + strlen(desc);
@@ -5384,6 +5387,16 @@ static void stdout_feature_show_fields(enum nvme_features_id fid,
53845387
printf("\tBoot Partition 0 Write Protection State (BP0WPS): %s\n",
53855388
nvme_bpwps_to_string(field));
53865389
break;
5390+
case NVME_FEAT_FID_POWER_LIMIT:
5391+
field = NVME_FEAT_POWER_LIMIT_PLS(result);
5392+
printf("\tPower Limit Scale (PLS): %u - %s\n", field,
5393+
nvme_feature_power_limit_scale_to_string(field));
5394+
printf("\tPower Limit Value (PLV): %u\n",
5395+
NVME_FEAT_POWER_LIMIT_PLV(result));
5396+
printf("\tPower Limit: ");
5397+
print_power_and_scale(NVME_FEAT_POWER_LIMIT_PLV(result), field);
5398+
printf("\n");
5399+
break;
53875400
default:
53885401
break;
53895402
}

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";
@@ -238,7 +239,6 @@ static const char *start_block = "64-bit LBA of first block to access";
238239
static const char *storage_tag = "storage tag for end-to-end PI";
239240
static const char *storage_tag_check = "This bit specifies if the Storage Tag field shall be checked as\n"
240241
"part of end-to-end data protection processing";
241-
static const char *uuid_index = "UUID index";
242242
static const char *uuid_index_specify = "specify uuid index";
243243
static const char dash[51] = {[0 ... 49] = '=', '\0'};
244244
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)