pp.c (24858B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: pp.c 8 * Purpose: Diagnostic helper routines 9 * Notes: Retrieve, check, or print Packet Pool table for Hercules 10 */ 11 12 /* 13 * This sequence of masks comes from an adaptation of the gen_ecc_table.cpp 14 * file in the hercules/rtl/pp directory. 15 * Inserting this code segment at line 132 (before the fclose) will 16 * produce the necessary numbers in the output file mmu_pp_ecc_gen_tbl.vh: 17 * 18 * fprintf (gen_fh, "\n") ; 19 * for (unsigned chkbit = 0; chkbit < NUM_CHK_BITS; chkbit++) { 20 * unsigned int chunks[6] = { 0, 0, 0, 0, 0, 0 }; 21 * fprintf (gen_fh, "ecc_xor_mask[%d] = { ", chkbit); 22 * for (int syn_idx = NUM_SYNDROMES-1; syn_idx >= 0; syn_idx--) { 23 * chunks[syn_idx/32] |= ((synd_list [syn_idx] >> chkbit) & 1) << (syn_idx % 32); 24 * } 25 * for (int ch_idx = 0; ch_idx < 6; ch_idx++) 26 * fprintf (gen_fh, "0x%08x, ", chunks[ch_idx]) ; 27 * fprintf (gen_fh, "};\n") ; 28 * } 29 */ 30 31 #include <sal/types.h> 32 #include <sal/core/boot.h> 33 #include <shared/bsl.h> 34 #include <soc/mem.h> 35 #include <soc/drv.h> 36 #include <soc/error.h> 37 #include <soc/hercules.h> 38 39 #include <appl/diag/pp.h> 40 41 static uint32 ecc_xor_mask[DIAG_PP_ECC_BITS][DIAG_PP_ECC_CHUNKS] = { 42 { 0xefdf7bb4, 0x9a46910f, 0xa769a476, 0x3b4d23dd, 43 0xef769eed, 0x00000103 }, 44 { 0xdfbef76a, 0x5525488f, 0x56d5526d, 0xb6aa93bb, 45 0xdeed5dda, 0x00000083 }, 46 { 0xbf7deed9, 0x2c93244f, 0xcdb2c95b, 0x6d964b76, 47 0xbddb3bb6, 0x00000043 }, 48 { 0x7efbddc7, 0xe388e22f, 0x3b8e38b8, 0xdc71c6ee, 49 0x7bb8f771, 0x00000823 }, 50 { 0xfdf7bc3f, 0xe0781e1e, 0xf87e0787, 0xc3f03de1, 51 0xf787ef0f, 0x00000412 }, 52 { 0xfbef83ff, 0x1ff801fd, 0xf801ff80, 0xc00ffc1f, 53 0xf07fe0ff, 0x00000209 }, 54 { 0xf7e07fff, 0x0007fffb, 0x07ffff80, 0x3ffffc00, 55 0x0fffe000, 0x00000e04 }, 56 { 0xf01fffff, 0xfffffff7, 0x0000007f, 0xfffffc00, 57 0x00001fff, 0x000001fc }, 58 { 0x0fffffff, 0xfffffff0, 0xffffffff, 0x000003ff, 59 0x00000000, 0x00000ffc } 60 }; 61 62 /* Masks to XOR a word into a bit */ 63 static uint32 compress_xor_mask[5] = { 64 0xaaaaaaaa, 0x44444444, 0x10101010, 0x01000100, 0x00010000 65 }; 66 67 /* 68 * Function: 69 * diag_mem_pp_word_check 70 * 71 * Description: 72 * Verify the ECC on a Hercules PP entry word. 73 * 74 * Parameters: 75 * unit - StrataSwitch PCI device unit number (driver internal). 76 * word_info - packet pool pre-digested word and syndrome info. 77 * address - entry address from which word sourced (needed for ECC). 78 * 79 * Returns: 80 * SOC_E_NONE Success 81 * SOC_E_INTERNAL Syndrome mismatch 82 * 83 * Notes: 84 */ 85 86 int 87 diag_mem_pp_word_check(int unit, diag_mem_pp_word_t *word_info, 88 int entry_addr) 89 { 90 uint32 synd_bit, chunk, cx; 91 uint32 xor_work, shift; 92 uint32 our_syndrome = 0; 93 94 COMPILER_REFERENCE(unit); 95 96 for (synd_bit = 0; synd_bit < DIAG_PP_ECC_BITS; synd_bit++) { 97 xor_work = 0; 98 for (chunk = 0; chunk < DIAG_PP_WORD_SIZE; chunk++) { 99 xor_work ^= word_info->data[chunk] & ecc_xor_mask[synd_bit][chunk]; 100 } 101 xor_work ^= entry_addr & 102 ecc_xor_mask[synd_bit][DIAG_PP_ECC_CHUNKS - 1]; 103 104 for (cx = 0, shift = 1; cx < 5; cx++, shift *= 2) { 105 xor_work ^= (xor_work & compress_xor_mask[cx]) >> shift; 106 } 107 108 our_syndrome |= (xor_work & 0x1) << synd_bit; 109 } 110 111 if ( our_syndrome != word_info->syndrome) { 112 /* Mismatch, now what? */ 113 /* return SOC_E_BAD_SYNDROME; */ 114 return SOC_E_INTERNAL; 115 } 116 117 return SOC_E_NONE; 118 } 119 120 /* 121 * Function: 122 * diag_mem_pp_word_decomp 123 * 124 * Description: 125 * Separate a PP entry into the four word structures. 126 * 127 * Parameters: 128 * unit - StrataSwitch PCI device unit number (driver internal). 129 * data - raw uint32 form of the PP entry 130 * entry - return structure for assembled data 131 * 132 * Returns: 133 * SOC_E_NONE Success 134 * SOC_E_INTERNAL Chip access failure 135 * 136 * Notes: 137 */ 138 139 int 140 diag_mem_pp_word_decomp(int unit, uint32 *data, 141 diag_mem_pp_entry_t *entry) 142 { 143 int ix, jx, dx = 0;; 144 145 for (ix = 0; ix < DIAG_PP_WORDS_PER_ENTRY; ix++) { 146 int shift = (ix * DIAG_PP_ECC_BITS); 147 uint32 word_mask = 0xffffffff >> shift; 148 for (jx = 0; jx < DIAG_PP_WORD_SIZE; jx++) { 149 entry->words[ix].data[jx] = ((data[dx] >> shift) & word_mask) | 150 ((data[dx + 1] << (32 - shift)) & ~word_mask); 151 dx++; 152 } 153 154 entry->words[ix].syndrome = 155 (data[dx] >> shift) & DIAG_PP_ECC_MASK; 156 } 157 158 /* Leftover adjustment for the last syndrome, which spans two uint32's */ 159 160 entry->words[DIAG_PP_WORDS_PER_ENTRY - 1].syndrome = 161 (entry->words[DIAG_PP_WORDS_PER_ENTRY - 1].syndrome & 0x1f) | 162 (data[dx] << 5); 163 164 return SOC_E_NONE; 165 } 166 167 /* 168 * Function: 169 * diag_mem_pp_byte_array 170 * 171 * Description: 172 * Convert decomposed PP entry into byte array. 173 * 174 * Parameters: 175 * unit - StrataSwitch PCI device unit number (driver internal). 176 * entry - return structure for assembled data 177 * data - uint8 return array 178 * 179 * Returns: 180 * SOC_E_NONE Success 181 * SOC_E_INTERNAL Chip access failure 182 * 183 * Notes: 184 */ 185 186 int 187 diag_mem_pp_byte_array(int unit, diag_mem_pp_entry_t *entry, uint8 *data) 188 { 189 int word_ptr, data_ptr, ret_ptr = 0; 190 uint32 data_bytes; 191 192 for (word_ptr = (DIAG_PP_WORDS_PER_ENTRY -1); word_ptr >= 0; word_ptr--) { 193 for (data_ptr = (DIAG_PP_WORD_SIZE - 1); data_ptr >= 0; data_ptr--) { 194 data_bytes = soc_htonl(entry->words[word_ptr]. 195 data[data_ptr]); 196 sal_memcpy(&data[ret_ptr], &data_bytes, 4); 197 ret_ptr += 4; 198 } 199 } 200 201 return SOC_E_NONE; 202 } 203 204 /* 205 * Function: 206 * diag_mem_pp_entry_check 207 * 208 * Description: 209 * Check ECC for the whole entry. 210 * 211 * Parameters: 212 * unit - StrataSwitch PCI device unit number (driver internal). 213 * entry - pre_digested words and syndromes 214 * address - entry address from which word sourced (needed for ECC). 215 * 216 * Returns: 217 * SOC_E_NONE Success 218 * SOC_E_INTERNAL Chip access failure 219 * 220 * Notes: 221 */ 222 223 int 224 diag_mem_pp_entry_check(int unit, diag_mem_pp_entry_t *entry, 225 int entry_addr) 226 { 227 int word; 228 229 for (word=0; word < DIAG_PP_WORDS_PER_ENTRY; word++) { 230 SOC_IF_ERROR_RETURN(diag_mem_pp_word_check(unit, &(entry->words[word]), 231 entry_addr)); 232 } 233 234 return SOC_E_NONE; 235 } 236 237 /* 238 * Function: 239 * diag_mem_pp_check 240 * 241 * Description: 242 * Check ECC for a range of the PP table. 243 * 244 * Parameters: 245 * unit - StrataSwitch PCI device unit number (driver internal). 246 * start - entry index to begin check 247 * end - entry index to finish check 248 * 249 * Returns: 250 * SOC_E_NONE Success 251 * SOC_E_XXX Various failures 252 * 253 * Notes: 254 */ 255 256 int 257 diag_mem_pp_check(int unit, int start, int end) 258 { 259 #ifdef BCM_HERCULES_SUPPORT 260 uint32 chip_entry[SOC_MAX_MEM_WORDS]; 261 diag_mem_pp_entry_t decomp_entry; 262 int ix; 263 int index_min = soc_mem_index_min(unit, MEM_PPm); 264 int index_max = soc_mem_index_max(unit, MEM_PPm); 265 266 if ( start < index_min ) { 267 start = index_min; 268 } 269 270 if ( end > index_max ) { 271 end = index_max; 272 } 273 274 for (ix = start; ix < end; ix++) { 275 int entry_addr = soc_mem_addr(unit, MEM_PPm, 0, 0, ix); 276 277 SOC_IF_ERROR_RETURN(READ_MEM_PPm(unit, 0, ix, chip_entry)); 278 279 SOC_IF_ERROR_RETURN(diag_mem_pp_word_decomp(unit, chip_entry, 280 &decomp_entry)); 281 SOC_IF_ERROR_RETURN(diag_mem_pp_entry_check(unit, &decomp_entry, 282 entry_addr)); 283 } 284 #endif 285 return SOC_E_NONE; 286 } 287 288 /* 289 * Function: 290 * diag_dump_xq_packet 291 * 292 * Purpose: 293 * Print the packet for an XQ entry in a given port. 294 * 295 * Parameters: 296 * unit - StrataSwitch PCI device unit number (driver internal). 297 * blk - selected block to dump XQ packets. 298 * xq_ptr - selected XQ entry indicating packet. 299 * 300 * Returns: 301 * SOC_E_NONE Success 302 * SOC_E_INTERNAL Chip access failure 303 * 304 * Notes: 305 */ 306 307 int 308 diag_dump_xq_packet(int unit, soc_block_t blk, int xq_ptr) 309 { 310 #ifdef BCM_HERCULES_SUPPORT 311 int offset, size, bytes, rv; 312 int pp_ptr, pp_data_p, pkt_data_p = 0; 313 uint32 read_data[SOC_MAX_MEM_WORDS]; 314 uint8 *pkt_data; 315 diag_mem_pp_entry_t dpp_entry; 316 uint8 pp_data[DIAG_PP_DATA_BYTES]; 317 318 319 SOC_IF_ERROR_RETURN(READ_MEM_XQm(unit, blk, xq_ptr, read_data)); 320 offset = soc_mem_field32_get(unit, MEM_XQm, read_data, OFFSETf); 321 bytes = size = soc_mem_field32_get(unit, MEM_XQm, read_data, SIZEf); 322 pp_ptr = soc_mem_field32_get(unit, MEM_XQm, read_data, PKTPTRf); 323 324 pkt_data = sal_alloc(size,"XQPacket"); 325 if (!pkt_data) { 326 return SOC_E_MEMORY; 327 } 328 329 while (bytes != 0) { 330 int copy_bytes = bytes; 331 332 rv = READ_MEM_PPm(unit, blk, pp_ptr, read_data); 333 if (SOC_FAILURE(rv)) { 334 sal_free(pkt_data); 335 return rv; 336 } 337 rv = diag_mem_pp_word_decomp(unit, read_data, &dpp_entry); 338 if (SOC_FAILURE(rv)) { 339 sal_free(pkt_data); 340 return rv; 341 } 342 343 rv = diag_mem_pp_byte_array(unit, &dpp_entry, pp_data); 344 if (SOC_FAILURE(rv)) { 345 sal_free(pkt_data); 346 return rv; 347 } 348 349 if (offset) { 350 pp_data_p = offset * DIAG_PP_XQ_OFFSET_BYTES; 351 } else { 352 pp_data_p = 0; 353 } 354 355 if (copy_bytes > (DIAG_PP_DATA_BYTES - pp_data_p)) { 356 copy_bytes = (DIAG_PP_DATA_BYTES - pp_data_p); 357 } 358 359 sal_memcpy(&(pkt_data[pkt_data_p]), &(pp_data[pp_data_p]), copy_bytes); 360 pkt_data_p += copy_bytes; 361 bytes -= copy_bytes; 362 363 if (bytes != 0) { 364 offset = 0; /* We've use this up */ 365 /* Follow to next PP entry */ 366 rv = READ_MEM_LLAm(unit, blk, pp_ptr, read_data); 367 if (SOC_FAILURE(rv)) { 368 sal_free(pkt_data); 369 return rv; 370 } 371 pp_ptr = soc_mem_field32_get(unit, MEM_LLAm, read_data, NEXTPTRf); 372 } 373 } 374 375 cli_out("XQ Packet: index[%d]\n", xq_ptr); 376 soc_dma_dump_pkt(unit, " ", pkt_data, size, TRUE); 377 cli_out("\tCRC(len-4) = 0x%08x; CRC(len) = 0x%08x\n", 378 ~_shr_crc32(~0, pkt_data, size - 4), 379 ~_shr_crc32(~0, pkt_data, size)); 380 381 sal_free(pkt_data); 382 #endif 383 return SOC_E_NONE; 384 } 385 386 /* 387 * Function: 388 * diag_dump_cos_packets 389 * 390 * Description: 391 * Print the packets for selected COS in a given port. 392 * 393 * Parameters: 394 * unit - StrataSwitch PCI device unit number (driver internal). 395 * port - selected port to dump XQ packets 396 * cos_start - begin with dumping this COS 397 * cos_end - finish with dumping this COS 398 * 399 * Returns: 400 * SOC_E_NONE Success 401 * SOC_E_INTERNAL Chip access failure 402 * 403 * Notes: 404 */ 405 406 int 407 diag_dump_cos_packets(int unit, soc_port_t port, int cos_start, int cos_end) 408 { 409 #ifdef BCM_HERCULES_SUPPORT 410 int cos, ptr_total, limit; 411 int num_cos = NUM_COS(unit); 412 int cos_read_ptr, cos_write_ptr, cos_ptr_wrap; 413 int cos_ptr_start[SOC_MAX_NUM_COS]; 414 int cos_ptr_end[SOC_MAX_NUM_COS]; 415 uint32 regval; 416 uint32 read_data[SOC_MAX_MEM_WORDS]; 417 int ptr_max = soc_mem_index_max(unit, MEM_XQm); 418 soc_block_t blk = SOC_PORT_BLOCK(unit, port); 419 420 ptr_total = 0; 421 cos_ptr_start[0] = -1; 422 /* Should this limit be cos_end? */ 423 for (cos = 0; cos < num_cos; cos++) { 424 SOC_IF_ERROR_RETURN(READ_MMU_PKTLMTCOS_UPPERr(unit, port, cos, ®val)); 425 limit = soc_reg_field_get(unit, MMU_PKTLMTCOS_UPPERr, regval, LIMITf); 426 427 if (limit != 0) { 428 if (ptr_total == 0) { 429 cos_ptr_start[cos] = 0; 430 } else { 431 cos_ptr_start[cos] = cos_ptr_end[cos - 1] + 1; 432 } 433 ptr_total += limit; 434 435 if (ptr_total > ptr_max) { 436 cos_ptr_end[cos] = ptr_max; 437 break; 438 } else { 439 cos_ptr_end[cos] = cos_ptr_start[cos] + limit - 1; 440 } 441 } else { 442 if (cos != 0) { 443 cos_ptr_end[cos] = cos_ptr_start[cos] = cos_ptr_end[cos - 1]; 444 } else { 445 cos_ptr_end[cos] = cos_ptr_start[cos]; 446 } 447 } 448 } 449 450 for (cos = cos_start; cos <= cos_end; cos++) { 451 SOC_IF_ERROR_RETURN(READ_MEM_XQ_PTRSm(unit, blk, cos, read_data)); 452 cos_read_ptr = 453 soc_mem_field32_get(unit, MEM_XQ_PTRSm, read_data, RDPTRf); 454 cos_write_ptr = 455 soc_mem_field32_get(unit, MEM_XQ_PTRSm, read_data, WRPTRf); 456 cos_ptr_wrap = 457 soc_mem_field32_get(unit, MEM_XQ_PTRSm, read_data, WRPTRWRAPf) != 458 soc_mem_field32_get(unit, MEM_XQ_PTRSm, read_data, RDPTRWRAPf); 459 460 if ((cos_read_ptr == cos_write_ptr) && !cos_ptr_wrap) { 461 /* Nothing in queue */ 462 continue; 463 } 464 465 do { 466 SOC_IF_ERROR_RETURN(diag_dump_xq_packet(unit, port, cos_read_ptr)); 467 468 cos_read_ptr++; 469 if (cos_read_ptr > cos_ptr_end[cos]) { 470 /* Wrap */ 471 cos_read_ptr = cos_ptr_start[cos]; 472 } 473 } while (cos_read_ptr != cos_write_ptr); 474 } 475 #endif 476 return SOC_E_NONE; 477 } 478 479 /* 480 * Function: 481 * diag_dump_ib_packet 482 * 483 * Description: 484 * Print the packet for the given port and ingress buffer range. 485 * 486 * Parameters: 487 * unit - StrataSwitch PCI device unit number (driver internal). 488 * blk - selected block to dump XQ packets. 489 * start - start index in Ingress Buffer 490 * end - end index in Ingress Buffer 491 * 492 * Returns: 493 * SOC_E_NONE Success 494 * SOC_E_INTERNAL Chip access failure 495 * 496 * Notes: 497 */ 498 499 int 500 diag_dump_ib_packet(int unit, soc_block_t blk, int start, int end, 501 int final_lanes) 502 { 503 #ifdef BCM_HERCULES_SUPPORT 504 uint32 read_data[SOC_MAX_MEM_WORDS]; 505 uint32 flipped_data[2]; 506 int ptr_max = soc_mem_index_max(unit, MEM_INGBUFm); 507 uint8 *pkt_data; 508 int size, read_ptr, pkt_data_p = 0; 509 510 511 if (end >= start) { 512 size = end - start + 1; 513 } else { 514 size = ptr_max - start + 1 + end; 515 } 516 517 size *= 8; 518 size -= final_lanes; 519 520 if (size > (9 * 1024)) { /* Jumbo packets are max size */ 521 cli_out("IngBuf Packet oversized, skipping range[%d,%d]\n", 522 start, end); 523 return SOC_E_NONE; 524 } 525 526 pkt_data = sal_alloc(size,"IBPacket"); 527 if (!pkt_data) { 528 return SOC_E_MEMORY; 529 } 530 531 read_ptr = start; 532 while (1) { 533 int rv; 534 535 if ((rv = (READ_MEM_INGBUFm(unit, blk, read_ptr, read_data))) < 0) { 536 sal_free(pkt_data); 537 return rv; 538 } 539 540 541 flipped_data[0] = read_data[1]; 542 flipped_data[1] = read_data[0]; 543 544 if (read_ptr == end) { 545 sal_memcpy(&(pkt_data[pkt_data_p]), flipped_data, 8 - final_lanes); 546 break; 547 } else { 548 sal_memcpy(&(pkt_data[pkt_data_p]), flipped_data, 8); 549 pkt_data_p += 8; 550 if (read_ptr == ptr_max) { 551 read_ptr = 0; 552 } else { 553 read_ptr++; 554 } 555 } 556 } 557 558 cli_out("IngBuf Packet: range[%d,%d]\n", start, end); 559 soc_dma_dump_pkt(unit, " ", pkt_data, size, TRUE); 560 sal_free(pkt_data); 561 #endif 562 return SOC_E_NONE; 563 } 564 565 /* 566 * Function: 567 * diag_dump_ib_packets 568 * 569 * Description: 570 * Print the packets buffered for a given port. 571 * 572 * Parameters: 573 * unit - StrataSwitch PCI device unit number (driver internal). 574 * port - selected port to dump Ingress Buffer packets 575 * 576 * Returns: 577 * SOC_E_NONE Success 578 * SOC_E_INTERNAL Chip access failure 579 * 580 * Notes: 581 */ 582 583 int 584 diag_dump_ib_packets(int unit, soc_port_t port) 585 { 586 #ifdef BCM_HERCULES_SUPPORT 587 uint32 read_data[SOC_MAX_MEM_WORDS]; 588 int ptr_max = soc_mem_index_max(unit, MEM_INGBUFm); 589 int start_index, end_index, wrap; 590 uint32 info_addr; 591 int blk = SOC_PORT_BLOCK(unit, port); 592 593 read_data[0] = 0; 594 start_index = 0; 595 wrap = FALSE; 596 while (!wrap) { 597 end_index = start_index; 598 do { 599 /* Only retrieve the info here */ 600 info_addr = soc_mem_addr(unit, MEM_INGBUFm, 0, blk, end_index) + 2; 601 SOC_IF_ERROR_RETURN(soc_hercules_mem_read_word( 602 unit, info_addr, read_data)); 603 604 if ((read_data[0] & DIAG_INGBUF_EOF_BIT) != 0) { 605 int final_lanes = read_data[0] & DIAG_INGBUF_LANES_MASK; 606 /* Dump the present packet */ 607 SOC_IF_ERROR_RETURN( 608 diag_dump_ib_packet(unit, blk, start_index, end_index, 609 final_lanes)); 610 start_index = end_index + 1; 611 break; 612 } else { 613 end_index++; 614 if (end_index > ptr_max ) { 615 end_index = 0; 616 wrap = TRUE; 617 } 618 } 619 } while (end_index != start_index); 620 } 621 #endif 622 return SOC_E_NONE; 623 } 624 625 /* 626 * Function: 627 * diag_set_xq_errors 628 * 629 * Purpose: 630 * Introduce errors for an XQ packet in a given port. 631 * 632 * Parameters: 633 * unit - StrataSwitch PCI device unit number (driver internal). 634 * blk - selected block to dump XQ packets. 635 * xq_ptr - selected XQ entry indicating packet. 636 * errors - number of bits to invert 637 * start_bit - first bit of the packet to trash 638 * 639 * Returns: 640 * SOC_E_NONE Success 641 * SOC_E_INTERNAL Chip access failure 642 * 643 * Notes: 644 */ 645 646 int 647 diag_set_xq_errors(int unit, soc_block_t blk, int xq_ptr, 648 int errors, int start_bit) 649 { 650 #ifdef BCM_HERCULES_SUPPORT 651 int offset, bytes; 652 int pp_ptr; 653 uint32 read_data[SOC_MAX_MEM_WORDS]; 654 int bit_bonus, the_chunk, the_word; 655 int entry_bit, entry_word; 656 int word_bit, word_addr; 657 soc_mem_info_t *meminfo = &SOC_MEM_INFO(unit, MEM_PPm); 658 659 SOC_IF_ERROR_RETURN(READ_MEM_XQm(unit, blk, xq_ptr, read_data)); 660 offset = soc_mem_field32_get(unit, MEM_XQm, read_data, OFFSETf); 661 bytes = soc_mem_field32_get(unit, MEM_XQm, read_data, SIZEf); 662 pp_ptr = soc_mem_field32_get(unit, MEM_XQm, read_data, PKTPTRf); 663 664 if (BYTES2BITS(bytes) < start_bit) { 665 start_bit = BYTES2BITS(bytes); 666 } 667 668 start_bit += offset * BYTES2BITS(DIAG_PP_XQ_OFFSET_BYTES); 669 670 while (start_bit > (DIAG_PP_WORD_BITS * DIAG_PP_WORDS_PER_ENTRY)) { 671 /* Follow to next PP entry */ 672 SOC_IF_ERROR_RETURN(READ_MEM_LLAm(unit, blk, pp_ptr, read_data)); 673 pp_ptr = soc_mem_field32_get(unit, MEM_LLAm, read_data, NEXTPTRf); 674 start_bit -= (DIAG_PP_WORD_BITS * DIAG_PP_WORDS_PER_ENTRY); 675 } 676 677 the_chunk = start_bit / DIAG_PP_WORD_BITS; 678 bit_bonus = (3 - the_chunk) * (DIAG_PP_WORD_BITS + DIAG_PP_ECC_BITS); 679 start_bit %= DIAG_PP_WORD_BITS; 680 681 the_word = BITS2WORDS(start_bit); 682 bit_bonus += WORDS2BITS(DIAG_PP_WORD_SIZE - the_word); 683 start_bit = 32 - (start_bit % 32); 684 685 entry_bit = start_bit + bit_bonus; 686 entry_word = entry_bit / 32; 687 word_bit = entry_bit % 32; 688 689 word_addr = soc_mem_addr(unit, MEM_PPm, 0, blk, 0) + 690 (pp_ptr * meminfo->gran) + entry_word; 691 692 /* Fun with A0 PP mem read problem */ 693 SOC_IF_ERROR_RETURN(soc_hercules_mem_read_word(unit, 694 word_addr, &(read_data[0]))); 695 SOC_IF_ERROR_RETURN(soc_hercules_mem_read_word(unit, 696 word_addr, &(read_data[0]))); 697 698 /* Do we need to endian swap the bytes? */ 699 while (errors--) { 700 read_data[0] ^= (1 << word_bit); 701 cli_out("Predicted error at entry %d, data word %d, bit %d\n", 702 pp_ptr, entry_bit / (DIAG_PP_WORD_BITS + DIAG_PP_ECC_BITS), 703 entry_bit % (DIAG_PP_WORD_BITS + DIAG_PP_ECC_BITS)); 704 entry_bit++; 705 word_bit--; 706 start_bit++; 707 if ( word_bit == 0 ) { 708 break; /* Give up crossing word-boundaries */ 709 } 710 if ( (start_bit % DIAG_PP_WORD_BITS) == 0 ) { 711 break; /* Give up crossing data-boundaries */ 712 } 713 } 714 715 SOC_IF_ERROR_RETURN(soc_hercules_mem_write_word(unit, 716 word_addr, &(read_data[0]))); 717 #endif 718 return SOC_E_NONE; 719 } 720 721 722 723 /* 724 * Function: 725 * diag_set_cos_errors 726 * 727 * Purpose: 728 * Introduce errors for XQ packets in selected COS's in a given port. 729 * 730 * Parameters: 731 * unit - StrataSwitch PCI device unit number (driver internal). 732 * port - selected port to trash XQ packets. 733 * cos_sel - COS to analyze 734 * errors - number of bits to invert 735 * packet - which packet number in the port/cos queue to trash 736 * start_bit - first bit of the packet to trash 737 * xq_ptr - selected XQ entry indicating packet. 738 * 739 * Returns: 740 * SOC_E_NONE Success 741 * SOC_E_INTERNAL Chip access failure 742 * 743 * Notes: 744 */ 745 746 int 747 diag_set_cos_errors(int unit, soc_port_t port, int cos_sel, 748 int errors, int packet, int start_bit) 749 { 750 #ifdef BCM_HERCULES_SUPPORT 751 int cos, ptr_total, limit; 752 int num_cos = NUM_COS(unit); 753 int cos_read_ptr, cos_write_ptr, cos_ptr_wrap; 754 int previous_cos_read_ptr; 755 int cos_ptr_start[SOC_MAX_NUM_COS]; 756 int cos_ptr_end[SOC_MAX_NUM_COS]; 757 uint32 regval; 758 uint32 read_data[SOC_MAX_MEM_WORDS]; 759 int ptr_max = soc_mem_index_max(unit, MEM_XQm); 760 int cur_pkt; 761 int blk = SOC_PORT_BLOCK(unit, port); 762 763 ptr_total = 0; 764 cos_ptr_start[0] = -1; 765 /* Should this limit be cos_end? */ 766 for (cos = 0; cos < num_cos; cos++) { 767 SOC_IF_ERROR_RETURN(READ_MMU_PKTLMTCOS_UPPERr(unit, port, cos, ®val)); 768 limit = soc_reg_field_get(unit, MMU_PKTLMTCOS_UPPERr, regval, LIMITf); 769 770 if (limit != 0) { 771 if (ptr_total == 0) { 772 cos_ptr_start[cos] = 0; 773 } else { 774 cos_ptr_start[cos] = cos_ptr_end[cos - 1] + 1; 775 } 776 ptr_total += limit; 777 778 if (ptr_total > ptr_max) { 779 cos_ptr_end[cos] = ptr_max; 780 break; 781 } else { 782 cos_ptr_end[cos] = cos_ptr_start[cos] + limit - 1; 783 } 784 } else { 785 if (cos != 0) { 786 cos_ptr_end[cos] = cos_ptr_start[cos] = cos_ptr_end[cos - 1]; 787 } else { 788 cos_ptr_end[cos] = cos_ptr_start[cos]; 789 } 790 } 791 } 792 793 cos = cos_sel; 794 SOC_IF_ERROR_RETURN(READ_MEM_XQ_PTRSm(unit, blk, cos, read_data)); 795 cos_read_ptr = 796 soc_mem_field32_get(unit, MEM_XQ_PTRSm, read_data, RDPTRf); 797 cos_write_ptr = 798 soc_mem_field32_get(unit, MEM_XQ_PTRSm, read_data, WRPTRf); 799 cos_ptr_wrap = 800 soc_mem_field32_get(unit, MEM_XQ_PTRSm, read_data, WRPTRWRAPf) != 801 soc_mem_field32_get(unit, MEM_XQ_PTRSm, read_data, RDPTRWRAPf); 802 803 if ((cos_read_ptr == cos_write_ptr) && !cos_ptr_wrap) { 804 /* Nothing in queue */ 805 return SOC_E_NONE; 806 } 807 808 cur_pkt = 0; 809 /* Note XQ used before current read pointer, reverse wrap if needed */ 810 if (cos_read_ptr == cos_ptr_start[cos]) { 811 previous_cos_read_ptr = cos_ptr_end[cos]; 812 } else { 813 previous_cos_read_ptr = cos_read_ptr - 1; 814 } 815 816 do { 817 if ( cur_pkt++ == packet ) { 818 SOC_IF_ERROR_RETURN(diag_set_xq_errors(unit, blk, 819 cos_read_ptr, 820 errors, start_bit)); 821 } 822 cos_read_ptr++; 823 if (cos_read_ptr > cos_ptr_end[cos]) { 824 /* Wrap */ 825 cos_read_ptr = cos_ptr_start[cos]; 826 } 827 } while (cos_read_ptr != cos_write_ptr); 828 829 /* The XQ memory does not latch the read it needs, thus reading it 830 * will probably corrupt the system. If we are only using one COS, 831 * then it is possible to fix this problem. 832 * Read to restore HW state to prevent pointer crash in XQ. 833 */ 834 SOC_IF_ERROR_RETURN(READ_MEM_XQm(unit, blk, 835 previous_cos_read_ptr, read_data)); 836 #endif 837 return SOC_E_NONE; 838 } 839