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