1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2019 Joyent, Inc. 14 */ 15 16 #include <sys/mdb_modapi.h> 17 #include <sys/usb/hcd/xhci/xhci.h> 18 19 #define XHCI_MDB_TRB_INDENT 4 20 21 static const char *xhci_mdb_epctx_eptypes[] = { 22 "Not Valid", 23 "ISOCH OUT", 24 "BULK OUT", 25 "INTR OUT", 26 "CONTROL", 27 "ISOCH IN", 28 "BULK IN", 29 "INTR IN" 30 }; 31 32 static const char *xhci_mdb_epctx_states[] = { 33 "Disabled", 34 "Running", 35 "Halted", 36 "Stopped", 37 "Error", 38 "<Unknown>", 39 "<Unknown>", 40 "<Unknown>" 41 }; 42 43 static const mdb_bitmask_t xhci_mdb_trb_flags[] = { 44 { "C", XHCI_TRB_CYCLE, XHCI_TRB_CYCLE }, 45 { "ENT", XHCI_TRB_ENT, XHCI_TRB_ENT }, 46 { "ISP", XHCI_TRB_ISP, XHCI_TRB_ISP }, 47 { "NS", XHCI_TRB_NOSNOOP, XHCI_TRB_NOSNOOP }, 48 { "CH", XHCI_TRB_CHAIN, XHCI_TRB_CHAIN }, 49 { "IOC", XHCI_TRB_IOC, XHCI_TRB_IOC }, 50 { "IDT", XHCI_TRB_IDT, XHCI_TRB_IDT }, 51 { "BEI", XHCI_TRB_BEI, XHCI_TRB_BEI }, 52 { NULL, 0, 0 } 53 }; 54 55 typedef struct xhci_mdb_walk_endpoint { 56 xhci_device_t xmwe_device; 57 uint_t xmwe_ep; 58 } xhci_mdb_walk_endpoint_t; 59 60 static const char * 61 xhci_mdb_trb_code_to_str(int code) 62 { 63 switch (code) { 64 case XHCI_CODE_INVALID: 65 return ("Invalid"); 66 case XHCI_CODE_SUCCESS: 67 return ("Success"); 68 case XHCI_CODE_DATA_BUF: 69 return ("Data Overrun or Underrun"); 70 case XHCI_CODE_BABBLE: 71 return ("Babble"); 72 case XHCI_CODE_TXERR: 73 return ("Transaction Error"); 74 case XHCI_CODE_TRB: 75 return ("Invalid TRB"); 76 case XHCI_CODE_STALL: 77 return ("Stall"); 78 case XHCI_CODE_RESOURCE: 79 return ("No Resources Available"); 80 case XHCI_CODE_BANDWIDTH: 81 return ("No Bandwidth Available"); 82 case XHCI_CODE_NO_SLOTS: 83 return ("No Slots Available"); 84 case XHCI_CODE_STREAM_TYPE: 85 return ("Stream Context Type Detected"); 86 case XHCI_CODE_SLOT_NOT_ON: 87 return ("Slot disabled"); 88 case XHCI_CODE_ENDP_NOT_ON: 89 return ("Endpoint disabled"); 90 case XHCI_CODE_SHORT_XFER: 91 return ("Short Transfer"); 92 case XHCI_CODE_RING_UNDERRUN: 93 return ("Isoch. Ring Underrun"); 94 case XHCI_CODE_RING_OVERRUN: 95 return ("Isoch. Ring Overrun"); 96 case XHCI_CODE_VF_RING_FULL: 97 return ("VF Ring Full"); 98 case XHCI_CODE_PARAMETER: 99 return ("Invalid Context Parameter"); 100 case XHCI_CODE_BW_OVERRUN: 101 return ("Bandwidth Overrun"); 102 case XHCI_CODE_CONTEXT_STATE: 103 return ("Illegal Context Transition"); 104 case XHCI_CODE_NO_PING_RESP: 105 return ("Failed to Complete Periodic Transfer"); 106 case XHCI_CODE_EV_RING_FULL: 107 return ("Event Ring Full"); 108 case XHCI_CODE_INCOMPAT_DEV: 109 return ("Incompatible Device"); 110 case XHCI_CODE_MISSED_SRV: 111 return ("Missed Isoch. Service Window"); 112 case XHCI_CODE_CMD_RING_STOP: 113 return ("Command Ring Stop"); 114 case XHCI_CODE_CMD_ABORTED: 115 return ("Command Aborted"); 116 case XHCI_CODE_XFER_STOPPED: 117 return ("Transfer Stopped"); 118 case XHCI_CODE_XFER_STOPINV: 119 return ("Invalid Transfer Length"); 120 case XHCI_CODE_XFER_STOPSHORT: 121 return ("Stopped before End of Transfer Descriptor"); 122 case XHCI_CODE_MELAT: 123 return ("Max Exit Latency too large"); 124 case XHCI_CODE_RESERVED: 125 return ("Reserved"); 126 case XHCI_CODE_ISOC_OVERRUN: 127 return ("Isochronus Overrun"); 128 case XHCI_CODE_EVENT_LOST: 129 return ("Event Lost"); 130 case XHCI_CODE_UNDEFINED: 131 return ("Undefined Fatal Error"); 132 case XHCI_CODE_INVALID_SID: 133 return ("Invalid Stream ID"); 134 case XHCI_CODE_SEC_BW: 135 return ("Secondary Bandwith Allocation Failure"); 136 case XHCI_CODE_SPLITERR: 137 return ("USB2 Split Transaction Error"); 138 default: 139 break; 140 } 141 142 if (code >= 192 && code <= 223) 143 return ("Vendor Defined Error"); 144 if (code >= 224 && code <= 255) 145 return ("Vendor Defined Info"); 146 147 return ("Reserved"); 148 } 149 150 static const char * 151 xhci_mdb_trb_type_to_str(int code) 152 { 153 /* 154 * The macros for the types are all already shifted over based on their 155 * place in the TRB, so shift there again ourselves. 156 */ 157 switch (code << 10) { 158 case XHCI_TRB_TYPE_NORMAL: 159 return ("Normal"); 160 case XHCI_TRB_TYPE_SETUP: 161 return ("Setup"); 162 case XHCI_TRB_TYPE_DATA: 163 return ("Data"); 164 case XHCI_TRB_TYPE_STATUS: 165 return ("Status"); 166 case XHCI_TRB_TYPE_LINK: 167 return ("Link"); 168 case XHCI_TRB_TYPE_EVENT: 169 return ("Event"); 170 case XHCI_TRB_TYPE_NOOP: 171 return ("No-Op"); 172 case XHCI_CMD_ENABLE_SLOT: 173 return ("Enable Slot"); 174 case XHCI_CMD_DISABLE_SLOT: 175 return ("Disable Slot"); 176 case XHCI_CMD_ADDRESS_DEVICE: 177 return ("Address Device"); 178 case XHCI_CMD_CONFIG_EP: 179 return ("Configure Endpoint"); 180 case XHCI_CMD_EVAL_CTX: 181 return ("Evaluate Context"); 182 case XHCI_CMD_RESET_EP: 183 return ("Reset Endpoint"); 184 case XHCI_CMD_STOP_EP: 185 return ("Stop Endpoint"); 186 case XHCI_CMD_SET_TR_DEQ: 187 return ("Set Transfer Ring Dequeue Pointer"); 188 case XHCI_CMD_RESET_DEV: 189 return ("Reset Device"); 190 case XHCI_CMD_FEVENT: 191 return ("Force Event"); 192 case XHCI_CMD_NEG_BW: 193 return ("Negotiate Bandwidth"); 194 case XHCI_CMD_SET_LT: 195 return ("Set Latency Tolerance"); 196 case XHCI_CMD_GET_BW: 197 return ("Get Bandwidth"); 198 case XHCI_CMD_FHEADER: 199 return ("Force Header"); 200 case XHCI_CMD_NOOP: 201 return ("No-Op Command"); 202 case XHCI_EVT_XFER: 203 return ("Transfer Event"); 204 case XHCI_EVT_CMD_COMPLETE: 205 return ("Command Completion Event"); 206 case XHCI_EVT_PORT_CHANGE: 207 return ("Port Status Change Event"); 208 case XHCI_EVT_BW_REQUEST: 209 return ("Bandwidth Request Event"); 210 case XHCI_EVT_DOORBELL: 211 return ("Doorbell Event"); 212 case XHCI_EVT_HOST_CTRL: 213 return ("Host Controller Event"); 214 case XHCI_EVT_DEVICE_NOTIFY: 215 return ("Device Notification Event"); 216 case XHCI_EVT_MFINDEX_WRAP: 217 return ("MFINDEX Wrap Event"); 218 default: 219 break; 220 } 221 222 if (code >= 43 && code <= 63) 223 return ("Vendor Defiend"); 224 return ("Reserved"); 225 } 226 227 /* ARGSUSED */ 228 static int 229 xhci_mdb_print_epctx(uintptr_t addr, uint_t flags, int argc, 230 const mdb_arg_t *argv) 231 { 232 uint32_t info, info2, txinfo; 233 xhci_endpoint_context_t epctx; 234 235 if (!(flags & DCMD_ADDRSPEC)) { 236 mdb_warn("::xhci_epctx requires an address\n"); 237 return (DCMD_USAGE); 238 } 239 240 if (mdb_vread(&epctx, sizeof (epctx), addr) != sizeof (epctx)) { 241 mdb_warn("failed to read xhci_endpoint_context_t at %p", addr); 242 return (DCMD_ERR); 243 } 244 245 info = LE_32(epctx.xec_info); 246 info2 = LE_32(epctx.xec_info2); 247 txinfo = LE_32(epctx.xec_txinfo); 248 249 mdb_printf("Endpoint State: %s (%d)\n", 250 xhci_mdb_epctx_states[XHCI_EPCTX_STATE(info)], 251 XHCI_EPCTX_STATE(info)); 252 253 mdb_printf("Mult: %d\n", XHCI_EPCTX_GET_MULT(info)); 254 mdb_printf("Max Streams: %d\n", XHCI_EPCTX_GET_MAXP_STREAMS(info)); 255 mdb_printf("LSA: %d\n", XHCI_EPCTX_GET_LSA(info)); 256 mdb_printf("Interval: %d\n", XHCI_EPCTX_GET_IVAL(info)); 257 mdb_printf("Max ESIT Hi: %d\n", XHCI_EPCTX_GET_MAX_ESIT_HI(info)); 258 259 mdb_printf("CErr: %d\n", XHCI_EPCTX_GET_CERR(info2)); 260 mdb_printf("EP Type: %s (%d)\n", 261 xhci_mdb_epctx_eptypes[XHCI_EPCTX_GET_EPTYPE(info2)], 262 XHCI_EPCTX_GET_EPTYPE(info2)); 263 mdb_printf("Host Initiate Disable: %d\n", XHCI_EPCTX_GET_HID(info2)); 264 mdb_printf("Max Burst: %d\n", XHCI_EPCTX_GET_MAXB(info2)); 265 mdb_printf("Max Packet Size: %d\n", XHCI_EPCTX_GET_MPS(info2)); 266 267 mdb_printf("Ring DCS: %d\n", LE_64(epctx.xec_dequeue) & 0x1); 268 mdb_printf("Ring PA: 0x%lx\n", LE_64(epctx.xec_dequeue) & ~0xf); 269 270 mdb_printf("Average TRB Length: %d\n", XHCI_EPCTX_AVG_TRB_LEN(txinfo)); 271 mdb_printf("Max ESIT: %d\n", XHCI_EPCTX_GET_MAX_ESIT_PAYLOAD(txinfo)); 272 273 return (DCMD_OK); 274 } 275 276 /* ARGSUSED */ 277 static int 278 xhci_mdb_print_slotctx(uintptr_t addr, uint_t flags, int argc, 279 const mdb_arg_t *argv) 280 { 281 uint32_t info, info2, tt, state; 282 xhci_slot_context_t sctx; 283 284 if (!(flags & DCMD_ADDRSPEC)) { 285 mdb_warn("::xhci_slotctx requires an address\n"); 286 return (DCMD_USAGE); 287 } 288 289 if (mdb_vread(&sctx, sizeof (sctx), addr) != sizeof (sctx)) { 290 mdb_warn("failed to read xhci_slot_context_t at %p", addr); 291 return (DCMD_ERR); 292 } 293 294 info = LE_32(sctx.xsc_info); 295 info2 = LE_32(sctx.xsc_info2); 296 tt = LE_32(sctx.xsc_tt); 297 state = LE_32(sctx.xsc_state); 298 299 mdb_printf("Route: 0x%x\n", XHCI_SCTX_GET_ROUTE(info)); 300 301 mdb_printf("Slot Speed: "); 302 switch (XHCI_SCTX_GET_SPEED(info)) { 303 case XHCI_SPEED_FULL: 304 mdb_printf("Full"); 305 break; 306 case XHCI_SPEED_LOW: 307 mdb_printf("Low"); 308 break; 309 case XHCI_SPEED_HIGH: 310 mdb_printf("High"); 311 break; 312 case XHCI_SPEED_SUPER: 313 mdb_printf("Super"); 314 break; 315 default: 316 mdb_printf("Unknown"); 317 break; 318 } 319 mdb_printf(" (%d)\n", XHCI_SCTX_GET_SPEED(info)); 320 321 322 mdb_printf("MTT: %d\n", XHCI_SCTX_GET_MTT(info)); 323 mdb_printf("HUB: %d\n", XHCI_SCTX_GET_HUB(info)); 324 mdb_printf("DCI: %d\n", XHCI_SCTX_GET_DCI(info)); 325 326 mdb_printf("Max Exit Latency: %d\n", XHCI_SCTX_GET_MAX_EL(info2)); 327 mdb_printf("Root Hub Port: %d\n", XHCI_SCTX_GET_RHPORT(info2)); 328 mdb_printf("Hub Number of Ports: %d\n", XHCI_SCTX_GET_NPORTS(info2)); 329 330 mdb_printf("TT Hub Slot id: %d\n", XHCI_SCTX_GET_TT_HUB_SID(tt)); 331 mdb_printf("TT Port Number: %d\n", XHCI_SCTX_GET_TT_PORT_NUM(tt)); 332 mdb_printf("TT Think Time: %d\n", XHCI_SCTX_GET_TT_THINK_TIME(tt)); 333 mdb_printf("IRQ Target: %d\n", XHCI_SCTX_GET_IRQ_TARGET(tt)); 334 335 mdb_printf("Device Address: 0x%x\n", XHCI_SCTX_GET_DEV_ADDR(state)); 336 mdb_printf("Slot State: "); 337 switch (XHCI_SCTX_GET_SLOT_STATE(state)) { 338 case XHCI_SLOT_DIS_ENAB: 339 mdb_printf("Disabled/Enabled"); 340 break; 341 case XHCI_SLOT_DEFAULT: 342 mdb_printf("Default"); 343 break; 344 case XHCI_SLOT_ADDRESSED: 345 mdb_printf("Addressed"); 346 break; 347 case XHCI_SLOT_CONFIGURED: 348 mdb_printf("Configured"); 349 break; 350 default: 351 mdb_printf("Unknown"); 352 break; 353 } 354 mdb_printf(" (%d)\n", XHCI_SCTX_GET_SLOT_STATE(state)); 355 356 return (DCMD_OK); 357 } 358 359 static int 360 xhci_mdb_print_transfer_event(uint64_t pa, uint32_t status, uint32_t flags) 361 { 362 mdb_printf("TRB Address: 0x%lx\n", pa); 363 mdb_printf("Transfer Length (Remain): %d\n", XHCI_TRB_REMAIN(status)); 364 mdb_printf("Completion Code: %s (%d)\n", 365 xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)), 366 XHCI_TRB_GET_CODE(status)); 367 368 mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags)); 369 mdb_printf("Event Data: %d\n", XHCI_TRB_GET_ED(flags)); 370 mdb_printf("Endpoint ID: %d\n", XHCI_TRB_GET_EP(flags)); 371 mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags)); 372 mdb_dec_indent(XHCI_MDB_TRB_INDENT); 373 374 return (DCMD_OK); 375 } 376 377 static int 378 xhci_mdb_print_command_event(uint64_t pa, uint32_t status, uint32_t flags) 379 { 380 mdb_printf("TRB Address: 0x%lx\n", pa); 381 mdb_printf("Command Param: 0x%x\n", XHCI_TRB_REMAIN(status)); 382 mdb_printf("Completion Code: %s (%d)\n", 383 xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)), 384 XHCI_TRB_GET_CODE(status)); 385 386 mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags)); 387 /* Skip VF ID as we don't support VFs */ 388 mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags)); 389 mdb_dec_indent(XHCI_MDB_TRB_INDENT); 390 391 return (DCMD_OK); 392 } 393 394 /* ARGSUSED */ 395 static int 396 xhci_mdb_print_psc(uint64_t pa, uint32_t status, uint32_t flags) 397 { 398 mdb_printf("Port: %d\n", XHCI_TRB_PORTID(pa)); 399 mdb_printf("Completion Code: %s (%d)\n", 400 xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)), 401 XHCI_TRB_GET_CODE(status)); 402 mdb_dec_indent(XHCI_MDB_TRB_INDENT); 403 return (DCMD_OK); 404 } 405 406 static int 407 xhci_mdb_print_normal_trb(uint64_t pa, uint32_t status, uint32_t flags) 408 { 409 mdb_printf("TRB Address: 0x%lx\n", pa); 410 mdb_printf("TRB Length: %d bytes\n", XHCI_TRB_LEN(status)); 411 mdb_printf("TRB TD Size: %d packets\n", XHCI_TRB_GET_TDREM(status)); 412 mdb_printf("TRB Interrupt: %d\n", XHCI_TRB_GET_INTR(status)); 413 mdb_printf("TRB Flags: %b (0x%x)\n", flags, xhci_mdb_trb_flags, 414 XHCI_TRB_GET_FLAGS(flags)); 415 mdb_dec_indent(XHCI_MDB_TRB_INDENT); 416 417 return (DCMD_OK); 418 } 419 420 /* ARGSUSED */ 421 static int 422 xhci_mdb_print_trb(uintptr_t addr, uint_t flags, int argc, 423 const mdb_arg_t *argv) 424 { 425 xhci_trb_t trb; 426 uint64_t pa; 427 uint32_t status, trbflags, type; 428 429 if (!(flags & DCMD_ADDRSPEC)) { 430 mdb_warn("::xhci_trb expects an address\n"); 431 return (DCMD_USAGE); 432 } 433 434 if (mdb_vread(&trb, sizeof (trb), addr) != sizeof (trb)) { 435 mdb_warn("failed to read xhci_trb_t at 0x%x", addr); 436 return (DCMD_ERR); 437 } 438 439 pa = LE_64(trb.trb_addr); 440 status = LE_32(trb.trb_status); 441 trbflags = LE_32(trb.trb_flags); 442 443 type = XHCI_TRB_GET_TYPE(trbflags); 444 445 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 446 mdb_printf("\n"); 447 448 mdb_set_dot(addr + sizeof (xhci_trb_t)); 449 mdb_printf("%s TRB (%d)\n", xhci_mdb_trb_type_to_str(type), type); 450 mdb_inc_indent(XHCI_MDB_TRB_INDENT); 451 452 switch (XHCI_RING_TYPE_SHIFT(type)) { 453 case XHCI_EVT_XFER: 454 return (xhci_mdb_print_transfer_event(pa, status, trbflags)); 455 case XHCI_EVT_CMD_COMPLETE: 456 return (xhci_mdb_print_command_event(pa, status, trbflags)); 457 case XHCI_EVT_PORT_CHANGE: 458 return (xhci_mdb_print_psc(pa, status, trbflags)); 459 case XHCI_TRB_TYPE_NORMAL: 460 return (xhci_mdb_print_normal_trb(pa, status, trbflags)); 461 } 462 463 /* 464 * Just print generic information if we don't have a specific printer 465 * for that TRB type. 466 */ 467 mdb_printf("TRB Address: 0x%lx\n", pa); 468 mdb_printf("TRB Status: 0x%x\n", status); 469 mdb_printf("TRB Flags: 0x%x\n", trbflags); 470 mdb_dec_indent(XHCI_MDB_TRB_INDENT); 471 472 return (DCMD_OK); 473 } 474 475 static int 476 xhci_mdb_walk_xhci_init(mdb_walk_state_t *wsp) 477 { 478 GElf_Sym sym; 479 uintptr_t addr; 480 481 if (wsp->walk_addr != 0) { 482 mdb_warn("::walk xhci only supports global walks\n"); 483 return (WALK_ERR); 484 } 485 486 if (mdb_lookup_by_obj("xhci", "xhci_soft_state", &sym) != 0) { 487 mdb_warn("failed to find xhci_soft_state symbol"); 488 return (WALK_ERR); 489 } 490 491 if (mdb_vread(&addr, sizeof (addr), sym.st_value) != sizeof (addr)) { 492 mdb_warn("failed to read xhci_soft_state at %p", addr); 493 return (WALK_ERR); 494 } 495 496 wsp->walk_addr = addr; 497 if (mdb_layered_walk("softstate", wsp) != 0) { 498 mdb_warn("failed to walk softstate"); 499 return (WALK_ERR); 500 } 501 502 return (WALK_NEXT); 503 } 504 505 static int 506 xhci_mdb_walk_xhci_step(mdb_walk_state_t *wsp) 507 { 508 xhci_t xhci; 509 510 if (mdb_vread(&xhci, sizeof (xhci), wsp->walk_addr) != sizeof (xhci)) { 511 mdb_warn("failed to read xhci_t at %p", wsp->walk_addr); 512 return (WALK_ERR); 513 } 514 515 return (wsp->walk_callback(wsp->walk_addr, &xhci, wsp->walk_cbdata)); 516 } 517 518 static int 519 xhci_mdb_walk_xhci_device_init(mdb_walk_state_t *wsp) 520 { 521 uintptr_t addr; 522 523 if (wsp->walk_addr == 0) { 524 mdb_warn("::walk xhci_device requires an xhci_t\n"); 525 return (WALK_ERR); 526 } 527 528 addr = wsp->walk_addr; 529 addr += offsetof(xhci_t, xhci_usba); 530 addr += offsetof(xhci_usba_t, xa_devices); 531 wsp->walk_addr = (uintptr_t)addr; 532 if (mdb_layered_walk("list", wsp) != 0) { 533 mdb_warn("failed to walk list"); 534 return (WALK_ERR); 535 } 536 537 return (WALK_NEXT); 538 } 539 540 static int 541 xhci_mdb_walk_xhci_device_step(mdb_walk_state_t *wsp) 542 { 543 xhci_device_t xd; 544 545 if (mdb_vread(&xd, sizeof (xd), wsp->walk_addr) != sizeof (xd)) { 546 mdb_warn("failed to read xhci_device_t at %p", wsp->walk_addr); 547 return (WALK_ERR); 548 } 549 550 return (wsp->walk_callback(wsp->walk_addr, &xd, wsp->walk_cbdata)); 551 } 552 553 static int 554 xhci_mdb_walk_xhci_endpoint_init(mdb_walk_state_t *wsp) 555 { 556 xhci_mdb_walk_endpoint_t *xm; 557 xhci_device_t *xd; 558 559 if (wsp->walk_addr == 0) { 560 mdb_warn("::walk xhci_endpoint requires an xhci_device_t\n"); 561 return (WALK_ERR); 562 } 563 564 xm = mdb_alloc(sizeof (xhci_mdb_walk_endpoint_t), UM_SLEEP | UM_GC); 565 xm->xmwe_ep = 0; 566 xd = &xm->xmwe_device; 567 if (mdb_vread(xd, sizeof (*xd), wsp->walk_addr) != sizeof (*xd)) { 568 mdb_warn("failed to read xhci_endpoint_t at %p", 569 wsp->walk_addr); 570 return (WALK_ERR); 571 } 572 wsp->walk_data = xm; 573 574 return (WALK_NEXT); 575 } 576 577 static int 578 xhci_mdb_walk_xhci_endpoint_step(mdb_walk_state_t *wsp) 579 { 580 int ret; 581 uintptr_t addr; 582 xhci_mdb_walk_endpoint_t *xm = wsp->walk_data; 583 584 if (xm->xmwe_ep >= XHCI_NUM_ENDPOINTS) 585 return (WALK_DONE); 586 587 addr = (uintptr_t)xm->xmwe_device.xd_endpoints[xm->xmwe_ep]; 588 if (addr != 0) { 589 xhci_endpoint_t xe; 590 591 if (mdb_vread(&xe, sizeof (xe), addr) != sizeof (xe)) { 592 mdb_warn("failed to read xhci_endpoint_t at %p", 593 xm->xmwe_device.xd_endpoints[xm->xmwe_ep]); 594 return (WALK_ERR); 595 } 596 597 ret = wsp->walk_callback(addr, &xe, wsp->walk_cbdata); 598 } else { 599 ret = WALK_NEXT; 600 } 601 xm->xmwe_ep++; 602 603 return (ret); 604 } 605 606 typedef struct xhci_mdb_find { 607 int xmf_slot; 608 int xmf_ep; 609 uintptr_t xmf_addr; 610 } xhci_mdb_find_t; 611 612 static int 613 xhci_mdb_find_endpoint_cb(uintptr_t addr, const void *data, void *arg) 614 { 615 const xhci_endpoint_t *xep = data; 616 xhci_mdb_find_t *xmf = arg; 617 618 /* 619 * The endpoints that are presented here are off by one from the actual 620 * endpoint ID in the xhci_endpoint_t, as we're really displaying the 621 * index into the device input context. 622 */ 623 if (xep->xep_num + 1 == xmf->xmf_ep) { 624 xmf->xmf_addr = addr; 625 return (WALK_DONE); 626 } 627 628 return (WALK_NEXT); 629 } 630 631 static int 632 xhci_mdb_find_device_cb(uintptr_t addr, const void *data, void *arg) 633 { 634 const xhci_device_t *xd = data; 635 xhci_mdb_find_t *xmf = arg; 636 637 if (xd->xd_slot == xmf->xmf_slot) { 638 if (xmf->xmf_ep == -1) { 639 xmf->xmf_addr = addr; 640 return (WALK_DONE); 641 } 642 643 if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_find_endpoint_cb, 644 xmf, addr) == -1) { 645 mdb_warn("failed to walk xhci_endpoint at %p", addr); 646 return (WALK_ERR); 647 } 648 649 return (WALK_DONE); 650 } 651 652 return (WALK_NEXT); 653 } 654 655 static int 656 xhci_mdb_find(uintptr_t addr, uint_t flags, int argc, 657 const mdb_arg_t *argv) 658 { 659 uintptr_t ep, slot; 660 boolean_t ep_set, slot_set; 661 xhci_mdb_find_t xmf; 662 663 if ((flags & DCMD_ADDRSPEC) == 0) 664 return (DCMD_USAGE); 665 666 ep_set = slot_set = B_FALSE; 667 if (mdb_getopts(argc, argv, 'e', MDB_OPT_UINTPTR_SET, &ep_set, &ep, 668 's', MDB_OPT_UINTPTR_SET, &slot_set, &slot, NULL) != argc) 669 return (DCMD_USAGE); 670 671 if (!slot_set) { 672 mdb_warn("-s is required\n"); 673 return (DCMD_USAGE); 674 } 675 676 xmf.xmf_slot = (int)slot; 677 if (ep_set) 678 xmf.xmf_ep = (int)ep; 679 else 680 xmf.xmf_ep = -1; 681 xmf.xmf_addr = 0; 682 683 if (mdb_pwalk("xhci`xhci_device", xhci_mdb_find_device_cb, 684 &xmf, addr) == -1) { 685 mdb_warn("failed to walk xhci_device at %p", addr); 686 return (DCMD_ERR); 687 } 688 689 if (xmf.xmf_addr == 0) { 690 if (ep_set) { 691 mdb_warn("failed to find xhci_endpoint_t for slot %d " 692 "and endpoint %d\n", slot, ep); 693 } else { 694 mdb_warn("failed to find xhci_device_t for slot %d\n", 695 slot); 696 } 697 return (DCMD_ERR); 698 } 699 700 mdb_printf("%p\n", xmf.xmf_addr); 701 return (DCMD_OK); 702 } 703 704 /* ARGSUSED */ 705 static int 706 xhci_mdb_endpoint_count(uintptr_t addr, const void *ep, void *arg) 707 { 708 int *countp = arg; 709 710 *countp += 1; 711 return (WALK_NEXT); 712 } 713 714 /* ARGSUSED */ 715 static int 716 xhci_mdb_print_endpoint_summary(uintptr_t addr, const void *ep, void *arg) 717 { 718 const xhci_device_t *xd = arg; 719 const xhci_endpoint_t *xep = ep; 720 const char *type; 721 const char *state; 722 xhci_endpoint_context_t epctx; 723 int eptype; 724 725 if (mdb_vread(&epctx, sizeof (epctx), 726 (uintptr_t)xd->xd_endout[xep->xep_num]) != sizeof (epctx)) { 727 mdb_warn("failed to read endpoint context at %p", 728 xd->xd_endout[xep->xep_num]); 729 return (WALK_ERR); 730 } 731 732 eptype = XHCI_EPCTX_GET_EPTYPE(LE_32(epctx.xec_info2)); 733 type = xhci_mdb_epctx_eptypes[eptype]; 734 state = xhci_mdb_epctx_states[XHCI_EPCTX_STATE(LE_32(epctx.xec_info))]; 735 736 mdb_printf("%-4d %-10s %-10s 0x%-04x 0x%-04x\n", xep->xep_num, type, 737 state, xep->xep_ring.xr_head, xep->xep_ring.xr_tail); 738 739 return (WALK_NEXT); 740 } 741 742 /* ARGSUSED */ 743 static int 744 xhci_mdb_print_device(uintptr_t addr, uint_t flags, int argc, 745 const mdb_arg_t *argv) 746 { 747 int count; 748 xhci_device_t xd; 749 usba_device_t ud; 750 char product[256], mfg[256]; 751 752 if (!(flags & DCMD_ADDRSPEC)) { 753 return (mdb_eval("::walk xhci`xhci | ::walk xhci`xhci_device | " 754 "::xhci_device")); 755 } 756 757 if (mdb_vread(&xd, sizeof (xd), addr) != sizeof (xd)) { 758 mdb_warn("failed to read xhci_device_t at 0x%x", addr); 759 return (DCMD_ERR); 760 } 761 762 if (mdb_vread(&ud, sizeof (ud), (uintptr_t)xd.xd_usbdev) != 763 sizeof (ud)) { 764 mdb_warn("failed to read usba_device_t at %p\n", xd.xd_usbdev); 765 return (DCMD_ERR); 766 } 767 768 if (ud.usb_mfg_str == NULL || mdb_readstr(mfg, sizeof (mfg), 769 (uintptr_t)ud.usb_mfg_str) <= 0) { 770 (void) strlcpy(mfg, "Unknown Manufacturer", sizeof (mfg)); 771 } 772 773 if (ud.usb_product_str == NULL || mdb_readstr(product, sizeof (product), 774 (uintptr_t)ud.usb_product_str) <= 0) { 775 (void) strlcpy(product, "Unknown Product", sizeof (product)); 776 } 777 778 mdb_printf("%<b>%s - %s%</b>\n", mfg, product); 779 780 count = 0; 781 if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_endpoint_count, &count, 782 addr) == -1) { 783 mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr); 784 return (DCMD_ERR); 785 } 786 787 mdb_printf("Port %02d | Slot %02d | # Endpoints %02d\n", xd.xd_port, 788 xd.xd_slot, count); 789 mdb_printf("%<u>%-4s %-10s %-10s %-6s %-6s%</u>\n", "EP", "Type", 790 "State", "Head", "Tail"); 791 792 if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_print_endpoint_summary, 793 &xd, addr) == -1) { 794 mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr); 795 return (DCMD_ERR); 796 } 797 798 799 mdb_printf("\n"); 800 801 return (DCMD_OK); 802 } 803 804 static int 805 xhci_mdb_find_trb(uintptr_t addr, uint_t flags, int argc, 806 const mdb_arg_t *argv) 807 { 808 xhci_ring_t xr; 809 uint64_t base, max, target; 810 811 if (!(flags & DCMD_ADDRSPEC)) { 812 mdb_warn("missing required xhci_ring_t\n"); 813 return (DCMD_USAGE); 814 } 815 816 if (argc == 0) { 817 mdb_warn("missing required PA of ring\n"); 818 return (DCMD_USAGE); 819 } 820 821 if (argc > 1) { 822 mdb_warn("too many arguments\n"); 823 return (DCMD_USAGE); 824 } 825 826 if (mdb_vread(&xr, sizeof (xr), addr) != sizeof (xr)) { 827 mdb_warn("failed to read xhci_ring_t at %p", addr); 828 return (DCMD_USAGE); 829 } 830 831 if (argv[0].a_type == MDB_TYPE_IMMEDIATE) { 832 target = argv[0].a_un.a_val; 833 } else if (argv[0].a_type == MDB_TYPE_STRING) { 834 target = mdb_strtoull(argv[0].a_un.a_str); 835 } else { 836 mdb_warn("argument is an unknown supported type: %d\n", 837 argv[0].a_type); 838 return (DCMD_USAGE); 839 } 840 target = roundup(target, sizeof (xhci_trb_t)); 841 842 base = xr.xr_dma.xdb_cookies[0].dmac_laddress; 843 max = base + xr.xr_ntrb * sizeof (xhci_trb_t); 844 845 if (target < base || target > max) { 846 mdb_warn("target address %p is outside the range of PAs for " 847 "TRBs in the ring [%p, %p)", target, base, max); 848 return (DCMD_ERR); 849 } 850 target -= base; 851 mdb_printf("0x%" PRIx64 "\n", target + (uintptr_t)xr.xr_trb); 852 853 return (DCMD_OK); 854 } 855 856 static const mdb_dcmd_t xhci_dcmds[] = { 857 { "xhci_epctx", ":", "print endpoint context", 858 xhci_mdb_print_epctx, NULL }, 859 { "xhci_slotctx", ":", "print slot context", 860 xhci_mdb_print_slotctx, NULL }, 861 { "xhci_trb", ":", "print TRB", 862 xhci_mdb_print_trb, NULL }, 863 { "xhci_find", ": -s slot [-e endpiont]", 864 "find given xhci slot or endpoint", 865 xhci_mdb_find, NULL }, 866 { "xhci_device", ":", "device summary", 867 xhci_mdb_print_device, NULL }, 868 { "xhci_find_trb", ": pa", "find trb with PA in ring", 869 xhci_mdb_find_trb, NULL }, 870 { NULL } 871 }; 872 873 static const mdb_walker_t xhci_walkers[] = { 874 { "xhci", "walk list of xhci_t structures", 875 xhci_mdb_walk_xhci_init, xhci_mdb_walk_xhci_step, NULL }, 876 { "xhci_device", "walk list of xhci_device_t structures", 877 xhci_mdb_walk_xhci_device_init, xhci_mdb_walk_xhci_device_step, 878 NULL }, 879 { "xhci_endpoint", "walk list of xhci_endpoint_t structures", 880 xhci_mdb_walk_xhci_endpoint_init, xhci_mdb_walk_xhci_endpoint_step, 881 NULL }, 882 { NULL } 883 }; 884 885 static const mdb_modinfo_t xhci_modinfo = { 886 MDB_API_VERSION, xhci_dcmds, xhci_walkers 887 }; 888 889 const mdb_modinfo_t * 890 _mdb_init(void) 891 { 892 return (&xhci_modinfo); 893 } 894