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", 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 break; 337 case TRB_STOP_RING: 338 ret = scnprintf(str, size, 339 "%s: ep%d%s(%d) slot %ld sp %d flags %c", 340 cdnsp_trb_type_string(type), 341 ep_num, ep_id % 2 ? "out" : "in", 342 TRB_TO_EP_INDEX(field3), 343 TRB_TO_SLOT_ID(field3), 344 TRB_TO_SUSPEND_PORT(field3), 345 field3 & TRB_CYCLE ? 'C' : 'c'); 346 break; 347 case TRB_SET_DEQ: 348 ret = scnprintf(str, size, 349 "%s: ep%d%s(%d) deq %08x%08x stream %ld slot %ld flags %c", 350 cdnsp_trb_type_string(type), 351 ep_num, ep_id % 2 ? "out" : "in", 352 TRB_TO_EP_INDEX(field3), field1, field0, 353 TRB_TO_STREAM_ID(field2), 354 TRB_TO_SLOT_ID(field3), 355 field3 & TRB_CYCLE ? 'C' : 'c'); 356 break; 357 case TRB_RESET_DEV: 358 ret = scnprintf(str, size, "%s: slot %ld flags %c", 359 cdnsp_trb_type_string(type), 360 TRB_TO_SLOT_ID(field3), 361 field3 & TRB_CYCLE ? 'C' : 'c'); 362 break; 363 case TRB_ENDPOINT_NRDY: 364 temp = TRB_TO_HOST_STREAM(field2); 365 366 ret = scnprintf(str, size, 367 "%s: ep%d%s(%d) H_SID %x%s%s D_SID %lx flags %c:%c", 368 cdnsp_trb_type_string(type), 369 ep_num, ep_id % 2 ? "out" : "in", 370 TRB_TO_EP_INDEX(field3), temp, 371 temp == STREAM_PRIME_ACK ? "(PRIME)" : "", 372 temp == STREAM_REJECTED ? "(REJECTED)" : "", 373 TRB_TO_DEV_STREAM(field0), 374 field3 & TRB_STAT ? 'S' : 's', 375 field3 & TRB_CYCLE ? 'C' : 'c'); 376 break; 377 default: 378 ret = scnprintf(str, size, 379 "type '%s' -> raw %08x %08x %08x %08x", 380 cdnsp_trb_type_string(type), 381 field0, field1, field2, field3); 382 } 383 384 if (ret == size - 1) 385 pr_info("CDNSP: buffer may be truncated.\n"); 386 387 return str; 388 } 389 390 static inline const char *cdnsp_decode_slot_context(u32 info, u32 info2, 391 u32 int_target, u32 state) 392 { 393 static char str[1024]; 394 int ret = 0; 395 u32 speed; 396 char *s; 397 398 speed = info & DEV_SPEED; 399 400 switch (speed) { 401 case SLOT_SPEED_FS: 402 s = "full-speed"; 403 break; 404 case SLOT_SPEED_HS: 405 s = "high-speed"; 406 break; 407 case SLOT_SPEED_SS: 408 s = "super-speed"; 409 break; 410 case SLOT_SPEED_SSP: 411 s = "super-speed plus"; 412 break; 413 default: 414 s = "UNKNOWN speed"; 415 } 416 417 ret = sprintf(str, "%s Ctx Entries %d", 418 s, (info & LAST_CTX_MASK) >> 27); 419 420 ret += sprintf(str + ret, " [Intr %ld] Addr %ld State %s", 421 GET_INTR_TARGET(int_target), state & DEV_ADDR_MASK, 422 cdnsp_slot_state_string(GET_SLOT_STATE(state))); 423 424 return str; 425 } 426 427 static inline const char *cdnsp_portsc_link_state_string(u32 portsc) 428 { 429 switch (portsc & PORT_PLS_MASK) { 430 case XDEV_U0: 431 return "U0"; 432 case XDEV_U1: 433 return "U1"; 434 case XDEV_U2: 435 return "U2"; 436 case XDEV_U3: 437 return "U3"; 438 case XDEV_DISABLED: 439 return "Disabled"; 440 case XDEV_RXDETECT: 441 return "RxDetect"; 442 case XDEV_INACTIVE: 443 return "Inactive"; 444 case XDEV_POLLING: 445 return "Polling"; 446 case XDEV_RECOVERY: 447 return "Recovery"; 448 case XDEV_HOT_RESET: 449 return "Hot Reset"; 450 case XDEV_COMP_MODE: 451 return "Compliance mode"; 452 case XDEV_TEST_MODE: 453 return "Test mode"; 454 case XDEV_RESUME: 455 return "Resume"; 456 default: 457 break; 458 } 459 460 return "Unknown"; 461 } 462 463 static inline const char *cdnsp_decode_portsc(char *str, size_t size, 464 u32 portsc) 465 { 466 int ret; 467 468 ret = scnprintf(str, size, "%s %s %s Link:%s PortSpeed:%d ", 469 portsc & PORT_POWER ? "Powered" : "Powered-off", 470 portsc & PORT_CONNECT ? "Connected" : "Not-connected", 471 portsc & PORT_PED ? "Enabled" : "Disabled", 472 cdnsp_portsc_link_state_string(portsc), 473 DEV_PORT_SPEED(portsc)); 474 475 if (portsc & PORT_RESET) 476 ret += scnprintf(str + ret, size - ret, "In-Reset "); 477 478 ret += scnprintf(str + ret, size - ret, "Change: "); 479 if (portsc & PORT_CSC) 480 ret += scnprintf(str + ret, size - ret, "CSC "); 481 if (portsc & PORT_WRC) 482 ret += scnprintf(str + ret, size - ret, "WRC "); 483 if (portsc & PORT_RC) 484 ret += scnprintf(str + ret, size - ret, "PRC "); 485 if (portsc & PORT_PLC) 486 ret += scnprintf(str + ret, size - ret, "PLC "); 487 if (portsc & PORT_CEC) 488 ret += scnprintf(str + ret, size - ret, "CEC "); 489 ret += scnprintf(str + ret, size - ret, "Wake: "); 490 if (portsc & PORT_WKCONN_E) 491 ret += scnprintf(str + ret, size - ret, "WCE "); 492 if (portsc & PORT_WKDISC_E) 493 ret += scnprintf(str + ret, size - ret, "WDE "); 494 495 return str; 496 } 497 498 static inline const char *cdnsp_ep_state_string(u8 state) 499 { 500 switch (state) { 501 case EP_STATE_DISABLED: 502 return "disabled"; 503 case EP_STATE_RUNNING: 504 return "running"; 505 case EP_STATE_HALTED: 506 return "halted"; 507 case EP_STATE_STOPPED: 508 return "stopped"; 509 case EP_STATE_ERROR: 510 return "error"; 511 default: 512 return "INVALID"; 513 } 514 } 515 516 static inline const char *cdnsp_ep_type_string(u8 type) 517 { 518 switch (type) { 519 case ISOC_OUT_EP: 520 return "Isoc OUT"; 521 case BULK_OUT_EP: 522 return "Bulk OUT"; 523 case INT_OUT_EP: 524 return "Int OUT"; 525 case CTRL_EP: 526 return "Ctrl"; 527 case ISOC_IN_EP: 528 return "Isoc IN"; 529 case BULK_IN_EP: 530 return "Bulk IN"; 531 case INT_IN_EP: 532 return "Int IN"; 533 default: 534 return "INVALID"; 535 } 536 } 537 538 static inline const char *cdnsp_decode_ep_context(char *str, size_t size, 539 u32 info, u32 info2, 540 u64 deq, u32 tx_info) 541 { 542 u8 max_pstr, ep_state, interval, ep_type, burst, cerr, mult; 543 bool lsa, hid; 544 u16 maxp, avg; 545 u32 esit; 546 int ret; 547 548 esit = CTX_TO_MAX_ESIT_PAYLOAD_HI(info) << 16 | 549 CTX_TO_MAX_ESIT_PAYLOAD_LO(tx_info); 550 551 ep_state = info & EP_STATE_MASK; 552 max_pstr = CTX_TO_EP_MAXPSTREAMS(info); 553 interval = CTX_TO_EP_INTERVAL(info); 554 mult = CTX_TO_EP_MULT(info) + 1; 555 lsa = !!(info & EP_HAS_LSA); 556 557 cerr = (info2 & (3 << 1)) >> 1; 558 ep_type = CTX_TO_EP_TYPE(info2); 559 hid = !!(info2 & (1 << 7)); 560 burst = CTX_TO_MAX_BURST(info2); 561 maxp = MAX_PACKET_DECODED(info2); 562 563 avg = EP_AVG_TRB_LENGTH(tx_info); 564 565 ret = scnprintf(str, size, "State %s mult %d max P. Streams %d %s", 566 cdnsp_ep_state_string(ep_state), mult, 567 max_pstr, lsa ? "LSA " : ""); 568 569 ret += scnprintf(str + ret, size - ret, 570 "interval %d us max ESIT payload %d CErr %d ", 571 (1 << interval) * 125, esit, cerr); 572 573 ret += scnprintf(str + ret, size - ret, 574 "Type %s %sburst %d maxp %d deq %016llx ", 575 cdnsp_ep_type_string(ep_type), hid ? "HID" : "", 576 burst, maxp, deq); 577 578 ret += scnprintf(str + ret, size - ret, "avg trb len %d", avg); 579 580 return str; 581 } 582 583 #endif /*__LINUX_CDNSP_DEBUG*/ 584