1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Cadence CDNSP DRD Driver. 4 * 5 * Copyright (C) 2020 Cadence. 6 * 7 * Author: Pawel Laszczak <pawell@cadence.com> 8 * 9 */ 10 #ifndef __LINUX_CDNSP_DEBUG 11 #define __LINUX_CDNSP_DEBUG 12 13 static inline const char *cdnsp_trb_comp_code_string(u8 status) 14 { 15 switch (status) { 16 case COMP_INVALID: 17 return "Invalid"; 18 case COMP_SUCCESS: 19 return "Success"; 20 case COMP_DATA_BUFFER_ERROR: 21 return "Data Buffer Error"; 22 case COMP_BABBLE_DETECTED_ERROR: 23 return "Babble Detected"; 24 case COMP_TRB_ERROR: 25 return "TRB Error"; 26 case COMP_RESOURCE_ERROR: 27 return "Resource Error"; 28 case COMP_NO_SLOTS_AVAILABLE_ERROR: 29 return "No Slots Available Error"; 30 case COMP_INVALID_STREAM_TYPE_ERROR: 31 return "Invalid Stream Type Error"; 32 case COMP_SLOT_NOT_ENABLED_ERROR: 33 return "Slot Not Enabled Error"; 34 case COMP_ENDPOINT_NOT_ENABLED_ERROR: 35 return "Endpoint Not Enabled Error"; 36 case COMP_SHORT_PACKET: 37 return "Short Packet"; 38 case COMP_RING_UNDERRUN: 39 return "Ring Underrun"; 40 case COMP_RING_OVERRUN: 41 return "Ring Overrun"; 42 case COMP_VF_EVENT_RING_FULL_ERROR: 43 return "VF Event Ring Full Error"; 44 case COMP_PARAMETER_ERROR: 45 return "Parameter Error"; 46 case COMP_CONTEXT_STATE_ERROR: 47 return "Context State Error"; 48 case COMP_EVENT_RING_FULL_ERROR: 49 return "Event Ring Full Error"; 50 case COMP_INCOMPATIBLE_DEVICE_ERROR: 51 return "Incompatible Device Error"; 52 case COMP_MISSED_SERVICE_ERROR: 53 return "Missed Service Error"; 54 case COMP_COMMAND_RING_STOPPED: 55 return "Command Ring Stopped"; 56 case COMP_COMMAND_ABORTED: 57 return "Command Aborted"; 58 case COMP_STOPPED: 59 return "Stopped"; 60 case COMP_STOPPED_LENGTH_INVALID: 61 return "Stopped - Length Invalid"; 62 case COMP_STOPPED_SHORT_PACKET: 63 return "Stopped - Short Packet"; 64 case COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR: 65 return "Max Exit Latency Too Large Error"; 66 case COMP_ISOCH_BUFFER_OVERRUN: 67 return "Isoch Buffer Overrun"; 68 case COMP_EVENT_LOST_ERROR: 69 return "Event Lost Error"; 70 case COMP_UNDEFINED_ERROR: 71 return "Undefined Error"; 72 case COMP_INVALID_STREAM_ID_ERROR: 73 return "Invalid Stream ID Error"; 74 default: 75 return "Unknown!!"; 76 } 77 } 78 79 static inline const char *cdnsp_trb_type_string(u8 type) 80 { 81 switch (type) { 82 case TRB_NORMAL: 83 return "Normal"; 84 case TRB_SETUP: 85 return "Setup Stage"; 86 case TRB_DATA: 87 return "Data Stage"; 88 case TRB_STATUS: 89 return "Status Stage"; 90 case TRB_ISOC: 91 return "Isoch"; 92 case TRB_LINK: 93 return "Link"; 94 case TRB_EVENT_DATA: 95 return "Event Data"; 96 case TRB_TR_NOOP: 97 return "No-Op"; 98 case TRB_ENABLE_SLOT: 99 return "Enable Slot Command"; 100 case TRB_DISABLE_SLOT: 101 return "Disable Slot Command"; 102 case TRB_ADDR_DEV: 103 return "Address Device Command"; 104 case TRB_CONFIG_EP: 105 return "Configure Endpoint Command"; 106 case TRB_EVAL_CONTEXT: 107 return "Evaluate Context Command"; 108 case TRB_RESET_EP: 109 return "Reset Endpoint Command"; 110 case TRB_STOP_RING: 111 return "Stop Ring Command"; 112 case TRB_SET_DEQ: 113 return "Set TR Dequeue Pointer Command"; 114 case TRB_RESET_DEV: 115 return "Reset Device Command"; 116 case TRB_FORCE_HEADER: 117 return "Force Header Command"; 118 case TRB_CMD_NOOP: 119 return "No-Op Command"; 120 case TRB_TRANSFER: 121 return "Transfer Event"; 122 case TRB_COMPLETION: 123 return "Command Completion Event"; 124 case TRB_PORT_STATUS: 125 return "Port Status Change Event"; 126 case TRB_HC_EVENT: 127 return "Device Controller Event"; 128 case TRB_MFINDEX_WRAP: 129 return "MFINDEX Wrap Event"; 130 case TRB_ENDPOINT_NRDY: 131 return "Endpoint Not ready"; 132 case TRB_HALT_ENDPOINT: 133 return "Halt Endpoint"; 134 default: 135 return "UNKNOWN"; 136 } 137 } 138 139 static inline const char *cdnsp_ring_type_string(enum cdnsp_ring_type type) 140 { 141 switch (type) { 142 case TYPE_CTRL: 143 return "CTRL"; 144 case TYPE_ISOC: 145 return "ISOC"; 146 case TYPE_BULK: 147 return "BULK"; 148 case TYPE_INTR: 149 return "INTR"; 150 case TYPE_STREAM: 151 return "STREAM"; 152 case TYPE_COMMAND: 153 return "CMD"; 154 case TYPE_EVENT: 155 return "EVENT"; 156 } 157 158 return "UNKNOWN"; 159 } 160 161 static inline char *cdnsp_slot_state_string(u32 state) 162 { 163 switch (state) { 164 case SLOT_STATE_ENABLED: 165 return "enabled/disabled"; 166 case SLOT_STATE_DEFAULT: 167 return "default"; 168 case SLOT_STATE_ADDRESSED: 169 return "addressed"; 170 case SLOT_STATE_CONFIGURED: 171 return "configured"; 172 default: 173 return "reserved"; 174 } 175 } 176 177 static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0, 178 u32 field1, u32 field2, u32 field3) 179 { 180 int ep_id = TRB_TO_EP_INDEX(field3) - 1; 181 int type = TRB_FIELD_TO_TYPE(field3); 182 unsigned int ep_num; 183 int ret; 184 u32 temp; 185 186 ep_num = DIV_ROUND_UP(ep_id, 2); 187 188 switch (type) { 189 case TRB_LINK: 190 ret = scnprintf(str, size, 191 "LINK %08x%08x intr %ld type '%s' flags %c:%c:%c:%c", 192 field1, field0, GET_INTR_TARGET(field2), 193 cdnsp_trb_type_string(type), 194 field3 & TRB_IOC ? 'I' : 'i', 195 field3 & TRB_CHAIN ? 'C' : 'c', 196 field3 & TRB_TC ? 'T' : 't', 197 field3 & TRB_CYCLE ? 'C' : 'c'); 198 break; 199 case TRB_TRANSFER: 200 case TRB_COMPLETION: 201 case TRB_PORT_STATUS: 202 case TRB_HC_EVENT: 203 ret = scnprintf(str, size, 204 "ep%d%s(%d) type '%s' TRB %08x%08x status '%s'" 205 " len %ld slot %ld flags %c:%c", 206 ep_num, ep_id % 2 ? "out" : "in", 207 TRB_TO_EP_INDEX(field3), 208 cdnsp_trb_type_string(type), field1, field0, 209 cdnsp_trb_comp_code_string(GET_COMP_CODE(field2)), 210 EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), 211 field3 & EVENT_DATA ? 'E' : 'e', 212 field3 & TRB_CYCLE ? 'C' : 'c'); 213 break; 214 case TRB_MFINDEX_WRAP: 215 ret = scnprintf(str, size, "%s: flags %c", 216 cdnsp_trb_type_string(type), 217 field3 & TRB_CYCLE ? 'C' : 'c'); 218 break; 219 case TRB_SETUP: 220 ret = scnprintf(str, size, 221 "type '%s' bRequestType %02x bRequest %02x " 222 "wValue %02x%02x wIndex %02x%02x wLength %d " 223 "length %ld TD size %ld intr %ld Setup ID %ld " 224 "flags %c:%c:%c", 225 cdnsp_trb_type_string(type), 226 field0 & 0xff, 227 (field0 & 0xff00) >> 8, 228 (field0 & 0xff000000) >> 24, 229 (field0 & 0xff0000) >> 16, 230 (field1 & 0xff00) >> 8, 231 field1 & 0xff, 232 (field1 & 0xff000000) >> 16 | 233 (field1 & 0xff0000) >> 16, 234 TRB_LEN(field2), GET_TD_SIZE(field2), 235 GET_INTR_TARGET(field2), 236 TRB_SETUPID_TO_TYPE(field3), 237 field3 & TRB_IDT ? 'D' : 'd', 238 field3 & TRB_IOC ? 'I' : 'i', 239 field3 & TRB_CYCLE ? 'C' : 'c'); 240 break; 241 case TRB_DATA: 242 ret = scnprintf(str, size, 243 "type '%s' Buffer %08x%08x length %ld TD size %ld " 244 "intr %ld flags %c:%c:%c:%c:%c:%c:%c", 245 cdnsp_trb_type_string(type), 246 field1, field0, TRB_LEN(field2), 247 GET_TD_SIZE(field2), 248 GET_INTR_TARGET(field2), 249 field3 & TRB_IDT ? 'D' : 'i', 250 field3 & TRB_IOC ? 'I' : 'i', 251 field3 & TRB_CHAIN ? 'C' : 'c', 252 field3 & TRB_NO_SNOOP ? 'S' : 's', 253 field3 & TRB_ISP ? 'I' : 'i', 254 field3 & TRB_ENT ? 'E' : 'e', 255 field3 & TRB_CYCLE ? 'C' : 'c'); 256 break; 257 case TRB_STATUS: 258 ret = scnprintf(str, size, 259 "Buffer %08x%08x length %ld TD size %ld intr" 260 "%ld type '%s' flags %c:%c:%c:%c", 261 field1, field0, TRB_LEN(field2), 262 GET_TD_SIZE(field2), 263 GET_INTR_TARGET(field2), 264 cdnsp_trb_type_string(type), 265 field3 & TRB_IOC ? 'I' : 'i', 266 field3 & TRB_CHAIN ? 'C' : 'c', 267 field3 & TRB_ENT ? 'E' : 'e', 268 field3 & TRB_CYCLE ? 'C' : 'c'); 269 break; 270 case TRB_NORMAL: 271 case TRB_ISOC: 272 case TRB_EVENT_DATA: 273 case TRB_TR_NOOP: 274 ret = scnprintf(str, size, 275 "type '%s' Buffer %08x%08x length %ld " 276 "TD size %ld intr %ld " 277 "flags %c:%c:%c:%c:%c:%c:%c:%c:%c", 278 cdnsp_trb_type_string(type), 279 field1, field0, TRB_LEN(field2), 280 GET_TD_SIZE(field2), 281 GET_INTR_TARGET(field2), 282 field3 & TRB_BEI ? 'B' : 'b', 283 field3 & TRB_IDT ? 'T' : 't', 284 field3 & TRB_IOC ? 'I' : 'i', 285 field3 & TRB_CHAIN ? 'C' : 'c', 286 field3 & TRB_NO_SNOOP ? 'S' : 's', 287 field3 & TRB_ISP ? 'I' : 'i', 288 field3 & TRB_ENT ? 'E' : 'e', 289 field3 & TRB_CYCLE ? 'C' : 'c', 290 !(field3 & TRB_EVENT_INVALIDATE) ? 'V' : 'v'); 291 break; 292 case TRB_CMD_NOOP: 293 case TRB_ENABLE_SLOT: 294 ret = scnprintf(str, size, "%s: flags %c", 295 cdnsp_trb_type_string(type), 296 field3 & TRB_CYCLE ? 'C' : 'c'); 297 break; 298 case TRB_DISABLE_SLOT: 299 ret = scnprintf(str, size, "%s: slot %ld flags %c", 300 cdnsp_trb_type_string(type), 301 TRB_TO_SLOT_ID(field3), 302 field3 & TRB_CYCLE ? 'C' : 'c'); 303 break; 304 case TRB_ADDR_DEV: 305 ret = scnprintf(str, size, 306 "%s: ctx %08x%08x slot %ld flags %c:%c", 307 cdnsp_trb_type_string(type), field1, field0, 308 TRB_TO_SLOT_ID(field3), 309 field3 & TRB_BSR ? 'B' : 'b', 310 field3 & TRB_CYCLE ? 'C' : 'c'); 311 break; 312 case TRB_CONFIG_EP: 313 ret = scnprintf(str, size, 314 "%s: ctx %08x%08x slot %ld flags %c:%c", 315 cdnsp_trb_type_string(type), field1, field0, 316 TRB_TO_SLOT_ID(field3), 317 field3 & TRB_DC ? 'D' : 'd', 318 field3 & TRB_CYCLE ? 'C' : 'c'); 319 break; 320 case TRB_EVAL_CONTEXT: 321 ret = scnprintf(str, size, 322 "%s: ctx %08x%08x slot %ld flags %c", 323 cdnsp_trb_type_string(type), field1, field0, 324 TRB_TO_SLOT_ID(field3), 325 field3 & TRB_CYCLE ? 'C' : 'c'); 326 break; 327 case TRB_RESET_EP: 328 case TRB_HALT_ENDPOINT: 329 ret = scnprintf(str, size, 330 "%s: ep%d%s(%d) ctx %08x%08x slot %ld flags %c %c", 331 cdnsp_trb_type_string(type), 332 ep_num, ep_id % 2 ? "out" : "in", 333 TRB_TO_EP_INDEX(field3), field1, field0, 334 TRB_TO_SLOT_ID(field3), 335 field3 & TRB_CYCLE ? 'C' : 'c', 336 field3 & TRB_ESP ? 'P' : 'p'); 337 break; 338 case TRB_STOP_RING: 339 ret = scnprintf(str, size, 340 "%s: ep%d%s(%d) slot %ld sp %d flags %c", 341 cdnsp_trb_type_string(type), 342 ep_num, ep_id % 2 ? "out" : "in", 343 TRB_TO_EP_INDEX(field3), 344 TRB_TO_SLOT_ID(field3), 345 TRB_TO_SUSPEND_PORT(field3), 346 field3 & TRB_CYCLE ? 'C' : 'c'); 347 break; 348 case TRB_SET_DEQ: 349 ret = scnprintf(str, size, 350 "%s: ep%d%s(%d) deq %08x%08x stream %ld slot %ld flags %c", 351 cdnsp_trb_type_string(type), 352 ep_num, ep_id % 2 ? "out" : "in", 353 TRB_TO_EP_INDEX(field3), field1, field0, 354 TRB_TO_STREAM_ID(field2), 355 TRB_TO_SLOT_ID(field3), 356 field3 & TRB_CYCLE ? 'C' : 'c'); 357 break; 358 case TRB_RESET_DEV: 359 ret = scnprintf(str, size, "%s: slot %ld flags %c", 360 cdnsp_trb_type_string(type), 361 TRB_TO_SLOT_ID(field3), 362 field3 & TRB_CYCLE ? 'C' : 'c'); 363 break; 364 case TRB_ENDPOINT_NRDY: 365 temp = TRB_TO_HOST_STREAM(field2); 366 367 ret = scnprintf(str, size, 368 "%s: ep%d%s(%d) H_SID %x%s%s D_SID %lx flags %c:%c", 369 cdnsp_trb_type_string(type), 370 ep_num, ep_id % 2 ? "out" : "in", 371 TRB_TO_EP_INDEX(field3), temp, 372 temp == STREAM_PRIME_ACK ? "(PRIME)" : "", 373 temp == STREAM_REJECTED ? "(REJECTED)" : "", 374 TRB_TO_DEV_STREAM(field0), 375 field3 & TRB_STAT ? 'S' : 's', 376 field3 & TRB_CYCLE ? 'C' : 'c'); 377 break; 378 default: 379 ret = scnprintf(str, size, 380 "type '%s' -> raw %08x %08x %08x %08x", 381 cdnsp_trb_type_string(type), 382 field0, field1, field2, field3); 383 } 384 385 if (ret == size - 1) 386 pr_info("CDNSP: buffer may be truncated.\n"); 387 388 return str; 389 } 390 391 static inline const char *cdnsp_decode_slot_context(u32 info, u32 info2, 392 u32 int_target, u32 state) 393 { 394 static char str[1024]; 395 int ret = 0; 396 u32 speed; 397 char *s; 398 399 speed = info & DEV_SPEED; 400 401 switch (speed) { 402 case SLOT_SPEED_FS: 403 s = "full-speed"; 404 break; 405 case SLOT_SPEED_HS: 406 s = "high-speed"; 407 break; 408 case SLOT_SPEED_SS: 409 s = "super-speed"; 410 break; 411 case SLOT_SPEED_SSP: 412 s = "super-speed plus"; 413 break; 414 default: 415 s = "UNKNOWN speed"; 416 } 417 418 ret = sprintf(str, "%s Ctx Entries %d", 419 s, (info & LAST_CTX_MASK) >> 27); 420 421 ret += sprintf(str + ret, " [Intr %ld] Addr %ld State %s", 422 GET_INTR_TARGET(int_target), state & DEV_ADDR_MASK, 423 cdnsp_slot_state_string(GET_SLOT_STATE(state))); 424 425 return str; 426 } 427 428 static inline const char *cdnsp_portsc_link_state_string(u32 portsc) 429 { 430 switch (portsc & PORT_PLS_MASK) { 431 case XDEV_U0: 432 return "U0"; 433 case XDEV_U1: 434 return "U1"; 435 case XDEV_U2: 436 return "U2"; 437 case XDEV_U3: 438 return "U3"; 439 case XDEV_DISABLED: 440 return "Disabled"; 441 case XDEV_RXDETECT: 442 return "RxDetect"; 443 case XDEV_INACTIVE: 444 return "Inactive"; 445 case XDEV_POLLING: 446 return "Polling"; 447 case XDEV_RECOVERY: 448 return "Recovery"; 449 case XDEV_HOT_RESET: 450 return "Hot Reset"; 451 case XDEV_COMP_MODE: 452 return "Compliance mode"; 453 case XDEV_TEST_MODE: 454 return "Test mode"; 455 case XDEV_RESUME: 456 return "Resume"; 457 default: 458 break; 459 } 460 461 return "Unknown"; 462 } 463 464 static inline const char *cdnsp_decode_portsc(char *str, size_t size, 465 u32 portsc) 466 { 467 int ret; 468 469 ret = scnprintf(str, size, "%s %s %s Link:%s PortSpeed:%d ", 470 portsc & PORT_POWER ? "Powered" : "Powered-off", 471 portsc & PORT_CONNECT ? "Connected" : "Not-connected", 472 portsc & PORT_PED ? "Enabled" : "Disabled", 473 cdnsp_portsc_link_state_string(portsc), 474 DEV_PORT_SPEED(portsc)); 475 476 if (portsc & PORT_RESET) 477 ret += scnprintf(str + ret, size - ret, "In-Reset "); 478 479 ret += scnprintf(str + ret, size - ret, "Change: "); 480 if (portsc & PORT_CSC) 481 ret += scnprintf(str + ret, size - ret, "CSC "); 482 if (portsc & PORT_WRC) 483 ret += scnprintf(str + ret, size - ret, "WRC "); 484 if (portsc & PORT_RC) 485 ret += scnprintf(str + ret, size - ret, "PRC "); 486 if (portsc & PORT_PLC) 487 ret += scnprintf(str + ret, size - ret, "PLC "); 488 if (portsc & PORT_CEC) 489 ret += scnprintf(str + ret, size - ret, "CEC "); 490 ret += scnprintf(str + ret, size - ret, "Wake: "); 491 if (portsc & PORT_WKCONN_E) 492 ret += scnprintf(str + ret, size - ret, "WCE "); 493 if (portsc & PORT_WKDISC_E) 494 ret += scnprintf(str + ret, size - ret, "WDE "); 495 496 return str; 497 } 498 499 static inline const char *cdnsp_ep_state_string(u8 state) 500 { 501 switch (state) { 502 case EP_STATE_DISABLED: 503 return "disabled"; 504 case EP_STATE_RUNNING: 505 return "running"; 506 case EP_STATE_HALTED: 507 return "halted"; 508 case EP_STATE_STOPPED: 509 return "stopped"; 510 case EP_STATE_ERROR: 511 return "error"; 512 default: 513 return "INVALID"; 514 } 515 } 516 517 static inline const char *cdnsp_ep_type_string(u8 type) 518 { 519 switch (type) { 520 case ISOC_OUT_EP: 521 return "Isoc OUT"; 522 case BULK_OUT_EP: 523 return "Bulk OUT"; 524 case INT_OUT_EP: 525 return "Int OUT"; 526 case CTRL_EP: 527 return "Ctrl"; 528 case ISOC_IN_EP: 529 return "Isoc IN"; 530 case BULK_IN_EP: 531 return "Bulk IN"; 532 case INT_IN_EP: 533 return "Int IN"; 534 default: 535 return "INVALID"; 536 } 537 } 538 539 static inline const char *cdnsp_decode_ep_context(char *str, size_t size, 540 u32 info, u32 info2, 541 u64 deq, u32 tx_info) 542 { 543 u8 max_pstr, ep_state, interval, ep_type, burst, cerr, mult; 544 bool lsa, hid; 545 u16 maxp, avg; 546 u32 esit; 547 int ret; 548 549 esit = CTX_TO_MAX_ESIT_PAYLOAD_HI(info) << 16 | 550 CTX_TO_MAX_ESIT_PAYLOAD_LO(tx_info); 551 552 ep_state = info & EP_STATE_MASK; 553 max_pstr = CTX_TO_EP_MAXPSTREAMS(info); 554 interval = CTX_TO_EP_INTERVAL(info); 555 mult = CTX_TO_EP_MULT(info) + 1; 556 lsa = !!(info & EP_HAS_LSA); 557 558 cerr = (info2 & (3 << 1)) >> 1; 559 ep_type = CTX_TO_EP_TYPE(info2); 560 hid = !!(info2 & (1 << 7)); 561 burst = CTX_TO_MAX_BURST(info2); 562 maxp = MAX_PACKET_DECODED(info2); 563 564 avg = EP_AVG_TRB_LENGTH(tx_info); 565 566 ret = scnprintf(str, size, "State %s mult %d max P. Streams %d %s", 567 cdnsp_ep_state_string(ep_state), mult, 568 max_pstr, lsa ? "LSA " : ""); 569 570 ret += scnprintf(str + ret, size - ret, 571 "interval %d us max ESIT payload %d CErr %d ", 572 (1 << interval) * 125, esit, cerr); 573 574 ret += scnprintf(str + ret, size - ret, 575 "Type %s %sburst %d maxp %d deq %016llx ", 576 cdnsp_ep_type_string(ep_type), hid ? "HID" : "", 577 burst, maxp, deq); 578 579 ret += scnprintf(str + ret, size - ret, "avg trb len %d", avg); 580 581 return str; 582 } 583 584 #endif /*__LINUX_CDNSP_DEBUG*/ 585