1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 2012-2016 Intel Corporation 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_nvme.h" 33 34 #include <sys/param.h> 35 #include <sys/bus.h> 36 #include <sys/sysctl.h> 37 38 #include "nvme_private.h" 39 40 #ifndef NVME_USE_NVD 41 #define NVME_USE_NVD 1 42 #endif 43 44 int nvme_use_nvd = NVME_USE_NVD; 45 46 SYSCTL_NODE(_hw, OID_AUTO, nvme, CTLFLAG_RD, 0, "NVMe sysctl tunables"); 47 SYSCTL_INT(_hw_nvme, OID_AUTO, use_nvd, CTLFLAG_RDTUN, 48 &nvme_use_nvd, 1, "1 = Create NVD devices, 0 = Create NDA devices"); 49 50 /* 51 * CTLTYPE_S64 and sysctl_handle_64 were added in r217616. Define these 52 * explicitly here for older kernels that don't include the r217616 53 * changeset. 54 */ 55 #ifndef CTLTYPE_S64 56 #define CTLTYPE_S64 CTLTYPE_QUAD 57 #define sysctl_handle_64 sysctl_handle_quad 58 #endif 59 60 static void 61 nvme_dump_queue(struct nvme_qpair *qpair) 62 { 63 struct nvme_completion *cpl; 64 struct nvme_command *cmd; 65 int i; 66 67 printf("id:%04Xh phase:%d\n", qpair->id, qpair->phase); 68 69 printf("Completion queue:\n"); 70 for (i = 0; i < qpair->num_entries; i++) { 71 cpl = &qpair->cpl[i]; 72 printf("%05d: ", i); 73 nvme_dump_completion(cpl); 74 } 75 76 printf("Submission queue:\n"); 77 for (i = 0; i < qpair->num_entries; i++) { 78 cmd = &qpair->cmd[i]; 79 printf("%05d: ", i); 80 nvme_dump_command(cmd); 81 } 82 } 83 84 85 static int 86 nvme_sysctl_dump_debug(SYSCTL_HANDLER_ARGS) 87 { 88 struct nvme_qpair *qpair = arg1; 89 uint32_t val = 0; 90 91 int error = sysctl_handle_int(oidp, &val, 0, req); 92 93 if (error) 94 return (error); 95 96 if (val != 0) 97 nvme_dump_queue(qpair); 98 99 return (0); 100 } 101 102 static int 103 nvme_sysctl_int_coal_time(SYSCTL_HANDLER_ARGS) 104 { 105 struct nvme_controller *ctrlr = arg1; 106 uint32_t oldval = ctrlr->int_coal_time; 107 int error = sysctl_handle_int(oidp, &ctrlr->int_coal_time, 0, 108 req); 109 110 if (error) 111 return (error); 112 113 if (oldval != ctrlr->int_coal_time) 114 nvme_ctrlr_cmd_set_interrupt_coalescing(ctrlr, 115 ctrlr->int_coal_time, ctrlr->int_coal_threshold, NULL, 116 NULL); 117 118 return (0); 119 } 120 121 static int 122 nvme_sysctl_int_coal_threshold(SYSCTL_HANDLER_ARGS) 123 { 124 struct nvme_controller *ctrlr = arg1; 125 uint32_t oldval = ctrlr->int_coal_threshold; 126 int error = sysctl_handle_int(oidp, &ctrlr->int_coal_threshold, 0, 127 req); 128 129 if (error) 130 return (error); 131 132 if (oldval != ctrlr->int_coal_threshold) 133 nvme_ctrlr_cmd_set_interrupt_coalescing(ctrlr, 134 ctrlr->int_coal_time, ctrlr->int_coal_threshold, NULL, 135 NULL); 136 137 return (0); 138 } 139 140 static int 141 nvme_sysctl_timeout_period(SYSCTL_HANDLER_ARGS) 142 { 143 struct nvme_controller *ctrlr = arg1; 144 uint32_t oldval = ctrlr->timeout_period; 145 int error = sysctl_handle_int(oidp, &ctrlr->timeout_period, 0, req); 146 147 if (error) 148 return (error); 149 150 if (ctrlr->timeout_period > NVME_MAX_TIMEOUT_PERIOD || 151 ctrlr->timeout_period < NVME_MIN_TIMEOUT_PERIOD) { 152 ctrlr->timeout_period = oldval; 153 return (EINVAL); 154 } 155 156 return (0); 157 } 158 159 static void 160 nvme_qpair_reset_stats(struct nvme_qpair *qpair) 161 { 162 163 qpair->num_cmds = 0; 164 qpair->num_intr_handler_calls = 0; 165 } 166 167 static int 168 nvme_sysctl_num_cmds(SYSCTL_HANDLER_ARGS) 169 { 170 struct nvme_controller *ctrlr = arg1; 171 int64_t num_cmds = 0; 172 int i; 173 174 num_cmds = ctrlr->adminq.num_cmds; 175 176 for (i = 0; i < ctrlr->num_io_queues; i++) 177 num_cmds += ctrlr->ioq[i].num_cmds; 178 179 return (sysctl_handle_64(oidp, &num_cmds, 0, req)); 180 } 181 182 static int 183 nvme_sysctl_num_intr_handler_calls(SYSCTL_HANDLER_ARGS) 184 { 185 struct nvme_controller *ctrlr = arg1; 186 int64_t num_intr_handler_calls = 0; 187 int i; 188 189 num_intr_handler_calls = ctrlr->adminq.num_intr_handler_calls; 190 191 for (i = 0; i < ctrlr->num_io_queues; i++) 192 num_intr_handler_calls += ctrlr->ioq[i].num_intr_handler_calls; 193 194 return (sysctl_handle_64(oidp, &num_intr_handler_calls, 0, req)); 195 } 196 197 static int 198 nvme_sysctl_reset_stats(SYSCTL_HANDLER_ARGS) 199 { 200 struct nvme_controller *ctrlr = arg1; 201 uint32_t i, val = 0; 202 203 int error = sysctl_handle_int(oidp, &val, 0, req); 204 205 if (error) 206 return (error); 207 208 if (val != 0) { 209 nvme_qpair_reset_stats(&ctrlr->adminq); 210 211 for (i = 0; i < ctrlr->num_io_queues; i++) 212 nvme_qpair_reset_stats(&ctrlr->ioq[i]); 213 } 214 215 return (0); 216 } 217 218 219 static void 220 nvme_sysctl_initialize_queue(struct nvme_qpair *qpair, 221 struct sysctl_ctx_list *ctrlr_ctx, struct sysctl_oid *que_tree) 222 { 223 struct sysctl_oid_list *que_list = SYSCTL_CHILDREN(que_tree); 224 225 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_entries", 226 CTLFLAG_RD, &qpair->num_entries, 0, 227 "Number of entries in hardware queue"); 228 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_trackers", 229 CTLFLAG_RD, &qpair->num_trackers, 0, 230 "Number of trackers pre-allocated for this queue pair"); 231 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_head", 232 CTLFLAG_RD, &qpair->sq_head, 0, 233 "Current head of submission queue (as observed by driver)"); 234 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_tail", 235 CTLFLAG_RD, &qpair->sq_tail, 0, 236 "Current tail of submission queue (as observed by driver)"); 237 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "cq_head", 238 CTLFLAG_RD, &qpair->cq_head, 0, 239 "Current head of completion queue (as observed by driver)"); 240 241 SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_cmds", 242 CTLFLAG_RD, &qpair->num_cmds, "Number of commands submitted"); 243 SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_intr_handler_calls", 244 CTLFLAG_RD, &qpair->num_intr_handler_calls, 245 "Number of times interrupt handler was invoked (will typically be " 246 "less than number of actual interrupts generated due to " 247 "coalescing)"); 248 249 SYSCTL_ADD_PROC(ctrlr_ctx, que_list, OID_AUTO, 250 "dump_debug", CTLTYPE_UINT | CTLFLAG_RW, qpair, 0, 251 nvme_sysctl_dump_debug, "IU", "Dump debug data"); 252 } 253 254 void 255 nvme_sysctl_initialize_ctrlr(struct nvme_controller *ctrlr) 256 { 257 struct sysctl_ctx_list *ctrlr_ctx; 258 struct sysctl_oid *ctrlr_tree, *que_tree; 259 struct sysctl_oid_list *ctrlr_list; 260 #define QUEUE_NAME_LENGTH 16 261 char queue_name[QUEUE_NAME_LENGTH]; 262 int i; 263 264 ctrlr_ctx = device_get_sysctl_ctx(ctrlr->dev); 265 ctrlr_tree = device_get_sysctl_tree(ctrlr->dev); 266 ctrlr_list = SYSCTL_CHILDREN(ctrlr_tree); 267 268 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_cpus_per_ioq", 269 CTLFLAG_RD, &ctrlr->num_cpus_per_ioq, 0, 270 "Number of CPUs assigned per I/O queue pair"); 271 272 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 273 "int_coal_time", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0, 274 nvme_sysctl_int_coal_time, "IU", 275 "Interrupt coalescing timeout (in microseconds)"); 276 277 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 278 "int_coal_threshold", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0, 279 nvme_sysctl_int_coal_threshold, "IU", 280 "Interrupt coalescing threshold"); 281 282 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 283 "timeout_period", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0, 284 nvme_sysctl_timeout_period, "IU", 285 "Timeout period (in seconds)"); 286 287 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 288 "num_cmds", CTLTYPE_S64 | CTLFLAG_RD, 289 ctrlr, 0, nvme_sysctl_num_cmds, "IU", 290 "Number of commands submitted"); 291 292 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 293 "num_intr_handler_calls", CTLTYPE_S64 | CTLFLAG_RD, 294 ctrlr, 0, nvme_sysctl_num_intr_handler_calls, "IU", 295 "Number of times interrupt handler was invoked (will " 296 "typically be less than number of actual interrupts " 297 "generated due to coalescing)"); 298 299 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 300 "reset_stats", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0, 301 nvme_sysctl_reset_stats, "IU", "Reset statistics to zero"); 302 303 que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, "adminq", 304 CTLFLAG_RD, NULL, "Admin Queue"); 305 306 nvme_sysctl_initialize_queue(&ctrlr->adminq, ctrlr_ctx, que_tree); 307 308 for (i = 0; i < ctrlr->num_io_queues; i++) { 309 snprintf(queue_name, QUEUE_NAME_LENGTH, "ioq%d", i); 310 que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, 311 queue_name, CTLFLAG_RD, NULL, "IO Queue"); 312 nvme_sysctl_initialize_queue(&ctrlr->ioq[i], ctrlr_ctx, 313 que_tree); 314 } 315 } 316