1993e3fafSRobert Mustacchi /*
2993e3fafSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3993e3fafSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4993e3fafSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5993e3fafSRobert Mustacchi  * 1.0 of the CDDL.
6993e3fafSRobert Mustacchi  *
7993e3fafSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8993e3fafSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9993e3fafSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10993e3fafSRobert Mustacchi  */
11993e3fafSRobert Mustacchi 
12993e3fafSRobert Mustacchi /*
13*3b442230SJordan Paige Hendricks  * Copyright 2019 Joyent, Inc.
14993e3fafSRobert Mustacchi  */
15993e3fafSRobert Mustacchi 
16993e3fafSRobert Mustacchi #include <sys/mdb_modapi.h>
17993e3fafSRobert Mustacchi #include <sys/usb/hcd/xhci/xhci.h>
18993e3fafSRobert Mustacchi 
19993e3fafSRobert Mustacchi #define	XHCI_MDB_TRB_INDENT	4
20993e3fafSRobert Mustacchi 
21993e3fafSRobert Mustacchi static const char *xhci_mdb_epctx_eptypes[] = {
22993e3fafSRobert Mustacchi 	"Not Valid",
23993e3fafSRobert Mustacchi 	"ISOCH OUT",
24993e3fafSRobert Mustacchi 	"BULK OUT",
25993e3fafSRobert Mustacchi 	"INTR OUT",
26993e3fafSRobert Mustacchi 	"CONTROL",
27993e3fafSRobert Mustacchi 	"ISOCH IN",
28993e3fafSRobert Mustacchi 	"BULK IN",
29993e3fafSRobert Mustacchi 	"INTR IN"
30993e3fafSRobert Mustacchi };
31993e3fafSRobert Mustacchi 
32993e3fafSRobert Mustacchi static const char *xhci_mdb_epctx_states[] = {
33993e3fafSRobert Mustacchi 	"Disabled",
34993e3fafSRobert Mustacchi 	"Running",
35993e3fafSRobert Mustacchi 	"Halted",
36993e3fafSRobert Mustacchi 	"Stopped",
37993e3fafSRobert Mustacchi 	"Error",
38993e3fafSRobert Mustacchi 	"<Unknown>",
39993e3fafSRobert Mustacchi 	"<Unknown>",
40993e3fafSRobert Mustacchi 	"<Unknown>"
41993e3fafSRobert Mustacchi };
42993e3fafSRobert Mustacchi 
43993e3fafSRobert Mustacchi static const mdb_bitmask_t xhci_mdb_trb_flags[] = {
44993e3fafSRobert Mustacchi 	{ "C", XHCI_TRB_CYCLE, XHCI_TRB_CYCLE },
45993e3fafSRobert Mustacchi 	{ "ENT", XHCI_TRB_ENT, XHCI_TRB_ENT },
46993e3fafSRobert Mustacchi 	{ "ISP", XHCI_TRB_ISP, XHCI_TRB_ISP },
47993e3fafSRobert Mustacchi 	{ "NS", XHCI_TRB_NOSNOOP, XHCI_TRB_NOSNOOP },
48993e3fafSRobert Mustacchi 	{ "CH", XHCI_TRB_CHAIN, XHCI_TRB_CHAIN },
49993e3fafSRobert Mustacchi 	{ "IOC", XHCI_TRB_IOC, XHCI_TRB_IOC },
50993e3fafSRobert Mustacchi 	{ "IDT", XHCI_TRB_IDT, XHCI_TRB_IDT },
51993e3fafSRobert Mustacchi 	{ "BEI", XHCI_TRB_BEI, XHCI_TRB_BEI },
52993e3fafSRobert Mustacchi 	{ NULL, 0, 0 }
53993e3fafSRobert Mustacchi };
54993e3fafSRobert Mustacchi 
55993e3fafSRobert Mustacchi typedef struct xhci_mdb_walk_endpoint {
56993e3fafSRobert Mustacchi 	xhci_device_t	xmwe_device;
57993e3fafSRobert Mustacchi 	uint_t		xmwe_ep;
58993e3fafSRobert Mustacchi } xhci_mdb_walk_endpoint_t;
59993e3fafSRobert Mustacchi 
60993e3fafSRobert Mustacchi static const char *
xhci_mdb_trb_code_to_str(int code)61993e3fafSRobert Mustacchi xhci_mdb_trb_code_to_str(int code)
62993e3fafSRobert Mustacchi {
63993e3fafSRobert Mustacchi 	switch (code) {
64993e3fafSRobert Mustacchi 	case XHCI_CODE_INVALID:
65993e3fafSRobert Mustacchi 		return ("Invalid");
66993e3fafSRobert Mustacchi 	case XHCI_CODE_SUCCESS:
67993e3fafSRobert Mustacchi 		return ("Success");
68993e3fafSRobert Mustacchi 	case XHCI_CODE_DATA_BUF:
69993e3fafSRobert Mustacchi 		return ("Data Overrun or Underrun");
70993e3fafSRobert Mustacchi 	case XHCI_CODE_BABBLE:
71993e3fafSRobert Mustacchi 		return ("Babble");
72993e3fafSRobert Mustacchi 	case XHCI_CODE_TXERR:
73993e3fafSRobert Mustacchi 		return ("Transaction Error");
74993e3fafSRobert Mustacchi 	case XHCI_CODE_TRB:
75993e3fafSRobert Mustacchi 		return ("Invalid TRB");
76993e3fafSRobert Mustacchi 	case XHCI_CODE_STALL:
77993e3fafSRobert Mustacchi 		return ("Stall");
78993e3fafSRobert Mustacchi 	case XHCI_CODE_RESOURCE:
79993e3fafSRobert Mustacchi 		return ("No Resources Available");
80993e3fafSRobert Mustacchi 	case XHCI_CODE_BANDWIDTH:
81993e3fafSRobert Mustacchi 		return ("No Bandwidth Available");
82993e3fafSRobert Mustacchi 	case XHCI_CODE_NO_SLOTS:
83993e3fafSRobert Mustacchi 		return ("No Slots Available");
84993e3fafSRobert Mustacchi 	case XHCI_CODE_STREAM_TYPE:
85993e3fafSRobert Mustacchi 		return ("Stream Context Type Detected");
86993e3fafSRobert Mustacchi 	case XHCI_CODE_SLOT_NOT_ON:
87993e3fafSRobert Mustacchi 		return ("Slot disabled");
88993e3fafSRobert Mustacchi 	case XHCI_CODE_ENDP_NOT_ON:
89993e3fafSRobert Mustacchi 		return ("Endpoint disabled");
90993e3fafSRobert Mustacchi 	case XHCI_CODE_SHORT_XFER:
91993e3fafSRobert Mustacchi 		return ("Short Transfer");
92993e3fafSRobert Mustacchi 	case XHCI_CODE_RING_UNDERRUN:
93993e3fafSRobert Mustacchi 		return ("Isoch. Ring Underrun");
94993e3fafSRobert Mustacchi 	case XHCI_CODE_RING_OVERRUN:
95993e3fafSRobert Mustacchi 		return ("Isoch. Ring Overrun");
96993e3fafSRobert Mustacchi 	case XHCI_CODE_VF_RING_FULL:
97993e3fafSRobert Mustacchi 		return ("VF Ring Full");
98993e3fafSRobert Mustacchi 	case XHCI_CODE_PARAMETER:
99993e3fafSRobert Mustacchi 		return ("Invalid Context Parameter");
100993e3fafSRobert Mustacchi 	case XHCI_CODE_BW_OVERRUN:
101993e3fafSRobert Mustacchi 		return ("Bandwidth Overrun");
102993e3fafSRobert Mustacchi 	case XHCI_CODE_CONTEXT_STATE:
103993e3fafSRobert Mustacchi 		return ("Illegal Context Transition");
104993e3fafSRobert Mustacchi 	case XHCI_CODE_NO_PING_RESP:
105993e3fafSRobert Mustacchi 		return ("Failed to Complete Periodic Transfer");
106993e3fafSRobert Mustacchi 	case XHCI_CODE_EV_RING_FULL:
107993e3fafSRobert Mustacchi 		return ("Event Ring Full");
108993e3fafSRobert Mustacchi 	case XHCI_CODE_INCOMPAT_DEV:
109993e3fafSRobert Mustacchi 		return ("Incompatible Device");
110993e3fafSRobert Mustacchi 	case XHCI_CODE_MISSED_SRV:
111993e3fafSRobert Mustacchi 		return ("Missed Isoch. Service Window");
112993e3fafSRobert Mustacchi 	case XHCI_CODE_CMD_RING_STOP:
113993e3fafSRobert Mustacchi 		return ("Command Ring Stop");
114993e3fafSRobert Mustacchi 	case XHCI_CODE_CMD_ABORTED:
115993e3fafSRobert Mustacchi 		return ("Command Aborted");
116993e3fafSRobert Mustacchi 	case XHCI_CODE_XFER_STOPPED:
117993e3fafSRobert Mustacchi 		return ("Transfer Stopped");
118993e3fafSRobert Mustacchi 	case XHCI_CODE_XFER_STOPINV:
119993e3fafSRobert Mustacchi 		return ("Invalid Transfer Length");
120993e3fafSRobert Mustacchi 	case XHCI_CODE_XFER_STOPSHORT:
121993e3fafSRobert Mustacchi 		return ("Stopped before End of Transfer Descriptor");
122993e3fafSRobert Mustacchi 	case XHCI_CODE_MELAT:
123993e3fafSRobert Mustacchi 		return ("Max Exit Latency too large");
124993e3fafSRobert Mustacchi 	case XHCI_CODE_RESERVED:
125993e3fafSRobert Mustacchi 		return ("Reserved");
126993e3fafSRobert Mustacchi 	case XHCI_CODE_ISOC_OVERRUN:
127993e3fafSRobert Mustacchi 		return ("Isochronus Overrun");
128993e3fafSRobert Mustacchi 	case XHCI_CODE_EVENT_LOST:
129993e3fafSRobert Mustacchi 		return ("Event Lost");
130993e3fafSRobert Mustacchi 	case XHCI_CODE_UNDEFINED:
131993e3fafSRobert Mustacchi 		return ("Undefined Fatal Error");
132993e3fafSRobert Mustacchi 	case XHCI_CODE_INVALID_SID:
133993e3fafSRobert Mustacchi 		return ("Invalid Stream ID");
134993e3fafSRobert Mustacchi 	case XHCI_CODE_SEC_BW:
135993e3fafSRobert Mustacchi 		return ("Secondary Bandwith Allocation Failure");
136993e3fafSRobert Mustacchi 	case XHCI_CODE_SPLITERR:
137993e3fafSRobert Mustacchi 		return ("USB2 Split Transaction Error");
138993e3fafSRobert Mustacchi 	default:
139993e3fafSRobert Mustacchi 		break;
140993e3fafSRobert Mustacchi 	}
141993e3fafSRobert Mustacchi 
142993e3fafSRobert Mustacchi 	if (code >= 192 && code <= 223)
143993e3fafSRobert Mustacchi 		return ("Vendor Defined Error");
144993e3fafSRobert Mustacchi 	if (code >= 224 && code <= 255)
145993e3fafSRobert Mustacchi 		return ("Vendor Defined Info");
146993e3fafSRobert Mustacchi 
147993e3fafSRobert Mustacchi 	return ("Reserved");
148993e3fafSRobert Mustacchi }
149993e3fafSRobert Mustacchi 
150993e3fafSRobert Mustacchi static const char *
xhci_mdb_trb_type_to_str(int code)151993e3fafSRobert Mustacchi xhci_mdb_trb_type_to_str(int code)
152993e3fafSRobert Mustacchi {
153993e3fafSRobert Mustacchi 	/*
154993e3fafSRobert Mustacchi 	 * The macros for the types are all already shifted over based on their
155993e3fafSRobert Mustacchi 	 * place in the TRB, so shift there again ourselves.
156993e3fafSRobert Mustacchi 	 */
157993e3fafSRobert Mustacchi 	switch (code << 10) {
158993e3fafSRobert Mustacchi 	case XHCI_TRB_TYPE_NORMAL:
159993e3fafSRobert Mustacchi 		return ("Normal");
160993e3fafSRobert Mustacchi 	case XHCI_TRB_TYPE_SETUP:
161993e3fafSRobert Mustacchi 		return ("Setup");
162993e3fafSRobert Mustacchi 	case XHCI_TRB_TYPE_DATA:
163993e3fafSRobert Mustacchi 		return ("Data");
164993e3fafSRobert Mustacchi 	case XHCI_TRB_TYPE_STATUS:
165993e3fafSRobert Mustacchi 		return ("Status");
166993e3fafSRobert Mustacchi 	case XHCI_TRB_TYPE_LINK:
167993e3fafSRobert Mustacchi 		return ("Link");
168993e3fafSRobert Mustacchi 	case XHCI_TRB_TYPE_EVENT:
169993e3fafSRobert Mustacchi 		return ("Event");
170993e3fafSRobert Mustacchi 	case XHCI_TRB_TYPE_NOOP:
171993e3fafSRobert Mustacchi 		return ("No-Op");
172993e3fafSRobert Mustacchi 	case XHCI_CMD_ENABLE_SLOT:
173993e3fafSRobert Mustacchi 		return ("Enable Slot");
174993e3fafSRobert Mustacchi 	case XHCI_CMD_DISABLE_SLOT:
175993e3fafSRobert Mustacchi 		return ("Disable Slot");
176993e3fafSRobert Mustacchi 	case XHCI_CMD_ADDRESS_DEVICE:
177993e3fafSRobert Mustacchi 		return ("Address Device");
178993e3fafSRobert Mustacchi 	case XHCI_CMD_CONFIG_EP:
179993e3fafSRobert Mustacchi 		return ("Configure Endpoint");
180993e3fafSRobert Mustacchi 	case XHCI_CMD_EVAL_CTX:
181993e3fafSRobert Mustacchi 		return ("Evaluate Context");
182993e3fafSRobert Mustacchi 	case XHCI_CMD_RESET_EP:
183993e3fafSRobert Mustacchi 		return ("Reset Endpoint");
184993e3fafSRobert Mustacchi 	case XHCI_CMD_STOP_EP:
185993e3fafSRobert Mustacchi 		return ("Stop Endpoint");
186993e3fafSRobert Mustacchi 	case XHCI_CMD_SET_TR_DEQ:
187993e3fafSRobert Mustacchi 		return ("Set Transfer Ring Dequeue Pointer");
188993e3fafSRobert Mustacchi 	case XHCI_CMD_RESET_DEV:
189993e3fafSRobert Mustacchi 		return ("Reset Device");
190993e3fafSRobert Mustacchi 	case XHCI_CMD_FEVENT:
191993e3fafSRobert Mustacchi 		return ("Force Event");
192993e3fafSRobert Mustacchi 	case XHCI_CMD_NEG_BW:
193993e3fafSRobert Mustacchi 		return ("Negotiate Bandwidth");
194993e3fafSRobert Mustacchi 	case XHCI_CMD_SET_LT:
195993e3fafSRobert Mustacchi 		return ("Set Latency Tolerance");
196993e3fafSRobert Mustacchi 	case XHCI_CMD_GET_BW:
197993e3fafSRobert Mustacchi 		return ("Get Bandwidth");
198993e3fafSRobert Mustacchi 	case XHCI_CMD_FHEADER:
199993e3fafSRobert Mustacchi 		return ("Force Header");
200993e3fafSRobert Mustacchi 	case XHCI_CMD_NOOP:
201993e3fafSRobert Mustacchi 		return ("No-Op Command");
202993e3fafSRobert Mustacchi 	case XHCI_EVT_XFER:
203993e3fafSRobert Mustacchi 		return ("Transfer Event");
204993e3fafSRobert Mustacchi 	case XHCI_EVT_CMD_COMPLETE:
205993e3fafSRobert Mustacchi 		return ("Command Completion Event");
206993e3fafSRobert Mustacchi 	case XHCI_EVT_PORT_CHANGE:
207993e3fafSRobert Mustacchi 		return ("Port Status Change Event");
208993e3fafSRobert Mustacchi 	case XHCI_EVT_BW_REQUEST:
209993e3fafSRobert Mustacchi 		return ("Bandwidth Request Event");
210993e3fafSRobert Mustacchi 	case XHCI_EVT_DOORBELL:
211993e3fafSRobert Mustacchi 		return ("Doorbell Event");
212993e3fafSRobert Mustacchi 	case XHCI_EVT_HOST_CTRL:
213993e3fafSRobert Mustacchi 		return ("Host Controller Event");
214993e3fafSRobert Mustacchi 	case XHCI_EVT_DEVICE_NOTIFY:
215993e3fafSRobert Mustacchi 		return ("Device Notification Event");
216993e3fafSRobert Mustacchi 	case XHCI_EVT_MFINDEX_WRAP:
217993e3fafSRobert Mustacchi 		return ("MFINDEX Wrap Event");
218993e3fafSRobert Mustacchi 	default:
219993e3fafSRobert Mustacchi 		break;
220993e3fafSRobert Mustacchi 	}
221993e3fafSRobert Mustacchi 
222993e3fafSRobert Mustacchi 	if (code >= 43 && code <= 63)
223993e3fafSRobert Mustacchi 		return ("Vendor Defiend");
224993e3fafSRobert Mustacchi 	return ("Reserved");
225993e3fafSRobert Mustacchi }
226993e3fafSRobert Mustacchi 
227993e3fafSRobert Mustacchi /* ARGSUSED */
228993e3fafSRobert Mustacchi static int
xhci_mdb_print_epctx(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)229993e3fafSRobert Mustacchi xhci_mdb_print_epctx(uintptr_t addr, uint_t flags, int argc,
230993e3fafSRobert Mustacchi     const mdb_arg_t *argv)
231993e3fafSRobert Mustacchi {
232993e3fafSRobert Mustacchi 	uint32_t info, info2, txinfo;
233993e3fafSRobert Mustacchi 	xhci_endpoint_context_t epctx;
234993e3fafSRobert Mustacchi 
235993e3fafSRobert Mustacchi 	if (!(flags & DCMD_ADDRSPEC)) {
236993e3fafSRobert Mustacchi 		mdb_warn("::xhci_epctx requires an address\n");
237993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
238993e3fafSRobert Mustacchi 	}
239993e3fafSRobert Mustacchi 
240993e3fafSRobert Mustacchi 	if (mdb_vread(&epctx, sizeof (epctx), addr) != sizeof (epctx)) {
241993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_endpoint_context_t at %p", addr);
242993e3fafSRobert Mustacchi 		return (DCMD_ERR);
243993e3fafSRobert Mustacchi 	}
244993e3fafSRobert Mustacchi 
245993e3fafSRobert Mustacchi 	info = LE_32(epctx.xec_info);
246993e3fafSRobert Mustacchi 	info2 = LE_32(epctx.xec_info2);
247993e3fafSRobert Mustacchi 	txinfo = LE_32(epctx.xec_txinfo);
248993e3fafSRobert Mustacchi 
249993e3fafSRobert Mustacchi 	mdb_printf("Endpoint State: %s (%d)\n",
250993e3fafSRobert Mustacchi 	    xhci_mdb_epctx_states[XHCI_EPCTX_STATE(info)],
251993e3fafSRobert Mustacchi 	    XHCI_EPCTX_STATE(info));
252993e3fafSRobert Mustacchi 
253993e3fafSRobert Mustacchi 	mdb_printf("Mult: %d\n", XHCI_EPCTX_GET_MULT(info));
254993e3fafSRobert Mustacchi 	mdb_printf("Max Streams: %d\n", XHCI_EPCTX_GET_MAXP_STREAMS(info));
255993e3fafSRobert Mustacchi 	mdb_printf("LSA: %d\n", XHCI_EPCTX_GET_LSA(info));
256993e3fafSRobert Mustacchi 	mdb_printf("Interval: %d\n", XHCI_EPCTX_GET_IVAL(info));
257993e3fafSRobert Mustacchi 	mdb_printf("Max ESIT Hi: %d\n", XHCI_EPCTX_GET_MAX_ESIT_HI(info));
258993e3fafSRobert Mustacchi 
259993e3fafSRobert Mustacchi 	mdb_printf("CErr: %d\n", XHCI_EPCTX_GET_CERR(info2));
260993e3fafSRobert Mustacchi 	mdb_printf("EP Type: %s (%d)\n",
261993e3fafSRobert Mustacchi 	    xhci_mdb_epctx_eptypes[XHCI_EPCTX_GET_EPTYPE(info2)],
262993e3fafSRobert Mustacchi 	    XHCI_EPCTX_GET_EPTYPE(info2));
263993e3fafSRobert Mustacchi 	mdb_printf("Host Initiate Disable: %d\n", XHCI_EPCTX_GET_HID(info2));
264993e3fafSRobert Mustacchi 	mdb_printf("Max Burst: %d\n", XHCI_EPCTX_GET_MAXB(info2));
265993e3fafSRobert Mustacchi 	mdb_printf("Max Packet Size: %d\n", XHCI_EPCTX_GET_MPS(info2));
266993e3fafSRobert Mustacchi 
267993e3fafSRobert Mustacchi 	mdb_printf("Ring DCS: %d\n", LE_64(epctx.xec_dequeue) & 0x1);
268993e3fafSRobert Mustacchi 	mdb_printf("Ring PA: 0x%lx\n", LE_64(epctx.xec_dequeue) & ~0xf);
269993e3fafSRobert Mustacchi 
270993e3fafSRobert Mustacchi 	mdb_printf("Average TRB Length: %d\n", XHCI_EPCTX_AVG_TRB_LEN(txinfo));
271993e3fafSRobert Mustacchi 	mdb_printf("Max ESIT: %d\n", XHCI_EPCTX_GET_MAX_ESIT_PAYLOAD(txinfo));
272993e3fafSRobert Mustacchi 
273993e3fafSRobert Mustacchi 	return (DCMD_OK);
274993e3fafSRobert Mustacchi }
275993e3fafSRobert Mustacchi 
276993e3fafSRobert Mustacchi /* ARGSUSED */
277993e3fafSRobert Mustacchi static int
xhci_mdb_print_slotctx(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)278993e3fafSRobert Mustacchi xhci_mdb_print_slotctx(uintptr_t addr, uint_t flags, int argc,
279993e3fafSRobert Mustacchi     const mdb_arg_t *argv)
280993e3fafSRobert Mustacchi {
281993e3fafSRobert Mustacchi 	uint32_t info, info2, tt, state;
282993e3fafSRobert Mustacchi 	xhci_slot_context_t sctx;
283993e3fafSRobert Mustacchi 
284993e3fafSRobert Mustacchi 	if (!(flags & DCMD_ADDRSPEC)) {
285993e3fafSRobert Mustacchi 		mdb_warn("::xhci_slotctx requires an address\n");
286993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
287993e3fafSRobert Mustacchi 	}
288993e3fafSRobert Mustacchi 
289993e3fafSRobert Mustacchi 	if (mdb_vread(&sctx, sizeof (sctx), addr) != sizeof (sctx)) {
290993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_slot_context_t at %p", addr);
291993e3fafSRobert Mustacchi 		return (DCMD_ERR);
292993e3fafSRobert Mustacchi 	}
293993e3fafSRobert Mustacchi 
294993e3fafSRobert Mustacchi 	info = LE_32(sctx.xsc_info);
295993e3fafSRobert Mustacchi 	info2 = LE_32(sctx.xsc_info2);
296993e3fafSRobert Mustacchi 	tt = LE_32(sctx.xsc_tt);
297993e3fafSRobert Mustacchi 	state = LE_32(sctx.xsc_state);
298993e3fafSRobert Mustacchi 
299993e3fafSRobert Mustacchi 	mdb_printf("Route: 0x%x\n", XHCI_SCTX_GET_ROUTE(info));
300993e3fafSRobert Mustacchi 
301993e3fafSRobert Mustacchi 	mdb_printf("Slot Speed: ");
302993e3fafSRobert Mustacchi 	switch (XHCI_SCTX_GET_SPEED(info)) {
303993e3fafSRobert Mustacchi 	case XHCI_SPEED_FULL:
304993e3fafSRobert Mustacchi 		mdb_printf("Full");
305993e3fafSRobert Mustacchi 		break;
306993e3fafSRobert Mustacchi 	case XHCI_SPEED_LOW:
307993e3fafSRobert Mustacchi 		mdb_printf("Low");
308993e3fafSRobert Mustacchi 		break;
309993e3fafSRobert Mustacchi 	case XHCI_SPEED_HIGH:
310993e3fafSRobert Mustacchi 		mdb_printf("High");
311993e3fafSRobert Mustacchi 		break;
312993e3fafSRobert Mustacchi 	case XHCI_SPEED_SUPER:
313993e3fafSRobert Mustacchi 		mdb_printf("Super");
314993e3fafSRobert Mustacchi 		break;
315993e3fafSRobert Mustacchi 	default:
316993e3fafSRobert Mustacchi 		mdb_printf("Unknown");
317993e3fafSRobert Mustacchi 		break;
318993e3fafSRobert Mustacchi 	}
319993e3fafSRobert Mustacchi 	mdb_printf(" (%d)\n", XHCI_SCTX_GET_SPEED(info));
320993e3fafSRobert Mustacchi 
321993e3fafSRobert Mustacchi 
322993e3fafSRobert Mustacchi 	mdb_printf("MTT: %d\n", XHCI_SCTX_GET_MTT(info));
323993e3fafSRobert Mustacchi 	mdb_printf("HUB: %d\n", XHCI_SCTX_GET_HUB(info));
324993e3fafSRobert Mustacchi 	mdb_printf("DCI: %d\n", XHCI_SCTX_GET_DCI(info));
325993e3fafSRobert Mustacchi 
326993e3fafSRobert Mustacchi 	mdb_printf("Max Exit Latency: %d\n", XHCI_SCTX_GET_MAX_EL(info2));
327993e3fafSRobert Mustacchi 	mdb_printf("Root Hub Port: %d\n", XHCI_SCTX_GET_RHPORT(info2));
328993e3fafSRobert Mustacchi 	mdb_printf("Hub Number of Ports: %d\n", XHCI_SCTX_GET_NPORTS(info2));
329993e3fafSRobert Mustacchi 
330993e3fafSRobert Mustacchi 	mdb_printf("TT Hub Slot id: %d\n", XHCI_SCTX_GET_TT_HUB_SID(tt));
331993e3fafSRobert Mustacchi 	mdb_printf("TT Port Number: %d\n", XHCI_SCTX_GET_TT_PORT_NUM(tt));
332993e3fafSRobert Mustacchi 	mdb_printf("TT Think Time: %d\n", XHCI_SCTX_GET_TT_THINK_TIME(tt));
333993e3fafSRobert Mustacchi 	mdb_printf("IRQ Target: %d\n", XHCI_SCTX_GET_IRQ_TARGET(tt));
334993e3fafSRobert Mustacchi 
335993e3fafSRobert Mustacchi 	mdb_printf("Device Address: 0x%x\n", XHCI_SCTX_GET_DEV_ADDR(state));
336993e3fafSRobert Mustacchi 	mdb_printf("Slot State: ");
337993e3fafSRobert Mustacchi 	switch (XHCI_SCTX_GET_SLOT_STATE(state)) {
338993e3fafSRobert Mustacchi 	case XHCI_SLOT_DIS_ENAB:
339993e3fafSRobert Mustacchi 		mdb_printf("Disabled/Enabled");
340993e3fafSRobert Mustacchi 		break;
341993e3fafSRobert Mustacchi 	case XHCI_SLOT_DEFAULT:
342993e3fafSRobert Mustacchi 		mdb_printf("Default");
343993e3fafSRobert Mustacchi 		break;
344993e3fafSRobert Mustacchi 	case XHCI_SLOT_ADDRESSED:
345993e3fafSRobert Mustacchi 		mdb_printf("Addressed");
346993e3fafSRobert Mustacchi 		break;
347993e3fafSRobert Mustacchi 	case XHCI_SLOT_CONFIGURED:
348993e3fafSRobert Mustacchi 		mdb_printf("Configured");
349993e3fafSRobert Mustacchi 		break;
350993e3fafSRobert Mustacchi 	default:
351993e3fafSRobert Mustacchi 		mdb_printf("Unknown");
352993e3fafSRobert Mustacchi 		break;
353993e3fafSRobert Mustacchi 	}
354993e3fafSRobert Mustacchi 	mdb_printf(" (%d)\n", XHCI_SCTX_GET_SLOT_STATE(state));
355993e3fafSRobert Mustacchi 
356993e3fafSRobert Mustacchi 	return (DCMD_OK);
357993e3fafSRobert Mustacchi }
358993e3fafSRobert Mustacchi 
359993e3fafSRobert Mustacchi static int
xhci_mdb_print_transfer_event(uint64_t pa,uint32_t status,uint32_t flags)360993e3fafSRobert Mustacchi xhci_mdb_print_transfer_event(uint64_t pa, uint32_t status, uint32_t flags)
361993e3fafSRobert Mustacchi {
362993e3fafSRobert Mustacchi 	mdb_printf("TRB Address: 0x%lx\n", pa);
363993e3fafSRobert Mustacchi 	mdb_printf("Transfer Length (Remain): %d\n", XHCI_TRB_REMAIN(status));
364993e3fafSRobert Mustacchi 	mdb_printf("Completion Code: %s (%d)\n",
365993e3fafSRobert Mustacchi 	    xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
366993e3fafSRobert Mustacchi 	    XHCI_TRB_GET_CODE(status));
367993e3fafSRobert Mustacchi 
368993e3fafSRobert Mustacchi 	mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags));
369993e3fafSRobert Mustacchi 	mdb_printf("Event Data: %d\n", XHCI_TRB_GET_ED(flags));
370993e3fafSRobert Mustacchi 	mdb_printf("Endpoint ID: %d\n", XHCI_TRB_GET_EP(flags));
371993e3fafSRobert Mustacchi 	mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags));
372993e3fafSRobert Mustacchi 	mdb_dec_indent(XHCI_MDB_TRB_INDENT);
373993e3fafSRobert Mustacchi 
374993e3fafSRobert Mustacchi 	return (DCMD_OK);
375993e3fafSRobert Mustacchi }
376993e3fafSRobert Mustacchi 
377993e3fafSRobert Mustacchi static int
xhci_mdb_print_command_event(uint64_t pa,uint32_t status,uint32_t flags)378993e3fafSRobert Mustacchi xhci_mdb_print_command_event(uint64_t pa, uint32_t status, uint32_t flags)
379993e3fafSRobert Mustacchi {
380993e3fafSRobert Mustacchi 	mdb_printf("TRB Address: 0x%lx\n", pa);
381993e3fafSRobert Mustacchi 	mdb_printf("Command Param: 0x%x\n", XHCI_TRB_REMAIN(status));
382993e3fafSRobert Mustacchi 	mdb_printf("Completion Code: %s (%d)\n",
383993e3fafSRobert Mustacchi 	    xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
384993e3fafSRobert Mustacchi 	    XHCI_TRB_GET_CODE(status));
385993e3fafSRobert Mustacchi 
386993e3fafSRobert Mustacchi 	mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags));
387993e3fafSRobert Mustacchi 	/* Skip VF ID as we don't support VFs */
388993e3fafSRobert Mustacchi 	mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags));
389993e3fafSRobert Mustacchi 	mdb_dec_indent(XHCI_MDB_TRB_INDENT);
390993e3fafSRobert Mustacchi 
391993e3fafSRobert Mustacchi 	return (DCMD_OK);
392993e3fafSRobert Mustacchi }
393993e3fafSRobert Mustacchi 
394993e3fafSRobert Mustacchi /* ARGSUSED */
395993e3fafSRobert Mustacchi static int
xhci_mdb_print_psc(uint64_t pa,uint32_t status,uint32_t flags)396993e3fafSRobert Mustacchi xhci_mdb_print_psc(uint64_t pa, uint32_t status, uint32_t flags)
397993e3fafSRobert Mustacchi {
398993e3fafSRobert Mustacchi 	mdb_printf("Port: %d\n", XHCI_TRB_PORTID(pa));
399993e3fafSRobert Mustacchi 	mdb_printf("Completion Code: %s (%d)\n",
400993e3fafSRobert Mustacchi 	    xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
401993e3fafSRobert Mustacchi 	    XHCI_TRB_GET_CODE(status));
402993e3fafSRobert Mustacchi 	mdb_dec_indent(XHCI_MDB_TRB_INDENT);
403993e3fafSRobert Mustacchi 	return (DCMD_OK);
404993e3fafSRobert Mustacchi }
405993e3fafSRobert Mustacchi 
406993e3fafSRobert Mustacchi static int
xhci_mdb_print_normal_trb(uint64_t pa,uint32_t status,uint32_t flags)407993e3fafSRobert Mustacchi xhci_mdb_print_normal_trb(uint64_t pa, uint32_t status, uint32_t flags)
408993e3fafSRobert Mustacchi {
409993e3fafSRobert Mustacchi 	mdb_printf("TRB Address: 0x%lx\n", pa);
410993e3fafSRobert Mustacchi 	mdb_printf("TRB Length: %d bytes\n", XHCI_TRB_LEN(status));
411993e3fafSRobert Mustacchi 	mdb_printf("TRB TD Size: %d packets\n", XHCI_TRB_GET_TDREM(status));
412993e3fafSRobert Mustacchi 	mdb_printf("TRB Interrupt: %d\n", XHCI_TRB_GET_INTR(status));
413993e3fafSRobert Mustacchi 	mdb_printf("TRB Flags: %b (0x%x)\n", flags, xhci_mdb_trb_flags,
414993e3fafSRobert Mustacchi 	    XHCI_TRB_GET_FLAGS(flags));
415993e3fafSRobert Mustacchi 	mdb_dec_indent(XHCI_MDB_TRB_INDENT);
416993e3fafSRobert Mustacchi 
417993e3fafSRobert Mustacchi 	return (DCMD_OK);
418993e3fafSRobert Mustacchi }
419993e3fafSRobert Mustacchi 
420993e3fafSRobert Mustacchi /* ARGSUSED */
421993e3fafSRobert Mustacchi static int
xhci_mdb_print_trb(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)422993e3fafSRobert Mustacchi xhci_mdb_print_trb(uintptr_t addr, uint_t flags, int argc,
423993e3fafSRobert Mustacchi     const mdb_arg_t *argv)
424993e3fafSRobert Mustacchi {
425993e3fafSRobert Mustacchi 	xhci_trb_t trb;
426993e3fafSRobert Mustacchi 	uint64_t pa;
427993e3fafSRobert Mustacchi 	uint32_t status, trbflags, type;
428993e3fafSRobert Mustacchi 
429993e3fafSRobert Mustacchi 	if (!(flags & DCMD_ADDRSPEC)) {
430993e3fafSRobert Mustacchi 		mdb_warn("::xhci_trb expects an address\n");
431993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
432993e3fafSRobert Mustacchi 	}
433993e3fafSRobert Mustacchi 
434993e3fafSRobert Mustacchi 	if (mdb_vread(&trb, sizeof (trb), addr) != sizeof (trb)) {
435993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_trb_t at 0x%x", addr);
436993e3fafSRobert Mustacchi 		return (DCMD_ERR);
437993e3fafSRobert Mustacchi 	}
438993e3fafSRobert Mustacchi 
439993e3fafSRobert Mustacchi 	pa = LE_64(trb.trb_addr);
440993e3fafSRobert Mustacchi 	status = LE_32(trb.trb_status);
441993e3fafSRobert Mustacchi 	trbflags = LE_32(trb.trb_flags);
442993e3fafSRobert Mustacchi 
443993e3fafSRobert Mustacchi 	type = XHCI_TRB_GET_TYPE(trbflags);
444993e3fafSRobert Mustacchi 
445993e3fafSRobert Mustacchi 	if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
446993e3fafSRobert Mustacchi 		mdb_printf("\n");
447993e3fafSRobert Mustacchi 
448993e3fafSRobert Mustacchi 	mdb_set_dot(addr + sizeof (xhci_trb_t));
449993e3fafSRobert Mustacchi 	mdb_printf("%s TRB (%d)\n", xhci_mdb_trb_type_to_str(type), type);
450993e3fafSRobert Mustacchi 	mdb_inc_indent(XHCI_MDB_TRB_INDENT);
451993e3fafSRobert Mustacchi 
452993e3fafSRobert Mustacchi 	switch (XHCI_RING_TYPE_SHIFT(type)) {
453993e3fafSRobert Mustacchi 	case XHCI_EVT_XFER:
454993e3fafSRobert Mustacchi 		return (xhci_mdb_print_transfer_event(pa, status, trbflags));
455993e3fafSRobert Mustacchi 	case XHCI_EVT_CMD_COMPLETE:
456993e3fafSRobert Mustacchi 		return (xhci_mdb_print_command_event(pa, status, trbflags));
457993e3fafSRobert Mustacchi 	case XHCI_EVT_PORT_CHANGE:
458993e3fafSRobert Mustacchi 		return (xhci_mdb_print_psc(pa, status, trbflags));
459993e3fafSRobert Mustacchi 	case XHCI_TRB_TYPE_NORMAL:
460993e3fafSRobert Mustacchi 		return (xhci_mdb_print_normal_trb(pa, status, trbflags));
461993e3fafSRobert Mustacchi 	}
462993e3fafSRobert Mustacchi 
463993e3fafSRobert Mustacchi 	/*
464993e3fafSRobert Mustacchi 	 * Just print generic information if we don't have a specific printer
465993e3fafSRobert Mustacchi 	 * for that TRB type.
466993e3fafSRobert Mustacchi 	 */
467993e3fafSRobert Mustacchi 	mdb_printf("TRB Address: 0x%lx\n", pa);
468993e3fafSRobert Mustacchi 	mdb_printf("TRB Status: 0x%x\n", status);
469993e3fafSRobert Mustacchi 	mdb_printf("TRB Flags: 0x%x\n", trbflags);
470993e3fafSRobert Mustacchi 	mdb_dec_indent(XHCI_MDB_TRB_INDENT);
471993e3fafSRobert Mustacchi 
472993e3fafSRobert Mustacchi 	return (DCMD_OK);
473993e3fafSRobert Mustacchi }
474993e3fafSRobert Mustacchi 
475993e3fafSRobert Mustacchi static int
xhci_mdb_walk_xhci_init(mdb_walk_state_t * wsp)476993e3fafSRobert Mustacchi xhci_mdb_walk_xhci_init(mdb_walk_state_t *wsp)
477993e3fafSRobert Mustacchi {
478993e3fafSRobert Mustacchi 	GElf_Sym sym;
479993e3fafSRobert Mustacchi 	uintptr_t addr;
480993e3fafSRobert Mustacchi 
481993e3fafSRobert Mustacchi 	if (wsp->walk_addr != 0) {
482993e3fafSRobert Mustacchi 		mdb_warn("::walk xhci only supports global walks\n");
483993e3fafSRobert Mustacchi 		return (WALK_ERR);
484993e3fafSRobert Mustacchi 	}
485993e3fafSRobert Mustacchi 
486993e3fafSRobert Mustacchi 	if (mdb_lookup_by_obj("xhci", "xhci_soft_state", &sym) != 0) {
487993e3fafSRobert Mustacchi 		mdb_warn("failed to find xhci_soft_state symbol");
488993e3fafSRobert Mustacchi 		return (WALK_ERR);
489993e3fafSRobert Mustacchi 	}
490993e3fafSRobert Mustacchi 
491993e3fafSRobert Mustacchi 	if (mdb_vread(&addr, sizeof (addr), sym.st_value) != sizeof (addr)) {
492993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_soft_state at %p", addr);
493993e3fafSRobert Mustacchi 		return (WALK_ERR);
494993e3fafSRobert Mustacchi 	}
495993e3fafSRobert Mustacchi 
496993e3fafSRobert Mustacchi 	wsp->walk_addr = addr;
497993e3fafSRobert Mustacchi 	if (mdb_layered_walk("softstate", wsp) != 0) {
498993e3fafSRobert Mustacchi 		mdb_warn("failed to walk softstate");
499993e3fafSRobert Mustacchi 		return (WALK_ERR);
500993e3fafSRobert Mustacchi 	}
501993e3fafSRobert Mustacchi 
502993e3fafSRobert Mustacchi 	return (WALK_NEXT);
503993e3fafSRobert Mustacchi }
504993e3fafSRobert Mustacchi 
505993e3fafSRobert Mustacchi static int
xhci_mdb_walk_xhci_step(mdb_walk_state_t * wsp)506993e3fafSRobert Mustacchi xhci_mdb_walk_xhci_step(mdb_walk_state_t *wsp)
507993e3fafSRobert Mustacchi {
508993e3fafSRobert Mustacchi 	xhci_t xhci;
509993e3fafSRobert Mustacchi 
510993e3fafSRobert Mustacchi 	if (mdb_vread(&xhci, sizeof (xhci), wsp->walk_addr) != sizeof (xhci)) {
511993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_t at %p", wsp->walk_addr);
512993e3fafSRobert Mustacchi 		return (WALK_ERR);
513993e3fafSRobert Mustacchi 	}
514993e3fafSRobert Mustacchi 
515993e3fafSRobert Mustacchi 	return (wsp->walk_callback(wsp->walk_addr, &xhci, wsp->walk_cbdata));
516993e3fafSRobert Mustacchi }
517993e3fafSRobert Mustacchi 
518993e3fafSRobert Mustacchi static int
xhci_mdb_walk_xhci_device_init(mdb_walk_state_t * wsp)519993e3fafSRobert Mustacchi xhci_mdb_walk_xhci_device_init(mdb_walk_state_t *wsp)
520993e3fafSRobert Mustacchi {
521993e3fafSRobert Mustacchi 	uintptr_t addr;
522993e3fafSRobert Mustacchi 
523993e3fafSRobert Mustacchi 	if (wsp->walk_addr == 0) {
524993e3fafSRobert Mustacchi 		mdb_warn("::walk xhci_device requires an xhci_t\n");
525993e3fafSRobert Mustacchi 		return (WALK_ERR);
526993e3fafSRobert Mustacchi 	}
527993e3fafSRobert Mustacchi 
528993e3fafSRobert Mustacchi 	addr = wsp->walk_addr;
529993e3fafSRobert Mustacchi 	addr += offsetof(xhci_t, xhci_usba);
530993e3fafSRobert Mustacchi 	addr += offsetof(xhci_usba_t, xa_devices);
531993e3fafSRobert Mustacchi 	wsp->walk_addr = (uintptr_t)addr;
532993e3fafSRobert Mustacchi 	if (mdb_layered_walk("list", wsp) != 0) {
533993e3fafSRobert Mustacchi 		mdb_warn("failed to walk list");
534993e3fafSRobert Mustacchi 		return (WALK_ERR);
535993e3fafSRobert Mustacchi 	}
536993e3fafSRobert Mustacchi 
537993e3fafSRobert Mustacchi 	return (WALK_NEXT);
538993e3fafSRobert Mustacchi }
539993e3fafSRobert Mustacchi 
540993e3fafSRobert Mustacchi static int
xhci_mdb_walk_xhci_device_step(mdb_walk_state_t * wsp)541993e3fafSRobert Mustacchi xhci_mdb_walk_xhci_device_step(mdb_walk_state_t *wsp)
542993e3fafSRobert Mustacchi {
543993e3fafSRobert Mustacchi 	xhci_device_t xd;
544993e3fafSRobert Mustacchi 
545993e3fafSRobert Mustacchi 	if (mdb_vread(&xd, sizeof (xd), wsp->walk_addr) != sizeof (xd)) {
546993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_device_t at %p", wsp->walk_addr);
547993e3fafSRobert Mustacchi 		return (WALK_ERR);
548993e3fafSRobert Mustacchi 	}
549993e3fafSRobert Mustacchi 
550993e3fafSRobert Mustacchi 	return (wsp->walk_callback(wsp->walk_addr, &xd, wsp->walk_cbdata));
551993e3fafSRobert Mustacchi }
552993e3fafSRobert Mustacchi 
553993e3fafSRobert Mustacchi static int
xhci_mdb_walk_xhci_endpoint_init(mdb_walk_state_t * wsp)554993e3fafSRobert Mustacchi xhci_mdb_walk_xhci_endpoint_init(mdb_walk_state_t *wsp)
555993e3fafSRobert Mustacchi {
556993e3fafSRobert Mustacchi 	xhci_mdb_walk_endpoint_t *xm;
557993e3fafSRobert Mustacchi 	xhci_device_t *xd;
558993e3fafSRobert Mustacchi 
559993e3fafSRobert Mustacchi 	if (wsp->walk_addr == 0) {
560993e3fafSRobert Mustacchi 		mdb_warn("::walk xhci_endpoint requires an xhci_device_t\n");
561993e3fafSRobert Mustacchi 		return (WALK_ERR);
562993e3fafSRobert Mustacchi 	}
563993e3fafSRobert Mustacchi 
564993e3fafSRobert Mustacchi 	xm = mdb_alloc(sizeof (xhci_mdb_walk_endpoint_t), UM_SLEEP | UM_GC);
565993e3fafSRobert Mustacchi 	xm->xmwe_ep = 0;
566993e3fafSRobert Mustacchi 	xd = &xm->xmwe_device;
567993e3fafSRobert Mustacchi 	if (mdb_vread(xd, sizeof (*xd), wsp->walk_addr) != sizeof (*xd)) {
568993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_endpoint_t at %p",
569993e3fafSRobert Mustacchi 		    wsp->walk_addr);
570993e3fafSRobert Mustacchi 		return (WALK_ERR);
571993e3fafSRobert Mustacchi 	}
572993e3fafSRobert Mustacchi 	wsp->walk_data = xm;
573993e3fafSRobert Mustacchi 
574993e3fafSRobert Mustacchi 	return (WALK_NEXT);
575993e3fafSRobert Mustacchi }
576993e3fafSRobert Mustacchi 
577993e3fafSRobert Mustacchi static int
xhci_mdb_walk_xhci_endpoint_step(mdb_walk_state_t * wsp)578993e3fafSRobert Mustacchi xhci_mdb_walk_xhci_endpoint_step(mdb_walk_state_t *wsp)
579993e3fafSRobert Mustacchi {
580993e3fafSRobert Mustacchi 	int ret;
581993e3fafSRobert Mustacchi 	uintptr_t addr;
582993e3fafSRobert Mustacchi 	xhci_mdb_walk_endpoint_t *xm = wsp->walk_data;
583993e3fafSRobert Mustacchi 
584993e3fafSRobert Mustacchi 	if (xm->xmwe_ep >= XHCI_NUM_ENDPOINTS)
585993e3fafSRobert Mustacchi 		return (WALK_DONE);
586993e3fafSRobert Mustacchi 
587993e3fafSRobert Mustacchi 	addr = (uintptr_t)xm->xmwe_device.xd_endpoints[xm->xmwe_ep];
588892ad162SToomas Soome 	if (addr != 0) {
589993e3fafSRobert Mustacchi 		xhci_endpoint_t xe;
590993e3fafSRobert Mustacchi 
591993e3fafSRobert Mustacchi 		if (mdb_vread(&xe, sizeof (xe), addr) != sizeof (xe)) {
592993e3fafSRobert Mustacchi 			mdb_warn("failed to read xhci_endpoint_t at %p",
593993e3fafSRobert Mustacchi 			    xm->xmwe_device.xd_endpoints[xm->xmwe_ep]);
594993e3fafSRobert Mustacchi 			return (WALK_ERR);
595993e3fafSRobert Mustacchi 		}
596993e3fafSRobert Mustacchi 
597993e3fafSRobert Mustacchi 		ret = wsp->walk_callback(addr, &xe, wsp->walk_cbdata);
598993e3fafSRobert Mustacchi 	} else {
599993e3fafSRobert Mustacchi 		ret = WALK_NEXT;
600993e3fafSRobert Mustacchi 	}
601993e3fafSRobert Mustacchi 	xm->xmwe_ep++;
602993e3fafSRobert Mustacchi 
603993e3fafSRobert Mustacchi 	return (ret);
604993e3fafSRobert Mustacchi }
605993e3fafSRobert Mustacchi 
606993e3fafSRobert Mustacchi typedef struct xhci_mdb_find {
607993e3fafSRobert Mustacchi 	int		xmf_slot;
608993e3fafSRobert Mustacchi 	int		xmf_ep;
609993e3fafSRobert Mustacchi 	uintptr_t	xmf_addr;
610993e3fafSRobert Mustacchi } xhci_mdb_find_t;
611993e3fafSRobert Mustacchi 
612993e3fafSRobert Mustacchi static int
xhci_mdb_find_endpoint_cb(uintptr_t addr,const void * data,void * arg)613993e3fafSRobert Mustacchi xhci_mdb_find_endpoint_cb(uintptr_t addr, const void *data, void *arg)
614993e3fafSRobert Mustacchi {
615993e3fafSRobert Mustacchi 	const xhci_endpoint_t *xep = data;
616993e3fafSRobert Mustacchi 	xhci_mdb_find_t *xmf = arg;
617993e3fafSRobert Mustacchi 
618993e3fafSRobert Mustacchi 	/*
619993e3fafSRobert Mustacchi 	 * The endpoints that are presented here are off by one from the actual
620993e3fafSRobert Mustacchi 	 * endpoint ID in the xhci_endpoint_t, as we're really displaying the
621993e3fafSRobert Mustacchi 	 * index into the device input context.
622993e3fafSRobert Mustacchi 	 */
623993e3fafSRobert Mustacchi 	if (xep->xep_num + 1 == xmf->xmf_ep) {
624993e3fafSRobert Mustacchi 		xmf->xmf_addr = addr;
625993e3fafSRobert Mustacchi 		return (WALK_DONE);
626993e3fafSRobert Mustacchi 	}
627993e3fafSRobert Mustacchi 
628993e3fafSRobert Mustacchi 	return (WALK_NEXT);
629993e3fafSRobert Mustacchi }
630993e3fafSRobert Mustacchi 
631993e3fafSRobert Mustacchi static int
xhci_mdb_find_device_cb(uintptr_t addr,const void * data,void * arg)632993e3fafSRobert Mustacchi xhci_mdb_find_device_cb(uintptr_t addr, const void *data, void *arg)
633993e3fafSRobert Mustacchi {
634993e3fafSRobert Mustacchi 	const xhci_device_t *xd = data;
635993e3fafSRobert Mustacchi 	xhci_mdb_find_t *xmf = arg;
636993e3fafSRobert Mustacchi 
637993e3fafSRobert Mustacchi 	if (xd->xd_slot == xmf->xmf_slot) {
638993e3fafSRobert Mustacchi 		if (xmf->xmf_ep == -1) {
639993e3fafSRobert Mustacchi 			xmf->xmf_addr = addr;
640993e3fafSRobert Mustacchi 			return (WALK_DONE);
641993e3fafSRobert Mustacchi 		}
642993e3fafSRobert Mustacchi 
643993e3fafSRobert Mustacchi 		if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_find_endpoint_cb,
644993e3fafSRobert Mustacchi 		    xmf, addr) == -1) {
645993e3fafSRobert Mustacchi 			mdb_warn("failed to walk xhci_endpoint at %p", addr);
646993e3fafSRobert Mustacchi 			return (WALK_ERR);
647993e3fafSRobert Mustacchi 		}
648993e3fafSRobert Mustacchi 
649993e3fafSRobert Mustacchi 		return (WALK_DONE);
650993e3fafSRobert Mustacchi 	}
651993e3fafSRobert Mustacchi 
652993e3fafSRobert Mustacchi 	return (WALK_NEXT);
653993e3fafSRobert Mustacchi }
654993e3fafSRobert Mustacchi 
655993e3fafSRobert Mustacchi static int
xhci_mdb_find(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)656993e3fafSRobert Mustacchi xhci_mdb_find(uintptr_t addr, uint_t flags, int argc,
657993e3fafSRobert Mustacchi     const mdb_arg_t *argv)
658993e3fafSRobert Mustacchi {
659993e3fafSRobert Mustacchi 	uintptr_t ep, slot;
660993e3fafSRobert Mustacchi 	boolean_t ep_set, slot_set;
661993e3fafSRobert Mustacchi 	xhci_mdb_find_t xmf;
662993e3fafSRobert Mustacchi 
663993e3fafSRobert Mustacchi 	if ((flags & DCMD_ADDRSPEC) == 0)
664993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
665993e3fafSRobert Mustacchi 
666993e3fafSRobert Mustacchi 	ep_set = slot_set = B_FALSE;
667993e3fafSRobert Mustacchi 	if (mdb_getopts(argc, argv, 'e', MDB_OPT_UINTPTR_SET, &ep_set, &ep,
668*3b442230SJordan Paige Hendricks 	    's', MDB_OPT_UINTPTR_SET, &slot_set, &slot, NULL) != argc)
669993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
670993e3fafSRobert Mustacchi 
671993e3fafSRobert Mustacchi 	if (!slot_set) {
672993e3fafSRobert Mustacchi 		mdb_warn("-s is required\n");
673993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
674993e3fafSRobert Mustacchi 	}
675993e3fafSRobert Mustacchi 
676993e3fafSRobert Mustacchi 	xmf.xmf_slot = (int)slot;
677993e3fafSRobert Mustacchi 	if (ep_set)
678993e3fafSRobert Mustacchi 		xmf.xmf_ep = (int)ep;
679993e3fafSRobert Mustacchi 	else
680993e3fafSRobert Mustacchi 		xmf.xmf_ep = -1;
681993e3fafSRobert Mustacchi 	xmf.xmf_addr = 0;
682993e3fafSRobert Mustacchi 
683993e3fafSRobert Mustacchi 	if (mdb_pwalk("xhci`xhci_device", xhci_mdb_find_device_cb,
684993e3fafSRobert Mustacchi 	    &xmf, addr) == -1) {
685993e3fafSRobert Mustacchi 		mdb_warn("failed to walk xhci_device at %p", addr);
686993e3fafSRobert Mustacchi 		return (DCMD_ERR);
687993e3fafSRobert Mustacchi 	}
688993e3fafSRobert Mustacchi 
689993e3fafSRobert Mustacchi 	if (xmf.xmf_addr == 0) {
690993e3fafSRobert Mustacchi 		if (ep_set) {
691993e3fafSRobert Mustacchi 			mdb_warn("failed to find xhci_endpoint_t for slot %d "
692993e3fafSRobert Mustacchi 			    "and endpoint %d\n", slot, ep);
693993e3fafSRobert Mustacchi 		} else {
694993e3fafSRobert Mustacchi 			mdb_warn("failed to find xhci_device_t for slot %d\n",
695993e3fafSRobert Mustacchi 			    slot);
696993e3fafSRobert Mustacchi 		}
697993e3fafSRobert Mustacchi 		return (DCMD_ERR);
698993e3fafSRobert Mustacchi 	}
699993e3fafSRobert Mustacchi 
700993e3fafSRobert Mustacchi 	mdb_printf("%p\n", xmf.xmf_addr);
701993e3fafSRobert Mustacchi 	return (DCMD_OK);
702993e3fafSRobert Mustacchi }
703993e3fafSRobert Mustacchi 
704993e3fafSRobert Mustacchi /* ARGSUSED */
705993e3fafSRobert Mustacchi static int
xhci_mdb_endpoint_count(uintptr_t addr,const void * ep,void * arg)706993e3fafSRobert Mustacchi xhci_mdb_endpoint_count(uintptr_t addr, const void *ep, void *arg)
707993e3fafSRobert Mustacchi {
708993e3fafSRobert Mustacchi 	int *countp = arg;
709993e3fafSRobert Mustacchi 
710993e3fafSRobert Mustacchi 	*countp += 1;
711993e3fafSRobert Mustacchi 	return (WALK_NEXT);
712993e3fafSRobert Mustacchi }
713993e3fafSRobert Mustacchi 
714993e3fafSRobert Mustacchi /* ARGSUSED */
715993e3fafSRobert Mustacchi static int
xhci_mdb_print_endpoint_summary(uintptr_t addr,const void * ep,void * arg)716993e3fafSRobert Mustacchi xhci_mdb_print_endpoint_summary(uintptr_t addr, const void *ep, void *arg)
717993e3fafSRobert Mustacchi {
718993e3fafSRobert Mustacchi 	const xhci_device_t *xd = arg;
719993e3fafSRobert Mustacchi 	const xhci_endpoint_t *xep = ep;
720993e3fafSRobert Mustacchi 	const char *type;
721993e3fafSRobert Mustacchi 	const char *state;
722993e3fafSRobert Mustacchi 	xhci_endpoint_context_t epctx;
723993e3fafSRobert Mustacchi 	int eptype;
724993e3fafSRobert Mustacchi 
725993e3fafSRobert Mustacchi 	if (mdb_vread(&epctx, sizeof (epctx),
726993e3fafSRobert Mustacchi 	    (uintptr_t)xd->xd_endout[xep->xep_num]) != sizeof (epctx)) {
727993e3fafSRobert Mustacchi 		mdb_warn("failed to read endpoint context at %p",
728993e3fafSRobert Mustacchi 		    xd->xd_endout[xep->xep_num]);
729993e3fafSRobert Mustacchi 		return (WALK_ERR);
730993e3fafSRobert Mustacchi 	}
731993e3fafSRobert Mustacchi 
732993e3fafSRobert Mustacchi 	eptype = XHCI_EPCTX_GET_EPTYPE(LE_32(epctx.xec_info2));
733993e3fafSRobert Mustacchi 	type = xhci_mdb_epctx_eptypes[eptype];
734993e3fafSRobert Mustacchi 	state = xhci_mdb_epctx_states[XHCI_EPCTX_STATE(LE_32(epctx.xec_info))];
735993e3fafSRobert Mustacchi 
736993e3fafSRobert Mustacchi 	mdb_printf("%-4d %-10s %-10s 0x%-04x 0x%-04x\n", xep->xep_num, type,
737993e3fafSRobert Mustacchi 	    state, xep->xep_ring.xr_head, xep->xep_ring.xr_tail);
738993e3fafSRobert Mustacchi 
739993e3fafSRobert Mustacchi 	return (WALK_NEXT);
740993e3fafSRobert Mustacchi }
741993e3fafSRobert Mustacchi 
742993e3fafSRobert Mustacchi /* ARGSUSED */
743993e3fafSRobert Mustacchi static int
xhci_mdb_print_device(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)744993e3fafSRobert Mustacchi xhci_mdb_print_device(uintptr_t addr, uint_t flags, int argc,
745993e3fafSRobert Mustacchi     const mdb_arg_t *argv)
746993e3fafSRobert Mustacchi {
747993e3fafSRobert Mustacchi 	int count;
748993e3fafSRobert Mustacchi 	xhci_device_t xd;
749993e3fafSRobert Mustacchi 	usba_device_t ud;
750993e3fafSRobert Mustacchi 	char product[256], mfg[256];
751993e3fafSRobert Mustacchi 
752993e3fafSRobert Mustacchi 	if (!(flags & DCMD_ADDRSPEC)) {
753993e3fafSRobert Mustacchi 		return (mdb_eval("::walk xhci`xhci | ::walk xhci`xhci_device | "
754993e3fafSRobert Mustacchi 		    "::xhci_device"));
755993e3fafSRobert Mustacchi 	}
756993e3fafSRobert Mustacchi 
757993e3fafSRobert Mustacchi 	if (mdb_vread(&xd, sizeof (xd), addr) != sizeof (xd)) {
758993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_device_t at 0x%x", addr);
759993e3fafSRobert Mustacchi 		return (DCMD_ERR);
760993e3fafSRobert Mustacchi 	}
761993e3fafSRobert Mustacchi 
762993e3fafSRobert Mustacchi 	if (mdb_vread(&ud, sizeof (ud), (uintptr_t)xd.xd_usbdev) !=
763993e3fafSRobert Mustacchi 	    sizeof (ud)) {
764993e3fafSRobert Mustacchi 		mdb_warn("failed to read usba_device_t at %p\n", xd.xd_usbdev);
765993e3fafSRobert Mustacchi 		return (DCMD_ERR);
766993e3fafSRobert Mustacchi 	}
767993e3fafSRobert Mustacchi 
768993e3fafSRobert Mustacchi 	if (ud.usb_mfg_str == NULL || mdb_readstr(mfg, sizeof (mfg),
769993e3fafSRobert Mustacchi 	    (uintptr_t)ud.usb_mfg_str) <= 0) {
770993e3fafSRobert Mustacchi 		(void) strlcpy(mfg, "Unknown Manufacturer", sizeof (mfg));
771993e3fafSRobert Mustacchi 	}
772993e3fafSRobert Mustacchi 
773993e3fafSRobert Mustacchi 	if (ud.usb_product_str == NULL || mdb_readstr(product, sizeof (product),
774993e3fafSRobert Mustacchi 	    (uintptr_t)ud.usb_product_str) <= 0) {
775993e3fafSRobert Mustacchi 		(void) strlcpy(product, "Unknown Product", sizeof (product));
776993e3fafSRobert Mustacchi 	}
777993e3fafSRobert Mustacchi 
778993e3fafSRobert Mustacchi 	mdb_printf("%<b>%s - %s%</b>\n", mfg, product);
779993e3fafSRobert Mustacchi 
780993e3fafSRobert Mustacchi 	count = 0;
781993e3fafSRobert Mustacchi 	if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_endpoint_count, &count,
782993e3fafSRobert Mustacchi 	    addr) == -1) {
783993e3fafSRobert Mustacchi 		mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr);
784993e3fafSRobert Mustacchi 		return (DCMD_ERR);
785993e3fafSRobert Mustacchi 	}
786993e3fafSRobert Mustacchi 
787993e3fafSRobert Mustacchi 	mdb_printf("Port %02d | Slot %02d | # Endpoints %02d\n", xd.xd_port,
788993e3fafSRobert Mustacchi 	    xd.xd_slot, count);
789993e3fafSRobert Mustacchi 	mdb_printf("%<u>%-4s %-10s %-10s %-6s %-6s%</u>\n", "EP", "Type",
790993e3fafSRobert Mustacchi 	    "State", "Head", "Tail");
791993e3fafSRobert Mustacchi 
792993e3fafSRobert Mustacchi 	if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_print_endpoint_summary,
793993e3fafSRobert Mustacchi 	    &xd, addr) == -1) {
794993e3fafSRobert Mustacchi 		mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr);
795993e3fafSRobert Mustacchi 		return (DCMD_ERR);
796993e3fafSRobert Mustacchi 	}
797993e3fafSRobert Mustacchi 
798993e3fafSRobert Mustacchi 
799993e3fafSRobert Mustacchi 	mdb_printf("\n");
800993e3fafSRobert Mustacchi 
801993e3fafSRobert Mustacchi 	return (DCMD_OK);
802993e3fafSRobert Mustacchi }
803993e3fafSRobert Mustacchi 
804993e3fafSRobert Mustacchi static int
xhci_mdb_find_trb(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)805993e3fafSRobert Mustacchi xhci_mdb_find_trb(uintptr_t addr, uint_t flags, int argc,
806993e3fafSRobert Mustacchi     const mdb_arg_t *argv)
807993e3fafSRobert Mustacchi {
808993e3fafSRobert Mustacchi 	xhci_ring_t xr;
809993e3fafSRobert Mustacchi 	uint64_t base, max, target;
810993e3fafSRobert Mustacchi 
811993e3fafSRobert Mustacchi 	if (!(flags & DCMD_ADDRSPEC)) {
812993e3fafSRobert Mustacchi 		mdb_warn("missing required xhci_ring_t\n");
813993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
814993e3fafSRobert Mustacchi 	}
815993e3fafSRobert Mustacchi 
816993e3fafSRobert Mustacchi 	if (argc == 0) {
817993e3fafSRobert Mustacchi 		mdb_warn("missing required PA of ring\n");
818993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
819993e3fafSRobert Mustacchi 	}
820993e3fafSRobert Mustacchi 
821993e3fafSRobert Mustacchi 	if (argc > 1) {
822993e3fafSRobert Mustacchi 		mdb_warn("too many arguments\n");
823993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
824993e3fafSRobert Mustacchi 	}
825993e3fafSRobert Mustacchi 
826993e3fafSRobert Mustacchi 	if (mdb_vread(&xr, sizeof (xr), addr) != sizeof (xr)) {
827993e3fafSRobert Mustacchi 		mdb_warn("failed to read xhci_ring_t at %p", addr);
828993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
829993e3fafSRobert Mustacchi 	}
830993e3fafSRobert Mustacchi 
831993e3fafSRobert Mustacchi 	if (argv[0].a_type == MDB_TYPE_IMMEDIATE) {
832993e3fafSRobert Mustacchi 		target = argv[0].a_un.a_val;
833993e3fafSRobert Mustacchi 	} else if (argv[0].a_type == MDB_TYPE_STRING) {
834993e3fafSRobert Mustacchi 		target = mdb_strtoull(argv[0].a_un.a_str);
835993e3fafSRobert Mustacchi 	} else {
836993e3fafSRobert Mustacchi 		mdb_warn("argument is an unknown supported type: %d\n",
837993e3fafSRobert Mustacchi 		    argv[0].a_type);
838993e3fafSRobert Mustacchi 		return (DCMD_USAGE);
839993e3fafSRobert Mustacchi 	}
840993e3fafSRobert Mustacchi 	target = roundup(target, sizeof (xhci_trb_t));
841993e3fafSRobert Mustacchi 
842993e3fafSRobert Mustacchi 	base = xr.xr_dma.xdb_cookies[0].dmac_laddress;
843993e3fafSRobert Mustacchi 	max = base + xr.xr_ntrb * sizeof (xhci_trb_t);
844993e3fafSRobert Mustacchi 
845993e3fafSRobert Mustacchi 	if (target < base || target > max) {
846993e3fafSRobert Mustacchi 		mdb_warn("target address %p is outside the range of PAs for "
847993e3fafSRobert Mustacchi 		    "TRBs in the ring [%p, %p)", target, base, max);
848993e3fafSRobert Mustacchi 		return (DCMD_ERR);
849993e3fafSRobert Mustacchi 	}
850993e3fafSRobert Mustacchi 	target -= base;
851993e3fafSRobert Mustacchi 	mdb_printf("0x%" PRIx64 "\n", target + (uintptr_t)xr.xr_trb);
852993e3fafSRobert Mustacchi 
853993e3fafSRobert Mustacchi 	return (DCMD_OK);
854993e3fafSRobert Mustacchi }
855993e3fafSRobert Mustacchi 
856993e3fafSRobert Mustacchi static const mdb_dcmd_t xhci_dcmds[] = {
857993e3fafSRobert Mustacchi 	{ "xhci_epctx", ":", "print endpoint context",
858993e3fafSRobert Mustacchi 	    xhci_mdb_print_epctx, NULL },
859993e3fafSRobert Mustacchi 	{ "xhci_slotctx", ":", "print slot context",
860993e3fafSRobert Mustacchi 	    xhci_mdb_print_slotctx, NULL },
861993e3fafSRobert Mustacchi 	{ "xhci_trb", ":", "print TRB",
862993e3fafSRobert Mustacchi 	    xhci_mdb_print_trb, NULL },
863993e3fafSRobert Mustacchi 	{ "xhci_find", ": -s slot [-e endpiont]",
864993e3fafSRobert Mustacchi 	    "find given xhci slot or endpoint",
865993e3fafSRobert Mustacchi 	    xhci_mdb_find, NULL },
866993e3fafSRobert Mustacchi 	{ "xhci_device", ":", "device summary",
867993e3fafSRobert Mustacchi 	    xhci_mdb_print_device, NULL },
868993e3fafSRobert Mustacchi 	{ "xhci_find_trb", ": pa", "find trb with PA in ring",
869993e3fafSRobert Mustacchi 	    xhci_mdb_find_trb, NULL },
870993e3fafSRobert Mustacchi 	{ NULL }
871993e3fafSRobert Mustacchi };
872993e3fafSRobert Mustacchi 
873993e3fafSRobert Mustacchi static const mdb_walker_t xhci_walkers[] = {
874993e3fafSRobert Mustacchi 	{ "xhci", "walk list of xhci_t structures",
875993e3fafSRobert Mustacchi 	    xhci_mdb_walk_xhci_init, xhci_mdb_walk_xhci_step, NULL },
876993e3fafSRobert Mustacchi 	{ "xhci_device", "walk list of xhci_device_t structures",
877993e3fafSRobert Mustacchi 	    xhci_mdb_walk_xhci_device_init, xhci_mdb_walk_xhci_device_step,
878993e3fafSRobert Mustacchi 	    NULL },
879993e3fafSRobert Mustacchi 	{ "xhci_endpoint", "walk list of xhci_endpoint_t structures",
880993e3fafSRobert Mustacchi 	    xhci_mdb_walk_xhci_endpoint_init, xhci_mdb_walk_xhci_endpoint_step,
881993e3fafSRobert Mustacchi 	    NULL },
882993e3fafSRobert Mustacchi 	{ NULL }
883993e3fafSRobert Mustacchi };
884993e3fafSRobert Mustacchi 
885993e3fafSRobert Mustacchi static const mdb_modinfo_t xhci_modinfo = {
886993e3fafSRobert Mustacchi 	MDB_API_VERSION, xhci_dcmds, xhci_walkers
887993e3fafSRobert Mustacchi };
888993e3fafSRobert Mustacchi 
889993e3fafSRobert Mustacchi const mdb_modinfo_t *
_mdb_init(void)890993e3fafSRobert Mustacchi _mdb_init(void)
891993e3fafSRobert Mustacchi {
892993e3fafSRobert Mustacchi 	return (&xhci_modinfo);
893993e3fafSRobert Mustacchi }
894