svn commit: r295087 - in head: sbin/nvmecontrol sys/dev/nvme

Warner Losh imp at FreeBSD.org
Sat Jan 30 22:48:08 UTC 2016


Author: imp
Date: Sat Jan 30 22:48:06 2016
New Revision: 295087
URL: https://svnweb.freebsd.org/changeset/base/295087

Log:
  Implement power command to list all power modes, find out the power
  mode we're in and to set the power mode.

Added:
  head/sbin/nvmecontrol/power.c   (contents, props changed)
Modified:
  head/sbin/nvmecontrol/Makefile
  head/sbin/nvmecontrol/nvmecontrol.8
  head/sbin/nvmecontrol/nvmecontrol.c
  head/sbin/nvmecontrol/nvmecontrol.h
  head/sys/dev/nvme/nvme.h

Modified: head/sbin/nvmecontrol/Makefile
==============================================================================
--- head/sbin/nvmecontrol/Makefile	Sat Jan 30 22:03:14 2016	(r295086)
+++ head/sbin/nvmecontrol/Makefile	Sat Jan 30 22:48:06 2016	(r295087)
@@ -2,7 +2,7 @@
 
 PROG=	nvmecontrol
 SRCS=	nvmecontrol.c devlist.c firmware.c identify.c logpage.c	\
-	perftest.c reset.c nvme_util.c
+	perftest.c reset.c nvme_util.c power.c
 MAN=	nvmecontrol.8
 
 .PATH:	${.CURDIR}/../../sys/dev/nvme

Modified: head/sbin/nvmecontrol/nvmecontrol.8
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.8	Sat Jan 30 22:03:14 2016	(r295086)
+++ head/sbin/nvmecontrol/nvmecontrol.8	Sat Jan 30 22:48:06 2016	(r295087)
@@ -70,6 +70,11 @@
 .Op Fl f Ar path_to_firmware
 .Op Fl a
 .Aq device id
+.Nm
+.Ic power
+.Op Fl l
+.Op Fl p power_state
+.Op fl w workload_hint
 .Sh DESCRIPTION
 NVM Express (NVMe) is a storage protocol standard, for SSDs and other
 high-speed storage devices over PCI Express.
@@ -120,6 +125,18 @@ Activate the firmware in slot 4 of the n
 .Pp
 Download the firmware image contained in "/tmp/nvme_firmware" to slot 7 of the
 nvme0 controller and activate it on the next reset.
+.Pp
+.Dl nvmecontrol power -l nvme0
+.Pp
+List all the current power modes.
+.Pp
+.Dl nvmecontrol power -p 3 nvme0
+.Pp
+Set the current power mode.
+.Pp
+.Dl nvmecontrol power nvme0
+.Pp
+Get the current power mode.
 .Sh AUTHORS
 .An -nosplit
 .Nm

Modified: head/sbin/nvmecontrol/nvmecontrol.c
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.c	Sat Jan 30 22:03:14 2016	(r295086)
+++ head/sbin/nvmecontrol/nvmecontrol.c	Sat Jan 30 22:48:06 2016	(r295087)
@@ -58,6 +58,7 @@ static struct nvme_function {
 	{"reset",	reset,		RESET_USAGE},
 	{"logpage",	logpage,	LOGPAGE_USAGE},
 	{"firmware",	firmware,	FIRMWARE_USAGE},
+	{"power",	power,		POWER_USAGE},
 	{NULL,		NULL,		NULL},
 };
 

Modified: head/sbin/nvmecontrol/nvmecontrol.h
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.h	Sat Jan 30 22:03:14 2016	(r295086)
+++ head/sbin/nvmecontrol/nvmecontrol.h	Sat Jan 30 22:48:06 2016	(r295087)
@@ -55,12 +55,16 @@
 #define FIRMWARE_USAGE							       \
 "       nvmecontrol firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n"
 
+#define POWER_USAGE							       \
+"       nvmecontrol power [-l] [-p new-state [-w workload-hint]] <controller id>\n"
+
 void devlist(int argc, char *argv[]);
 void identify(int argc, char *argv[]);
 void perftest(int argc, char *argv[]);
 void reset(int argc, char *argv[]);
 void logpage(int argc, char *argv[]);
 void firmware(int argc, char *argv[]);
+void power(int argc, char *argv[]);
 
 int open_dev(const char *str, int *fd, int show_error, int exit_on_error);
 void parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid);

Added: head/sbin/nvmecontrol/power.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sbin/nvmecontrol/power.c	Sat Jan 30 22:48:06 2016	(r295087)
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2016 Netflix, Inc
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+_Static_assert(sizeof(struct nvme_power_state) == 256 / NBBY,
+	       "nvme_power_state size wrong");
+
+static void
+power_usage(void)
+{
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, POWER_USAGE);
+	exit(1);
+}
+
+static void
+power_list_one(int i, struct nvme_power_state *nps)
+{
+	int mpower, apower, ipower;
+
+	mpower = nps->mp;
+	if (nps->mps == 0)
+		mpower *= 100;
+	ipower = nps->idlp;
+	if (nps->ips == 1)
+		ipower *= 100;
+	apower = nps->actp;
+	if (nps->aps == 1)
+		apower *= 100;
+	printf("%2d: %2d.%04dW%c %3d.%03dms %3d.%03dms %2d %2d %2d %2d %2d.%04dW %2d.%04dW %d\n",
+	       i, mpower / 10000, mpower % 10000,
+	       nps->nops ? '*' : ' ', nps->enlat / 1000, nps->enlat % 1000,
+	       nps->exlat / 1000, nps->exlat % 1000, nps->rrt, nps->rrl,
+	       nps->rwt, nps->rwl, ipower / 10000, ipower % 10000,
+	       apower / 10000, apower % 10000, nps->apw);
+}
+
+static void
+power_list(struct nvme_controller_data *cdata)
+{
+	int i;
+
+	printf("\nPower States Supported: %d\n\n", cdata->npss + 1);
+	printf(" #   Max pwr  Enter Lat  Exit Lat RT RL WT WL Idle Pwr  Act Pwr Workloadd\n");
+	printf("--  --------  --------- --------- -- -- -- -- -------- -------- --\n");
+	for (i = 0; i <= cdata->npss; i++)
+		power_list_one(i, &cdata->power_state[i]);
+}
+
+static void
+power_set(int fd, int power, int workload, int perm)
+{
+	struct nvme_pt_command	pt;
+	uint32_t p;
+
+	p = perm ? (1u << 31) : 0;
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_SET_FEATURES;
+	pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT | p;
+	pt.cmd.cdw11 = power | (workload << 5);
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "set feature power mgmt request failed");
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "set feature power mgmt request returned error");
+}
+
+static void
+power_show(int fd)
+{
+	struct nvme_pt_command	pt;
+
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_GET_FEATURES;
+	pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT;
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "set feature power mgmt request failed");
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "set feature power mgmt request returned error");
+
+	printf("Current Power Mode is %d\n", pt.cpl.cdw0);
+}
+
+void
+power(int argc, char *argv[])
+{
+	struct nvme_controller_data	cdata;
+	int				ch, listflag = 0, powerflag = 0, power = 0, fd;
+	int				workload = 0;
+	char				*end;
+
+	while ((ch = getopt(argc, argv, "lp:w:")) != -1) {
+		switch ((char)ch) {
+		case 'l':
+			listflag = 1;
+			break;
+		case 'p':
+			powerflag = 1;
+			power = strtol(optarg, &end, 0);
+			if (*end != '\0') {
+				fprintf(stderr, "Invalid power state number: %s\n", optarg);
+				power_usage();
+			}
+			break;
+		case 'w':
+			workload = strtol(optarg, &end, 0);
+			if (*end != '\0') {
+				fprintf(stderr, "Invalid workload hint: %s\n", optarg);
+				power_usage();
+			}
+			break;
+		default:
+			power_usage();
+		}
+	}
+
+	/* Check that a controller was specified. */
+	if (optind >= argc)
+		power_usage();
+
+	if (listflag && powerflag) {
+		fprintf(stderr, "Can't set power and list power states\n");
+		power_usage();
+	}
+
+	open_dev(argv[optind], &fd, 1, 1);
+	read_controller_data(fd, &cdata);
+
+	if (listflag) {
+		power_list(&cdata);
+		goto out;
+	}
+
+	if (powerflag) {
+		power_set(fd, power, workload, 0);
+		goto out;
+	}
+	power_show(fd);
+
+out:
+	close(fd);
+	exit(0);
+}

Modified: head/sys/dev/nvme/nvme.h
==============================================================================
--- head/sys/dev/nvme/nvme.h	Sat Jan 30 22:03:14 2016	(r295086)
+++ head/sys/dev/nvme/nvme.h	Sat Jan 30 22:48:06 2016	(r295087)
@@ -392,6 +392,34 @@ enum nvme_activate_action {
 	NVME_AA_ACTIVATE			= 0x2,
 };
 
+struct nvme_power_state {
+	/** Maximum Power */
+	uint16_t	mp;			/* Maximum Power */
+	uint8_t		ps_rsvd1;
+	uint8_t		mps      : 1;		/* Max Power Scale */
+	uint8_t		nops     : 1;		/* Non-Operational State */
+	uint8_t		ps_rsvd2 : 6;
+	uint32_t	enlat;			/* Entry Latency */
+	uint32_t	exlat;			/* Exit Latency */
+	uint8_t		rrt      : 5;		/* Relative Read Throughput */
+	uint8_t		ps_rsvd3 : 3;
+	uint8_t		rrl      : 5;		/* Relative Read Latency */
+	uint8_t		ps_rsvd4 : 3;
+	uint8_t		rwt      : 5;		/* Relative Write Throughput */
+	uint8_t		ps_rsvd5 : 3;
+	uint8_t		rwl      : 5;		/* Relative Write Latency */
+	uint8_t		ps_rsvd6 : 3;
+	uint16_t	idlp;			/* Idle Power */
+	uint8_t		ps_rsvd7 : 6;
+	uint8_t		ips      : 2;		/* Idle Power Scale */
+	uint8_t		ps_rsvd8;
+	uint16_t	actp;			/* Active Power */
+	uint8_t		apw      : 3;		/* Active Power Workload */
+	uint8_t		ps_rsvd9 : 3;
+	uint8_t		aps      : 2;		/* Active Power Scale */
+	uint8_t		ps_rsvd10[9];
+} __packed;
+
 #define NVME_SERIAL_NUMBER_LENGTH	20
 #define NVME_MODEL_NUMBER_LENGTH	40
 #define NVME_FIRMWARE_REVISION_LENGTH	8
@@ -532,7 +560,7 @@ struct nvme_controller_data {
 	uint8_t			reserved5[1344];
 
 	/* bytes 2048-3071: power state descriptors */
-	uint8_t			reserved6[1024];
+	struct nvme_power_state power_state[32];
 
 	/* bytes 3072-4095: vendor specific */
 	uint8_t			vs[1024];


More information about the svn-src-head mailing list