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];
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to