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

brd_chassis_smlb.c (58938B)


      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:        brd_chassis_smlb.c
      8  * Purpose:     BCM956000 Chassis source-modid based load balancing
      9  */
     10 
     11 #include <shared/bsl.h>
     12 #include <shared/alloc.h>
     13 
     14 #include <bcm/error.h>
     15 #include <bcm/stack.h>
     16 #include <bcm/topo.h>
     17 #include <bcm/mirror.h>
     18 #include <appl/stktask/topo_brd.h>
     19 #include <appl/stktask/stktask.h>       /* bcm_st_reserved_modid_enable_get */
     20 #include <appl/cputrans/nh_tx.h>        /* nh_tx_src_get */
     21 #include <appl/cputrans/cpu2cpu.h>      /* nh_tx_src_get */
     22 
     23 #include "topo_int.h"
     24 #include "brd_chassis_int.h"
     25 
     26 #if defined(INCLUDE_CHASSIS)
     27 
     28 /*
     29  * Chassis cfm board
     30  *     5675
     31  * External stack ports are unit 0 ports 1-8
     32  */
     33 
     34 /*
     35  * Support functions for programming XGS3 switches connected to an XGS
     36  * fabric. XGS3 switches may have more than one Higig port that could
     37  * connect to a fabric, so it is no longer possible to rely on
     38  * bcm_stk_port_set() to return 'the' stack port; board programming
     39  * has to be told which port to use. The connection array, indexed by
     40  * unit, contains the connectivity. connection.from is the switch port
     41  * of the indexed unit, connection.to is the fabric port (on unit
     42  * 'funit').
     43  */
     44 
     45 #define EVEN_IDX              0
     46 #define ODD_IDX               1
     47 #define IS_ODD(i)             (i % 2)
     48 #define IS_EVEN(i)            (!IS_ODD(i))
     49 #define EVEN_ODD_IDX_GET(i)   ((IS_EVEN(i)) ? EVEN_IDX : ODD_IDX)
     50 
     51 /*
     52  * Function:    topo_chassis_modids_assign
     53  *
     54  * Purpose:
     55  *     Assign module IDs to the specified CPU database.
     56  * Parameters:
     57  *     db_ref   - Pointer to CPU database
     58  * Returns:
     59  *    BCM_E_NONE
     60  */
     61 
     62 int
     63 topo_chassis_modids_assign(cpudb_ref_t db_ref)
     64 {
     65     cpudb_entry_t            *entry;
     66     int                      unit;
     67     bcm_module_t             modid;
     68 
     69     /* 
     70      * Notes:
     71      *    Since the board type can only be inquired locally,
     72      *    the 'mod_ids_req' field will be used to assign mod ids.
     73      *
     74      *    Eventually, we want the master to know the
     75      *    board type for each slot.  Perhaps, this information
     76      *    can be passed around during discovery, or, the board
     77      *    type can be programmed in the EEPROM which can be accessed
     78      *    by the master module.
     79      */
     80 
     81     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
     82                 (BSL_META("TOPO: Assigning chassis mod ids\n")));
     83     CPUDB_FOREACH_ENTRY(db_ref, entry) {
     84         modid = MODID_OFFSET_GET(entry->base.slot_id);
     85 
     86         if (entry->base.num_units == 2) {
     87             /* 
     88              * Special modID assignment for LM XGS3-48G
     89              *     Unit0 connected to CFM1 needs an ODD modID
     90              *     Unit1 connected to CFM0 needs an EVEN modID
     91              * Since the modID for a LM starts at an even number,
     92              * increment to get odd for unit0.
     93              */
     94             modid++;
     95         }
     96 
     97         /*
     98          * Special modID assignment for 1 unit LMs based
     99          * on LM even/odd slot,
    100          *     LM on odd slot get an ODD modID
    101          *     LM on even slot get an EVEN modID
    102          */
    103         if ((IS_LM_SLOT(entry->base.slot_id)) &&
    104             (entry->base.num_units == 1)){
    105             if (IS_ODD(entry->base.slot_id)) {
    106                 /* This assumes that modID for a LM starts at even number */
    107                 modid++;
    108             }
    109         }
    110 
    111         for (unit = 0; unit < entry->base.num_units; unit++) {
    112             if (entry->base.mod_ids_req[unit] > 0) {
    113                 entry->mod_ids[unit] = modid;
    114                 modid += entry->base.mod_ids_req[unit];
    115             }
    116         }
    117     }
    118 
    119     return BCM_E_NONE;
    120 }
    121 
    122 /*
    123  * Function:    is_slot_valid
    124  *
    125  * Purpose:
    126  *     Checks if specified slot is valid.
    127  * Parameters:
    128  *     slot      - Slot to check
    129  *     db_ref    - Pointer to CPU database
    130  * Returns:
    131  *    TRUE  - If slot is valid
    132  *    FALSE - If slot is not valid
    133  * Notes:
    134  *     Currently, a slot is considered valid if the slot is 
    135  *     found in the CPU database.
    136  */
    137 STATIC int
    138 is_slot_valid(int slot, cpudb_ref_t db_ref)
    139 {
    140     cpudb_entry_t *cur;
    141 
    142     if (db_ref) {
    143         CPUDB_FOREACH_ENTRY(db_ref, cur) {
    144             if (cur->base.slot_id == slot) {
    145                 return TRUE;
    146             }
    147         }
    148     }
    149 
    150     return FALSE;
    151 }
    152 
    153 /*
    154  * Function:    chassis_unit_modid_get
    155  *
    156  * Purpose:
    157  *     Returns the mod ID for given unit.
    158  *     (-1) indicates an invalid mod ID.
    159  */
    160 STATIC int
    161 chassis_unit_modid_get(int unit, cpudb_entry_t *entry)
    162 {
    163     int modid = -1;
    164 
    165     /* 
    166      * Notes:
    167      *    If the 'board type' is known for all remote devices,
    168      *    the module ID can be extracted using the 'slot' and 'unit',
    169      *    without using the cpudb information.
    170      */
    171     if (entry->base.mod_ids_req[unit] > 0) {
    172         modid = entry->mod_ids[unit];
    173     }
    174 
    175     return modid;
    176 }
    177 
    178 
    179 /*
    180  * The following function wrappers help isolate the device specific
    181  * BCM call for setting the modport mapping.
    182  */
    183 
    184 /*
    185  * Function:    xgs2_modport_set_hport
    186  *
    187  * Purpose:
    188  *     Set the dstmod-port mapping on specified HiGig stack port for
    189  *     given unit.
    190  * Notes:
    191  *     The mod-port mapping is ONLY set for the indicated HiGig port.
    192  */
    193 STATIC int
    194 xgs2_modport_set_hport(int unit, bcm_port_t hport,
    195                        int dst_modid, bcm_port_t stk_port)
    196 {
    197     bcm_pbmp_t           empty;
    198     bcm_pbmp_t           pbmp; 
    199 
    200     BCM_PBMP_CLEAR(empty);
    201     BCM_PBMP_PORT_SET(pbmp, stk_port);
    202     BCM_IF_ERROR_RETURN(bcm_stk_ucbitmap_set(unit, hport, dst_modid,
    203                                              hport == stk_port ?
    204                                              empty : pbmp));
    205     return BCM_E_NONE;
    206 }
    207 
    208 
    209 /*
    210  * The following function wrappers help isolate the device specific
    211  * BCM call for setting the modport mapping.
    212  */
    213 
    214 /*
    215  * Function:    xxx_modport_set
    216  *
    217  * Purpose:
    218  *     Set the dstmod-port mapping on given unit.
    219  */
    220 STATIC int
    221 xgs2_modport_set(int unit, int dst_modid, bcm_port_t stk_port)
    222 {
    223     bcm_port_config_t    config;
    224     bcm_port_t           hport;
    225     bcm_pbmp_t           empty;
    226     bcm_pbmp_t           pbmp; 
    227 
    228     BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
    229     BCM_PBMP_CLEAR(empty);
    230     BCM_PBMP_PORT_SET(pbmp, stk_port);
    231     BCM_PBMP_ITER(config.hg, hport) {
    232         BCM_IF_ERROR_RETURN(bcm_stk_ucbitmap_set(unit, hport, dst_modid,
    233                                                  hport == stk_port ?
    234                                                  empty : pbmp));
    235     }
    236 
    237     return BCM_E_NONE;
    238 }
    239 STATIC int
    240 xgs3_modport_set(int unit, int dst_modid, bcm_port_t stk_port)
    241 {
    242     return bcm_stk_modport_set(unit, dst_modid, stk_port);
    243 }
    244 
    245 /*
    246  * Function:    xxx_internal_sp_set
    247  *
    248  * Purpose:
    249  *     Notify BCM layer of internal stack ports on given unit.
    250  */
    251 STATIC int
    252 xgs3_internal_sp_set(int unit, int dst_unit, bcm_port_t stk_port)
    253 {
    254     COMPILER_REFERENCE(dst_unit);
    255 
    256     /* Notify BCM layer of internal stack ports */
    257     BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(unit, stk_port));
    258 
    259     return BCM_E_NONE;
    260 }
    261 STATIC int
    262 xgs2_internal_sp_set(int unit, int dst_unit, bcm_port_t stk_port)
    263 {
    264     uint32 flags;
    265 
    266     /* Notify BCM layer of internal stack ports */
    267     BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(unit, stk_port));
    268 
    269     if (bcm_stk_port_get(dst_unit, BCM_STK_USE_HG_IF, &flags) < 0) {
    270         LOG_WARN(BSL_LS_TKS_TOPOLOGY,
    271                  (BSL_META_U(unit,
    272                  "Could not get IPIC stack info for unit %d\n"),
    273                   dst_unit));
    274     } else {
    275         if (!(flags & BCM_STK_ENABLE)) {
    276             BCM_IF_ERROR_RETURN(bcm_stk_port_set(dst_unit,
    277                                                  BCM_STK_USE_HG_IF,
    278                                                  BCM_BOARD_INT_STK_FLAGS));
    279         }
    280     }
    281 
    282     return BCM_E_NONE;
    283 }
    284 
    285 /*
    286  * Function:    chassis_iroute
    287  *
    288  * Purpose:
    289  *     Set the forwarding of UC packets among local units on given board.
    290  */
    291 STATIC int
    292 chassis_iroute(int num_units, to_unit_t *to_unit, cpudb_ref_t db_ref)
    293 {
    294     cpudb_entry_t    *l_entry;
    295     int              src_unit;
    296     bcm_port_t       stk_port;
    297     int              dst_unit;
    298     int              dst_num_units;
    299     bcm_module_t     modid;
    300     modport_set_f    modport_set;
    301     int_sp_set_f     internal_sp_set;
    302     to_unit_t        *to_unit_ptr;
    303     int              u, i;
    304     int              auto_trunk;
    305 
    306 
    307     /* Set routes to local units */
    308     l_entry = db_ref->local_entry;
    309     to_unit_ptr = to_unit;
    310     
    311     BCM_IF_ERROR_RETURN(bcm_board_auto_trunk_get(&auto_trunk));
    312     for (src_unit = 0; src_unit < num_units; src_unit++, to_unit_ptr++) {
    313         dst_num_units   = to_unit_ptr->unit_cnt;
    314         modport_set     = to_unit_ptr->modport_set_fn;
    315         internal_sp_set = to_unit_ptr->internal_sp_set_fn;
    316 
    317         for (u = 0; u < dst_num_units; u++) {
    318             dst_unit = to_unit_ptr->unit[u].dst;
    319             stk_port = to_unit_ptr->unit[u].sp.port[0];
    320             modid = chassis_unit_modid_get(dst_unit, l_entry);
    321             if (modid >= 0) {
    322                 BCM_IF_ERROR_RETURN(modport_set(src_unit, modid, stk_port));
    323             }
    324 
    325             for (i = 0; i < to_unit_ptr->unit[u].sp.port_cnt; i++) {
    326                 stk_port = to_unit_ptr->unit[u].sp.port[i];
    327                 BCM_IF_ERROR_RETURN(internal_sp_set(src_unit, dst_unit, stk_port));
    328 
    329                 /* Only allow 1 internal stack port, if auto trunk is disabled */
    330                 if (!auto_trunk) {
    331                     break;
    332                 }
    333             }
    334         }
    335     }
    336 
    337     return BCM_E_NONE;
    338 }
    339 
    340 /*
    341  * Function:    chassis_eroute_cfm
    342  *
    343  * Purpose:
    344  *     Set the forwarding of UC packets to CFMs on specified LM.
    345  * Notes:
    346  *     'sp_list' returns the list of valid stack ports for CFMs:
    347  *     The port in index 0 will contain the stack port for the even slot CFM,
    348  *     the port in index 1 will contain the stack port for the odd slot CFM.
    349  */
    350 STATIC int
    351 chassis_eroute_lm_cfm(int num_units, to_slot_t *to_cfm, sp_list_t *sp_list,
    352                       cpudb_ref_t db_ref)
    353 {
    354     int              dst_slot;
    355     bcm_port_t       stk_port;
    356     int              cfm;
    357     int              unit;
    358     int              sp_cnt;
    359     int              sp_idx;
    360     bcm_module_t     dst_modid;
    361     modport_set_f    modport_set;
    362 
    363 
    364     /* Init sp list */
    365     for (unit = 0; unit < num_units; unit++) {
    366         sp_list[unit].port_cnt = 0;
    367         for (sp_idx = 0; sp_idx < STK_PORTS_MAX; sp_idx++) {
    368             sp_list[unit].port[sp_idx] = -1;
    369         }
    370     }
    371 
    372     /* Set routes to CFMs */
    373     for (unit = 0; unit < num_units; unit++) {
    374         sp_cnt = sp_idx= 0;
    375 
    376         for (cfm = 0; cfm < to_cfm[unit].slot_cnt; cfm++) {
    377             dst_slot = to_cfm[unit].slot[cfm].dst;
    378             if (!is_slot_valid(dst_slot, db_ref)) {
    379                 continue;
    380             }
    381             stk_port    = to_cfm[unit].slot[cfm].sp.port[0];
    382             modport_set = to_cfm[unit].modport_set_fn;
    383 
    384             FOREACH_MODID(dst_slot, dst_modid) {
    385                 BCM_IF_ERROR_RETURN(modport_set(unit, dst_modid, stk_port));
    386             }
    387 
    388             /* Add port to list of available external stack ports */
    389             sp_idx = EVEN_ODD_IDX_GET(dst_slot);
    390             sp_list[unit].port[sp_idx] = stk_port;
    391             sp_cnt++;
    392         }
    393         sp_list[unit].port_cnt = sp_cnt;
    394     }
    395     
    396     return BCM_E_NONE;
    397 }
    398 
    399 /*
    400  * Function:    chassis_xgs2_eroute_lm_lm
    401  *
    402  * Purpose:
    403  *     Set the forwarding of UC packets on given unit (XGS2 fabric)
    404  *     to other LMs.
    405  */
    406 STATIC int
    407 chassis_xgs2_eroute_lm_lm(int unit, to_unit_t *to_unit,
    408                           sp_list_t *sp_list, cpudb_ref_t db_ref)
    409 {
    410     cpudb_entry_t    *l_entry;
    411     int              l_slot;
    412     int              dst_slot;
    413     bcm_port_t       hport;
    414     bcm_port_t       stk_port;
    415     bcm_module_t     src_modid;
    416     bcm_module_t     dst_modid;
    417     int              i;
    418 
    419     if (sp_list->port_cnt == 0) {
    420         return BCM_E_NONE;
    421     }
    422 
    423     l_entry = db_ref->local_entry;
    424     l_slot = l_entry->base.slot_id;
    425     for (i = 0; i < to_unit->unit_cnt; i++) {
    426         src_modid = chassis_unit_modid_get(to_unit->unit[i].dst, l_entry);
    427         if (src_modid < 0) {
    428             continue;
    429         }
    430 
    431         if (IS_EVEN(src_modid)) {
    432             if ((stk_port = sp_list->port[EVEN_IDX]) < 0) {
    433                 if ((stk_port = sp_list->port[ODD_IDX]) < 0) {
    434                     continue;    /* No valid stack port */
    435                 }
    436             }
    437         } else {
    438             if ((stk_port = sp_list->port[ODD_IDX]) < 0) {
    439                 if ((stk_port = sp_list->port[EVEN_IDX]) < 0) {
    440                     continue;    /* No valid stack port */
    441                 }
    442             }
    443         }
    444 
    445         hport = to_unit->unit[i].sp.port[0];
    446         for (dst_slot = LM_SLOT_OFFSET; dst_slot < NUM_SLOT; dst_slot++) {
    447             if (dst_slot == l_slot) {    /* Skip local slot */
    448                 continue; 
    449             }
    450             FOREACH_MODID(dst_slot, dst_modid) {
    451                 BCM_IF_ERROR_RETURN(xgs2_modport_set_hport(unit, hport,
    452                                                            dst_modid, stk_port));
    453             }
    454         }
    455     }
    456 
    457     return BCM_E_NONE;
    458 }
    459 
    460 /*
    461  * Function:    chassis_xgs3_eroute_lm_lm
    462  *
    463  * Purpose:
    464  *     Set the forwarding of UC packets on specified unit (XGS3 switch)
    465  *     with indicated stack port to other LMs.
    466  */
    467 STATIC int
    468 chassis_xgs3_eroute_lm_lm(int unit, bcm_port_t stk_port, int l_slot)
    469 {
    470     int              dst_slot;
    471     bcm_module_t     dst_modid;
    472 
    473     /* Set routes to other LMs */
    474     for (dst_slot = LM_SLOT_OFFSET; dst_slot < NUM_SLOT; dst_slot++) {
    475         if (dst_slot == l_slot) {    /* Skip local slot */
    476             continue; 
    477         }
    478         FOREACH_MODID(dst_slot, dst_modid) {
    479             BCM_IF_ERROR_RETURN(bcm_stk_modport_set(unit, dst_modid, stk_port));
    480         }
    481     }
    482 
    483     return BCM_E_NONE;
    484 }
    485 
    486 /*
    487  * Function:    chassis_internal_modid_filter
    488  *
    489  * Purpose:
    490  *     Set source mod IDs filtering for internal stack ports.
    491  */
    492 /*
    493  * Function:    chassis_internal_modid_filter
    494  *
    495  * Purpose:
    496  *     Set source mod IDs filtering for internal stack ports.
    497  */
    498 STATIC int
    499 chassis_internal_modid_filter(int num_units,
    500                               sp_list_t *internal_sp)
    501 {
    502     int           unit;
    503     int           i;
    504     bcm_port_t    stk_port;
    505 
    506     /* Allow any mod IDs for internal stack ports */
    507     for (unit = 0; unit < num_units; unit++) {
    508         for(i = 0; i < internal_sp[unit].port_cnt; i++) {
    509             stk_port = internal_sp[unit].port[i];
    510             BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, stk_port,
    511                                                           -1, TRUE));
    512         }
    513     }
    514 
    515     return BCM_E_NONE;
    516 }
    517 
    518 /*
    519  * Function:    chassis_external_modid_filter
    520  *
    521  * Purpose:
    522  *     Set mod IDs filtering for external stack ports on
    523  *     specified unit.
    524  */
    525 STATIC int
    526 chassis_external_modid_filter(int unit, sp_list_t *external_sp, int l_slot, 
    527                               cpudb_ref_t db_ref)
    528 {
    529     bcm_port_t           stk_port;
    530     bcm_module_t         src_modid;
    531     int                  slot;
    532     int                  enable;
    533     int                  i;
    534 
    535 
    536     /* Enable CPU source mod ID */
    537     BCM_IF_ERROR_RETURN(c2c_src_mod_get(&src_modid));
    538     for (i = 0; i < external_sp->port_cnt; i++) {
    539         stk_port = external_sp->port[i];
    540         BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, stk_port,
    541                                                       src_modid, TRUE));
    542     }
    543 
    544     /* Enable source mod IDs from other valid slots */
    545     for (slot = 0; slot < NUM_SLOT; slot++) {
    546         if ((is_slot_valid(slot, db_ref)) && (slot != l_slot)) {
    547             enable = TRUE;
    548         } else {
    549             enable = FALSE;
    550         }
    551 
    552         FOREACH_MODID(slot, src_modid) {
    553             for(i = 0; i < external_sp->port_cnt; i++) {
    554                 stk_port = external_sp->port[i];
    555                 BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, stk_port,
    556                                                               src_modid,
    557                                                               enable));
    558             }
    559         }
    560     }
    561 
    562     return BCM_E_NONE;
    563 }
    564 
    565 
    566 /*
    567  * Function:    chassis_nh_modid_filter
    568  *
    569  * Purpose:
    570  *     Enable NH source mod ID in external stack ports.
    571  */
    572 STATIC int
    573 chassis_nh_modid_filter(int num_units,
    574                         sp_list_t *external_sp)
    575 {
    576     int           unit;
    577     int           i;
    578     bcm_port_t    stk_port;
    579     int           nhmod, nhport;
    580     int           num_modids;
    581 
    582     /* Enable NH mod ID for external stack ports */
    583     BCM_IF_ERROR_RETURN(bcm_board_num_modid_get(&num_modids));
    584     for (unit = 0; unit < num_units; unit++) {
    585         for (i = 0; i < external_sp[unit].port_cnt; i++) {
    586             stk_port = external_sp[unit].port[i];
    587             nhmod = -1;
    588             if (bcm_st_reserved_modid_enable_get() ||
    589                 nh_tx_src_mod_port_get(unit, stk_port, &nhmod, &nhport) < 0 ||
    590                 nhmod < 0) {
    591                 if (nh_tx_src_get(&nhmod, &nhport) < 0 || nhmod < 0) {
    592                     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    593                                 (BSL_META_U(unit,
    594                                 "TOPO: Could not get default NH src modid.\n")));
    595                 }
    596             }
    597             if (nhmod >= 0 && nhmod < num_modids) {
    598                 BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, stk_port,
    599                                                               nhmod, TRUE));
    600             }
    601         }
    602     }
    603 
    604     return BCM_E_NONE;
    605 }
    606 
    607 /*
    608  * Function:    chassis_xgs2_flood_set
    609  *
    610  * Purpose:
    611  *     Set the appropriate flood block flag in stack ports to
    612  *     prevent looping.
    613  */
    614 STATIC int
    615 chassis_xgs2_flood_set(int unit, sp_list_t *external_sp,
    616                        to_slot_t *to_cfm, cpudb_ref_t db_ref)
    617 {
    618     int                  rv;
    619     bcm_pbmp_t           external_all;
    620     bcm_pbmp_t           external_disable;
    621     bcm_port_t           port, eport;
    622     bcm_port_config_t    *config = NULL;
    623     uint32               flags;
    624     int                  cfm;
    625     int                  i;
    626 
    627     config = sal_alloc(sizeof(bcm_port_config_t), "bcm_port_config_t");
    628     if (config == NULL) {
    629         return BCM_E_MEMORY;
    630     }
    631     bcm_port_config_t_init(config);
    632 
    633     rv = bcm_port_config_get(unit, config);
    634     if (BCM_FAILURE(rv)) {
    635         sal_free(config);
    636         return (rv);
    637     }
    638 
    639     BCM_PBMP_CLEAR(external_all);
    640     BCM_PBMP_CLEAR(external_disable);
    641     for (i = 0; i < external_sp->port_cnt; i++) {
    642         BCM_PBMP_PORT_ADD(external_all, external_sp->port[i]);
    643     }
    644 
    645     for (cfm = 0; cfm < to_cfm->slot_cnt; cfm++) {
    646         if (!is_slot_valid(to_cfm->slot[cfm].dst, db_ref)) {
    647             for (i = 0; i < to_cfm->slot[cfm].sp.port_cnt; i++) {
    648                 port = to_cfm->slot[cfm].sp.port[i];
    649                 if (BCM_PBMP_MEMBER(external_all, port)) {
    650                     BCM_PBMP_PORT_ADD(external_disable, port);
    651                 }
    652             }
    653         }
    654     }
    655 
    656     BCM_PBMP_ITER(config->hg, port) {
    657         BCM_PBMP_ITER(config->hg, eport) {
    658             if ((BCM_PBMP_MEMBER(external_disable, port)) ||
    659                 (BCM_PBMP_MEMBER(external_disable, eport))) {
    660                 flags = DISABLE_FLOOD;
    661             } else {
    662                 flags = ENABLE_FLOOD;
    663             }
    664             bcm_port_flood_block_set(unit, port, eport, flags);
    665         }
    666     }
    667     sal_free(config);
    668 
    669     return BCM_E_NONE;
    670 }
    671 
    672 /*
    673  * Function:    chassis_xgs3_flood_set
    674  *
    675  * Purpose:
    676  *     Set the appropriate flood block flag in stack ports to
    677  *     prevent looping.
    678  */
    679 STATIC int
    680 chassis_xgs3_flood_set(int unit, sp_list_t *external_sp,
    681                        to_slot_t *to_cfm, cpudb_ref_t db_ref, int num_cfms)
    682 {
    683     int                  rv;
    684     bcm_pbmp_t           external_all;
    685     bcm_pbmp_t           flood_ports;
    686     bcm_port_t           port, eport;
    687     bcm_port_config_t    *config = NULL;
    688     bcm_module_t         src_modid;
    689     uint32               flags;
    690     int                  cfm;
    691     int                  i;
    692 
    693     config = sal_alloc(sizeof(bcm_port_config_t), "bcm_port_config_t");
    694     if (config == NULL) {
    695         return BCM_E_MEMORY;
    696     }
    697     bcm_port_config_t_init(config);
    698 
    699     /* 0 or 1 CFM */
    700     if (num_cfms < 2) {    /* Just like the xgs2 fabric */
    701         sal_free(config);
    702         return chassis_xgs2_flood_set(unit, external_sp, to_cfm, db_ref);
    703     }
    704 
    705     /* 2 CFMs */
    706     rv = bcm_port_config_get(unit, config);
    707     if (BCM_FAILURE(rv)) {
    708         sal_free(config);
    709         return (rv);
    710     }
    711 
    712     BCM_PBMP_CLEAR(external_all);
    713     BCM_PBMP_CLEAR(flood_ports);
    714     for (i = 0; i < external_sp->port_cnt; i++) {
    715         BCM_PBMP_PORT_ADD(external_all, external_sp->port[i]);
    716     }
    717 
    718     /* Determine the egress ports for flooding */
    719     src_modid = chassis_unit_modid_get(unit, db_ref->local_entry);
    720     if (IS_EVEN(src_modid)) {
    721         cfm = EVEN_IDX;
    722     } else {
    723         cfm = ODD_IDX;
    724     }
    725     for (i = 0; i < to_cfm->slot[cfm].sp.port_cnt; i++) {
    726         BCM_PBMP_PORT_ADD(flood_ports, to_cfm->slot[cfm].sp.port[i]);
    727     }
    728 
    729     /*
    730      * Ether Ports
    731      *     If external stack ports are flood ports, enable egress to
    732      *     external stack ports, disable otherwise
    733      */
    734     BCM_PBMP_ITER(config->e, port) {
    735         BCM_PBMP_ITER(external_all, eport) {
    736             if (BCM_PBMP_MEMBER(flood_ports, eport)) {
    737                 flags = ENABLE_FLOOD;
    738             } else {
    739                 flags = DISABLE_FLOOD;
    740             }
    741             bcm_port_flood_block_set(unit, port, eport, flags);
    742         }
    743     }
    744 
    745     /* 
    746      * HiGig Ports
    747      *     Block internal to external stack port IF external is
    748      *     member of the flood ports
    749      */
    750     BCM_PBMP_ITER(config->hg, port) {
    751         BCM_PBMP_ITER(config->hg, eport) {
    752             if ((!BCM_PBMP_MEMBER(external_all, port)) &&
    753                 (BCM_PBMP_MEMBER(external_all, eport)) &&
    754                 (BCM_PBMP_MEMBER(flood_ports, eport))) {
    755                 flags = DISABLE_FLOOD;
    756             } else {
    757                 flags = ENABLE_FLOOD;
    758             }
    759             bcm_port_flood_block_set(unit, port, eport, flags);
    760         }
    761     }
    762     sal_free(config);
    763 
    764     return BCM_E_NONE;
    765 }
    766 
    767 
    768 
    769 /*
    770  * Function:    chassis_xgs2_mirror_to_set
    771  *
    772  * Purpose:
    773  *     Set the appropriate mirrored-to-port for given unit to send
    774  *     mirrored packets through correct CFM.  This routine should be
    775  *     called by LMs XGS-2 Fabric devices with external stack ports.
    776  *
    777  * Note:
    778  *     This routine MUST be called AFTER the external lm routes
    779  *     are set through chassis_xgs2_eroute_lm_lm() or
    780  *     chassis_xgs3_eroute_lm_lm().
    781  */
    782 STATIC int
    783 chassis_xgs2_mirror_to_set(int unit, sp_list_t *external_sp,
    784                            int l_slot, cpudb_ref_t db_ref)
    785 {
    786     cpudb_entry_t     *cur;
    787     bcm_module_t      mirror_modid;
    788     bcm_port_config_t config;
    789     bcm_port_t        hport;
    790     bcm_pbmp_t        pbmp;
    791     bcm_pbmp_t        pbmp_ext;
    792     int               i;
    793 
    794     /* Since LB is based on src-mod ID, any valid non-local LM
    795        dest-mod ID will work to get the righ MTP */
    796     mirror_modid = -1;
    797     CPUDB_FOREACH_ENTRY(db_ref, cur) {
    798         if ((cur->base.slot_id != l_slot) && IS_LM_SLOT(cur->base.slot_id)){
    799             mirror_modid = MODID_OFFSET_GET(cur->base.slot_id);
    800             break;
    801         }
    802     }
    803     if (mirror_modid < 0) {
    804         return BCM_E_NONE;
    805     }
    806 
    807     /*
    808      *  XGS-2 Fabric device needs to use the UC bitmap
    809      *  to set each HiGig port individually
    810      */
    811 
    812     BCM_PBMP_CLEAR(pbmp_ext);
    813     for (i = 0; i < external_sp->port_cnt; i++) {
    814         BCM_PBMP_PORT_ADD(pbmp_ext, external_sp->port[i]);
    815     }
    816 
    817     BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
    818     BCM_PBMP_ITER(config.hg, hport) {
    819         BCM_PBMP_CLEAR(pbmp);
    820         BCM_IF_ERROR_RETURN(bcm_mirror_to_pbmp_get(unit, hport, &pbmp));
    821 
    822         /* If MTP is set and is an external stack port, update */
    823         if (BCM_PBMP_NOT_NULL(pbmp)) {
    824             BCM_PBMP_AND(pbmp, pbmp_ext);
    825             if (BCM_PBMP_NOT_NULL(pbmp)) {
    826                 BCM_IF_ERROR_RETURN(bcm_stk_ucbitmap_get(unit, hport,
    827                                                          mirror_modid, &pbmp));
    828                 BCM_IF_ERROR_RETURN(bcm_mirror_to_pbmp_set(unit, hport, pbmp));
    829             }
    830 
    831         }
    832     }
    833     
    834     return BCM_E_NONE;
    835 }
    836 
    837 
    838 /*
    839  * Function:    chassis_xgs3_mirror_to_set
    840  *
    841  * Purpose:
    842  *     Set the appropriate mirrored-to-port for given unit to send
    843  *     mirrored packets through correct CFM.  This routine should be
    844  *     called by LMs XGS-3 Switch devices with external stack ports.
    845  *
    846  * Note:
    847  *     This routine MUST be called AFTER the external lm routes
    848  *     are set through chassis_xgs2_eroute_lm_lm() or
    849  *     chassis_xgs3_eroute_lm_lm().
    850  */
    851 STATIC int
    852 chassis_xgs3_mirror_to_set(int unit, sp_list_t *external_sp,
    853                            int l_slot, cpudb_ref_t db_ref)
    854 {
    855     cpudb_entry_t     *cur;
    856     bcm_module_t      mirror_modid;
    857     bcm_port_config_t config;
    858     bcm_port_t        mtp;
    859     bcm_pbmp_t        pbmp_ext;
    860     int               i;
    861 
    862     /* Since LB is based on src-mod ID, any valid non-local LM
    863        dest-mod ID will work to get the righ MTP */
    864     mirror_modid = -1;
    865     CPUDB_FOREACH_ENTRY(db_ref, cur) {
    866         if ((cur->base.slot_id != l_slot) && IS_LM_SLOT(cur->base.slot_id)){
    867             mirror_modid = MODID_OFFSET_GET(cur->base.slot_id);
    868             break;
    869         }
    870     }
    871     if (mirror_modid < 0) {
    872         return BCM_E_NONE;
    873     }
    874 
    875 
    876     BCM_IF_ERROR_RETURN(bcm_mirror_to_get(unit, &mtp));
    877 
    878     BCM_PBMP_CLEAR(pbmp_ext);
    879     for (i = 0; i < external_sp->port_cnt; i++) {
    880         BCM_PBMP_PORT_ADD(pbmp_ext, external_sp->port[i]);
    881     }
    882         
    883     /* If MTP is set and is an external stack port, update it */
    884     if ((mtp >= 0) && BCM_PBMP_MEMBER(pbmp_ext, mtp)) {
    885         BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
    886         if (BCM_PBMP_MEMBER(config.hg, mtp)) {
    887             BCM_IF_ERROR_RETURN(bcm_topo_port_get(unit, mirror_modid, &mtp));
    888             BCM_IF_ERROR_RETURN(bcm_mirror_to_set(unit, mtp));
    889         }
    890     }
    891 
    892     return BCM_E_NONE;
    893 }
    894 
    895 
    896 /*
    897  * Function:    chassis_smlb_cfm_xgs2
    898  *
    899  * Purpose:
    900  *     Program the XGS2 CFM board using Chassis Load Balancing.
    901  */
    902 int
    903 chassis_smlb_cfm_xgs2(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
    904 {
    905     cpudb_entry_t         *l_entry;
    906     int                   l_slot;                        
    907     int                   unit;                          
    908     bcm_port_t            stk_port;                      
    909     int                   dst_slot;                      
    910     int                   src_modid;                      
    911     int                   peer_cfm_slot;                 
    912     bcm_module_t          modid;                         
    913     int                   lm_to_cfm;                     
    914     int                   lm; 
    915     int                   i, j;
    916     int                   enable;
    917     int                   lb_even_odd;
    918     bcm_board_cfm_info_t  cfm_info;
    919     bcm_port_config_t     config;
    920 
    921     static sp_list_t    external_sp = {8, {1, 2, 3, 4, 5, 6, 7, 8}};
    922     static to_slot_t    to_lm = {
    923         xgs2_modport_set,
    924         4, {{2, {2, {1, 2}}},
    925             {3, {2, {3, 4}}},
    926             {4, {2, {5, 6}}},
    927             {5, {2, {7, 8}}}}
    928     };
    929 
    930     COMPILER_REFERENCE(tp_cpu);
    931     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    932                 (BSL_META("TOPO: XGS 5675 BCM956000 CFM (Load Balancing)\n")));
    933 
    934     /* Only 1 unit */
    935     unit = 0;
    936     l_entry = db_ref->local_entry;
    937     l_slot = l_entry->base.slot_id;
    938     bcm_board_cfm_info(db_ref, &cfm_info);
    939 
    940     /* Set mod ID for fabric unit */
    941     modid = l_entry->dest_mod;
    942     BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(0, modid));
    943     BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
    944     BCM_PBMP_ITER(config.hg, stk_port) {
    945         BCM_IF_ERROR_RETURN(bcm_stk_ucbitmap_set(unit, stk_port, modid,
    946                                                  config.cpu));
    947     }
    948 
    949     /* Set and enable CPU source mod ID */
    950     BCM_IF_ERROR_RETURN(c2c_src_mod_get(&src_modid));
    951     for (i = 0; i < external_sp.port_cnt; i++) {
    952         stk_port = external_sp.port[i];
    953         BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, stk_port,
    954                                                       src_modid, TRUE));
    955     }
    956 
    957     /*
    958      * Set source mod ID filtering for LMs
    959      *     If one CFM
    960      *         accept all mod IDs,
    961      *     Else
    962      *         CFM on even slot should only accept even mod IDs
    963      *         CFM on odd slot should only accept odd mod IDs
    964      */
    965 
    966     /* For each external CFM stack port */
    967     for (i = 0; i < external_sp.port_cnt; i++) {
    968         stk_port = external_sp.port[i];
    969 
    970         /* For each LM */
    971         for (lm = 0; lm < to_lm.slot_cnt; lm++) {
    972             enable = FALSE;
    973             lb_even_odd = FALSE;
    974             dst_slot = to_lm.slot[lm].dst;
    975 
    976             /*
    977              * If LM is valid and external stack port is
    978              * connected directly to LM:
    979              *   - If only 1 CFM, allow all mod IDs from LM
    980              *   - If 2 CFMs, allow mod IDs based on even/odd logic
    981              */
    982             if (is_slot_valid(dst_slot, db_ref)) {
    983                 for (j = 0; j < to_lm.slot[lm].sp.port_cnt; j++) {
    984                     if (stk_port == to_lm.slot[lm].sp.port[j]) {
    985                         if (cfm_info.count == 1) {
    986                             enable = TRUE;
    987                         } else {
    988                             lb_even_odd = TRUE;
    989                         }
    990                         break;
    991                     }
    992                 }
    993             }
    994 
    995             /* For each mod ID that corresponds to a given LM */
    996             FOREACH_MODID(dst_slot, modid) {
    997                 if (lb_even_odd) {
    998                     if (((IS_EVEN(l_slot)) && (IS_EVEN(modid))) ||
    999                         ((IS_ODD(l_slot)) && (IS_ODD(modid)))) {
   1000                         enable = TRUE;
   1001                     }
   1002                     else {
   1003                         enable = FALSE;
   1004                     }
   1005                 }
   1006                 BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, stk_port,
   1007                                                               modid, enable));
   1008             }
   1009         }
   1010     }
   1011 
   1012     /* Set source module filtering for NH */
   1013     chassis_nh_modid_filter(1, &external_sp);
   1014 
   1015     /* Set routes to LMs */
   1016     lm_to_cfm = -1;
   1017     for (lm = 0; lm < to_lm.slot_cnt; lm++) {
   1018         dst_slot = to_lm.slot[lm].dst;
   1019         if (!is_slot_valid(dst_slot, db_ref)) {
   1020             continue;
   1021         }
   1022 
   1023         /* Use first port, other ports will be trunked */
   1024         stk_port = to_lm.slot[lm].sp.port[0];
   1025         lm_to_cfm = lm;
   1026         FOREACH_MODID(dst_slot, modid) {
   1027             BCM_IF_ERROR_RETURN(xgs2_modport_set(unit, modid, stk_port));
   1028         }
   1029     }
   1030 
   1031 
   1032     /* If there is an available external stack port, set route to peer CFM */
   1033     if (lm_to_cfm >= 0) {
   1034         if (l_entry->base.slot_id == 0) {
   1035             peer_cfm_slot = 1;
   1036         } else {
   1037             peer_cfm_slot = 0;
   1038         }
   1039         if (is_slot_valid(peer_cfm_slot, db_ref)) {
   1040             /* Enable peer CFM source mod ID in all external stack ports */
   1041             for (i = 0; i < external_sp.port_cnt; i++) {
   1042                 stk_port = external_sp.port[i];
   1043                 FOREACH_MODID(peer_cfm_slot, modid) {
   1044                     BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit,
   1045                                                                   stk_port,
   1046                                                                   modid,
   1047                                                                   TRUE));
   1048                 }
   1049             }
   1050             stk_port = to_lm.slot[lm_to_cfm].sp.port[0];
   1051             FOREACH_MODID(peer_cfm_slot, modid) {
   1052                 BCM_IF_ERROR_RETURN(xgs2_modport_set(unit, modid, stk_port));
   1053             }
   1054         }
   1055     }
   1056 
   1057     /* Set trunks */
   1058     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(l_entry, db_ref,
   1059                                                BCM_BOARD_TRUNK_NORMAL));
   1060 
   1061     /* Set mod IDs */
   1062     /* Mod ID for fabric is set by caller */
   1063     bcm_board_unknown_src_modid_setup(l_entry);
   1064 
   1065     return BCM_E_NONE;
   1066 }
   1067 
   1068 
   1069 /*
   1070  * Function:    chassis_smlb_xgs2_48g
   1071  *
   1072  * Purpose:
   1073  *     Program the XGS2-48G LM board using Chassis Load Balancing.
   1074  */
   1075 #define NUM_UNIT_XGS2_48G    5
   1076 int
   1077 chassis_smlb_xgs2_48g(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
   1078 {
   1079     cpudb_entry_t    *l_entry;
   1080     int              unit;
   1081     int              num_units;
   1082     bcm_module_t     modid;
   1083     sp_list_t        sp_list;
   1084 
   1085     static sp_list_t    internal_sp = {4, {1, 2, 3, 4}};
   1086     static sp_list_t    external_sp = {4, {5, 6, 7, 8}};
   1087     static to_unit_t    to_unit = {
   1088         xgs2_modport_set, xgs2_internal_sp_set,    /* Unit 0:5675 */
   1089         4, {{1, {1, {1}}},
   1090             {2, {1, {2}}},
   1091             {3, {1, {3}}},
   1092             {4, {1, {4}}}}
   1093     };
   1094     static to_slot_t    to_cfm = {
   1095         xgs2_modport_set,                          /* Unit 0:5675 */
   1096         2, {{0, {2, {5, 7}}},
   1097             {1, {2, {6, 8}}}}
   1098     };
   1099 
   1100     COMPILER_REFERENCE(tp_cpu);
   1101     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
   1102                 (BSL_META("TOPO: XGS 569x 48GE BCM956000 LM (Load Balancing)\n")));
   1103 
   1104     /* 
   1105      * Note:
   1106      *     Although this LM has 5 units, units 1-4 are 5695s.
   1107      *     The 5695 does not need its stack ports to be programmed.
   1108      */
   1109     num_units = 1;
   1110     l_entry = db_ref->local_entry;
   1111 
   1112     /* Set packet forwarding tables */
   1113     BCM_IF_ERROR_RETURN(chassis_iroute(num_units, &to_unit, db_ref));
   1114     BCM_IF_ERROR_RETURN(chassis_eroute_lm_cfm(num_units,
   1115                                               &to_cfm, &sp_list, db_ref));
   1116     BCM_IF_ERROR_RETURN(chassis_xgs2_eroute_lm_lm(0, &to_unit, &sp_list, db_ref));
   1117 
   1118 
   1119     /* Set source module filtering */
   1120     BCM_IF_ERROR_RETURN(chassis_internal_modid_filter(num_units, &internal_sp));
   1121     BCM_IF_ERROR_RETURN(chassis_external_modid_filter(0, &external_sp,
   1122                                                       l_entry->base.slot_id,
   1123                                                       db_ref));
   1124     BCM_IF_ERROR_RETURN(chassis_nh_modid_filter(num_units, &external_sp));
   1125 
   1126     /* Set flood blocking */
   1127     BCM_IF_ERROR_RETURN(chassis_xgs2_flood_set(0, &external_sp,
   1128                                                &to_cfm, db_ref));
   1129 
   1130     /* Set trunks */
   1131     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(l_entry, db_ref,
   1132                                                BCM_BOARD_TRUNK_NORMAL));
   1133 
   1134     /* Set mirroring */
   1135     BCM_IF_ERROR_RETURN(chassis_xgs2_mirror_to_set(0, &external_sp,
   1136                                                    l_entry->base.slot_id,
   1137                                                    db_ref));
   1138 
   1139     /* Set mod IDs */
   1140     bcm_board_unknown_src_modid_setup(l_entry);
   1141     for (unit = 0; unit < NUM_UNIT_XGS2_48G; unit++) {
   1142         if ((modid = chassis_unit_modid_get(unit, l_entry)) < 0) {
   1143             continue;
   1144         }
   1145         BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, modid));
   1146         BCM_IF_ERROR_RETURN(bcm_stk_modport_clear_all(unit));
   1147     }
   1148 
   1149     return BCM_E_NONE;
   1150 }
   1151 
   1152 /*
   1153  * Function:    chassis_smlb_xgs2_6x
   1154  *
   1155  * Purpose:
   1156  *     Program the XGS2-6X LM board using Chassis Load Balancing.
   1157  */
   1158 #define NUM_UNIT_XGS2_6X 7
   1159 int
   1160 chassis_smlb_xgs2_6x(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
   1161 {
   1162     cpudb_entry_t    *l_entry;
   1163     int              unit;
   1164     int              num_units;
   1165     bcm_module_t     modid;
   1166     sp_list_t        sp_list;
   1167 
   1168     static sp_list_t    internal_sp = {6, {6, 7, 8, 1, 2, 3}};
   1169     static sp_list_t    external_sp = {2, {4, 5}};
   1170     static to_unit_t    to_unit = {
   1171         xgs2_modport_set, xgs2_internal_sp_set,    /* Unit 0:5675 */
   1172         6, {{1, {1, {6}}},
   1173             {2, {1, {7}}},
   1174             {3, {1, {8}}},
   1175             {4, {1, {1}}},
   1176             {5, {1, {2}}},
   1177             {6, {1, {3}}}}
   1178     };
   1179     static to_slot_t    to_cfm = {
   1180         xgs2_modport_set,                          /* Unit 0:5675 */
   1181         2, {{0, {1, {4}}},
   1182             {1, {1, {5}}}}
   1183     };
   1184 
   1185     COMPILER_REFERENCE(tp_cpu);
   1186     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
   1187                 (BSL_META("TOPO: XGS 5674 6X BCM956000 LM (Load Balancing)\n")));
   1188 
   1189     /* 
   1190      * Note:
   1191      *     Although this LM has 7 units, units 1-6 are 5674s.
   1192      *     The 5674 does not need its stack ports to be programmed.
   1193      */
   1194     num_units = 1;
   1195     l_entry = db_ref->local_entry;
   1196 
   1197     /* Set packet forwarding tables */
   1198     BCM_IF_ERROR_RETURN(chassis_iroute(num_units, &to_unit, db_ref));
   1199     BCM_IF_ERROR_RETURN(chassis_eroute_lm_cfm(num_units,
   1200                                               &to_cfm, &sp_list, db_ref));
   1201     BCM_IF_ERROR_RETURN(chassis_xgs2_eroute_lm_lm(0, &to_unit, &sp_list, db_ref));
   1202 
   1203 
   1204     /* Set source module filtering */
   1205     BCM_IF_ERROR_RETURN(chassis_internal_modid_filter(num_units, &internal_sp));
   1206     BCM_IF_ERROR_RETURN(chassis_external_modid_filter(0, &external_sp,
   1207                                                       l_entry->base.slot_id,
   1208                                                       db_ref));
   1209     BCM_IF_ERROR_RETURN(chassis_nh_modid_filter(num_units, &external_sp));
   1210 
   1211     /* Set flood blocking */
   1212     BCM_IF_ERROR_RETURN(chassis_xgs2_flood_set(0, &external_sp,
   1213                                                &to_cfm, db_ref));
   1214     /* Set mirroring */
   1215     BCM_IF_ERROR_RETURN(chassis_xgs2_mirror_to_set(0, &external_sp,
   1216                                                    l_entry->base.slot_id,
   1217                                                    db_ref));
   1218 
   1219     /* Set mod IDs */
   1220     bcm_board_unknown_src_modid_setup(l_entry);
   1221     for (unit = 0; unit < NUM_UNIT_XGS2_6X; unit++) {
   1222         if ((modid = chassis_unit_modid_get(unit, l_entry)) < 0) {
   1223             continue;
   1224         }
   1225         BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, modid));
   1226         BCM_IF_ERROR_RETURN(bcm_stk_modport_clear_all(unit));
   1227     }
   1228 
   1229     return BCM_E_NONE;
   1230 }
   1231 
   1232 /*
   1233  * Function:    chassis_smlb_xgs3_12x
   1234  *
   1235  * Purpose:
   1236  *     Program the XGS3-12X LM board using Chassis Load Balancing.
   1237  */
   1238 #define NUM_UNIT_XGS3_12X    5
   1239 int
   1240 chassis_smlb_xgs3_12x(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
   1241 {
   1242     cpudb_entry_t    *l_entry;
   1243     int              unit;
   1244     bcm_module_t     modid;
   1245     sp_list_t        sp_list[NUM_UNIT_XGS3_12X];
   1246 
   1247     static sp_list_t    internal_sp_tbl[NUM_UNIT_XGS3_12X] = {
   1248         {4, {1, 2, 7, 8}},                            /* Unit 0 */
   1249         {1, {27}}, {1, {27}}, {1, {27}}, {1, {27}}    /* Units 1-4 */
   1250     };
   1251     static sp_list_t    external_sp_tbl[NUM_UNIT_XGS3_12X] = {
   1252         {4, {3, 4, 5, 6}},      /* Unit 0 */
   1253         {0}, {0}, {0}, {0}      /* Units 1-4 */
   1254     };
   1255     static to_unit_t    to_unit_tbl[NUM_UNIT_XGS3_12X] = {
   1256         { xgs2_modport_set, xgs3_internal_sp_set,    /* Unit 0: 5675 */
   1257           4, {{1, {1, {7}}},
   1258               {2, {1, {8}}}, 
   1259               {3, {1, {1}}}, 
   1260               {4, {1, {2}}}} },
   1261         { xgs3_modport_set, xgs3_internal_sp_set,    /* Unit 1: 56501 */
   1262           4, {{0, {1, {27}}},
   1263               {2, {1, {27}}},
   1264               {3, {1, {27}}},
   1265               {4, {1, {27}}}} },
   1266         { xgs3_modport_set, xgs3_internal_sp_set,    /* Unit 2: 56501 */
   1267           4, {{0, {1, {27}}},
   1268               {1, {1, {27}}},
   1269               {3, {1, {27}}},
   1270               {4, {1, {27}}}} },
   1271         { xgs3_modport_set, xgs3_internal_sp_set,    /* Unit 3: 56501 */
   1272           4, {{0, {1, {27}}},
   1273               {1, {1, {27}}},
   1274               {2, {1, {27}}},
   1275               {4, {1, {27}}}} },
   1276         { xgs3_modport_set, xgs3_internal_sp_set,    /* Unit 4: 56501 */
   1277           4, {{0, {1, {27}}},
   1278               {1, {1, {27}}},
   1279               {2, {1, {27}}},
   1280               {3, {1, {27}}}} },
   1281     };
   1282     static to_slot_t    to_cfm8[NUM_UNIT_XGS3_12X] = {
   1283         { xgs2_modport_set,
   1284           2, {{0, {2, {3, 5}}},   /* Unit 0: 5675 */
   1285               {1, {2, {4, 6}}}} },
   1286         { xgs3_modport_set,
   1287           2, {{0, {1, {27}}},     /* Unit 1: 5695 */
   1288               {1, {1, {27}}}}   },
   1289         { xgs3_modport_set,
   1290           2, {{0, {1, {27}}},     /* Unit 2: 5695 */
   1291               {1, {1, {27}}}}   },
   1292         { xgs3_modport_set,
   1293           2, {{0, {1, {27}}},     /* Unit 3: 5695 */
   1294               {1, {1, {27}}}}   },
   1295         { xgs3_modport_set,
   1296           2, {{0, {1, {27}}},     /* Unit 4: 5695 */
   1297               {1, {1, {27}}}}   }
   1298     };
   1299     static to_slot_t    to_cfm16[NUM_UNIT_XGS3_12X] = {
   1300         { xgs2_modport_set,
   1301           2, {{0, {2, {3, 6}}},   /* Unit 0: 5675 */
   1302               {1, {2, {4, 5}}}} },
   1303         { xgs3_modport_set,
   1304           2, {{0, {1, {27}}},     /* Unit 1: 5695 */
   1305               {1, {1, {27}}}}   },
   1306         { xgs3_modport_set,
   1307           2, {{0, {1, {27}}},     /* Unit 2: 5695 */
   1308               {1, {1, {27}}}}   },
   1309         { xgs3_modport_set,
   1310           2, {{0, {1, {27}}},     /* Unit 3: 5695 */
   1311               {1, {1, {27}}}}   },
   1312         { xgs3_modport_set,
   1313           2, {{0, {1, {27}}},     /* Unit 4: 5695 */
   1314               {1, {1, {27}}}}   }
   1315     };
   1316 
   1317     int               master_slot;
   1318     to_slot_t         *to_cfm;
   1319 
   1320     COMPILER_REFERENCE(tp_cpu);
   1321 
   1322     to_cfm = (db_ref->master_entry != NULL &&
   1323               db_ref->master_entry->base.flags & CPUDB_BASE_F_CHASSIS_10SLOT) ?
   1324         to_cfm16 : to_cfm8;
   1325 
   1326     master_slot = db_ref->master_entry ?
   1327         db_ref->master_entry->base.slot_id : -1;
   1328     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
   1329                 (BSL_META("TOPO: XGS3 56501 12XE BCM956000 LM (Load Balancing)\n")));
   1330     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
   1331                 (BSL_META("      master on slot %d\n"),
   1332                  master_slot));
   1333 
   1334     l_entry = db_ref->local_entry;
   1335 
   1336     /* Set forwarding to local units */
   1337     BCM_IF_ERROR_RETURN(chassis_iroute(NUM_UNIT_XGS3_12X,
   1338                                        to_unit_tbl, db_ref));
   1339     /* Set forwarding to CFMs */
   1340     BCM_IF_ERROR_RETURN(chassis_eroute_lm_cfm(NUM_UNIT_XGS3_12X, 
   1341                                               to_cfm, sp_list, db_ref));
   1342     /* Set forwarding to LMs */
   1343     unit = 0;
   1344     BCM_IF_ERROR_RETURN(chassis_xgs2_eroute_lm_lm(unit, &to_unit_tbl[unit],
   1345                                                   &sp_list[unit], db_ref));
   1346     for (unit = 1; unit < NUM_UNIT_XGS3_12X; unit++){
   1347         BCM_IF_ERROR_RETURN(chassis_xgs3_eroute_lm_lm(unit,
   1348                                                       internal_sp_tbl[unit].port[0],
   1349                                                       l_entry->base.slot_id));
   1350     }
   1351 
   1352 
   1353     /* Set source module filtering */
   1354     unit = 0;
   1355     BCM_IF_ERROR_RETURN(chassis_internal_modid_filter(NUM_UNIT_XGS3_12X,
   1356                                                       internal_sp_tbl));
   1357     BCM_IF_ERROR_RETURN(chassis_external_modid_filter(unit, &external_sp_tbl[unit],
   1358                                                       l_entry->base.slot_id,
   1359                                                       db_ref));
   1360     BCM_IF_ERROR_RETURN(chassis_nh_modid_filter(NUM_UNIT_XGS3_12X,
   1361                                                 external_sp_tbl));
   1362 
   1363     /* Set flood blocking */
   1364     BCM_IF_ERROR_RETURN(chassis_xgs2_flood_set(unit, &external_sp_tbl[unit],
   1365                                                &to_cfm[unit], db_ref));
   1366 
   1367 
   1368     /* Set trunks */
   1369     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(l_entry, db_ref,
   1370                                                BCM_BOARD_TRUNK_NORMAL));
   1371     
   1372     /* Set mirroring */
   1373     BCM_IF_ERROR_RETURN(chassis_xgs2_mirror_to_set(0, &external_sp_tbl[unit],
   1374                                                    l_entry->base.slot_id,
   1375                                                    db_ref));
   1376 
   1377     /* Set mod IDs */
   1378     bcm_board_unknown_src_modid_setup(l_entry);
   1379     for (unit = 0; unit < NUM_UNIT_XGS3_12X; unit++) {
   1380         if ((modid = chassis_unit_modid_get(unit, l_entry)) < 0) {
   1381             continue;
   1382         }
   1383         BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, modid));
   1384     }
   1385 
   1386     return BCM_E_NONE;
   1387 }
   1388 
   1389 
   1390 /*
   1391  * Function:    chassis_smlb_xgs3_48g
   1392  *
   1393  * Purpose:
   1394  *     Program the XGS3-48G LM board using Chassis Load Balancing.
   1395  */
   1396 #define NUM_UNIT_XGS3_48G  2
   1397 
   1398 #define FB_UNIT0 0
   1399 #define FB_UNIT1 1
   1400 
   1401 int
   1402 chassis_smlb_xgs3_48g(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
   1403 {
   1404     cpudb_entry_t        *l_entry;
   1405     int                  unit;
   1406     bcm_module_t         src_modid;
   1407     bcm_module_t         dst_modid;
   1408     bcm_port_t           stk_port;
   1409     sp_list_t            sp_list[NUM_UNIT_XGS3_48G];
   1410     bcm_board_cfm_info_t cfm_info;
   1411     int                  master_slot;
   1412 
   1413     static sp_list_t    internal_sp_tbl[NUM_UNIT_XGS3_48G] = {
   1414         {2, {26, 27}},    /* Unit 0 */
   1415         {2, {26, 27}}     /* Unit 1 */
   1416     };
   1417     static sp_list_t    external_sp_tbl[NUM_UNIT_XGS3_48G] = {
   1418         {2, {24, 25}},    /* Unit 0 */
   1419         {2, {24, 25}}     /* Unit 1 */
   1420     };
   1421     static to_unit_t    to_unit_tbl[NUM_UNIT_XGS3_48G] = {
   1422         { xgs3_modport_set, xgs3_internal_sp_set,    /* Unit 0: 56504 */
   1423           1, {{1, {2, {26, 27}}}} },
   1424         { xgs3_modport_set, xgs3_internal_sp_set,    /* Unit 1: 56504 */
   1425           1, {{0, {2, {26, 27}}}} }
   1426     };
   1427 
   1428     static to_slot_t    to_cfm8[NUM_UNIT_XGS3_48G] = {
   1429         { xgs3_modport_set,
   1430           2, {{0, {2, {26, 27}}},                    /* Unit 0: 56504 */
   1431               {1, {2, {24, 25}}}} },
   1432         { xgs3_modport_set,
   1433           2, {{0, {2, {24, 25}}},                    /* Unit 1: 56504 */
   1434               {1, {2, {26, 27}}}} }
   1435     };
   1436 
   1437     static to_slot_t    to_cfm16[NUM_UNIT_XGS3_48G] = {
   1438         { xgs3_modport_set,
   1439           2, {{0, {2, {24, 25}}},                    /* Unit 0: 56504 */
   1440               {1, {2, {26, 27}}}} },
   1441         { xgs3_modport_set,
   1442           2, {{0, {2, {26, 27}}},                    /* Unit 1: 56504 */
   1443               {1, {2, {24, 25}}}} }
   1444     };
   1445 
   1446     to_slot_t     *to_cfm;
   1447 
   1448     to_cfm = (db_ref->master_entry != NULL &&
   1449               db_ref->master_entry->base.flags & CPUDB_BASE_F_CHASSIS_10SLOT) ?
   1450         to_cfm16 : to_cfm8;
   1451     
   1452     /* If there's no master yet, set self as master */
   1453     master_slot = db_ref->master_entry ?
   1454         db_ref->master_entry->base.slot_id : -1;
   1455     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
   1456                 (BSL_META("TOPO: XGS3 56504 48GE BCM956000 LM (Load Balancing)\n")));
   1457     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
   1458                 (BSL_META("      master on slot %d\n"),
   1459                  master_slot));
   1460 
   1461     l_entry = db_ref->local_entry;
   1462     bcm_board_cfm_info(db_ref, &cfm_info);
   1463 
   1464     /* Set forwarding to local units */
   1465     BCM_IF_ERROR_RETURN(chassis_iroute(NUM_UNIT_XGS3_48G,
   1466                                        to_unit_tbl, db_ref));
   1467     /* Set forwarding to CFMs */
   1468     sal_memset(sp_list, 0, sizeof(sp_list));
   1469     BCM_IF_ERROR_RETURN(chassis_eroute_lm_cfm(NUM_UNIT_XGS3_48G,
   1470                                               to_cfm, sp_list, db_ref));
   1471     /* Set forwarding to LMs */
   1472     /* Use unit's source mod ID even/odd */
   1473     for (unit = 0; unit < NUM_UNIT_XGS3_48G; unit++){
   1474         src_modid = chassis_unit_modid_get(unit, l_entry);
   1475         if (IS_EVEN(src_modid)) {
   1476             if ((stk_port = sp_list[unit].port[EVEN_IDX]) < 0) {
   1477                 if ((stk_port = sp_list[unit].port[ODD_IDX]) < 0) {
   1478                     continue;
   1479                 }
   1480             }
   1481         } else {
   1482             if ((stk_port = sp_list[unit].port[ODD_IDX]) < 0) {
   1483                 if ((stk_port = sp_list[unit].port[EVEN_IDX]) < 0) {
   1484                     continue;
   1485                 }
   1486             }
   1487         }
   1488         BCM_IF_ERROR_RETURN(chassis_xgs3_eroute_lm_lm(unit, stk_port,
   1489                                                       l_entry->base.slot_id));
   1490     }
   1491 
   1492     /* Set module filtering */
   1493     BCM_IF_ERROR_RETURN(chassis_internal_modid_filter(NUM_UNIT_XGS3_48G,
   1494                                                       internal_sp_tbl));
   1495     for (unit = 0; unit < NUM_UNIT_XGS3_48G; unit++) {
   1496         /* Ignore error, since some FB revs do not support source modID filter */
   1497         (void)chassis_external_modid_filter(unit,
   1498                                       &external_sp_tbl[unit],
   1499                                       l_entry->base.slot_id,
   1500                                       db_ref);
   1501     }
   1502     BCM_IF_ERROR_RETURN(chassis_nh_modid_filter(NUM_UNIT_XGS3_48G,
   1503                                                 external_sp_tbl));
   1504 
   1505     /* Set flood blocking */
   1506     for (unit = 0; unit < NUM_UNIT_XGS3_48G; unit++) {
   1507         BCM_IF_ERROR_RETURN(chassis_xgs3_flood_set(unit, &external_sp_tbl[unit],
   1508                                                    &to_cfm[unit], db_ref,
   1509                                                    cfm_info.count));
   1510     }
   1511 
   1512 
   1513     /* Set trunks */
   1514     /* External stack ports */
   1515     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(l_entry, db_ref,
   1516                                                BCM_BOARD_TRUNK_NORMAL));
   1517     /* Intraboard trunk */
   1518     BCM_IF_ERROR_RETURN(_bcm_board_setup_trunk_lm_xgs3_48g());
   1519 
   1520     /* Set mirroring */
   1521     for (unit = 0; unit < NUM_UNIT_XGS3_48G; unit++) {
   1522         BCM_IF_ERROR_RETURN(chassis_xgs3_mirror_to_set(unit,
   1523                                                        &external_sp_tbl[unit],
   1524                                                        l_entry->base.slot_id,
   1525                                                        db_ref));
   1526     }
   1527 
   1528     /* Set mod IDs */
   1529     for (unit = 0; unit < NUM_UNIT_XGS3_48G; unit++) {
   1530         if ((dst_modid = chassis_unit_modid_get(unit, l_entry)) < 0) {
   1531             continue;
   1532         }
   1533         BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, dst_modid));
   1534     }
   1535 
   1536 #ifdef BCM_BOARD_AUTO_E2E
   1537     /* intra-board end to end flow control, if available */
   1538     BCM_IF_ERROR_RETURN
   1539         (_bcm_board_dual_xgs3_e2e_set(FB_UNIT0,
   1540                                       tp_cpu->local_entry.mod_ids[0],
   1541                                       FB_UNIT1,
   1542                                       tp_cpu->local_entry.mod_ids[1]));
   1543 #endif  /* BCM_BOARD_AUTO_E2E */
   1544 
   1545     return BCM_E_NONE;
   1546 }
   1547 
   1548 #undef FB_UNIT0
   1549 #undef FB_UNIT1
   1550 
   1551 /*
   1552  * Function:    chassis_smlb_cfm_xgs3
   1553  *
   1554  * Purpose:
   1555  *     Program the XGS3 CFM board using Chassis Load Balancing.
   1556  */
   1557 int
   1558 chassis_smlb_cfm_xgs3(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
   1559 {
   1560     cpudb_entry_t         *l_entry;
   1561     int                   l_slot;                        
   1562     int                   unit;                          
   1563     bcm_port_t            stk_port;                      
   1564     int                   dst_slot;                      
   1565     int                   src_modid;                      
   1566     int                   peer_cfm_slot;                 
   1567     bcm_module_t          modid;                         
   1568     int                   lm_to_cfm;                     
   1569     int                   lm; 
   1570     int                   i, j;
   1571     int                   enable;
   1572     int                   lb_even_odd;
   1573     bcm_board_cfm_info_t  cfm_info;
   1574     bcm_port_config_t     config;
   1575     bcm_port_t            port;
   1576 
   1577     static sp_list_t    external_sp = {
   1578         16,
   1579         {0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17}
   1580     };
   1581     static to_slot_t    to_lm = {
   1582         xgs3_modport_set,
   1583         8, {{2, {2, {7, 10}}},
   1584             {3, {2, {6, 11}}},
   1585             {4, {2, {5, 12}}},
   1586             {5, {2, {4, 13}}},
   1587             {6, {2, {3, 14}}},
   1588             {7, {2, {2, 15}}},
   1589             {8, {2, {1, 16}}},
   1590             {9, {2, {0, 17}}}}};
   1591 
   1592 
   1593     COMPILER_REFERENCE(tp_cpu);
   1594     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
   1595                 (BSL_META("TOPO: XGS 56700 BCM956010 CFM (Load Balancing)\n")));
   1596 
   1597     /* Only 1 unit */
   1598     unit = 0;
   1599     l_entry = db_ref->local_entry;
   1600     l_slot = l_entry->base.slot_id;
   1601     bcm_board_cfm_info(db_ref, &cfm_info);
   1602 
   1603     /* Set CPU mod ID for fabric unit */
   1604     modid = l_entry->dest_mod;
   1605     BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
   1606     BCM_PBMP_ITER(config.cpu, port) {
   1607         break;   /* Get CPU port */
   1608     }
   1609 
   1610     BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(0, modid));
   1611     BCM_IF_ERROR_RETURN(bcm_stk_modport_set(unit, modid, port));
   1612 
   1613     /* Set and enable CPU source mod ID */
   1614     BCM_IF_ERROR_RETURN(c2c_src_mod_get(&src_modid));
   1615     for (i = 0; i < external_sp.port_cnt; i++) {
   1616         stk_port = external_sp.port[i];
   1617         BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, stk_port,
   1618                                                       src_modid, TRUE));
   1619     }
   1620 
   1621     /*
   1622      * Set source mod ID filtering for LMs
   1623      *     If one CFM
   1624      *         accept all mod IDs,
   1625      *     Else
   1626      *         CFM on even slot should only accept even mod IDs
   1627      *         CFM on odd slot should only accept odd mod IDs
   1628      */
   1629 
   1630     /* For each external CFM stack port */
   1631     for (i = 0; i < external_sp.port_cnt; i++) {
   1632         stk_port = external_sp.port[i];
   1633 
   1634         /* For each LM */
   1635         for (lm = 0; lm < to_lm.slot_cnt; lm++) {
   1636             enable = FALSE;
   1637             lb_even_odd = FALSE;
   1638             dst_slot = to_lm.slot[lm].dst;
   1639 
   1640             /*
   1641              * If LM is valid and external stack port is
   1642              * connected directly to LM:
   1643              *   - If only 1 CFM, allow all mod IDs from LM
   1644              *   - If 2 CFMs, allow mod IDs based on even/odd logic
   1645              */
   1646             if (is_slot_valid(dst_slot, db_ref)) {
   1647                 for (j = 0; j < to_lm.slot[lm].sp.port_cnt; j++) {
   1648                     if (stk_port == to_lm.slot[lm].sp.port[j]) {
   1649                         if (cfm_info.count == 1) {
   1650                             enable = TRUE;
   1651                         } else {
   1652                             lb_even_odd = TRUE;
   1653                         }
   1654                         break;
   1655                     }
   1656                 }
   1657             }
   1658 
   1659             /* For each mod ID that corresponds to a given LM */
   1660             FOREACH_MODID(dst_slot, modid) {
   1661                 if (lb_even_odd) {
   1662                     if (((IS_EVEN(l_slot)) && (IS_EVEN(modid))) ||
   1663                         ((IS_ODD(l_slot)) && (IS_ODD(modid)))) {
   1664                         enable = TRUE;
   1665                     }
   1666                     else {
   1667                         enable = FALSE;
   1668                     }
   1669                 }
   1670                 BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, stk_port,
   1671                                                               modid, enable));
   1672             }
   1673         }
   1674     }
   1675 
   1676     /* Set source module filtering for NH */
   1677     chassis_nh_modid_filter(1, &external_sp);
   1678 
   1679     /* Set routes to LMs */
   1680     lm_to_cfm = -1;
   1681     for (lm = 0; lm < to_lm.slot_cnt; lm++) {
   1682         dst_slot = to_lm.slot[lm].dst;
   1683         if (!is_slot_valid(dst_slot, db_ref)) {
   1684             continue;
   1685         }
   1686 
   1687         /* Use first port, other ports will be trunked */
   1688         stk_port = to_lm.slot[lm].sp.port[0];
   1689         lm_to_cfm = lm;
   1690         FOREACH_MODID(dst_slot, modid) {
   1691             BCM_IF_ERROR_RETURN(xgs3_modport_set(unit, modid, stk_port));
   1692         }
   1693     }
   1694 
   1695 
   1696     /* If there is an available external stack port, set route to peer CFM */
   1697     if (lm_to_cfm >= 0) {
   1698         if (l_entry->base.slot_id == 0) {
   1699             peer_cfm_slot = 1;
   1700         } else {
   1701             peer_cfm_slot = 0;
   1702         }
   1703         if (is_slot_valid(peer_cfm_slot, db_ref)) {
   1704             /* Enable peer CFM source mod ID in all external stack ports */
   1705             for (i = 0; i < external_sp.port_cnt; i++) {
   1706                 stk_port = external_sp.port[i];
   1707                 FOREACH_MODID(peer_cfm_slot, modid) {
   1708                     BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit,
   1709                                                                   stk_port,
   1710                                                                   modid,
   1711                                                                   TRUE));
   1712                 }
   1713             }
   1714             stk_port = to_lm.slot[lm_to_cfm].sp.port[0];
   1715             FOREACH_MODID(peer_cfm_slot, modid) {
   1716                 BCM_IF_ERROR_RETURN(xgs3_modport_set(unit, modid, stk_port));
   1717             }
   1718         }
   1719     }
   1720 
   1721     /* Set trunks */
   1722     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(l_entry, db_ref,
   1723                                                BCM_BOARD_TRUNK_NORMAL));
   1724 
   1725     /* Set mod IDs */
   1726     /* Mod ID for fabric is set by caller */
   1727     bcm_board_unknown_src_modid_setup(l_entry);
   1728 
   1729     return BCM_E_NONE;
   1730 }
   1731 
   1732 int
   1733 chassis_smlb_56800_12x(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
   1734 {
   1735     cpudb_entry_t    *l_entry;
   1736     int              num_units;
   1737     sp_list_t        sp_list;
   1738     bcm_board_cfm_info_t cfm_info;
   1739     bcm_port_config_t    config;
   1740     bcm_port_t           port;
   1741     bcm_port_t       stk_port;
   1742     bcm_module_t         src_modid;
   1743 
   1744     static sp_list_t    external_sp = {4, {0, 1, 2, 3}};
   1745     static to_slot_t    to_cfm = {
   1746         xgs3_modport_set,                          /* Unit 0:56800 */
   1747         2, {{0, {2, {1, 3}}},
   1748             {1, {2, {0, 2}}}}
   1749     };
   1750 
   1751     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
   1752                 (BSL_META("TOPO: XGS3 56800 LM (Load Balancing)\n")));
   1753 
   1754     BCM_IF_ERROR_RETURN(bcm_port_config_get(0, &config));
   1755         
   1756     bcm_board_cfm_info(db_ref, &cfm_info);
   1757     num_units = 1;
   1758     l_entry = db_ref->local_entry;
   1759 
   1760     /* Set CPU port */
   1761     BCM_PBMP_ITER(config.cpu, port) {
   1762         break;   /* Get CPU port */
   1763     }
   1764     BCM_IF_ERROR_RETURN(bcm_stk_modport_set(0, l_entry->mod_ids[0], port));
   1765 
   1766     
   1767     /* Set packet forwarding tables */
   1768     BCM_IF_ERROR_RETURN(chassis_eroute_lm_cfm(num_units,
   1769                                               &to_cfm, &sp_list, db_ref));
   1770 
   1771     src_modid = chassis_unit_modid_get(0, l_entry);
   1772     if (IS_EVEN(src_modid)) {
   1773         if ((stk_port = sp_list.port[EVEN_IDX]) < 0) {
   1774             stk_port = sp_list.port[ODD_IDX];
   1775         }
   1776     } else {
   1777         if ((stk_port = sp_list.port[ODD_IDX]) < 0) {
   1778             stk_port = sp_list.port[EVEN_IDX];
   1779         }
   1780     }
   1781 
   1782     if (stk_port >= 0) {
   1783         BCM_IF_ERROR_RETURN(chassis_xgs3_eroute_lm_lm(0, stk_port,
   1784                                                       l_entry->base.slot_id));
   1785     }
   1786     /* Set source module filtering */
   1787     BCM_IF_ERROR_RETURN(chassis_external_modid_filter(0, &external_sp,
   1788                                                       l_entry->base.slot_id,
   1789                                                       db_ref));
   1790     BCM_IF_ERROR_RETURN(chassis_nh_modid_filter(num_units, &external_sp));
   1791 
   1792     /* Set flood blocking */
   1793     BCM_IF_ERROR_RETURN(chassis_xgs3_flood_set(0, &external_sp,
   1794                                                &to_cfm, db_ref,
   1795                                                cfm_info.count));
   1796 
   1797     /* Set trunks */
   1798     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(l_entry, db_ref,
   1799                                                BCM_BOARD_TRUNK_NORMAL));
   1800 
   1801     /* Set mirroring */
   1802     BCM_IF_ERROR_RETURN(chassis_xgs3_mirror_to_set(0, &external_sp,
   1803                                                    l_entry->base.slot_id,
   1804                                                    db_ref));
   1805 
   1806     /* Set mod IDs */
   1807     bcm_board_unknown_src_modid_setup(l_entry);
   1808     BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(0, l_entry->dest_mod));
   1809 
   1810     return BCM_E_NONE;
   1811 }
   1812 
   1813 #else
   1814 int _brd_chassis_smlb_not_empty;
   1815 #endif /* INCLUDE_CHASSIS */