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