1 /*- 2 * Copyright (c) 2025, Samsung Electronics Co., Ltd. 3 * Written by Jaeyoon Choi 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8 #include <sys/param.h> 9 #include <sys/systm.h> 10 #include <sys/bus.h> 11 #include <sys/sysctl.h> 12 13 #include "ufshci_private.h" 14 15 static int 16 ufshci_sysctl_timeout_period(SYSCTL_HANDLER_ARGS) 17 { 18 uint32_t *ptr = arg1; 19 uint32_t newval = *ptr; 20 int error = sysctl_handle_int(oidp, &newval, 0, req); 21 22 if (error || (req->newptr == NULL)) 23 return (error); 24 25 if (newval > UFSHCI_MAX_TIMEOUT_PERIOD || 26 newval < UFSHCI_MIN_TIMEOUT_PERIOD) { 27 return (EINVAL); 28 } else { 29 *ptr = newval; 30 } 31 32 return (0); 33 } 34 35 static int 36 ufshci_sysctl_num_cmds(SYSCTL_HANDLER_ARGS) 37 { 38 struct ufshci_controller *ctrlr = arg1; 39 int64_t num_cmds = 0; 40 int i; 41 42 num_cmds = ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q].num_cmds; 43 44 if (ctrlr->transfer_req_queue.hwq != NULL) { 45 for (i = 0; i < ctrlr->num_io_queues; i++) 46 num_cmds += ctrlr->transfer_req_queue.hwq[i].num_cmds; 47 } 48 49 return (sysctl_handle_64(oidp, &num_cmds, 0, req)); 50 } 51 52 static int 53 ufshci_sysctl_num_intr_handler_calls(SYSCTL_HANDLER_ARGS) 54 { 55 struct ufshci_controller *ctrlr = arg1; 56 int64_t num_intr_handler_calls = 0; 57 int i; 58 59 num_intr_handler_calls = 60 ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q].num_intr_handler_calls; 61 62 if (ctrlr->transfer_req_queue.hwq != NULL) { 63 for (i = 0; i < ctrlr->num_io_queues; i++) 64 num_intr_handler_calls += ctrlr->transfer_req_queue 65 .hwq[i] 66 .num_intr_handler_calls; 67 } 68 69 return (sysctl_handle_64(oidp, &num_intr_handler_calls, 0, req)); 70 } 71 72 static int 73 ufshci_sysctl_num_retries(SYSCTL_HANDLER_ARGS) 74 { 75 struct ufshci_controller *ctrlr = arg1; 76 int64_t num_retries = 0; 77 int i; 78 79 num_retries = ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q].num_retries; 80 81 if (ctrlr->transfer_req_queue.hwq != NULL) { 82 for (i = 0; i < ctrlr->num_io_queues; i++) 83 num_retries += 84 ctrlr->transfer_req_queue.hwq[i].num_retries; 85 } 86 87 return (sysctl_handle_64(oidp, &num_retries, 0, req)); 88 } 89 90 static int 91 ufshci_sysctl_num_failures(SYSCTL_HANDLER_ARGS) 92 { 93 struct ufshci_controller *ctrlr = arg1; 94 int64_t num_failures = 0; 95 int i; 96 97 num_failures = 98 ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q].num_failures; 99 100 if (ctrlr->transfer_req_queue.hwq != NULL) { 101 for (i = 0; i < ctrlr->num_io_queues; i++) 102 num_failures += 103 ctrlr->transfer_req_queue.hwq[i].num_failures; 104 } 105 106 return (sysctl_handle_64(oidp, &num_failures, 0, req)); 107 } 108 109 static void 110 ufshci_sysctl_initialize_queue(struct ufshci_hw_queue *hwq, 111 struct sysctl_ctx_list *ctrlr_ctx, struct sysctl_oid *que_tree) 112 { 113 struct sysctl_oid_list *que_list = SYSCTL_CHILDREN(que_tree); 114 115 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_entries", 116 CTLFLAG_RD, &hwq->num_entries, 0, 117 "Number of entries in hardware queue"); 118 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_trackers", 119 CTLFLAG_RD, &hwq->num_trackers, 0, 120 "Number of trackers pre-allocated for this queue pair"); 121 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_head", CTLFLAG_RD, 122 &hwq->sq_head, 0, 123 "Current head of submission queue (as observed by driver)"); 124 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_tail", CTLFLAG_RD, 125 &hwq->sq_tail, 0, 126 "Current tail of submission queue (as observed by driver)"); 127 SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "cq_head", CTLFLAG_RD, 128 &hwq->cq_head, 0, 129 "Current head of completion queue (as observed by driver)"); 130 131 SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_cmds", CTLFLAG_RD, 132 &hwq->num_cmds, "Number of commands submitted"); 133 SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_intr_handler_calls", 134 CTLFLAG_RD, &hwq->num_intr_handler_calls, 135 "Number of times interrupt handler was invoked (will typically be " 136 "less than number of actual interrupts generated due to " 137 "interrupt aggregation)"); 138 SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_retries", 139 CTLFLAG_RD, &hwq->num_retries, "Number of commands retried"); 140 SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_failures", 141 CTLFLAG_RD, &hwq->num_failures, 142 "Number of commands ending in failure after all retries"); 143 144 /* TODO: Implement num_ignored */ 145 /* TODO: Implement recovery state */ 146 /* TODO: Implement dump debug */ 147 } 148 149 void 150 ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr) 151 { 152 struct sysctl_ctx_list *ctrlr_ctx; 153 struct sysctl_oid *ctrlr_tree, *que_tree, *ioq_tree; 154 struct sysctl_oid_list *ctrlr_list, *ioq_list; 155 #define QUEUE_NAME_LENGTH 16 156 char queue_name[QUEUE_NAME_LENGTH]; 157 int i; 158 159 ctrlr_ctx = device_get_sysctl_ctx(ctrlr->dev); 160 ctrlr_tree = device_get_sysctl_tree(ctrlr->dev); 161 ctrlr_list = SYSCTL_CHILDREN(ctrlr_tree); 162 163 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "major_version", 164 CTLFLAG_RD, &ctrlr->major_version, 0, "UFS spec major version"); 165 166 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "minor_version", 167 CTLFLAG_RD, &ctrlr->minor_version, 0, "UFS spec minor version"); 168 169 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "io_queue_mode", 170 CTLFLAG_RD, &ctrlr->transfer_req_queue.queue_mode, 0, 171 "Active host-side queuing scheme " 172 "(Single-Doorbell or Multi-Circular-Queue)"); 173 174 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_io_queues", 175 CTLFLAG_RD, &ctrlr->num_io_queues, 0, "Number of I/O queue pairs"); 176 177 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "cap", CTLFLAG_RD, 178 &ctrlr->cap, 0, "Number of I/O queue pairs"); 179 180 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "timeout_period", 181 CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &ctrlr->timeout_period, 182 0, ufshci_sysctl_timeout_period, "IU", 183 "Timeout period for I/O queues (in seconds)"); 184 185 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_cmds", 186 CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0, 187 ufshci_sysctl_num_cmds, "IU", "Number of commands submitted"); 188 189 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 190 "num_intr_handler_calls", CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, 191 ctrlr, 0, ufshci_sysctl_num_intr_handler_calls, "IU", 192 "Number of times interrupt handler was invoked (will " 193 "typically be less than number of actual interrupts " 194 "generated due to coalescing)"); 195 196 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_retries", 197 CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0, 198 ufshci_sysctl_num_retries, "IU", "Number of commands retried"); 199 200 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_failures", 201 CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0, 202 ufshci_sysctl_num_failures, "IU", 203 "Number of commands ending in failure after all retries"); 204 205 que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, "utmrq", 206 CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 207 "UTP Task Management Request Queue"); 208 209 ufshci_sysctl_initialize_queue( 210 &ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q], ctrlr_ctx, que_tree); 211 212 /* 213 * Make sure that we've constructed the I/O queues before setting up the 214 * sysctls. Failed controllers won't allocate it, but we want the rest 215 * of the sysctls to diagnose things. 216 */ 217 if (ctrlr->transfer_req_queue.hwq != NULL) { 218 ioq_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, 219 "ioq", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 220 "UTP Transfer Request Queue (I/O Queue)"); 221 ioq_list = SYSCTL_CHILDREN(ioq_tree); 222 223 for (i = 0; i < ctrlr->num_io_queues; i++) { 224 snprintf(queue_name, QUEUE_NAME_LENGTH, "%d", i); 225 que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ioq_list, 226 OID_AUTO, queue_name, CTLFLAG_RD | CTLFLAG_MPSAFE, 227 NULL, "IO Queue"); 228 ufshci_sysctl_initialize_queue( 229 &ctrlr->transfer_req_queue.hwq[i], ctrlr_ctx, 230 que_tree); 231 } 232 } 233 } 234