1240616Sjimharris/*- 2293352Sjimharris * Copyright (C) 2012-2016 Intel Corporation 3240616Sjimharris * All rights reserved. 4240616Sjimharris * 5240616Sjimharris * Redistribution and use in source and binary forms, with or without 6240616Sjimharris * modification, are permitted provided that the following conditions 7240616Sjimharris * are met: 8240616Sjimharris * 1. Redistributions of source code must retain the above copyright 9240616Sjimharris * notice, this list of conditions and the following disclaimer. 10240616Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 11240616Sjimharris * notice, this list of conditions and the following disclaimer in the 12240616Sjimharris * documentation and/or other materials provided with the distribution. 13240616Sjimharris * 14240616Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15240616Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16240616Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17240616Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18240616Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240616Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20240616Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21240616Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22240616Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23240616Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24240616Sjimharris * SUCH DAMAGE. 25240616Sjimharris */ 26240616Sjimharris 27240616Sjimharris#include <sys/cdefs.h> 28240616Sjimharris__FBSDID("$FreeBSD: stable/11/sys/dev/nvme/nvme_sysctl.c 328692 2018-02-01 16:53:08Z mav $"); 29240616Sjimharris 30328692Smav#include "opt_nvme.h" 31328692Smav 32240616Sjimharris#include <sys/param.h> 33240616Sjimharris#include <sys/bus.h> 34240616Sjimharris#include <sys/sysctl.h> 35240616Sjimharris 36240616Sjimharris#include "nvme_private.h" 37240616Sjimharris 38328692Smav#ifndef NVME_USE_NVD 39328692Smav#define NVME_USE_NVD 1 40328692Smav#endif 41328681Smav 42328692Smavint nvme_use_nvd = NVME_USE_NVD; 43328692Smav 44328681SmavSYSCTL_NODE(_hw, OID_AUTO, nvme, CTLFLAG_RD, 0, "NVMe sysctl tunables"); 45328681SmavSYSCTL_INT(_hw_nvme, OID_AUTO, use_nvd, CTLFLAG_RDTUN, 46328681Smav &nvme_use_nvd, 1, "1 = Create NVD devices, 0 = Create NDA devices"); 47328681Smav 48241434Sjimharris/* 49241434Sjimharris * CTLTYPE_S64 and sysctl_handle_64 were added in r217616. Define these 50241434Sjimharris * explicitly here for older kernels that don't include the r217616 51241434Sjimharris * changeset. 52241434Sjimharris */ 53241434Sjimharris#ifndef CTLTYPE_S64 54241434Sjimharris#define CTLTYPE_S64 CTLTYPE_QUAD 55241434Sjimharris#define sysctl_handle_64 sysctl_handle_quad 56241434Sjimharris#endif 57241434Sjimharris 58240616Sjimharrisstatic void 59240616Sjimharrisnvme_dump_queue(struct nvme_qpair *qpair) 60240616Sjimharris{ 61240616Sjimharris struct nvme_completion *cpl; 62240616Sjimharris struct nvme_command *cmd; 63240616Sjimharris int i; 64240616Sjimharris 65240616Sjimharris printf("id:%04Xh phase:%d\n", qpair->id, qpair->phase); 66240616Sjimharris 67240616Sjimharris printf("Completion queue:\n"); 68240616Sjimharris for (i = 0; i < qpair->num_entries; i++) { 69240616Sjimharris cpl = &qpair->cpl[i]; 70240616Sjimharris printf("%05d: ", i); 71240616Sjimharris nvme_dump_completion(cpl); 72240616Sjimharris } 73240616Sjimharris 74240616Sjimharris printf("Submission queue:\n"); 75240616Sjimharris for (i = 0; i < qpair->num_entries; i++) { 76240616Sjimharris cmd = &qpair->cmd[i]; 77240616Sjimharris printf("%05d: ", i); 78240616Sjimharris nvme_dump_command(cmd); 79240616Sjimharris } 80240616Sjimharris} 81240616Sjimharris 82240616Sjimharris 83240616Sjimharrisstatic int 84240616Sjimharrisnvme_sysctl_dump_debug(SYSCTL_HANDLER_ARGS) 85240616Sjimharris{ 86240616Sjimharris struct nvme_qpair *qpair = arg1; 87240616Sjimharris uint32_t val = 0; 88240616Sjimharris 89240616Sjimharris int error = sysctl_handle_int(oidp, &val, 0, req); 90240616Sjimharris 91240616Sjimharris if (error) 92240616Sjimharris return (error); 93240616Sjimharris 94240616Sjimharris if (val != 0) 95240616Sjimharris nvme_dump_queue(qpair); 96240616Sjimharris 97240616Sjimharris return (0); 98240616Sjimharris} 99240616Sjimharris 100240616Sjimharrisstatic int 101240616Sjimharrisnvme_sysctl_int_coal_time(SYSCTL_HANDLER_ARGS) 102240616Sjimharris{ 103240616Sjimharris struct nvme_controller *ctrlr = arg1; 104240616Sjimharris uint32_t oldval = ctrlr->int_coal_time; 105240616Sjimharris int error = sysctl_handle_int(oidp, &ctrlr->int_coal_time, 0, 106240616Sjimharris req); 107240616Sjimharris 108240616Sjimharris if (error) 109240616Sjimharris return (error); 110240616Sjimharris 111240616Sjimharris if (oldval != ctrlr->int_coal_time) 112240616Sjimharris nvme_ctrlr_cmd_set_interrupt_coalescing(ctrlr, 113240616Sjimharris ctrlr->int_coal_time, ctrlr->int_coal_threshold, NULL, 114240616Sjimharris NULL); 115240616Sjimharris 116240616Sjimharris return (0); 117240616Sjimharris} 118240616Sjimharris 119240616Sjimharrisstatic int 120240616Sjimharrisnvme_sysctl_int_coal_threshold(SYSCTL_HANDLER_ARGS) 121240616Sjimharris{ 122240616Sjimharris struct nvme_controller *ctrlr = arg1; 123240616Sjimharris uint32_t oldval = ctrlr->int_coal_threshold; 124240616Sjimharris int error = sysctl_handle_int(oidp, &ctrlr->int_coal_threshold, 0, 125240616Sjimharris req); 126240616Sjimharris 127240616Sjimharris if (error) 128240616Sjimharris return (error); 129240616Sjimharris 130240616Sjimharris if (oldval != ctrlr->int_coal_threshold) 131240616Sjimharris nvme_ctrlr_cmd_set_interrupt_coalescing(ctrlr, 132240616Sjimharris ctrlr->int_coal_time, ctrlr->int_coal_threshold, NULL, 133240616Sjimharris NULL); 134240616Sjimharris 135240616Sjimharris return (0); 136240616Sjimharris} 137240616Sjimharris 138248749Sjimharrisstatic int 139248749Sjimharrisnvme_sysctl_timeout_period(SYSCTL_HANDLER_ARGS) 140248749Sjimharris{ 141248749Sjimharris struct nvme_controller *ctrlr = arg1; 142248749Sjimharris uint32_t oldval = ctrlr->timeout_period; 143248749Sjimharris int error = sysctl_handle_int(oidp, &ctrlr->timeout_period, 0, req); 144248749Sjimharris 145248749Sjimharris if (error) 146248749Sjimharris return (error); 147248749Sjimharris 148248749Sjimharris if (ctrlr->timeout_period > NVME_MAX_TIMEOUT_PERIOD || 149248749Sjimharris ctrlr->timeout_period < NVME_MIN_TIMEOUT_PERIOD) { 150248749Sjimharris ctrlr->timeout_period = oldval; 151248749Sjimharris return (EINVAL); 152248749Sjimharris } 153248749Sjimharris 154248749Sjimharris return (0); 155248749Sjimharris} 156248749Sjimharris 157240616Sjimharrisstatic void 158241434Sjimharrisnvme_qpair_reset_stats(struct nvme_qpair *qpair) 159241434Sjimharris{ 160241434Sjimharris 161241434Sjimharris qpair->num_cmds = 0; 162241434Sjimharris qpair->num_intr_handler_calls = 0; 163241434Sjimharris} 164241434Sjimharris 165241434Sjimharrisstatic int 166241434Sjimharrisnvme_sysctl_num_cmds(SYSCTL_HANDLER_ARGS) 167241434Sjimharris{ 168241434Sjimharris struct nvme_controller *ctrlr = arg1; 169241434Sjimharris int64_t num_cmds = 0; 170241434Sjimharris int i; 171241434Sjimharris 172241434Sjimharris num_cmds = ctrlr->adminq.num_cmds; 173241434Sjimharris 174241434Sjimharris for (i = 0; i < ctrlr->num_io_queues; i++) 175241434Sjimharris num_cmds += ctrlr->ioq[i].num_cmds; 176241434Sjimharris 177241434Sjimharris return (sysctl_handle_64(oidp, &num_cmds, 0, req)); 178241434Sjimharris} 179241434Sjimharris 180241434Sjimharrisstatic int 181241434Sjimharrisnvme_sysctl_num_intr_handler_calls(SYSCTL_HANDLER_ARGS) 182241434Sjimharris{ 183241434Sjimharris struct nvme_controller *ctrlr = arg1; 184241434Sjimharris int64_t num_intr_handler_calls = 0; 185241434Sjimharris int i; 186241434Sjimharris 187241434Sjimharris num_intr_handler_calls = ctrlr->adminq.num_intr_handler_calls; 188241434Sjimharris 189241434Sjimharris for (i = 0; i < ctrlr->num_io_queues; i++) 190241434Sjimharris num_intr_handler_calls += ctrlr->ioq[i].num_intr_handler_calls; 191241434Sjimharris 192241434Sjimharris return (sysctl_handle_64(oidp, &num_intr_handler_calls, 0, req)); 193241434Sjimharris} 194241434Sjimharris 195241434Sjimharrisstatic int 196241434Sjimharrisnvme_sysctl_reset_stats(SYSCTL_HANDLER_ARGS) 197241434Sjimharris{ 198241434Sjimharris struct nvme_controller *ctrlr = arg1; 199241434Sjimharris uint32_t i, val = 0; 200241434Sjimharris 201241434Sjimharris int error = sysctl_handle_int(oidp, &val, 0, req); 202241434Sjimharris 203241434Sjimharris if (error) 204241434Sjimharris return (error); 205241434Sjimharris 206241434Sjimharris if (val != 0) { 207241434Sjimharris nvme_qpair_reset_stats(&ctrlr->adminq); 208241434Sjimharris 209241434Sjimharris for (i = 0; i < ctrlr->num_io_queues; i++) 210241434Sjimharris nvme_qpair_reset_stats(&ctrlr->ioq[i]); 211241434Sjimharris } 212241434Sjimharris 213241434Sjimharris return (0); 214241434Sjimharris} 215241434Sjimharris 216241434Sjimharris 217241434Sjimharrisstatic void 218240616Sjimharrisnvme_sysctl_initialize_queue(struct nvme_qpair *qpair, 219240616Sjimharris struct sysctl_ctx_list *ctrlr_ctx, struct sysctl_oid *que_tree) 220240616Sjimharris{ 221240616Sjimharris struct sysctl_oid_list *que_list = SYSCTL_CHILDREN(que_tree); 222240616Sjimharris 223240616Sjimharris SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_entries", 224240616Sjimharris CTLFLAG_RD, &qpair->num_entries, 0, 225240616Sjimharris "Number of entries in hardware queue"); 226241664Sjimharris SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_trackers", 227241664Sjimharris CTLFLAG_RD, &qpair->num_trackers, 0, 228241664Sjimharris "Number of trackers pre-allocated for this queue pair"); 229240616Sjimharris SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_head", 230240616Sjimharris CTLFLAG_RD, &qpair->sq_head, 0, 231240616Sjimharris "Current head of submission queue (as observed by driver)"); 232240616Sjimharris SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_tail", 233240616Sjimharris CTLFLAG_RD, &qpair->sq_tail, 0, 234240616Sjimharris "Current tail of submission queue (as observed by driver)"); 235240616Sjimharris SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "cq_head", 236240616Sjimharris CTLFLAG_RD, &qpair->cq_head, 0, 237240616Sjimharris "Current head of completion queue (as observed by driver)"); 238240616Sjimharris 239240616Sjimharris SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_cmds", 240240616Sjimharris CTLFLAG_RD, &qpair->num_cmds, "Number of commands submitted"); 241241434Sjimharris SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_intr_handler_calls", 242241434Sjimharris CTLFLAG_RD, &qpair->num_intr_handler_calls, 243241434Sjimharris "Number of times interrupt handler was invoked (will typically be " 244241434Sjimharris "less than number of actual interrupts generated due to " 245241434Sjimharris "coalescing)"); 246240616Sjimharris 247240616Sjimharris SYSCTL_ADD_PROC(ctrlr_ctx, que_list, OID_AUTO, 248240616Sjimharris "dump_debug", CTLTYPE_UINT | CTLFLAG_RW, qpair, 0, 249240616Sjimharris nvme_sysctl_dump_debug, "IU", "Dump debug data"); 250240616Sjimharris} 251240616Sjimharris 252240616Sjimharrisvoid 253240616Sjimharrisnvme_sysctl_initialize_ctrlr(struct nvme_controller *ctrlr) 254240616Sjimharris{ 255240616Sjimharris struct sysctl_ctx_list *ctrlr_ctx; 256240616Sjimharris struct sysctl_oid *ctrlr_tree, *que_tree; 257240616Sjimharris struct sysctl_oid_list *ctrlr_list; 258240616Sjimharris#define QUEUE_NAME_LENGTH 16 259240616Sjimharris char queue_name[QUEUE_NAME_LENGTH]; 260240616Sjimharris int i; 261240616Sjimharris 262240616Sjimharris ctrlr_ctx = device_get_sysctl_ctx(ctrlr->dev); 263240616Sjimharris ctrlr_tree = device_get_sysctl_tree(ctrlr->dev); 264240616Sjimharris ctrlr_list = SYSCTL_CHILDREN(ctrlr_tree); 265240616Sjimharris 266293352Sjimharris SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_cpus_per_ioq", 267293352Sjimharris CTLFLAG_RD, &ctrlr->num_cpus_per_ioq, 0, 268293352Sjimharris "Number of CPUs assigned per I/O queue pair"); 269293352Sjimharris 270248763Sjimharris SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 271248763Sjimharris "int_coal_time", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0, 272248763Sjimharris nvme_sysctl_int_coal_time, "IU", 273248763Sjimharris "Interrupt coalescing timeout (in microseconds)"); 274240616Sjimharris 275248763Sjimharris SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 276248763Sjimharris "int_coal_threshold", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0, 277248763Sjimharris nvme_sysctl_int_coal_threshold, "IU", 278248763Sjimharris "Interrupt coalescing threshold"); 279241434Sjimharris 280248763Sjimharris SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 281248763Sjimharris "timeout_period", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0, 282248763Sjimharris nvme_sysctl_timeout_period, "IU", 283248763Sjimharris "Timeout period (in seconds)"); 284248749Sjimharris 285248763Sjimharris SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 286248763Sjimharris "num_cmds", CTLTYPE_S64 | CTLFLAG_RD, 287248763Sjimharris ctrlr, 0, nvme_sysctl_num_cmds, "IU", 288248763Sjimharris "Number of commands submitted"); 289241434Sjimharris 290248763Sjimharris SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 291248763Sjimharris "num_intr_handler_calls", CTLTYPE_S64 | CTLFLAG_RD, 292248763Sjimharris ctrlr, 0, nvme_sysctl_num_intr_handler_calls, "IU", 293248763Sjimharris "Number of times interrupt handler was invoked (will " 294248763Sjimharris "typically be less than number of actual interrupts " 295248763Sjimharris "generated due to coalescing)"); 296241434Sjimharris 297248763Sjimharris SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 298248763Sjimharris "reset_stats", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0, 299248763Sjimharris nvme_sysctl_reset_stats, "IU", "Reset statistics to zero"); 300240616Sjimharris 301240616Sjimharris que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, "adminq", 302240616Sjimharris CTLFLAG_RD, NULL, "Admin Queue"); 303240616Sjimharris 304240616Sjimharris nvme_sysctl_initialize_queue(&ctrlr->adminq, ctrlr_ctx, que_tree); 305240616Sjimharris 306240616Sjimharris for (i = 0; i < ctrlr->num_io_queues; i++) { 307240616Sjimharris snprintf(queue_name, QUEUE_NAME_LENGTH, "ioq%d", i); 308240616Sjimharris que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, 309240616Sjimharris queue_name, CTLFLAG_RD, NULL, "IO Queue"); 310240616Sjimharris nvme_sysctl_initialize_queue(&ctrlr->ioq[i], ctrlr_ctx, 311240616Sjimharris que_tree); 312240616Sjimharris } 313240616Sjimharris} 314