cvmx-pow.c revision 256281
1/***********************license start*************** 2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Inc. nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40 41 42 43 44 45 46/** 47 * @file 48 * 49 * Interface to the hardware Packet Order / Work unit. 50 * 51 * <hr>$Revision: 29727 $<hr> 52 */ 53 54#include "cvmx.h" 55#include "cvmx-pow.h" 56 57/** 58 * @INTERNAL 59 * This structure stores the internal POW state captured by 60 * cvmx_pow_capture(). It is purposely not exposed to the user 61 * since the format may change without notice. 62 */ 63typedef struct 64{ 65 cvmx_pow_tag_load_resp_t sstatus[CVMX_MAX_CORES][8]; 66 cvmx_pow_tag_load_resp_t smemload[2048][8]; 67 cvmx_pow_tag_load_resp_t sindexload[64][8]; 68} __cvmx_pow_dump_t; 69 70typedef enum 71{ 72 CVMX_POW_LIST_UNKNOWN=0, 73 CVMX_POW_LIST_FREE=1, 74 CVMX_POW_LIST_INPUT=2, 75 CVMX_POW_LIST_CORE=CVMX_POW_LIST_INPUT+8, 76 CVMX_POW_LIST_DESCHED=CVMX_POW_LIST_CORE+32, 77 CVMX_POW_LIST_NOSCHED=CVMX_POW_LIST_DESCHED+64, 78} __cvmx_pow_list_types_t; 79 80static const char *__cvmx_pow_list_names[] = { 81 "Unknown", 82 "Free List", 83 "Queue 0", "Queue 1", "Queue 2", "Queue 3", 84 "Queue 4", "Queue 5", "Queue 6", "Queue 7", 85 "Core 0", "Core 1", "Core 2", "Core 3", 86 "Core 4", "Core 5", "Core 6", "Core 7", 87 "Core 8", "Core 9", "Core 10", "Core 11", 88 "Core 12", "Core 13", "Core 14", "Core 15", 89 "Core 16", "Core 17", "Core 18", "Core 19", 90 "Core 20", "Core 21", "Core 22", "Core 23", 91 "Core 24", "Core 25", "Core 26", "Core 27", 92 "Core 28", "Core 29", "Core 30", "Core 31", 93 "Desched 0", "Desched 1", "Desched 2", "Desched 3", 94 "Desched 4", "Desched 5", "Desched 6", "Desched 7", 95 "Desched 8", "Desched 9", "Desched 10", "Desched 11", 96 "Desched 12", "Desched 13", "Desched 14", "Desched 15", 97 "Desched 16", "Desched 17", "Desched 18", "Desched 19", 98 "Desched 20", "Desched 21", "Desched 22", "Desched 23", 99 "Desched 24", "Desched 25", "Desched 26", "Desched 27", 100 "Desched 28", "Desched 29", "Desched 30", "Desched 31", 101 "Desched 32", "Desched 33", "Desched 34", "Desched 35", 102 "Desched 36", "Desched 37", "Desched 38", "Desched 39", 103 "Desched 40", "Desched 41", "Desched 42", "Desched 43", 104 "Desched 44", "Desched 45", "Desched 46", "Desched 47", 105 "Desched 48", "Desched 49", "Desched 50", "Desched 51", 106 "Desched 52", "Desched 53", "Desched 54", "Desched 55", 107 "Desched 56", "Desched 57", "Desched 58", "Desched 59", 108 "Desched 60", "Desched 61", "Desched 62", "Desched 63", 109 "Nosched 0" 110}; 111 112 113/** 114 * Return the number of POW entries supported by this chip 115 * 116 * @return Number of POW entries 117 */ 118int cvmx_pow_get_num_entries(void) 119{ 120 if (OCTEON_IS_MODEL(OCTEON_CN30XX)) 121 return 64; 122 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 123 return 256; 124 else if (OCTEON_IS_MODEL(OCTEON_CN52XX) 125 || OCTEON_IS_MODEL(OCTEON_CN61XX) 126 || OCTEON_IS_MODEL(OCTEON_CNF71XX)) 127 return 512; 128 else if (OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CN66XX)) 129 return 1024; 130 else 131 return 2048; 132} 133 134 135static int __cvmx_pow_capture_v1(void *buffer, int buffer_size) 136{ 137 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer; 138 int num_cores; 139 int num_pow_entries = cvmx_pow_get_num_entries(); 140 int core; 141 int index; 142 int bits; 143 144 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t)) 145 { 146 cvmx_dprintf("cvmx_pow_capture: Buffer too small\n"); 147 return -1; 148 } 149 150 num_cores = cvmx_octeon_num_cores(); 151 152 /* Read all core related state */ 153 for (core=0; core<num_cores; core++) 154 { 155 cvmx_pow_load_addr_t load_addr; 156 load_addr.u64 = 0; 157 load_addr.sstatus.mem_region = CVMX_IO_SEG; 158 load_addr.sstatus.is_io = 1; 159 load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; 160 load_addr.sstatus.coreid = core; 161 for (bits=0; bits<8; bits++) 162 { 163 load_addr.sstatus.get_rev = (bits & 1) != 0; 164 load_addr.sstatus.get_cur = (bits & 2) != 0; 165 load_addr.sstatus.get_wqp = (bits & 4) != 0; 166 if ((load_addr.sstatus.get_cur == 0) && load_addr.sstatus.get_rev) 167 dump->sstatus[core][bits].u64 = -1; 168 else 169 dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64); 170 } 171 } 172 173 /* Read all internal POW entries */ 174 for (index=0; index<num_pow_entries; index++) 175 { 176 cvmx_pow_load_addr_t load_addr; 177 load_addr.u64 = 0; 178 load_addr.smemload.mem_region = CVMX_IO_SEG; 179 load_addr.smemload.is_io = 1; 180 load_addr.smemload.did = CVMX_OCT_DID_TAG_TAG2; 181 load_addr.smemload.index = index; 182 for (bits=0; bits<3; bits++) 183 { 184 load_addr.smemload.get_des = (bits & 1) != 0; 185 load_addr.smemload.get_wqp = (bits & 2) != 0; 186 dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64); 187 } 188 } 189 190 /* Read all group and queue pointers */ 191 for (index=0; index<16; index++) 192 { 193 cvmx_pow_load_addr_t load_addr; 194 load_addr.u64 = 0; 195 load_addr.sindexload.mem_region = CVMX_IO_SEG; 196 load_addr.sindexload.is_io = 1; 197 load_addr.sindexload.did = CVMX_OCT_DID_TAG_TAG3; 198 load_addr.sindexload.qosgrp = index; 199 for (bits=0; bits<4; bits++) 200 { 201 load_addr.sindexload.get_rmt = (bits & 1) != 0; 202 load_addr.sindexload.get_des_get_tail = (bits & 2) != 0; 203 /* The first pass only has 8 valid index values */ 204 if ((load_addr.sindexload.get_rmt == 0) && 205 (load_addr.sindexload.get_des_get_tail == 0) && 206 (index >= 8)) 207 dump->sindexload[index][bits].u64 = -1; 208 else 209 dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64); 210 } 211 } 212 return 0; 213} 214 215static int __cvmx_pow_capture_v2(void *buffer, int buffer_size) 216{ 217 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer; 218 int num_cores; 219 int num_pow_entries = cvmx_pow_get_num_entries(); 220 int core; 221 int index; 222 int bits; 223 224 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t)) 225 { 226 cvmx_dprintf("cvmx_pow_capture: Buffer too small\n"); 227 return -1; 228 } 229 230 num_cores = cvmx_octeon_num_cores(); 231 232 /* Read all core related state */ 233 for (core=0; core<num_cores; core++) 234 { 235 cvmx_pow_load_addr_t load_addr; 236 load_addr.u64 = 0; 237 load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG; 238 load_addr.sstatus_cn68xx.is_io = 1; 239 load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5; 240 load_addr.sstatus_cn68xx.coreid = core; 241 for (bits=1; bits<6; bits++) 242 { 243 load_addr.sstatus_cn68xx.opcode = bits; 244 dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64); 245 } 246 } 247 /* Read all internal POW entries */ 248 for (index=0; index<num_pow_entries; index++) 249 { 250 cvmx_pow_load_addr_t load_addr; 251 load_addr.u64 = 0; 252 load_addr.smemload_cn68xx.mem_region = CVMX_IO_SEG; 253 load_addr.smemload_cn68xx.is_io = 1; 254 load_addr.smemload_cn68xx.did = CVMX_OCT_DID_TAG_TAG2; 255 load_addr.smemload_cn68xx.index = index; 256 for (bits=1; bits<5; bits++) 257 { 258 load_addr.smemload_cn68xx.opcode = bits; 259 dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64); 260 } 261 } 262 263 /* Read all group and queue pointers */ 264 for (index=0; index<64; index++) 265 { 266 cvmx_pow_load_addr_t load_addr; 267 load_addr.u64 = 0; 268 load_addr.sindexload_cn68xx.mem_region = CVMX_IO_SEG; 269 load_addr.sindexload_cn68xx.is_io = 1; 270 load_addr.sindexload_cn68xx.did = CVMX_OCT_DID_TAG_TAG3; 271 load_addr.sindexload_cn68xx.qos_grp = index; 272 for (bits=1; bits<7; bits++) 273 { 274 load_addr.sindexload_cn68xx.opcode = bits; 275 dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64); 276 } 277 } 278 return 0; 279} 280 281/** 282 * Store the current POW internal state into the supplied 283 * buffer. It is recommended that you pass a buffer of at least 284 * 128KB. The format of the capture may change based on SDK 285 * version and Octeon chip. 286 * 287 * @param buffer Buffer to store capture into 288 * @param buffer_size 289 * The size of the supplied buffer 290 * 291 * @return Zero on sucess, negative on failure 292 */ 293int cvmx_pow_capture(void *buffer, int buffer_size) 294{ 295 if (octeon_has_feature(OCTEON_FEATURE_PKND)) 296 return __cvmx_pow_capture_v2(buffer, buffer_size); 297 else 298 return __cvmx_pow_capture_v1(buffer, buffer_size); 299} 300 301/** 302 * Function to display a POW internal queue to the user 303 * 304 * @param name User visible name for the queue 305 * @param name_param Parameter for printf in creating the name 306 * @param valid Set if the queue contains any elements 307 * @param has_one Set if the queue contains exactly one element 308 * @param head The head pointer 309 * @param tail The tail pointer 310 */ 311static void __cvmx_pow_display_list(const char *name, int name_param, int valid, int has_one, uint64_t head, uint64_t tail) 312{ 313 printf(name, name_param); 314 printf(": "); 315 if (valid) 316 { 317 if (has_one) 318 printf("One element index=%llu(0x%llx)\n", CAST64(head), CAST64(head)); 319 else 320 printf("Multiple elements head=%llu(0x%llx) tail=%llu(0x%llx)\n", CAST64(head), CAST64(head), CAST64(tail), CAST64(tail)); 321 } 322 else 323 printf("Empty\n"); 324} 325 326 327/** 328 * Mark which list a POW entry is on. Print a warning message if the 329 * entry is already on a list. This happens if the POW changed while 330 * the capture was running. 331 * 332 * @param entry_num Entry number to mark 333 * @param entry_type List type 334 * @param entry_list Array to store marks 335 * 336 * @return Zero on success, negative if already on a list 337 */ 338static int __cvmx_pow_entry_mark_list(int entry_num, __cvmx_pow_list_types_t entry_type, uint8_t entry_list[]) 339{ 340 if (entry_list[entry_num] == 0) 341 { 342 entry_list[entry_num] = entry_type; 343 return 0; 344 } 345 else 346 { 347 printf("\nWARNING: Entry %d already on list %s, but we tried to add it to %s\n", 348 entry_num, __cvmx_pow_list_names[entry_list[entry_num]], __cvmx_pow_list_names[entry_type]); 349 return -1; 350 } 351} 352 353 354/** 355 * Display a list and mark all elements on the list as belonging to 356 * the list. 357 * 358 * @param entry_type Type of the list to display and mark 359 * @param dump POW capture data 360 * @param entry_list Array to store marks in 361 * @param valid Set if the queue contains any elements 362 * @param has_one Set if the queue contains exactly one element 363 * @param head The head pointer 364 * @param tail The tail pointer 365 */ 366static void __cvmx_pow_display_list_and_walk(__cvmx_pow_list_types_t entry_type, 367 __cvmx_pow_dump_t *dump, uint8_t entry_list[], 368 int valid, int has_one, uint64_t head, uint64_t tail) 369{ 370 __cvmx_pow_display_list(__cvmx_pow_list_names[entry_type], 0, valid, has_one, head, tail); 371 if (valid) 372 { 373 if (has_one) 374 __cvmx_pow_entry_mark_list(head, entry_type, entry_list); 375 else 376 { 377 while (head != tail) 378 { 379 if (__cvmx_pow_entry_mark_list(head, entry_type, entry_list)) 380 break; 381 if (octeon_has_feature(OCTEON_FEATURE_PKND)) 382 { 383 if (entry_type >= CVMX_POW_LIST_INPUT && entry_type < CVMX_POW_LIST_CORE) 384 385 head = dump->smemload[head][4].s_smemload3_cn68xx.next_index; 386 else 387 head = dump->smemload[head][4].s_smemload3_cn68xx.fwd_index; 388 } 389 else 390 head = dump->smemload[head][0].s_smemload0.next_index; 391 } 392 __cvmx_pow_entry_mark_list(tail, entry_type, entry_list); 393 } 394 } 395} 396 397 398void __cvmx_pow_display_v1(void *buffer, int buffer_size) 399{ 400 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer; 401 int num_pow_entries = cvmx_pow_get_num_entries(); 402 int num_cores; 403 int core; 404 int index; 405 uint8_t entry_list[2048]; 406 407 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t)) 408 { 409 cvmx_dprintf("cvmx_pow_dump: Buffer too small\n"); 410 return; 411 } 412 413 memset(entry_list, 0, sizeof(entry_list)); 414 num_cores = cvmx_octeon_num_cores(); 415 416 /* Print the free list info */ 417 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_FREE, dump, entry_list, 418 dump->sindexload[0][0].sindexload0.free_val, 419 dump->sindexload[0][0].sindexload0.free_one, 420 dump->sindexload[0][0].sindexload0.free_head, 421 dump->sindexload[0][0].sindexload0.free_tail); 422 423 /* Print the core state */ 424 for (core=0; core<num_cores; core++) 425 { 426 const int bit_rev = 1; 427 const int bit_cur = 2; 428 const int bit_wqp = 4; 429 printf("Core %d State: tag=%s,0x%08x", core, 430 OCT_TAG_TYPE_STRING(dump->sstatus[core][bit_cur].s_sstatus2.tag_type), 431 dump->sstatus[core][bit_cur].s_sstatus2.tag); 432 if (dump->sstatus[core][bit_cur].s_sstatus2.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL) 433 { 434 __cvmx_pow_entry_mark_list(dump->sstatus[core][bit_cur].s_sstatus2.index, CVMX_POW_LIST_CORE + core, entry_list); 435 printf(" grp=%d", dump->sstatus[core][bit_cur].s_sstatus2.grp); 436 printf(" wqp=0x%016llx", CAST64(dump->sstatus[core][bit_cur|bit_wqp].s_sstatus4.wqp)); 437 printf(" index=%d", dump->sstatus[core][bit_cur].s_sstatus2.index); 438 if (dump->sstatus[core][bit_cur].s_sstatus2.head) 439 printf(" head"); 440 else 441 printf(" prev=%d", dump->sstatus[core][bit_cur|bit_rev].s_sstatus3.revlink_index); 442 if (dump->sstatus[core][bit_cur].s_sstatus2.tail) 443 printf(" tail"); 444 else 445 printf(" next=%d", dump->sstatus[core][bit_cur].s_sstatus2.link_index); 446 } 447 448 if (dump->sstatus[core][0].s_sstatus0.pend_switch) 449 { 450 printf(" pend_switch=%d", dump->sstatus[core][0].s_sstatus0.pend_switch); 451 printf(" pend_switch_full=%d", dump->sstatus[core][0].s_sstatus0.pend_switch_full); 452 printf(" pend_switch_null=%d", dump->sstatus[core][0].s_sstatus0.pend_switch_null); 453 } 454 455 if (dump->sstatus[core][0].s_sstatus0.pend_desched) 456 { 457 printf(" pend_desched=%d", dump->sstatus[core][0].s_sstatus0.pend_desched); 458 printf(" pend_desched_switch=%d", dump->sstatus[core][0].s_sstatus0.pend_desched_switch); 459 printf(" pend_nosched=%d", dump->sstatus[core][0].s_sstatus0.pend_nosched); 460 if (dump->sstatus[core][0].s_sstatus0.pend_desched_switch) 461 printf(" pend_grp=%d", dump->sstatus[core][0].s_sstatus0.pend_grp); 462 } 463 464 if (dump->sstatus[core][0].s_sstatus0.pend_new_work) 465 { 466 if (dump->sstatus[core][0].s_sstatus0.pend_new_work_wait) 467 printf(" (Waiting for work)"); 468 else 469 printf(" (Getting work)"); 470 } 471 if (dump->sstatus[core][0].s_sstatus0.pend_null_rd) 472 printf(" pend_null_rd=%d", dump->sstatus[core][0].s_sstatus0.pend_null_rd); 473 if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr) 474 { 475 printf(" pend_nosched_clr=%d", dump->sstatus[core][0].s_sstatus0.pend_nosched_clr); 476 printf(" pend_index=%d", dump->sstatus[core][0].s_sstatus0.pend_index); 477 } 478 if (dump->sstatus[core][0].s_sstatus0.pend_switch || 479 (dump->sstatus[core][0].s_sstatus0.pend_desched && 480 dump->sstatus[core][0].s_sstatus0.pend_desched_switch)) 481 { 482 printf(" pending tag=%s,0x%08x", 483 OCT_TAG_TYPE_STRING(dump->sstatus[core][0].s_sstatus0.pend_type), 484 dump->sstatus[core][0].s_sstatus0.pend_tag); 485 } 486 if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr) 487 printf(" pend_wqp=0x%016llx\n", CAST64(dump->sstatus[core][bit_wqp].s_sstatus1.pend_wqp)); 488 printf("\n"); 489 } 490 491 /* Print out the state of the nosched list and the 16 deschedule lists. */ 492 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED, dump, entry_list, 493 dump->sindexload[0][2].sindexload1.nosched_val, 494 dump->sindexload[0][2].sindexload1.nosched_one, 495 dump->sindexload[0][2].sindexload1.nosched_head, 496 dump->sindexload[0][2].sindexload1.nosched_tail); 497 for (index=0; index<16; index++) 498 { 499 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list, 500 dump->sindexload[index][2].sindexload1.des_val, 501 dump->sindexload[index][2].sindexload1.des_one, 502 dump->sindexload[index][2].sindexload1.des_head, 503 dump->sindexload[index][2].sindexload1.des_tail); 504 } 505 506 /* Print out the state of the 8 internal input queues */ 507 for (index=0; index<8; index++) 508 { 509 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list, 510 dump->sindexload[index][0].sindexload0.loc_val, 511 dump->sindexload[index][0].sindexload0.loc_one, 512 dump->sindexload[index][0].sindexload0.loc_head, 513 dump->sindexload[index][0].sindexload0.loc_tail); 514 } 515 516 /* Print out the state of the 16 memory queues */ 517 for (index=0; index<8; index++) 518 { 519 const char *name; 520 if (dump->sindexload[index][1].sindexload2.rmt_is_head) 521 name = "Queue %da Memory (is head)"; 522 else 523 name = "Queue %da Memory"; 524 __cvmx_pow_display_list(name, index, 525 dump->sindexload[index][1].sindexload2.rmt_val, 526 dump->sindexload[index][1].sindexload2.rmt_one, 527 dump->sindexload[index][1].sindexload2.rmt_head, 528 dump->sindexload[index][3].sindexload3.rmt_tail); 529 if (dump->sindexload[index+8][1].sindexload2.rmt_is_head) 530 name = "Queue %db Memory (is head)"; 531 else 532 name = "Queue %db Memory"; 533 __cvmx_pow_display_list(name, index, 534 dump->sindexload[index+8][1].sindexload2.rmt_val, 535 dump->sindexload[index+8][1].sindexload2.rmt_one, 536 dump->sindexload[index+8][1].sindexload2.rmt_head, 537 dump->sindexload[index+8][3].sindexload3.rmt_tail); 538 } 539 540 /* Print out each of the internal POW entries. Each entry has a tag, group, 541 wqe, and possibly a next pointer. The next pointer is only valid if this 542 entry isn't make as a tail */ 543 for (index=0; index<num_pow_entries; index++) 544 { 545 printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index, 546 __cvmx_pow_list_names[entry_list[index]], 547 OCT_TAG_TYPE_STRING(dump->smemload[index][0].s_smemload0.tag_type), 548 dump->smemload[index][0].s_smemload0.tag, 549 dump->smemload[index][0].s_smemload0.grp, 550 CAST64(dump->smemload[index][2].s_smemload1.wqp)); 551 if (dump->smemload[index][0].s_smemload0.tail) 552 printf(" tail"); 553 else 554 printf(" next=%d", dump->smemload[index][0].s_smemload0.next_index); 555 if (entry_list[index] >= CVMX_POW_LIST_DESCHED) 556 { 557 printf(" nosched=%d", dump->smemload[index][1].s_smemload2.nosched); 558 if (dump->smemload[index][1].s_smemload2.pend_switch) 559 { 560 printf(" pending tag=%s,0x%08x", 561 OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload2.pend_type), 562 dump->smemload[index][1].s_smemload2.pend_tag); 563 } 564 } 565 printf("\n"); 566 } 567} 568 569void __cvmx_pow_display_v2(void *buffer, int buffer_size) 570{ 571 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer; 572 int num_pow_entries = cvmx_pow_get_num_entries(); 573 int num_cores; 574 int core; 575 int index; 576 uint8_t entry_list[2048]; 577 578 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t)) 579 { 580 cvmx_dprintf("cvmx_pow_dump: Buffer too small, pow_dump_t = 0x%x, buffer_size = 0x%x\n", (int)sizeof(__cvmx_pow_dump_t), buffer_size); 581 return; 582 } 583 584 memset(entry_list, 0, sizeof(entry_list)); 585 num_cores = cvmx_octeon_num_cores(); 586 587 /* Print the free list info */ 588 { 589 int valid[3], has_one[3], head[3], tail[3], qnum_head, qnum_tail; 590 int idx; 591 592 valid[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_val; 593 valid[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_val; 594 valid[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_val; 595 has_one[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_one; 596 has_one[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_one; 597 has_one[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_one; 598 head[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_head; 599 head[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_head; 600 head[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_head; 601 tail[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_tail; 602 tail[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_tail; 603 tail[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_tail; 604 qnum_head = dump->sindexload[0][4].sindexload1_cn68xx.qnum_head; 605 qnum_tail = dump->sindexload[0][4].sindexload1_cn68xx.qnum_tail; 606 607 printf("Free List: qnum_head=%d, qnum_tail=%d\n", qnum_head, qnum_tail); 608 printf("Free0: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[0], has_one[0], CAST64(head[0]), CAST64(tail[0])); 609 printf("Free1: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[1], has_one[1], CAST64(head[1]), CAST64(tail[1])); 610 printf("Free2: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[2], has_one[2], CAST64(head[2]), CAST64(tail[2])); 611 612 idx=qnum_head; 613 while (valid[0] || valid[1] || valid[2]) 614 { 615 int qidx = idx % 3; 616 617 if (head[qidx] == tail[qidx]) 618 valid[qidx] = 0; 619 620 if (__cvmx_pow_entry_mark_list(head[qidx], CVMX_POW_LIST_FREE, entry_list)) 621 break; 622 head[qidx] = dump->smemload[head[qidx]][4].s_smemload3_cn68xx.fwd_index; 623 //printf("qidx = %d, idx = %d, head[qidx] = %d\n", qidx, idx, head[qidx]); 624 idx++; 625 } 626 } 627 628 /* Print the core state */ 629 for (core = 0; core < num_cores; core++) 630 { 631 int pendtag = 1; 632 int pendwqp = 2; 633 int tag = 3; 634 int wqp = 4; 635 int links = 5; 636 637 printf("Core %d State: tag=%s,0x%08x", core, 638 OCT_TAG_TYPE_STRING(dump->sstatus[core][tag].s_sstatus2_cn68xx.tag_type), 639 dump->sstatus[core][tag].s_sstatus2_cn68xx.tag); 640 if (dump->sstatus[core][tag].s_sstatus2_cn68xx.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL) 641 { 642 __cvmx_pow_entry_mark_list(dump->sstatus[core][tag].s_sstatus2_cn68xx.index, CVMX_POW_LIST_CORE + core, entry_list); 643 printf(" grp=%d", dump->sstatus[core][tag].s_sstatus2_cn68xx.grp); 644 printf(" wqp=0x%016llx", CAST64(dump->sstatus[core][wqp].s_sstatus3_cn68xx.wqp)); 645 printf(" index=%d", dump->sstatus[core][tag].s_sstatus2_cn68xx.index); 646 if (dump->sstatus[core][links].s_sstatus4_cn68xx.head) 647 printf(" head"); 648 else 649 printf(" prev=%d", dump->sstatus[core][links].s_sstatus4_cn68xx.revlink_index); 650 if (dump->sstatus[core][links].s_sstatus4_cn68xx.tail) 651 printf(" tail"); 652 else 653 printf(" next=%d", dump->sstatus[core][links].s_sstatus4_cn68xx.link_index); 654 } 655 if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch) 656 { 657 printf(" pend_switch=%d", dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch); 658 } 659 660 if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_desched) 661 { 662 printf(" pend_desched=%d", dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_desched); 663 printf(" pend_nosched=%d", dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched); 664 } 665 if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_get_work) 666 { 667 if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_get_work_wait) 668 printf(" (Waiting for work)"); 669 else 670 printf(" (Getting work)"); 671 } 672 if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_alloc_we) 673 printf(" pend_alloc_we=%d", dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_alloc_we); 674 if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched_clr) 675 { 676 printf(" pend_nosched_clr=%d", dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched_clr); 677 printf(" pend_index=%d", dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_index); 678 } 679 if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch) 680 { 681 printf(" pending tag=%s,0x%08x", 682 OCT_TAG_TYPE_STRING(dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_type), 683 dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_tag); 684 } 685 if (dump->sstatus[core][pendwqp].s_sstatus1_cn68xx.pend_nosched_clr) 686 printf(" pend_wqp=0x%016llx\n", CAST64(dump->sstatus[core][pendwqp].s_sstatus1_cn68xx.pend_wqp)); 687 printf("\n"); 688 } 689 690 /* Print out the state of the nosched list and the 16 deschedule lists. */ 691 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED, dump, entry_list, 692 dump->sindexload[0][3].sindexload0_cn68xx.queue_val, 693 dump->sindexload[0][3].sindexload0_cn68xx.queue_one, 694 dump->sindexload[0][3].sindexload0_cn68xx.queue_head, 695 dump->sindexload[0][3].sindexload0_cn68xx.queue_tail); 696 for (index=0; index<64; index++) 697 { 698 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list, 699 dump->sindexload[index][2].sindexload0_cn68xx.queue_val, 700 dump->sindexload[index][2].sindexload0_cn68xx.queue_one, 701 dump->sindexload[index][2].sindexload0_cn68xx.queue_head, 702 dump->sindexload[index][2].sindexload0_cn68xx.queue_tail); 703 } 704 705 /* Print out the state of the 8 internal input queues */ 706 for (index=0; index<8; index++) 707 { 708 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list, 709 dump->sindexload[index][1].sindexload0_cn68xx.queue_val, 710 dump->sindexload[index][1].sindexload0_cn68xx.queue_one, 711 dump->sindexload[index][1].sindexload0_cn68xx.queue_head, 712 dump->sindexload[index][1].sindexload0_cn68xx.queue_tail); 713 } 714 715 /* Print out the state of the 16 memory queues */ 716 for (index=0; index<8; index++) 717 { 718 const char *name; 719 if (dump->sindexload[index][1].sindexload0_cn68xx.queue_head) 720 name = "Queue %da Memory (is head)"; 721 else 722 name = "Queue %da Memory"; 723 __cvmx_pow_display_list(name, index, 724 dump->sindexload[index][1].sindexload0_cn68xx.queue_val, 725 dump->sindexload[index][1].sindexload0_cn68xx.queue_one, 726 dump->sindexload[index][1].sindexload0_cn68xx.queue_head, 727 dump->sindexload[index][1].sindexload0_cn68xx.queue_tail); 728 if (dump->sindexload[index+8][1].sindexload0_cn68xx.queue_head) 729 name = "Queue %db Memory (is head)"; 730 else 731 name = "Queue %db Memory"; 732 __cvmx_pow_display_list(name, index, 733 dump->sindexload[index+8][1].sindexload0_cn68xx.queue_val, 734 dump->sindexload[index+8][1].sindexload0_cn68xx.queue_one, 735 dump->sindexload[index+8][1].sindexload0_cn68xx.queue_head, 736 dump->sindexload[index+8][1].sindexload0_cn68xx.queue_tail); 737 } 738 739 /* Print out each of the internal POW entries. Each entry has a tag, group, 740 wqe, and possibly a next pointer. The next pointer is only valid if this 741 entry isn't make as a tail */ 742 for (index=0; index<num_pow_entries; index++) 743 { 744 printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index, 745 __cvmx_pow_list_names[entry_list[index]], 746 OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload0_cn68xx.tag_type), 747 dump->smemload[index][1].s_smemload0_cn68xx.tag, 748 dump->smemload[index][2].s_smemload1_cn68xx.grp, 749 CAST64(dump->smemload[index][2].s_smemload1_cn68xx.wqp)); 750 if (dump->smemload[index][1].s_smemload0_cn68xx.tail) 751 printf(" tail"); 752 else 753 printf(" next=%d", dump->smemload[index][4].s_smemload3_cn68xx.fwd_index); 754 if (entry_list[index] >= CVMX_POW_LIST_DESCHED) 755 { 756 printf(" prev=%d", dump->smemload[index][4].s_smemload3_cn68xx.fwd_index); 757 printf(" nosched=%d", dump->smemload[index][1].s_smemload1_cn68xx.nosched); 758 if (dump->smemload[index][3].s_smemload2_cn68xx.pend_switch) 759 { 760 printf(" pending tag=%s,0x%08x", 761 OCT_TAG_TYPE_STRING(dump->smemload[index][3].s_smemload2_cn68xx.pend_type), 762 dump->smemload[index][3].s_smemload2_cn68xx.pend_tag); 763 } 764 } 765 printf("\n"); 766 } 767} 768 769/** 770 * Dump a POW capture to the console in a human readable format. 771 * 772 * @param buffer POW capture from cvmx_pow_capture() 773 * @param buffer_size 774 * Size of the buffer 775 */ 776void cvmx_pow_display(void *buffer, int buffer_size) 777{ 778 printf("POW Display Start\n"); 779 780 if (octeon_has_feature(OCTEON_FEATURE_PKND)) 781 __cvmx_pow_display_v2(buffer, buffer_size); 782 else 783 __cvmx_pow_display_v1(buffer, buffer_size); 784 785 printf("POW Display End\n"); 786 return; 787} 788 789