1 /*- 2 * Copyright (c) 2016 Netflix, Inc 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/ioccom.h> 32 33 #include <ctype.h> 34 #include <err.h> 35 #include <fcntl.h> 36 #include <stddef.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include "nvmecontrol.h" 43 44 _Static_assert(sizeof(struct nvme_power_state) == 256 / NBBY, 45 "nvme_power_state size wrong"); 46 47 static void 48 power_usage(void) 49 { 50 fprintf(stderr, "usage:\n"); 51 fprintf(stderr, POWER_USAGE); 52 exit(1); 53 } 54 55 static void 56 power_list_one(int i, struct nvme_power_state *nps) 57 { 58 int mpower, apower, ipower; 59 uint8_t mps, nops, aps, apw; 60 61 mps = (nps->mps_nops >> NVME_PWR_ST_MPS_SHIFT) & 62 NVME_PWR_ST_MPS_MASK; 63 nops = (nps->mps_nops >> NVME_PWR_ST_NOPS_SHIFT) & 64 NVME_PWR_ST_NOPS_MASK; 65 apw = (nps->apw_aps >> NVME_PWR_ST_APW_SHIFT) & 66 NVME_PWR_ST_APW_MASK; 67 aps = (nps->apw_aps >> NVME_PWR_ST_APS_SHIFT) & 68 NVME_PWR_ST_APS_MASK; 69 70 mpower = nps->mp; 71 if (mps == 0) 72 mpower *= 100; 73 ipower = nps->idlp; 74 if (nps->ips == 1) 75 ipower *= 100; 76 apower = nps->actp; 77 if (aps == 1) 78 apower *= 100; 79 printf("%2d: %2d.%04dW%c %3d.%03dms %3d.%03dms %2d %2d %2d %2d %2d.%04dW %2d.%04dW %d\n", 80 i, mpower / 10000, mpower % 10000, 81 nops ? '*' : ' ', nps->enlat / 1000, nps->enlat % 1000, 82 nps->exlat / 1000, nps->exlat % 1000, nps->rrt, nps->rrl, 83 nps->rwt, nps->rwl, ipower / 10000, ipower % 10000, 84 apower / 10000, apower % 10000, apw); 85 } 86 87 static void 88 power_list(struct nvme_controller_data *cdata) 89 { 90 int i; 91 92 printf("\nPower States Supported: %d\n\n", cdata->npss + 1); 93 printf(" # Max pwr Enter Lat Exit Lat RT RL WT WL Idle Pwr Act Pwr Workloadd\n"); 94 printf("-- -------- --------- --------- -- -- -- -- -------- -------- --\n"); 95 for (i = 0; i <= cdata->npss; i++) 96 power_list_one(i, &cdata->power_state[i]); 97 } 98 99 static void 100 power_set(int fd, int power_val, int workload, int perm) 101 { 102 struct nvme_pt_command pt; 103 uint32_t p; 104 105 p = perm ? (1u << 31) : 0; 106 memset(&pt, 0, sizeof(pt)); 107 pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_SET_FEATURES); 108 pt.cmd.cdw10 = htole32(NVME_FEAT_POWER_MANAGEMENT | p); 109 pt.cmd.cdw11 = htole32(power_val | (workload << 5)); 110 111 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 112 err(1, "set feature power mgmt request failed"); 113 114 if (nvme_completion_is_error(&pt.cpl)) 115 errx(1, "set feature power mgmt request returned error"); 116 } 117 118 static void 119 power_show(int fd) 120 { 121 struct nvme_pt_command pt; 122 123 memset(&pt, 0, sizeof(pt)); 124 pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_GET_FEATURES); 125 pt.cmd.cdw10 = htole32(NVME_FEAT_POWER_MANAGEMENT); 126 127 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 128 err(1, "set feature power mgmt request failed"); 129 130 if (nvme_completion_is_error(&pt.cpl)) 131 errx(1, "set feature power mgmt request returned error"); 132 133 printf("Current Power Mode is %d\n", pt.cpl.cdw0); 134 } 135 136 void 137 power(int argc, char *argv[]) 138 { 139 struct nvme_controller_data cdata; 140 int ch, listflag = 0, powerflag = 0, power_val = 0, fd; 141 int workload = 0; 142 char *end; 143 144 while ((ch = getopt(argc, argv, "lp:w:")) != -1) { 145 switch ((char)ch) { 146 case 'l': 147 listflag = 1; 148 break; 149 case 'p': 150 powerflag = 1; 151 power_val = strtol(optarg, &end, 0); 152 if (*end != '\0') { 153 fprintf(stderr, "Invalid power state number: %s\n", optarg); 154 power_usage(); 155 } 156 break; 157 case 'w': 158 workload = strtol(optarg, &end, 0); 159 if (*end != '\0') { 160 fprintf(stderr, "Invalid workload hint: %s\n", optarg); 161 power_usage(); 162 } 163 break; 164 default: 165 power_usage(); 166 } 167 } 168 169 /* Check that a controller was specified. */ 170 if (optind >= argc) 171 power_usage(); 172 173 if (listflag && powerflag) { 174 fprintf(stderr, "Can't set power and list power states\n"); 175 power_usage(); 176 } 177 178 open_dev(argv[optind], &fd, 1, 1); 179 read_controller_data(fd, &cdata); 180 181 if (listflag) { 182 power_list(&cdata); 183 goto out; 184 } 185 186 if (powerflag) { 187 power_set(fd, power_val, workload, 0); 188 goto out; 189 } 190 power_show(fd); 191 192 out: 193 close(fd); 194 exit(0); 195 } 196