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