xref: /freebsd/sys/dev/ufshci/ufshci_sysctl.c (revision db8b06468baefb9d9b5db5f91084d85071bfb5cb)
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 #include "ufshci_reg.h"
15 
16 static int
ufshci_sysctl_timeout_period(SYSCTL_HANDLER_ARGS)17 ufshci_sysctl_timeout_period(SYSCTL_HANDLER_ARGS)
18 {
19 	uint32_t *ptr = arg1;
20 	uint32_t newval = *ptr;
21 	int error = sysctl_handle_int(oidp, &newval, 0, req);
22 
23 	if (error || (req->newptr == NULL))
24 		return (error);
25 
26 	if (newval > UFSHCI_MAX_TIMEOUT_PERIOD ||
27 	    newval < UFSHCI_MIN_TIMEOUT_PERIOD) {
28 		return (EINVAL);
29 	} else {
30 		*ptr = newval;
31 	}
32 
33 	return (0);
34 }
35 
36 static int
ufshci_sysctl_num_cmds(SYSCTL_HANDLER_ARGS)37 ufshci_sysctl_num_cmds(SYSCTL_HANDLER_ARGS)
38 {
39 	struct ufshci_controller *ctrlr = arg1;
40 	int64_t num_cmds = 0;
41 	int i;
42 
43 	num_cmds = ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q].num_cmds;
44 
45 	if (ctrlr->transfer_req_queue.hwq != NULL) {
46 		for (i = 0; i < ctrlr->num_io_queues; i++)
47 			num_cmds += ctrlr->transfer_req_queue.hwq[i].num_cmds;
48 	}
49 
50 	return (sysctl_handle_64(oidp, &num_cmds, 0, req));
51 }
52 
53 static int
ufshci_sysctl_num_intr_handler_calls(SYSCTL_HANDLER_ARGS)54 ufshci_sysctl_num_intr_handler_calls(SYSCTL_HANDLER_ARGS)
55 {
56 	struct ufshci_controller *ctrlr = arg1;
57 	int64_t num_intr_handler_calls = 0;
58 	int i;
59 
60 	num_intr_handler_calls =
61 	    ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q].num_intr_handler_calls;
62 
63 	if (ctrlr->transfer_req_queue.hwq != NULL) {
64 		for (i = 0; i < ctrlr->num_io_queues; i++)
65 			num_intr_handler_calls += ctrlr->transfer_req_queue
66 						      .hwq[i]
67 						      .num_intr_handler_calls;
68 	}
69 
70 	return (sysctl_handle_64(oidp, &num_intr_handler_calls, 0, req));
71 }
72 
73 static int
ufshci_sysctl_num_retries(SYSCTL_HANDLER_ARGS)74 ufshci_sysctl_num_retries(SYSCTL_HANDLER_ARGS)
75 {
76 	struct ufshci_controller *ctrlr = arg1;
77 	int64_t num_retries = 0;
78 	int i;
79 
80 	num_retries = ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q].num_retries;
81 
82 	if (ctrlr->transfer_req_queue.hwq != NULL) {
83 		for (i = 0; i < ctrlr->num_io_queues; i++)
84 			num_retries +=
85 			    ctrlr->transfer_req_queue.hwq[i].num_retries;
86 	}
87 
88 	return (sysctl_handle_64(oidp, &num_retries, 0, req));
89 }
90 
91 static int
ufshci_sysctl_num_failures(SYSCTL_HANDLER_ARGS)92 ufshci_sysctl_num_failures(SYSCTL_HANDLER_ARGS)
93 {
94 	struct ufshci_controller *ctrlr = arg1;
95 	int64_t num_failures = 0;
96 	int i;
97 
98 	num_failures =
99 	    ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q].num_failures;
100 
101 	if (ctrlr->transfer_req_queue.hwq != NULL) {
102 		for (i = 0; i < ctrlr->num_io_queues; i++)
103 			num_failures +=
104 			    ctrlr->transfer_req_queue.hwq[i].num_failures;
105 	}
106 
107 	return (sysctl_handle_64(oidp, &num_failures, 0, req));
108 }
109 
110 static int
ufshci_sysctl_ahit(SYSCTL_HANDLER_ARGS)111 ufshci_sysctl_ahit(SYSCTL_HANDLER_ARGS)
112 {
113 	struct ufshci_controller *ctrlr = arg1;
114 	int64_t scale, timer;
115 	const int64_t scale_factor = 10;
116 
117 	scale = UFSHCIV(UFSHCI_AHIT_REG_TS, ctrlr->ufs_dev.ahit);
118 	timer = UFSHCIV(UFSHCI_AHIT_REG_AH8ITV, ctrlr->ufs_dev.ahit);
119 
120 	while (scale--)
121 		timer *= scale_factor;
122 
123 	return (sysctl_handle_64(oidp, &timer, 0, req));
124 }
125 
126 static void
ufshci_sysctl_initialize_queue(struct ufshci_hw_queue * hwq,struct sysctl_ctx_list * ctrlr_ctx,struct sysctl_oid * que_tree)127 ufshci_sysctl_initialize_queue(struct ufshci_hw_queue *hwq,
128     struct sysctl_ctx_list *ctrlr_ctx, struct sysctl_oid *que_tree)
129 {
130 	struct sysctl_oid_list *que_list = SYSCTL_CHILDREN(que_tree);
131 
132 	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_entries",
133 	    CTLFLAG_RD, &hwq->num_entries, 0,
134 	    "Number of entries in hardware queue");
135 	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_trackers",
136 	    CTLFLAG_RD, &hwq->num_trackers, 0,
137 	    "Number of trackers pre-allocated for this queue pair");
138 	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_head", CTLFLAG_RD,
139 	    &hwq->sq_head, 0,
140 	    "Current head of submission queue (as observed by driver)");
141 	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_tail", CTLFLAG_RD,
142 	    &hwq->sq_tail, 0,
143 	    "Current tail of submission queue (as observed by driver)");
144 	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "cq_head", CTLFLAG_RD,
145 	    &hwq->cq_head, 0,
146 	    "Current head of completion queue (as observed by driver)");
147 
148 	SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_cmds", CTLFLAG_RD,
149 	    &hwq->num_cmds, "Number of commands submitted");
150 	SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_intr_handler_calls",
151 	    CTLFLAG_RD, &hwq->num_intr_handler_calls,
152 	    "Number of times interrupt handler was invoked (will typically be "
153 	    "less than number of actual interrupts generated due to "
154 	    "interrupt aggregation)");
155 	SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_retries",
156 	    CTLFLAG_RD, &hwq->num_retries, "Number of commands retried");
157 	SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_failures",
158 	    CTLFLAG_RD, &hwq->num_failures,
159 	    "Number of commands ending in failure after all retries");
160 
161 	/* TODO: Implement num_ignored */
162 	/* TODO: Implement recovery state */
163 	/* TODO: Implement dump debug */
164 }
165 
166 void
ufshci_sysctl_initialize_ctrlr(struct ufshci_controller * ctrlr)167 ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr)
168 {
169 	struct sysctl_ctx_list *ctrlr_ctx;
170 	struct sysctl_oid *ctrlr_tree, *que_tree, *ioq_tree;
171 	struct sysctl_oid_list *ctrlr_list, *ioq_list;
172 	struct ufshci_device *dev = &ctrlr->ufs_dev;
173 #define QUEUE_NAME_LENGTH 16
174 	char queue_name[QUEUE_NAME_LENGTH];
175 	int i;
176 
177 	ctrlr_ctx = device_get_sysctl_ctx(ctrlr->dev);
178 	ctrlr_tree = device_get_sysctl_tree(ctrlr->dev);
179 	ctrlr_list = SYSCTL_CHILDREN(ctrlr_tree);
180 
181 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "major_version",
182 	    CTLFLAG_RD, &ctrlr->major_version, 0, "UFS spec major version");
183 
184 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "minor_version",
185 	    CTLFLAG_RD, &ctrlr->minor_version, 0, "UFS spec minor version");
186 
187 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "io_queue_mode",
188 	    CTLFLAG_RD, &ctrlr->transfer_req_queue.queue_mode, 0,
189 	    "Active host-side queuing scheme "
190 	    "(Single-Doorbell or Multi-Circular-Queue)");
191 
192 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_io_queues",
193 	    CTLFLAG_RD, &ctrlr->num_io_queues, 0, "Number of I/O queue pairs");
194 
195 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "cap", CTLFLAG_RD,
196 	    &ctrlr->cap, 0, "Number of I/O queue pairs");
197 
198 	SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_enabled",
199 	    CTLFLAG_RD, &dev->is_wb_enabled, 0, "WriteBooster enable/disable");
200 
201 	SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_flush_enabled",
202 	    CTLFLAG_RD, &dev->is_wb_flush_enabled, 0,
203 	    "WriteBooster flush enable/disable");
204 
205 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_buffer_type",
206 	    CTLFLAG_RD, &dev->wb_buffer_type, 0, "WriteBooster type");
207 
208 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_buffer_size_mb",
209 	    CTLFLAG_RD, &dev->wb_buffer_size_mb, 0,
210 	    "WriteBooster buffer size in MB");
211 
212 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO,
213 	    "wb_user_space_config_option", CTLFLAG_RD,
214 	    &dev->wb_user_space_config_option, 0,
215 	    "WriteBooster preserve user space mode");
216 
217 	SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "power_mode_supported",
218 	    CTLFLAG_RD, &dev->power_mode_supported, 0,
219 	    "Device power mode support");
220 
221 	SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO,
222 	    "auto_hibernation_supported", CTLFLAG_RD,
223 	    &dev->auto_hibernation_supported, 0,
224 	    "Device auto hibernation support");
225 
226 	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
227 	    "auto_hibernate_idle_timer_value",
228 	    CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0,
229 	    ufshci_sysctl_ahit, "IU",
230 	    "Auto-Hibernate Idle Timer Value (in microseconds)");
231 
232 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "power_mode",
233 	    CTLFLAG_RD, &dev->power_mode, 0, "Current device power mode");
234 
235 	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "timeout_period",
236 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &ctrlr->timeout_period,
237 	    0, ufshci_sysctl_timeout_period, "IU",
238 	    "Timeout period for I/O queues (in seconds)");
239 
240 	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_cmds",
241 	    CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0,
242 	    ufshci_sysctl_num_cmds, "IU", "Number of commands submitted");
243 
244 	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
245 	    "num_intr_handler_calls", CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
246 	    ctrlr, 0, ufshci_sysctl_num_intr_handler_calls, "IU",
247 	    "Number of times interrupt handler was invoked (will "
248 	    "typically be less than number of actual interrupts "
249 	    "generated due to coalescing)");
250 
251 	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_retries",
252 	    CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0,
253 	    ufshci_sysctl_num_retries, "IU", "Number of commands retried");
254 
255 	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_failures",
256 	    CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0,
257 	    ufshci_sysctl_num_failures, "IU",
258 	    "Number of commands ending in failure after all retries");
259 
260 	que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, "utmrq",
261 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
262 	    "UTP Task Management Request Queue");
263 
264 	ufshci_sysctl_initialize_queue(
265 	    &ctrlr->task_mgmt_req_queue.hwq[UFSHCI_SDB_Q], ctrlr_ctx, que_tree);
266 
267 	/*
268 	 * Make sure that we've constructed the I/O queues before setting up the
269 	 * sysctls. Failed controllers won't allocate it, but we want the rest
270 	 * of the sysctls to diagnose things.
271 	 */
272 	if (ctrlr->transfer_req_queue.hwq != NULL) {
273 		ioq_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO,
274 		    "ioq", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
275 		    "UTP Transfer Request Queue (I/O Queue)");
276 		ioq_list = SYSCTL_CHILDREN(ioq_tree);
277 
278 		for (i = 0; i < ctrlr->num_io_queues; i++) {
279 			snprintf(queue_name, QUEUE_NAME_LENGTH, "%d", i);
280 			que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ioq_list,
281 			    OID_AUTO, queue_name, CTLFLAG_RD | CTLFLAG_MPSAFE,
282 			    NULL, "IO Queue");
283 			ufshci_sysctl_initialize_queue(
284 			    &ctrlr->transfer_req_queue.hwq[i], ctrlr_ctx,
285 			    que_tree);
286 		}
287 	}
288 }
289