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 struct ufshci_device *dev = &ctrlr->ufs_dev; 156 #define QUEUE_NAME_LENGTH 16 157 char queue_name[QUEUE_NAME_LENGTH]; 158 int i; 159 160 ctrlr_ctx = device_get_sysctl_ctx(ctrlr->dev); 161 ctrlr_tree = device_get_sysctl_tree(ctrlr->dev); 162 ctrlr_list = SYSCTL_CHILDREN(ctrlr_tree); 163 164 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "major_version", 165 CTLFLAG_RD, &ctrlr->major_version, 0, "UFS spec major version"); 166 167 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "minor_version", 168 CTLFLAG_RD, &ctrlr->minor_version, 0, "UFS spec minor version"); 169 170 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "io_queue_mode", 171 CTLFLAG_RD, &ctrlr->transfer_req_queue.queue_mode, 0, 172 "Active host-side queuing scheme " 173 "(Single-Doorbell or Multi-Circular-Queue)"); 174 175 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_io_queues", 176 CTLFLAG_RD, &ctrlr->num_io_queues, 0, "Number of I/O queue pairs"); 177 178 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "cap", CTLFLAG_RD, 179 &ctrlr->cap, 0, "Number of I/O queue pairs"); 180 181 SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_enabled", 182 CTLFLAG_RD, &dev->is_wb_enabled, 0, "WriteBooster enable/disable"); 183 184 SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_flush_enabled", 185 CTLFLAG_RD, &dev->is_wb_flush_enabled, 0, 186 "WriteBooster flush enable/disable"); 187 188 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_buffer_type", 189 CTLFLAG_RD, &dev->wb_buffer_type, 0, "WriteBooster type"); 190 191 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_buffer_size_mb", 192 CTLFLAG_RD, &dev->wb_buffer_size_mb, 0, 193 "WriteBooster buffer size in MB"); 194 195 SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, 196 "wb_user_space_config_option", CTLFLAG_RD, 197 &dev->wb_user_space_config_option, 0, 198 "WriteBooster preserve user space mode"); 199 200 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "timeout_period", 201 CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &ctrlr->timeout_period, 202 0, ufshci_sysctl_timeout_period, "IU", 203 "Timeout period for I/O queues (in seconds)"); 204 205 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_cmds", 206 CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0, 207 ufshci_sysctl_num_cmds, "IU", "Number of commands submitted"); 208 209 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, 210 "num_intr_handler_calls", CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, 211 ctrlr, 0, ufshci_sysctl_num_intr_handler_calls, "IU", 212 "Number of times interrupt handler was invoked (will " 213 "typically be less than number of actual interrupts " 214 "generated due to coalescing)"); 215 216 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_retries", 217 CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0, 218 ufshci_sysctl_num_retries, "IU", "Number of commands retried"); 219 220 SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_failures", 221 CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0, 222 ufshci_sysctl_num_failures, "IU", 223 "Number of commands ending in failure after all retries"); 224 225 que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, "utmrq", 226 CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 227 "UTP Task Management Request Queue"); 228 229 ufshci_sysctl_initialize_queue( 230 &ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q], ctrlr_ctx, que_tree); 231 232 /* 233 * Make sure that we've constructed the I/O queues before setting up the 234 * sysctls. Failed controllers won't allocate it, but we want the rest 235 * of the sysctls to diagnose things. 236 */ 237 if (ctrlr->transfer_req_queue.hwq != NULL) { 238 ioq_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, 239 "ioq", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 240 "UTP Transfer Request Queue (I/O Queue)"); 241 ioq_list = SYSCTL_CHILDREN(ioq_tree); 242 243 for (i = 0; i < ctrlr->num_io_queues; i++) { 244 snprintf(queue_name, QUEUE_NAME_LENGTH, "%d", i); 245 que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ioq_list, 246 OID_AUTO, queue_name, CTLFLAG_RD | CTLFLAG_MPSAFE, 247 NULL, "IO Queue"); 248 ufshci_sysctl_initialize_queue( 249 &ctrlr->transfer_req_queue.hwq[i], ctrlr_ctx, 250 que_tree); 251 } 252 } 253 } 254