openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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, &regval));
    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, &regval));
    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