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

hercules.c (30675B)


      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:        hercules.c
      8  * Purpose:     Driver functions for 5670/5675
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <soc/hercules.h>
     14 #include <soc/higig.h>
     15 #include <soc/error.h>
     16 #include <shared/bsl.h>
     17 #include <soc/mem.h>
     18 #include <soc/debug.h>
     19 
     20 #ifdef BCM_HERCULES_SUPPORT
     21 
     22 STATIC int
     23 soc_hercules_uc_port_set(int unit, soc_port_t ingress_port, int modid, pbmp_t pbmp);
     24 STATIC int
     25 soc_hercules_vlan_port_init(int unit, soc_port_t ingress_port);
     26 STATIC int
     27 soc_hercules_vlan_port_init_all(int unit);
     28 STATIC int
     29 soc_hercules_vlan_port_set(int unit,
     30                       soc_port_t ingress_port, vlan_id_t vid, pbmp_t pbmp);
     31 STATIC int
     32 soc_hercules_mc_port_init(int unit, soc_port_t ingress_port);
     33 STATIC int
     34 soc_hercules_mc_port_init_all(int unit);
     35 STATIC int
     36 soc_hercules_mc_port_set(int unit, soc_port_t ingress_port, int mcidx, pbmp_t pbmp);
     37 STATIC int
     38 soc_hercules_mc_port_set_all(int unit, int mcidx, pbmp_t pbmp);
     39 STATIC int
     40 soc_hercules_port_mmu_init(int unit, int port);
     41 STATIC int
     42 soc_hercules_pie_init(int unit, int port, pbmp_t pbmp, int testmode);
     43 
     44 /*
     45  * ICM/Module Driver/API locals
     46  */
     47 
     48 #define VLAN_RANGE_CHECK(unit)\
     49     if (vid < soc_mem_index_min(unit, MEM_VIDm) ||\
     50         vid > soc_mem_index_max(unit, MEM_VIDm)) {\
     51         return SOC_E_BADID;\
     52     }
     53 #define MODID_RANGE_CHECK(unit)\
     54     if (modid < soc_mem_index_min(unit, MEM_UCm) ||\
     55         modid > soc_mem_index_max(unit, MEM_UCm)) {\
     56         return SOC_E_BADID;\
     57     }
     58 #define MCIDX_RANGE_CHECK(unit)\
     59     if (mcidx < soc_mem_index_min(unit, MEM_MCm) ||\
     60         mcidx > soc_mem_index_max(unit, MEM_MCm)) {\
     61         return SOC_E_BADID;\
     62     }
     63 
     64 /*
     65  * Hercules 1.5 chip driver functions.
     66  */
     67 soc_functions_t soc_hercules15_drv_funs = {
     68     soc_hercules_misc_init,
     69     soc_hercules_mmu_init,
     70     soc_hercules_age_timer_get,
     71     soc_hercules_age_timer_max_get,
     72     soc_hercules_age_timer_set,
     73 };
     74 
     75 int
     76 soc_hercules_misc_init(int unit)
     77 {
     78     uint32 reg, oreg;
     79     int use12G, eJitter, port;
     80 
     81     use12G = soc_property_get(unit, spn_CORE_CLOCK_12G, 0);
     82     READ_CMIC_RATE_ADJUSTr(unit, &reg);
     83     oreg = reg;
     84     soc_reg_field_set(unit, CMIC_RATE_ADJUSTr, &reg, DIVISORf,
     85                       (use12G ? 189 : 157));
     86     if (reg != oreg) {
     87         WRITE_CMIC_RATE_ADJUSTr(unit, reg);
     88     }
     89     eJitter = soc_property_get(unit, spn_MMU_HOL_JITTER, 0);
     90     PBMP_ALL_ITER(unit, port) {
     91         SOC_IF_ERROR_RETURN(READ_MMU_CFGr(unit, port, &reg));
     92         oreg = reg;
     93         soc_reg_field_set(unit, MMU_CFGr, &reg, JITTER_ENf,
     94                           eJitter ? 1 : 0);
     95         /* Enable parity generation and checking */
     96         soc_reg_field_set(unit, MMU_CFGr, &reg,
     97                           PARITY_DIAGf, (SAL_BOOT_SIMULATION) ? 0 : 1);
     98         if (reg != oreg) {
     99             SOC_IF_ERROR_RETURN(WRITE_MMU_CFGr(unit, port, reg));
    100         }
    101     }
    102     reg = 0;
    103     soc_reg_field_set(unit, ING_CTRL2r, &reg,
    104                       DISABLE_MIRROR_SRCMODBLKf, 1);
    105     PBMP_HG_ITER(unit, port) {
    106         SOC_IF_ERROR_RETURN(WRITE_ING_CTRL2r(unit, port, reg));
    107     }
    108 
    109     /*
    110      * The following tables should be initialized with Valid parity
    111      * before enabling parity error interrupts.
    112      * MEM_UCm
    113      * MEM_VIDm
    114      * MEM_INGBUFm - initialized by packet store operations.
    115      * MEM_MCm
    116      * MEM_IPMCm
    117      * MEM_ING_SRCMODBLKm
    118      * MEM_ING_MODMAPm
    119      * MEM_EGR_MODMAPm
    120      */
    121 
    122     return SOC_E_NONE;
    123 }
    124 
    125 
    126 /*
    127  * Initialize Hercules MMU Hardware
    128  * and setup module database definitions for API Layer.
    129  */
    130 int
    131 soc_hercules_mmu_init(int unit)
    132 {
    133     uint32      tmp;
    134     int         done, mod, port, rv;
    135     pbmp_t      pbmp_tmp;
    136     char        pfmt[SOC_PBMP_FMT_LEN];
    137     int         idx_min, idx_max;
    138     mem_ing_srcmodblk_entry_t   mod_blk;
    139 
    140     /* Only valid driver for interconnect devices */
    141     if (!SOC_IS_XGS_FABRIC(unit)) {
    142         return SOC_E_NONE;
    143     }
    144 
    145     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    146                 (BSL_META_U(unit,
    147                             "soc_hercules_mmu_init: unit %d\n"), unit));
    148 
    149     /* Initialize MMU in CMIC */
    150     rv = soc_hercules_port_mmu_init(unit, CMIC_PORT(unit));
    151     if (rv < 0) {
    152         LOG_CLI((BSL_META_U(unit,
    153                             "soc_hercules_mmu_init: CMIC MMU init failed.\n")));
    154     }
    155 
    156     /* Setup Hercules 10G Port Interface Controller Registers */
    157     PBMP_PORT_ITER(unit, port) {
    158         /* Initialize MMU per-port, set test mode on PLI */
    159         rv = soc_hercules_port_mmu_init(unit, port);
    160 
    161         if (rv < 0) {
    162             LOG_CLI((BSL_META_U(unit,
    163                                 "soc_hercules_mmu_init: "
    164                                 "MMU init failed (port %s).\n"),
    165                      SOC_PORT_NAME(unit, port)));
    166         }
    167 
    168         /* Initialize PIE per-port */
    169         rv = soc_hercules_pie_init(unit, port,
    170                                    PBMP_ALL(unit), SAL_BOOT_PLISIM);
    171         if (rv < 0) {
    172             LOG_CLI((BSL_META_U(unit,
    173                                 "soc_hercules_mmu_init: "
    174                                 "Ingress/Egress init failed (port %s).\n"),
    175                      SOC_PORT_NAME(unit, port)));
    176         }
    177     }
    178 
    179     /* Wait for H/W to finish initializing itself
    180      * NOTE: this is several microseconds, so you would need
    181      * a really fast processor to ever see this error, but we
    182      * do this to synchronize with the H/W to be safe.
    183      */
    184     if (!SAL_BOOT_PLISIM) {
    185         PBMP_PORT_ITER(unit, port) {
    186             do {
    187                 SOC_IF_ERROR_RETURN(
    188                     READ_MMU_ERRSTATr(unit, port, &tmp));
    189                 done = soc_reg_field_get(unit, MMU_ERRSTATr, tmp, HW_INITf);
    190                 if (!done)
    191                     LOG_CLI((BSL_META_U(unit,
    192                                         "Notice: HW initializing (port %s)\n"),
    193                              SOC_PORT_NAME(unit, port)));
    194             } while (!done);
    195         }
    196     }
    197 
    198     /*
    199      * Should ideally move to misc_init. Init below also genarates the correct
    200      * parity bits for the following tables
    201      *
    202      * The following tables should be initialized with Valid parity
    203      * before enabling parity error interrupts.
    204      * MEM_UCm
    205      * MEM_VIDm
    206      * MEM_INGBUFm - initialized by packet store operations.
    207      * MEM_MCm
    208      * MEM_ING_MODMAPm
    209      * MEM_EGR_MODMAPm
    210      * MEM_IPMCm
    211      * MEM_ING_SRCMODBLKm
    212      *
    213      *
    214      * Zero Module ID table.
    215  */
    216     SOC_PBMP_CLEAR(pbmp_tmp);
    217     idx_min = soc_mem_index_min(unit, MEM_UCm);
    218     idx_max = soc_mem_index_max(unit, MEM_UCm);
    219     mod = 0;
    220 
    221     if (!SAL_BOOT_SIMULATION) {
    222         for (mod = idx_min; mod <= idx_max; mod++) {
    223             rv = soc_hercules_uc_port_set_all(unit, mod, pbmp_tmp);
    224             if (rv < 0) break;
    225         }
    226     } else {
    227             rv = soc_hercules_uc_port_set_all(unit, mod, PBMP_CMIC(unit));
    228     }
    229 
    230     if (rv < 0) {
    231         LOG_CLI((BSL_META_U(unit,
    232                             "soc_hercules_mmu_init: "
    233                             "set UC[MH.MODID=%d] to %s failed.\n"),
    234                  mod, SOC_PBMP_FMT(PBMP_ALL(unit), pfmt)));
    235     }
    236 
    237     /* Flush VLAN table */
    238     if (!SAL_BOOT_SIMULATION) { /* Way too slow for sim */
    239         rv = soc_hercules_vlan_port_init_all(unit);
    240         if (rv < 0) {
    241             LOG_CLI((BSL_META_U(unit,
    242                                 "ERROR: clearing VLAN tables failed.\n")));
    243         }
    244     }
    245 
    246     /* VLAN / DLF Packets (CPU) VID=0 */
    247     rv = soc_hercules_vlan_port_set_all(unit, 0, PBMP_CMIC(unit));
    248     if (rv < 0) {
    249         LOG_CLI((BSL_META_U(unit,
    250                             "soc_hercules_mmu_init: "
    251                             "set VID[MH.MODID=%d] to %s failed.\n"),
    252                  VLAN_ID_DEFAULT, SOC_PBMP_FMT(PBMP_ALL(unit), pfmt)));
    253     }
    254 
    255     /* VLAN / DLF Packets (VID=1) */
    256     rv = soc_hercules_vlan_port_set_all(unit, VLAN_ID_DEFAULT, PBMP_ALL(unit));
    257     if (rv < 0) {
    258         LOG_CLI((BSL_META_U(unit,
    259                             "soc_hercules_mmu_init: "
    260                             "set VID[MH.MODID=%d] to %s failed.\n"),
    261                  VLAN_ID_DEFAULT, SOC_PBMP_FMT(PBMP_ALL(unit), pfmt)));
    262     }
    263 
    264     /* MC / IPMC DLF Packets */
    265     if (!SAL_BOOT_SIMULATION) { /* Way too slow for sim */
    266         rv = soc_hercules_mc_port_init_all(unit);
    267         if (rv < 0) {
    268             LOG_CLI((BSL_META_U(unit,
    269                                 "ERROR: clearing MC tables failed.\n")));
    270         }
    271     }
    272 
    273     /* MC / IPMC DLF Packets */
    274     rv = soc_hercules_mc_port_set_all(unit, SOC_HIGIG_DST_MOD_CPU,
    275                                  PBMP_ALL(unit));
    276     if (rv < 0) {
    277         LOG_CLI((BSL_META_U(unit,
    278                             "soc_hercules_mmu_init: "
    279                             "set MC[MH.MODID=%d] to %s failed.\n"),
    280                  SOC_HIGIG_DST_MOD_CPU,
    281                  SOC_PBMP_FMT(PBMP_ALL(unit), pfmt)));
    282     }
    283 
    284     rv = soc_mem_clear(unit, MEM_ING_MODMAPm, MEM_BLOCK_ALL, TRUE);
    285     if (rv < 0) {
    286         LOG_CLI((BSL_META_U(unit,
    287                             "soc_hercules_mmu_init: ING_MODMAP clear failed\n")));
    288     }
    289     rv = soc_mem_clear(unit, MEM_EGR_MODMAPm, MEM_BLOCK_ALL, TRUE);
    290     if (rv < 0) {
    291         LOG_CLI((BSL_META_U(unit,
    292                             "soc_hercules_mmu_init: EGR_MODMAP clear failed\n")));
    293     }
    294     rv = soc_mem_clear(unit, MEM_TRUNK_PORT_POOLm, MEM_BLOCK_ALL, TRUE);
    295     if (rv < 0) {
    296         LOG_CLI((BSL_META_U(unit,
    297                             "soc_hercules_mmu_init: TRUNK_PORT_POOL clear failed\n")));
    298     }
    299     rv = soc_mem_clear(unit, MEM_IPMCm, MEM_BLOCK_ALL, TRUE);
    300     if (rv < 0) {
    301         LOG_CLI((BSL_META_U(unit,
    302                             "soc_hercules_mmu_init: IPMC clear failed\n")));
    303     }
    304 
    305     sal_memset(&mod_blk, 0, sizeof(mod_blk));
    306     soc_mem_field32_set(unit, MEM_ING_SRCMODBLKm, &mod_blk,
    307                         BITMAPf, SOC_PBMP_WORD_GET(PBMP_ALL(unit), 0));
    308 
    309     idx_min = soc_mem_index_min(unit, MEM_ING_SRCMODBLKm);
    310     idx_max = soc_mem_index_max(unit, MEM_ING_SRCMODBLKm);
    311     for (mod = idx_min; mod <= idx_max; mod++) {
    312         rv = soc_mem_write(unit, MEM_ING_SRCMODBLKm, MEM_BLOCK_ALL,
    313                            mod, &mod_blk);
    314         if (rv < 0) {
    315             LOG_CLI((BSL_META_U(unit,
    316                                 "soc_hercules_mmu_init: ING_SRCMODBLK init failed\n")));
    317             break;
    318         }
    319     }
    320     PBMP_ALL_ITER(unit, port) {
    321         /* Clear any outstanding parity error notification */
    322         SOC_IF_ERROR_RETURN(
    323             WRITE_MMU_INTCLRr(unit, port, SOC_ERR_HAND_MMU_ALL_H15));
    324     }
    325 
    326     /* Prep MMU error handling */
    327     SOC_IF_ERROR_RETURN(soc_mmu_error_init(unit));
    328 
    329     return rv;
    330 }
    331 
    332 int
    333 soc_hercules_age_timer_get(int unit, int *age_seconds, int *enabled)
    334 {
    335     COMPILER_REFERENCE(unit);
    336     COMPILER_REFERENCE(age_seconds);
    337     COMPILER_REFERENCE(enabled);
    338 
    339     return SOC_E_NONE;
    340 }
    341 
    342 int
    343 soc_hercules_age_timer_set(int unit, int age_seconds, int enabled)
    344 {
    345     COMPILER_REFERENCE(unit);
    346     COMPILER_REFERENCE(age_seconds);
    347     COMPILER_REFERENCE(enabled);
    348 
    349     return SOC_E_NONE;
    350 }
    351 
    352 int
    353 soc_hercules_age_timer_max_get(int unit, int *max_seconds)
    354 {
    355     COMPILER_REFERENCE(unit);
    356     COMPILER_REFERENCE(max_seconds);
    357 
    358     *max_seconds = 0x7fffffff; /* Use max int for BCMX purposes */
    359 
    360     return SOC_E_NONE;
    361 }
    362 
    363 
    364 /*
    365  * Function:
    366  *      soc_hercules_mem_read
    367  * Purpose:
    368  *      Read a Hercules word addressed memory internal to the SOC.
    369  * Notes:
    370  *      This should only be used for hercules.
    371  */
    372 
    373 int
    374 soc_hercules_mem_read(int unit,
    375              soc_mem_t mem,
    376              int copyno,
    377              int index,
    378              void *entry_data)
    379 {
    380     uint32 entry_addr;
    381     soc_mem_info_t *meminfo = &SOC_MEM_INFO(unit, mem);
    382     int entry_words, word;
    383     uint32 *data = (uint32 *)entry_data;
    384 
    385     entry_words = soc_mem_entry_words(unit, mem);
    386 
    387     entry_addr = soc_mem_addr(unit, mem, 0, copyno, 0);
    388     entry_addr += index * meminfo->gran;
    389 
    390     if (mem == MEM_PPm && !soc_feature(unit, soc_feature_fabric_debug)) {
    391         /* Workaround for A0 problem */
    392         SOC_IF_ERROR_RETURN(soc_hercules_mem_read_word(unit,
    393                                 entry_addr, &(data[0])));
    394     }
    395 
    396     for (word = 0; word < entry_words; word++) {
    397         SOC_IF_ERROR_RETURN(soc_hercules_mem_read_word(unit,
    398                                 entry_addr + word, &(data[word])));
    399     }
    400 
    401     if (NULL != meminfo->snoop_cb && 
    402         (SOC_MEM_SNOOP_READ & meminfo->snoop_flags)) {
    403         meminfo->snoop_cb(unit, mem, SOC_MEM_SNOOP_READ, copyno, index, index, 
    404                            entry_data, meminfo->snoop_user_data);
    405     }
    406     return SOC_E_NONE;
    407 }
    408 
    409 /*
    410  * Function:
    411  *      soc_hercules_mem_read_word
    412  * Purpose:
    413  *      Read a memory word internal to the SOC.
    414  * Notes:
    415  *      This should only be used for hercules.
    416  */
    417 
    418 int
    419 soc_hercules_mem_read_word(int unit, uint32 addr, void *word_data)
    420 {
    421     schan_msg_t schan_msg;
    422     int src_blk;
    423     int opcode;
    424 
    425     /* Setup S-Channel command packet */
    426     schan_msg_clear(&schan_msg);
    427     src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit));
    428     soc_schan_header_cmd_set(unit, &schan_msg.header, READ_MEMORY_CMD_MSG,
    429                              0, src_blk, 0, 4, 0, 0);  
    430 
    431     schan_msg.readcmd.address = addr;
    432 
    433     /*
    434      * Write onto S-Channel "memory read" command packet consisting of header
    435      * word + address word, and read back header word + entry_dw data words.
    436      */
    437     SOC_IF_ERROR_RETURN(soc_schan_op(unit, &schan_msg, 2, 2, 0));
    438 
    439     /* Check result */
    440     soc_schan_header_status_get(unit, &schan_msg.header, &opcode, NULL, NULL,
    441                                 NULL, NULL, NULL);
    442     if (opcode != READ_MEMORY_ACK_MSG) {
    443         LOG_ERROR(BSL_LS_SOC_COMMON,
    444                   (BSL_META_U(unit,
    445                               "soc_hercules_mem_read_word: "
    446                               "invalid S-Channel reply, expected READ_MEMORY_ACK:\n")));
    447         soc_schan_dump(unit, &schan_msg, 2);
    448         return SOC_E_INTERNAL;
    449     }
    450 
    451     sal_memcpy(word_data,
    452                schan_msg.readresp.data,
    453                sizeof (uint32));
    454 
    455     if (bsl_check(bslLayerSoc, bslSourceMem, bslSeverityNormal, unit)) {
    456         LOG_CLI((BSL_META_U(unit,
    457                             "soc_hercules_mem_read_word: u=%d: "
    458                             "addr=0x%08x: value=0x%08x\n"),
    459                  unit, addr, *(uint32 *)word_data));
    460     }
    461     return SOC_E_NONE;
    462 }
    463 
    464 /*
    465  * Function:
    466  *      soc_hercules_mem_write
    467  * Purpose:
    468  *      Write a Hercules word addressed memory internal to the SOC.
    469  * Notes:
    470  *      This should only be used for hercules.
    471  */
    472 
    473 int
    474 soc_hercules_mem_write(int unit,
    475              soc_mem_t mem,
    476              int copyno,
    477              int index,
    478              void *entry_data)
    479 {
    480     uint32 entry_addr;
    481     int entry_words, word;
    482     uint32 *data = (uint32 *)entry_data;
    483     soc_mem_info_t *meminfo = &SOC_MEM_INFO(unit, mem);
    484     int blk;
    485 
    486     entry_words = soc_mem_entry_words(unit, mem);
    487 
    488     if (copyno != COPYNO_ALL) {
    489         if (!SOC_MEM_BLOCK_VALID(unit, mem, copyno)) {
    490             LOG_WARN(BSL_LS_SOC_COMMON,
    491                      (BSL_META_U(unit,
    492                                  "soc_hercules_mem_write: "
    493                                  "invalid copy %d for table %s\n"),
    494                       copyno, SOC_MEM_NAME(unit, mem)));
    495             return SOC_E_PARAM;
    496         }
    497     }
    498 
    499     /* Write to one or all copies of the memory */
    500     SOC_MEM_BLOCK_ITER(unit, mem, blk) {
    501         if (copyno != COPYNO_ALL && copyno != blk) {
    502             continue;
    503         }
    504 
    505         entry_addr = soc_mem_addr(unit, mem, 0, blk, 0);
    506         entry_addr += index * meminfo->gran;
    507 
    508         for (word = 0; word < entry_words; word++) {
    509             SOC_IF_ERROR_RETURN(soc_hercules_mem_write_word(unit,
    510                                     entry_addr + word, &(data[word])));
    511         }
    512     }
    513 
    514     if (NULL != meminfo->snoop_cb && 
    515         (SOC_MEM_SNOOP_WRITE & meminfo->snoop_flags)) {
    516         meminfo->snoop_cb(unit, mem, SOC_MEM_SNOOP_WRITE, copyno, index, index,
    517                           entry_data, meminfo->snoop_user_data);
    518     }
    519 
    520     return SOC_E_NONE;
    521 }
    522 
    523 /*
    524  * Function:
    525  *      soc_hercules_mem_write_word
    526  * Purpose:
    527  *      Write a memory word internal to the SOC.
    528  * Notes:
    529  */
    530 
    531 int
    532 soc_hercules_mem_write_word(int unit, uint32 addr, void *word_data)
    533 {
    534     schan_msg_t schan_msg;
    535     int src_blk;
    536 
    537     /*
    538      * Setup S-Channel command packet
    539      *
    540      * NOTE: the datalen field matters only for the Write Memory and
    541      * Write Register commands, where it is used only by the CMIC to
    542      * determine how much data to send, and is in units of bytes.
    543      */
    544 
    545     schan_msg_clear(&schan_msg);
    546     src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit));
    547     soc_schan_header_cmd_set(unit, &schan_msg.header, WRITE_MEMORY_CMD_MSG,
    548                              0, src_blk, 0, 4, 0, 0);  
    549     schan_msg.writecmd.address = addr;
    550 
    551     sal_memcpy(schan_msg.writecmd.data,
    552                word_data,
    553                sizeof (uint32));
    554 
    555     if (bsl_check(bslLayerSoc, bslSourceMem, bslSeverityNormal, unit)) {
    556         LOG_CLI((BSL_META_U(unit,
    557                             "soc_hercules_mem_write_word: u=%d: "
    558                             "addr=0x%08x: value=0x%08x\n"),
    559                  unit, addr, *(uint32 *)word_data));
    560     }
    561 
    562     /* Write header + address + entry_dw data DWORDs */
    563     /* Note: The hardware does not send WRITE_MEMORY_ACK_MSG. */
    564     SOC_IF_ERROR_RETURN(soc_schan_op(unit, &schan_msg,
    565                                      3, 0, 0));
    566 
    567     return SOC_E_NONE;
    568 }
    569 
    570 
    571 /*
    572  * Setup all ingress ports for a UNICAST entry to flood to the given port
    573  * bitmap
    574  */
    575 int
    576 soc_hercules_uc_port_set_all(int unit, int modid, pbmp_t pbmp)
    577 {
    578     int port;
    579 
    580     PBMP_PORT_ITER(unit, port) {
    581         SOC_IF_ERROR_RETURN(soc_hercules_uc_port_set(unit, port, modid, pbmp));
    582     }
    583     return SOC_E_NONE;
    584 }
    585 
    586 /*
    587  * Update all DLF/Broadcast (VID) table entries specifying the flood group
    588  * bitmaps for the given VLAN ID (VID).
    589  */
    590 int
    591 soc_hercules_vlan_port_set_all(int unit, vlan_id_t vid, pbmp_t pbmp)
    592 {
    593     int port;
    594 
    595     PBMP_PORT_ITER(unit, port) {
    596         SOC_IF_ERROR_RETURN(soc_hercules_vlan_port_set(unit, port, vid, pbmp));
    597     }
    598     return SOC_E_NONE;
    599 }
    600 
    601 /*
    602  * Configure a Hercules port's packet and cell limits.
    603  */
    604 
    605 int
    606 soc_hercules15_mmu_limits_config(int unit, int port, int num_ports,
    607 				 int num_cos, int lossless)
    608 {
    609     int cos, xq_entries, hysteresis;
    610     soc_port_t other_port;
    611     uint32 lla_cells;
    612     uint32 lla_cells_good = SOC_CONTROL(unit)->lla_cells_good[port];
    613 
    614     assert(num_cos > 0 && num_cos <= NUM_COS(unit));
    615 
    616     /*
    617      * Allowing for future decrease in the max XQ used.
    618      * NB:  Use one less than the total number of entries, as
    619      * pktlmting is one bit too small to handle the full size of XQ.
    620      */
    621     xq_entries = soc_mem_index_max(unit, MEM_XQm) -
    622                  soc_mem_index_min(unit, MEM_XQm);
    623 
    624     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    625                 (BSL_META_U(unit,
    626                             "soc_hercules15_mmu_limits_config: "
    627                             "unit=%d port=%s nports=%d ncos=%d loss%s\n"),
    628                  unit, SOC_PORT_NAME(unit, port),
    629                  num_ports, num_cos, lossless ? "y" : "less"));
    630 
    631     /* Set up COS specific registers per port */
    632 
    633    hysteresis = soc_property_get(unit, spn_MMU_HOL_HYSTERESIS, 0);
    634 
    635     for (cos = 0; cos < NUM_COS(unit); cos++) {
    636         if (cos < num_cos) {
    637             /* Packet Limit / COS */
    638             SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTCOS_UPPERr(unit, port, cos,
    639                                                      xq_entries / num_cos));
    640             SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTCOS_LOWERr(unit, port, cos,
    641                    hysteresis ? ((xq_entries / num_cos)- (xq_entries / num_cos / 50))
    642                               : (xq_entries / num_cos)));
    643             /* Cell Limit / COS */
    644             lla_cells = (hysteresis) ?
    645 		((lla_cells_good / num_cos) - (lla_cells_good / num_cos / 50))
    646 		: (lla_cells_good / num_cos);
    647             SOC_IF_ERROR_RETURN(WRITE_MMU_CELLLMTCOS_UPPERr(unit, port, cos,
    648                    lossless ? lla_cells_good : (lla_cells_good / num_cos)));
    649             SOC_IF_ERROR_RETURN(WRITE_MMU_CELLLMTCOS_LOWERr(unit, port, cos, 
    650                    lossless ? lla_cells_good : lla_cells));
    651         } else {
    652             /* Packet Limit / COS */
    653             SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTCOS_UPPERr(unit, port, cos, 0));
    654             SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTCOS_LOWERr(unit, port, cos, 0));
    655             /* Cell Limit / COS */
    656             SOC_IF_ERROR_RETURN(WRITE_MMU_CELLLMTCOS_UPPERr(unit, port, cos, 0));
    657             SOC_IF_ERROR_RETURN(WRITE_MMU_CELLLMTCOS_LOWERr(unit, port, cos, 0));
    658         }
    659     }
    660 
    661     if (lossless) { /* Lossless mode */
    662         assert(num_ports > 0);
    663 
    664         PBMP_ALL_ITER(unit, other_port) {
    665             /* Diagonals don't exist for these registers. */
    666             if (other_port != port) {
    667                 /* Per Ingress Packet Limit / Port / COS (less 2 packets margin) */
    668                 SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTINGr(unit, port,
    669                                           other_port,
    670                                           xq_entries / num_ports / num_cos - 2));
    671 
    672                 /* Per Ingress Cell Limit / Port (less 3 cells margin) */
    673                 SOC_IF_ERROR_RETURN(
    674                        WRITE_MMU_CELLLMTINGr(unit, port, other_port,
    675                                              lla_cells_good / num_ports - 3));
    676                 /* Note:  We've pulled a fast one here.  NUM_PORT does not
    677                  * include the CMIC, so it is one short of all of the ports
    678                  * that we are studying here.  However, since we want to skip
    679                  * the port itself, it works out.  For now. -jwd
    680                  */
    681             }
    682         }
    683    } else { /* Throughput or "Lossy" mode */
    684         PBMP_ALL_ITER(unit, other_port) {
    685             /* Diagonals don't exist for these registers. */
    686             if (other_port != port) {
    687                 /* All XQ entries */
    688                 SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTINGr(unit, port,
    689                                           other_port, xq_entries));
    690 
    691                 /* All good LLA/PP */
    692                 SOC_IF_ERROR_RETURN(
    693                        WRITE_MMU_CELLLMTINGr(unit, port, other_port,
    694                                              lla_cells_good));
    695             }
    696         }
    697     }
    698 
    699     if (IS_HG_PORT(unit, port)) {  /* CMIC has no ING_CTRLr */
    700         uint32 reg, oreg;
    701         SOC_IF_ERROR_RETURN(READ_ING_CTRLr(unit, port, &reg));
    702         oreg = reg;
    703         /* Mark this lossless */
    704         soc_reg_field_set(unit, ING_CTRLr, &reg, LOSSLESSENf,
    705                           (lossless ? 1 : 0));
    706         if (reg != oreg) {
    707             SOC_IF_ERROR_RETURN(WRITE_ING_CTRLr(unit, port, reg));
    708         }
    709     }
    710 
    711     return SOC_E_NONE;
    712 }
    713 
    714 /*
    715  * Set a Unicast(UC) table entry specifying the forwarding egress port
    716  * bitmap for the ingress port and module ID.
    717  *
    718  * Note: Port zero is not the first port, but rather the CMIC port.
    719  */
    720 STATIC int
    721 soc_hercules_uc_port_set(int unit, soc_port_t ingress_port, int modid,
    722 			 pbmp_t pbmp)
    723 {
    724     mem_uc_entry_t uc;
    725     char pfmt[SOC_PBMP_FMT_LEN];
    726 
    727     MODID_RANGE_CHECK(unit);
    728     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    729                 (BSL_META_U(unit,
    730                             "soc_hercules_uc_port_set: unit=%d port=%s modid=%d pbmp=%s\n"),
    731                  unit, SOC_PORT_NAME(unit, ingress_port), modid,
    732                  SOC_PBMP_FMT(pbmp, pfmt)));
    733     sal_memset(&uc, 0, sizeof(uc));
    734     soc_MEM_UCm_field32_set(unit, &uc, UCBITMAPf, SOC_PBMP_WORD_GET(pbmp, 0));
    735     return WRITE_MEM_UCm(unit, SOC_PORT_BLOCK(unit, ingress_port),
    736                        modid, &uc);
    737 }
    738 
    739 /*
    740  * Flush out the VLAN table at inital startup
    741  */
    742 STATIC int
    743 soc_hercules_vlan_port_init(int unit, soc_port_t ingress_port)
    744 {
    745     mem_vid_entry_t vdata;
    746     int vid, vid_min, vid_max, blk;
    747 
    748     vid_min = soc_mem_index_min(unit, MEM_VIDm);
    749     vid_max = soc_mem_index_max(unit, MEM_VIDm);
    750     blk = SOC_PORT_BLOCK(unit, ingress_port);
    751 
    752     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    753                 (BSL_META_U(unit,
    754                             "soc_hercules_vlan_port_init: unit=%d port=%s\n"),
    755                  unit, SOC_PORT_NAME(unit, ingress_port)));
    756     sal_memset(&vdata, 0, sizeof(mem_vid_entry_t));
    757 
    758     for (vid = vid_min; vid <= vid_max; vid++) {
    759         SOC_IF_ERROR_RETURN(WRITE_MEM_VIDm(unit, blk, vid, &vdata));
    760     }
    761     return SOC_E_NONE;
    762 }
    763 
    764 /*
    765  * Same operation as above, applied to all ports.
    766  */
    767 STATIC int
    768 soc_hercules_vlan_port_init_all(int unit)
    769 {
    770     int port;
    771 
    772     PBMP_PORT_ITER(unit, port) {
    773         SOC_IF_ERROR_RETURN(soc_hercules_vlan_port_init(unit, port));
    774     }
    775     return SOC_E_NONE;
    776 }
    777 
    778 /*
    779  * Update a DLF/Broadcast (VID) table entry specifying the flood group
    780  * bitmap for the given VLAN ID (VID).
    781  */
    782 STATIC int
    783 soc_hercules_vlan_port_set(int unit,
    784 			   soc_port_t ingress_port, vlan_id_t vid, pbmp_t pbmp)
    785 {
    786     int blk;
    787     mem_vid_entry_t vdata;
    788     char pfmt[SOC_PBMP_FMT_LEN];
    789 
    790     VLAN_RANGE_CHECK(unit);
    791     blk = SOC_PORT_BLOCK(unit, ingress_port);
    792     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    793                 (BSL_META_U(unit,
    794                             "soc_hercules_vlan_port_set: unit=%d port=%s vid=%d pbmp=%s\n"),
    795                  unit, SOC_PORT_NAME(unit, ingress_port),
    796                  vid, SOC_PBMP_FMT(pbmp, pfmt)));
    797     sal_memset(&vdata, 0, sizeof(vdata));
    798     soc_MEM_VIDm_field32_set(unit, &vdata, VIDBITMAPf,
    799                              SOC_PBMP_WORD_GET(pbmp, 0));
    800     return WRITE_MEM_VIDm(unit, blk, vid, &vdata);
    801 }
    802 
    803 /*
    804  * Init a Multicast/IP Multicast (MC) table entry specifying the flood group
    805  * bitmap for the given Multicast index and port number.
    806  *
    807  * The MCBITMAP and IPMCBITMAP are both updated with the specified
    808  * bitmap at the given index into the MC table.
    809  */
    810 STATIC int
    811 soc_hercules_mc_port_init(int unit, soc_port_t ingress_port)
    812 {
    813     mem_mc_entry_t mcdata;
    814     int mcidx, mcidx_min, mcidx_max, blk;
    815 
    816     mcidx_min = soc_mem_index_min(unit, MEM_MCm);
    817     mcidx_max = soc_mem_index_max(unit, MEM_MCm);
    818     blk = SOC_PORT_BLOCK(unit, ingress_port);
    819     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    820                 (BSL_META_U(unit,
    821                             "soc_hercules_mc_port_init: unit=%d port=%s\n"),
    822                  unit, SOC_PORT_NAME(unit, ingress_port)));
    823     sal_memset(&mcdata, 0, sizeof(mem_mc_entry_t));
    824     for (mcidx = mcidx_min; mcidx <= mcidx_max; mcidx++) {
    825         SOC_IF_ERROR_RETURN(WRITE_MEM_MCm(unit, blk, mcidx, &mcdata));
    826     }
    827     return SOC_E_NONE;
    828 }
    829 
    830 STATIC int
    831 soc_hercules_mc_port_init_all(int unit)
    832 {
    833     int port;
    834 
    835     PBMP_HG_ITER(unit, port) {
    836         SOC_IF_ERROR_RETURN(soc_hercules_mc_port_init(unit, port));
    837     }
    838     return SOC_E_NONE;
    839 }
    840 
    841 /*
    842  * Update a L2 Multicast (MC) table entry specifying the flood group
    843  * bitmap for the given Multicast index and port number.
    844  */
    845 STATIC int
    846 soc_hercules_mc_port_set(int unit, soc_port_t ingress_port, int mcidx,
    847 			 pbmp_t pbmp)
    848 {
    849     mem_mc_entry_t mcdata;
    850     char pfmt[SOC_PBMP_FMT_LEN];
    851     int blk;
    852 
    853     MCIDX_RANGE_CHECK(unit);
    854 
    855     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    856                 (BSL_META_U(unit,
    857                             "soc_hercules_mc_port_set: unit=%d port=%s mcidx=%d pbmp=%s\n"),
    858                  unit, SOC_PORT_NAME(unit, ingress_port),
    859                  mcidx, SOC_PBMP_FMT(pbmp, pfmt)));
    860 
    861     blk = SOC_PORT_BLOCK(unit, ingress_port);
    862     sal_memset(&mcdata, 0, sizeof(mcdata));
    863     SOC_IF_ERROR_RETURN(READ_MEM_MCm(unit, blk, mcidx, &mcdata));
    864     soc_MEM_MCm_field32_set(unit, &mcdata,
    865                             MCBITMAPf, SOC_PBMP_WORD_GET(pbmp, 0));
    866     SOC_IF_ERROR_RETURN(WRITE_MEM_MCm(unit, blk, mcidx, &mcdata));
    867 
    868     return SOC_E_NONE;
    869 }
    870 
    871 STATIC int
    872 soc_hercules_mc_port_set_all(int unit, int mcidx, pbmp_t pbmp)
    873 {
    874     int port;
    875 
    876     PBMP_HG_ITER(unit, port) {
    877         SOC_IF_ERROR_RETURN(soc_hercules_mc_port_set(unit, port, mcidx, pbmp));
    878     }
    879     return SOC_E_NONE;
    880 }
    881 
    882 /*
    883  * Initialize an MMU (port0=CMIC, 1-8 = PIE)
    884  *       THIS IS FOR HERCULES ONLY
    885  */
    886 STATIC int
    887 soc_hercules_port_mmu_init(int unit, int port)
    888 {
    889     uint32 lla_cells_good = SOC_CONTROL(unit)->lla_cells_good[port];
    890 
    891     /* Enable MMU interrupts */
    892     SOC_IF_ERROR_RETURN(WRITE_MMU_INTCLRr(unit, port, SOC_MMU_ERR_CLEAR_ALL));
    893 
    894     SOC_IF_ERROR_RETURN
    895         (WRITE_MMU_INTCLRr(unit, port, SOC_ERR_HAND_MMU_ALL_H15));
    896     if (SOC_CONTROL(unit)->sbe_disable[port]) {
    897         SOC_IF_ERROR_RETURN(WRITE_MMU_INTCTRLr(unit, port,
    898                                                (port == 0) ? 0 :
    899                                                SOC_ERR_HAND_MMU_ALL_H15 ^
    900                                                SOC_ERR_HAND_MMU_PP_SBE));
    901     } else {
    902         SOC_IF_ERROR_RETURN(WRITE_MMU_INTCTRLr(unit, port,
    903                                                (port == 0) ? 0 :
    904                                                SOC_ERR_HAND_MMU_ALL_H15));
    905     }
    906 
    907     /* Total Cell Limit/Port */
    908     SOC_IF_ERROR_RETURN(
    909         WRITE_MMU_CELLLMTTOTAL_UPPERr(unit, port, lla_cells_good));
    910     SOC_IF_ERROR_RETURN(
    911         WRITE_MMU_CELLLMTTOTAL_LOWERr(unit, port, lla_cells_good));
    912 
    913     return SOC_E_NONE;
    914 }
    915 
    916 /*
    917  * Initialize a Port Ingress/Egress (PIE) Module
    918  */
    919 STATIC int
    920 soc_hercules_pie_init(int unit, int port, pbmp_t pbmp, int testmode)
    921 {
    922     uint32 reg;
    923 
    924     /* DEBUG/TEST/BRINGUP stuff */
    925 
    926     if (testmode) {
    927         /*
    928          * Set Ingress test mode. In this mode, the first entry
    929          * in the UC table is always used as the final egress
    930          * bitmap for the packet - no matter what.
    931          */
    932 
    933 	reg = 0;
    934         soc_reg_field_set(unit, ING_CTRLr, &reg, TSTMODEENf, 1);
    935         SOC_IF_ERROR_RETURN(WRITE_ING_CTRLr(unit, port, reg));
    936         LOG_CLI((BSL_META_U(unit,
    937                             "NOTICE: port %s: INGRESS test mode enabled.\n"),
    938                  SOC_PORT_NAME(unit, port)));
    939     }
    940 
    941     /*
    942      * Set EGRMSKBMAPr
    943      * Initially, allow egressing to any of the ports.
    944      */
    945     SOC_IF_ERROR_RETURN
    946 	(WRITE_ING_EGRMSKBMAPr(unit, port, SOC_PBMP_WORD_GET(pbmp, 0)));
    947 
    948     /*
    949      * Set ING_CPUTOBMAP
    950      * This register defines the ports which CPU packets need to
    951      * be forwarded to (always CPU port bitmap).
    952      */
    953     SOC_IF_ERROR_RETURN
    954 	(WRITE_ING_CPUTOBMAPr(unit, port,
    955 			      SOC_PBMP_WORD_GET(PBMP_CMIC(unit), 0)));
    956 
    957     /*
    958      * Set ING_EPC_LNKBMAPr register to cmic-only forwarding.
    959      * Linkscan will add the rest.
    960      */
    961     
    962     SOC_IF_ERROR_RETURN
    963 	(WRITE_ING_EPC_LNKBMAPr(unit, port,
    964 				SOC_PBMP_WORD_GET(PBMP_CMIC(unit), 0)));
    965 
    966     return SOC_E_NONE;
    967 }
    968 
    969 #endif  /* BCM_HERCULES_SUPPORT */