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_ast.c (22153B)


      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_ast.c
      8  * Purpose:     BCM956000 Chassis asymmetric trunk based load balancing
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <bcm/error.h>
     14 #include <bcm/stack.h>
     15 #include <bcm/topo.h>
     16 #include <bcm/mirror.h>
     17 #include <bcm/field.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 
     22 #include "topo_int.h"
     23 #include "brd_chassis_int.h"
     24 
     25 #if defined(INCLUDE_CHASSIS)
     26 
     27 /* CFM and LM Hash Selection
     28 
     29 
     30    CFM and LM hashes are different so packets received from an LM has
     31    an opportunity to be load balanced on the outgoing CFM trunk. This
     32    is because the LMs use alternate links to connect to each CFM,
     33    e.g. hg0 and hg2 go to one CFM and hg1 and hg3 go to the other. If
     34    the same hash is used for both the LM and CFM, then the packets
     35    egressing the CFM would always use the same link, leaving half the
     36    available bandwidth unused:
     37 
     38      LM hg0 -> CFM0 trunk-link0
     39      LM hg1 -> CFM1 trunk-link1
     40      LM hg2 -> CFM0 trunk-link0
     41      LM hg3 -> CFM1 trunk-link1
     42 
     43    where "trunk-linkN" is the Nth member of the CFM egress trunk.
     44 
     45    If the CFM uses a different hash than the LM, then there's a
     46    reasonable chance that the traffic egressing the CFM will use both
     47    members of the trunk.
     48    
     49 */
     50 
     51 #define XGS2_CFM_HASH (BCM_TRUNK_PSC_SRCDSTMAC | \
     52                        BCM_TRUNK_PSC_IPMACSA   | \
     53                        BCM_TRUNK_PSC_MACSA)
     54 
     55 #define XGS2_LM_HASH  (BCM_TRUNK_PSC_SRCDSTMAC | \
     56                        BCM_TRUNK_PSC_IPMACDA   | \
     57                        BCM_TRUNK_PSC_MACDA)
     58 
     59 
     60 
     61 static int _chassis_ast_default_lm_psc  = BCM_TRUNK_PSC_DSTMAC;
     62 static int _chassis_ast_default_cfm_psc = BCM_TRUNK_PSC_SRCMAC;
     63 
     64 /* CFM Trunk create callback handler */
     65 STATIC int
     66 chassis_ast_cfm_trunk(int unit, int tid,
     67                       bcm_trunk_info_t *trunk,
     68                       int member_count,
     69                       bcm_trunk_member_t *member_array,
     70                       void *cookie)
     71 {
     72     COMPILER_REFERENCE(cookie);
     73     trunk->psc = _chassis_ast_default_cfm_psc;
     74     return bcm_trunk_set(unit, tid, trunk, member_count, member_array);
     75 }
     76 
     77 /* Single device CFM */
     78 STATIC int
     79 chassis_ast_cfm(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
     80 {
     81     int                  unit;
     82     bcm_module_t         mod;
     83     int                  rv = BCM_E_NONE;
     84     bcm_port_t           port;
     85     bcm_port_config_t    config;
     86 
     87     unit = 0;            /* board fabric unit */
     88 
     89     BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
     90     BCM_PBMP_ITER(config.cpu, port) {
     91         break;   /* Get CPU port */
     92     }
     93     mod = db_ref->local_entry->mod_ids[0];
     94 
     95     BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, mod));
     96     BCM_IF_ERROR_RETURN(bcm_stk_modport_set(unit, mod, port));
     97     BCM_IF_ERROR_RETURN(bcm_board_fab_mod_map(unit,
     98                                               tp_cpu,
     99                                               db_ref->local_entry));
    100     bcm_board_unknown_src_modid_setup(db_ref->local_entry);
    101     bcm_board_trunk_callback_add(chassis_ast_cfm_trunk, NULL);
    102     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(&tp_cpu->local_entry,
    103                                                db_ref, BCM_BOARD_TRUNK_NORMAL));
    104     return rv;
    105 }
    106 
    107 /* LM Trunk create callback handler */
    108 STATIC int
    109 chassis_ast_lm_trunk(int unit, int tid,
    110                      bcm_trunk_info_t *trunk,
    111                      int member_count,
    112                      bcm_trunk_member_t *member_array,
    113                      void *cookie)
    114 {
    115     int i,j;
    116     int slot;
    117     bcm_module_t modid;
    118     bcm_board_cfm_info_t *cfm_info = (bcm_board_cfm_info_t *)cookie;
    119     bcm_port_t local_port;
    120 
    121     trunk->psc = _chassis_ast_default_lm_psc;
    122     BCM_IF_ERROR_RETURN(bcm_trunk_set(unit, tid, trunk, member_count,
    123                 member_array));
    124 
    125     for (i=0; i<member_count; i++) {
    126         BCM_IF_ERROR_RETURN(
    127             bcm_port_local_get(unit, member_array[i].gport, &local_port));
    128         for (j=0; j<cfm_info->count; j++) {
    129             slot = cfm_info->cfm[j].slot;
    130             modid = cfm_info->cfm[j].modid;
    131             LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    132                         (BSL_META("slot:%d unit:%d tid:%d modid:%d port:%d n:%d\n"),
    133                          slot,
    134                          unit,
    135                          tid,
    136                          modid,
    137                          local_port,
    138                          cfm_info->count));
    139             /* Override trunking of CFM modid if there is more than
    140                one CFM */
    141             BCM_IF_ERROR_RETURN(
    142                 bcm_trunk_override_ucast_set(unit, local_port, tid,
    143                                              modid,
    144                                              (cfm_info->count > 1)));
    145         }
    146     }
    147 
    148     return BCM_E_NONE;
    149 }
    150 
    151 /* LM with a single device that connects to the CFMs */
    152 
    153 static int cfm_fp_entries = 0;
    154 static bcm_field_group_t cfm_fp_group ;
    155 static bcm_field_entry_t cfm_fp_entry[NUM_CFM];
    156 
    157 STATIC int
    158 install_cfm_fp(int unit, bcm_board_cfm_info_t *cfm_info)
    159 {
    160     
    161     if (cfm_info->count > 1) {
    162         /* Install fp rule to redirect CFM destination packets. This
    163          is needed because the default L2 switch forwarding will not
    164          forward a packet on the link or trunk it was received
    165          on. Because all the LM external stack ports are trunked, that
    166          means that any packet received from one CFM that is destined
    167          for another CFM will be dropped.
    168         */
    169         bcm_field_qset_t  qset;
    170         bcm_port_t dstport;
    171         bcm_pbmp_t dstpbmp;
    172         int i;
    173 
    174         BCM_FIELD_QSET_INIT(qset);
    175         BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyDstPort);
    176         BCM_FIELD_QSET_ADD(qset, bcmFieldQualifySrcPort);
    177 
    178         /* Destroy previous group if needed; ignore errors for now */
    179         if (cfm_fp_entries > 0) {
    180             int rv;
    181 
    182             for ( i=0; i<cfm_fp_entries; i++) {
    183                 rv = bcm_field_entry_remove(unit, cfm_fp_entry[i]);
    184                 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    185                             (BSL_META("bcm_field_entry_remove(%d, %d)=%d\n"),
    186                              unit,
    187                              cfm_fp_entry[i],
    188                              rv));
    189             }
    190             rv = bcm_field_group_destroy(unit, cfm_fp_group);
    191             LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    192                         (BSL_META("bcm_field_group_destroy(%d, %d)=%d\n"),
    193                          unit,
    194                          cfm_fp_group,
    195                          rv));
    196         }
    197         
    198         /* Create group */
    199         BCM_IF_ERROR_RETURN(bcm_field_group_create(unit, qset, 
    200                                                    BCM_FIELD_GROUP_PRIO_ANY,
    201                                                    &cfm_fp_group));
    202         /* Create entries for each CFM */
    203 
    204         cfm_fp_entries = 0;
    205 
    206         for ( i=0; i<cfm_info->count; i++) {
    207 
    208             BCM_IF_ERROR_RETURN
    209                 (bcm_field_entry_create(unit, cfm_fp_group, &cfm_fp_entry[i]));
    210 
    211             { int partner = (i == 0) ? 1 : 0;
    212             /* coverity[copy_paste_error] */
    213             BCM_IF_ERROR_RETURN
    214                 (bcm_field_qualify_SrcPort(unit, cfm_fp_entry[i], 
    215                                             cfm_info->cfm[partner].modid,
    216                                             BCM_FIELD_EXACT_MATCH_MASK, 0, 0));
    217             }
    218 
    219             BCM_IF_ERROR_RETURN
    220                 (bcm_field_qualify_DstPort(unit, cfm_fp_entry[i], 
    221                                             cfm_info->cfm[i].modid,
    222                                             BCM_FIELD_EXACT_MATCH_MASK, 0, 0));
    223 
    224             BCM_PBMP_CLEAR(dstpbmp);
    225             BCM_IF_ERROR_RETURN
    226                 (bcm_topo_port_get(unit,
    227                                    cfm_info->cfm[i].modid,
    228                                    &dstport));
    229             BCM_PBMP_PORT_SET(dstpbmp, dstport);
    230             LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    231                         (BSL_META_U(unit,
    232                         "port:%d pbmp[0]:%x\n"),
    233                          dstport,
    234                          _SHR_PBMP_WORD_GET(dstpbmp, 0)));
    235 
    236             BCM_IF_ERROR_RETURN
    237                 (bcm_field_action_ports_add(unit, cfm_fp_entry[i], 
    238                                             bcmFieldActionRedirectPbmp,
    239                                             dstpbmp));
    240 
    241             BCM_IF_ERROR_RETURN
    242                 (bcm_field_entry_install(unit, cfm_fp_entry[i]));
    243 
    244             cfm_fp_entries++;
    245         }
    246         
    247     }
    248     
    249     return BCM_E_NONE;
    250 }
    251 
    252 STATIC int
    253 chassis_ast_lm(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref,
    254                bcm_board_port_connection_t *connection)
    255 {
    256     int                  unit;
    257     bcm_module_t         mod;
    258     int                  rv = BCM_E_NONE;
    259     bcm_port_t           port;
    260     bcm_port_config_t    config;
    261     bcm_board_cfm_info_t cfm_info;
    262 
    263     unit = 0;            /* board fabric unit */
    264 
    265     bcm_board_cfm_info(db_ref, &cfm_info);
    266     BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
    267     BCM_PBMP_ITER(config.cpu, port) {
    268         break;   /* Get CPU port */
    269     }
    270     mod = db_ref->local_entry->mod_ids[0];
    271 
    272     if (connection) {
    273         BCM_IF_ERROR_RETURN(
    274             bcm_board_xgs_local_switch(unit, tp_cpu, &config, connection));
    275         BCM_IF_ERROR_RETURN(
    276             bcm_board_xgs_local_fabric(unit, tp_cpu, &config));
    277     } else {
    278         BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, mod));
    279         BCM_IF_ERROR_RETURN(bcm_stk_modport_set(unit, mod, port));
    280     }
    281     
    282     BCM_IF_ERROR_RETURN(bcm_board_fab_mod_map(unit,
    283                                               tp_cpu,
    284                                               db_ref->local_entry));
    285 
    286     bcm_board_unknown_src_modid_setup(db_ref->local_entry);
    287     /* Trunk everything seen with hash 2, trunk create callback
    288        will handle CFM trunk override if necessary */
    289 
    290     bcm_board_trunk_callback_add(chassis_ast_lm_trunk, (void *)&cfm_info);
    291     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(&tp_cpu->local_entry,
    292                                                db_ref,
    293                                                BCM_BOARD_TRUNK_ALL));
    294 
    295     BCM_IF_ERROR_RETURN(install_cfm_fp(unit, &cfm_info));
    296     
    297     return rv;
    298 }
    299 
    300 
    301 /*
    302  * Function:    chassis_ast_cfm_xgs2
    303  *
    304  * Purpose:
    305  *     Program the XGS2 CFM board using asymmetric trunking.
    306  */
    307 int
    308 chassis_ast_cfm_xgs2(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
    309 {
    310     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    311                 (BSL_META("TOPO: XGS 5675 BCM956000 CFM (Asymmetric Trunk)\n")));
    312     _chassis_ast_default_cfm_psc = XGS2_CFM_HASH;
    313     return chassis_ast_cfm(tp_cpu, db_ref);
    314 }
    315 
    316 
    317 /*
    318  * Function:    chassis_ast_xgs2_48g
    319  *
    320  * Purpose:
    321  *     Program the XGS2-48G LM board using asymmetric trunking.
    322  */
    323 int
    324 chassis_ast_xgs2_48g(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
    325 {
    326     bcm_board_port_connection_t connection[5] = {
    327         { -1, -1 }, /* 5675 unit 0 */
    328         { 12, 1  }, /* 5695 unit 1 is on port 1 */
    329         { 12, 2  }, /* 5695 unit 2 is on port 2 */
    330         { 12, 3  }, /* 5673 unit 3 is on port 3 */
    331         { 12, 4  }, /* 5673 unit 4 is on port 4 */
    332     };
    333 
    334     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    335                 (BSL_META("TOPO: XGS 569x 48GE BCM956000 LM (Asymmetric Trunk)\n")));
    336     _chassis_ast_default_lm_psc = XGS2_LM_HASH;
    337     return chassis_ast_lm(tp_cpu, db_ref, connection);
    338 }
    339 
    340 /*
    341  * Function:    chassis_ast_xgs2_6x
    342  *
    343  * Purpose:
    344  *     Program the XGS2-6X LM board using asymmetric trunking.
    345  */
    346 int
    347 chassis_ast_xgs2_6x(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
    348 {
    349     bcm_board_port_connection_t connection[7] = {
    350         { -1, -1 },  /* 5675 unit 0 */
    351         {  1, 6  },  /* 5673 unit 1 is on port 6 */
    352         {  1, 7  },  /* 5673 unit 2 is on port 7 */
    353         {  1, 8  },  /* 5673 unit 3 is on port 8 */
    354         {  1, 1  },  /* 5673 unit 4 is on port 1 */
    355         {  1, 2  },  /* 5673 unit 5 is on port 2 */
    356         {  1, 3  },  /* 5673 unit 6 is on port 3 */
    357     };
    358 
    359     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    360                 (BSL_META("TOPO: XGS 5674 6XE BCM956000 LM (Asymmetric Trunk)\n")));
    361     _chassis_ast_default_lm_psc = XGS2_LM_HASH;
    362     return chassis_ast_lm(tp_cpu, db_ref, connection);
    363 }
    364 
    365 /*
    366  * Function:    chassis_ast_xgs3_12x
    367  *
    368  * Purpose:
    369  *     Program the XGS3-12X LM board using asymmetric trunking.
    370  */
    371 int
    372 chassis_ast_xgs3_12x(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
    373 {
    374     bcm_board_port_connection_t connection[5] = {
    375         { -1, -1 }, /* 5675 unit 0 - no connection map entry */
    376         { 27, 7  }, /* 56501 unit 1 port 27 connects to 5675 port 7 */
    377         { 27, 8  }, /* 56501 unit 2 port 27 connects to 5675 port 8 */
    378         { 27, 1  }, /* 56501 unit 3 port 27 connects to 5675 port 1 */
    379         { 27, 2  }, /* 56501 unit 4 port 27 connects to 5675 port 2 */
    380     };
    381 
    382     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    383                 (BSL_META("TOPO: XGS3 56501 12XE BCM956000 LM (Asymmetric Trunk)\n")));
    384     _chassis_ast_default_lm_psc = XGS2_LM_HASH;
    385     return chassis_ast_lm(tp_cpu, db_ref, connection);
    386 }
    387 
    388 
    389 /*
    390  * Function:    chassis_ast_cfm_xgs3
    391  *
    392  * Purpose:
    393  *     Program the XGS3 CFM board using asymmetric trunking.
    394  */
    395 int
    396 chassis_ast_cfm_xgs3(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
    397 {
    398     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    399                 (BSL_META("TOPO: XGS 56700 BCM956000 CFM (Asymmetric Trunk)\n")));
    400     return chassis_ast_cfm(tp_cpu, db_ref);
    401 }
    402 
    403 /*
    404  * Function:    chassis_ast_cfm_xgs3
    405  *
    406  * Purpose:
    407  *     Program the 56800 LM board using asymmetric trunking.
    408  */
    409 int
    410 chassis_ast_56800_12x(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
    411 {
    412     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    413                 (BSL_META("TOPO: XGS3 56800 BCM956000 LM (Asymmetric Trunk)\n")));
    414     return chassis_ast_lm(tp_cpu, db_ref, NULL);
    415 }
    416 
    417 /*****************************************************************************
    418 
    419   LM XGS3 48G
    420 
    421   The XGS3 48G Line module is more complex that the others because
    422 
    423    (a) Load balancing is unit based, rather than trunk based due to
    424        the board connectivity
    425 
    426    (b) Unlike the other LMs, it introduces a loop into the system
    427        topology, which must be pruned to eliminate multicast storms.
    428 
    429   The two units on the board are labled as 'master' and 'partner'. The
    430   master unit is the unit that connects directly to the master CFM;
    431   the partner is the other unit. This relationship varies, depending
    432   on the CFM and backplane, so make the determination is made
    433   dynamically.
    434 
    435  */
    436 
    437 #define FB_HG0 24 /* External */
    438 #define FB_HG1 25 /* External */
    439 #define FB_HG2 26 /* Internal */
    440 #define FB_HG3 27 /* Internal */
    441 
    442 /*
    443 
    444   Determine which unit is connected to the master CFM and which is the
    445   partner.
    446 
    447  */
    448 
    449 STATIC int
    450 _ast_xgs3_48g_unit(topo_cpu_t *tp_cpu,
    451                   bcm_board_cfm_info_t *cfm_info,
    452                   int *master,
    453                   int *partner)
    454 {
    455     int             i,m;
    456     topo_stk_port_t *tsp;
    457     cpudb_entry_t   *l_entry = &tp_cpu->local_entry;
    458     int             unit, master_unit = -1;
    459     bcm_module_t    cfm_modid;
    460 
    461     if (cfm_info->count == 0) {
    462         /* No CFM */
    463         *master = 0;
    464         *partner = 1;
    465         return BCM_E_NONE;
    466     }
    467 
    468     cfm_modid = cfm_info->cfm[cfm_info->master].modid;
    469     for (i = 0; i < l_entry->base.num_stk_ports; i++) {
    470         if (!(l_entry->sp_info[i].flags & CPUDB_SPF_TX_RESOLVED)) {
    471             /* Skip unresolved ports */
    472             continue;
    473         }
    474 
    475         tsp = &tp_cpu->tp_stk_port[i];
    476         unit = l_entry->base.stk_ports[i].unit;
    477 
    478         if (master_unit < 0) {
    479             for (m = 0; m < tsp->tx_mod_num; m++) {
    480                 if (tsp->tx_mods[m] == cfm_modid) {
    481                     *master = unit;
    482                     *partner = (unit == 0) ? 1 : 0;
    483                     return BCM_E_NONE;
    484                 }
    485             }
    486         }
    487     }
    488 
    489     return BCM_E_NOT_FOUND;
    490 }
    491 
    492 /*
    493 
    494    Program the external module mapping. If there's only one CFM,
    495    then the master unit points to all the external modids, and the
    496    partner points to the master unit. If there's two CFMs, then both
    497    units can point to all the external modids.
    498 
    499  */
    500 
    501 STATIC int
    502 _ast_xgs3_48g_ext_mod_program(topo_cpu_t *tp_cpu,
    503                               bcm_board_cfm_info_t *cfm_info,
    504                               int master, int partner)
    505 {
    506     int             i,m;
    507     topo_stk_port_t *tsp;
    508     cpudb_entry_t   *l_entry = &tp_cpu->local_entry;
    509     bcm_port_t      port;
    510     bcm_module_t    mod;
    511     int             dual = (cfm_info->count > 1);
    512 
    513     for (i = 0; i < l_entry->base.num_stk_ports; i++) {
    514         if (!(l_entry->sp_info[i].flags & CPUDB_SPF_TX_RESOLVED)) {
    515             /* Skip unresolved ports */
    516             continue;
    517         }
    518 
    519         tsp = &tp_cpu->tp_stk_port[i];
    520         port = l_entry->base.stk_ports[i].port;
    521 
    522         for (m = 0; m < tsp->tx_mod_num; m++) {
    523             mod = tsp->tx_mods[m];
    524             BCM_IF_ERROR_RETURN(bcm_stk_modport_set(master, mod, port));
    525             BCM_IF_ERROR_RETURN(bcm_stk_modport_set(partner, mod,
    526                                                     (dual) ? port : FB_HG2));
    527         }
    528     }
    529 
    530     return BCM_E_NONE;
    531 }
    532 
    533 /*
    534  * Function:    chassis_ast_xgs3_48g
    535  *
    536  * Purpose:
    537  *     Program the XGS3-48G LM board using asymmetric trunking.
    538  */
    539 int
    540 chassis_ast_xgs3_48g(topo_cpu_t *tp_cpu, cpudb_ref_t db_ref)
    541 {
    542     bcm_module_t             master_modid;
    543     bcm_module_t             partner_modid;
    544     bcm_board_cfm_info_t     cfm_info;
    545     bcm_port_config_t        config;
    546     int                      master, partner;
    547 
    548     bcm_board_cfm_info(db_ref, &cfm_info);
    549 
    550     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    551                 (BSL_META("TOPO: XGS3 56504 48GE BCM956000 LM (Asymmetric Trunk)\n")));
    552 
    553     /* Get master and partner units and modids */
    554     BCM_IF_ERROR_RETURN(_ast_xgs3_48g_unit(tp_cpu, &cfm_info,
    555                                            &master, &partner));
    556 
    557     if ((master < 0) || (master > 1) || (partner < 0) || (partner > 1)) {
    558         LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    559                     (BSL_META("Parameter error: master=%d partner=%d\n"),
    560                      master, partner));
    561         return BCM_E_INTERNAL;
    562     }
    563 
    564     master_modid = tp_cpu->local_entry.mod_ids[master];
    565     partner_modid = tp_cpu->local_entry.mod_ids[partner];
    566 
    567     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    568                 (BSL_META("Master: %d,%d\n"),
    569                  master, master_modid));
    570     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    571                 (BSL_META("Partner: %d,%d\n"),
    572                  partner, partner_modid));
    573 
    574     /* Assign modids */
    575     BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(master, master_modid));
    576     BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(partner, partner_modid));
    577 
    578     /* Set external modid mapping */
    579     BCM_IF_ERROR_RETURN(_ast_xgs3_48g_ext_mod_program(tp_cpu, &cfm_info,
    580                                                   master, partner));
    581 
    582     /* Set internal modid mapping */
    583     BCM_IF_ERROR_RETURN(bcm_stk_modport_set(master,
    584                                             partner_modid,
    585                                             FB_HG2));
    586 
    587     BCM_IF_ERROR_RETURN(bcm_stk_modport_set(partner,
    588                                             master_modid,
    589                                             FB_HG2));
    590 
    591     /* Add internal stack ports */
    592     BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(master,
    593                                                         FB_HG2));
    594     BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(master,
    595                                                         FB_HG3));
    596     BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(partner,
    597                                                         FB_HG2));
    598     BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(partner,
    599                                                         FB_HG3));
    600 
    601     /* Create trunks */
    602 
    603     bcm_board_trunk_callback_add(chassis_ast_lm_trunk, (void *)&cfm_info);
    604     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(&tp_cpu->local_entry, db_ref,
    605                                                BCM_BOARD_TRUNK_NORMAL));
    606     BCM_IF_ERROR_RETURN(_bcm_board_setup_trunk_lm_xgs3_48g());
    607 
    608     BCM_IF_ERROR_RETURN(bcm_port_config_get(0, &config));
    609     BCM_IF_ERROR_RETURN(bcm_board_module_filter(0, tp_cpu, db_ref,
    610                                                 &config));
    611     BCM_IF_ERROR_RETURN(bcm_port_config_get(1, &config));
    612     BCM_IF_ERROR_RETURN(bcm_board_module_filter(1, tp_cpu, db_ref,
    613                                                 &config));
    614     if (cfm_info.count > 1) {
    615         /* flood block internal to external stack ports */
    616         BCM_IF_ERROR_RETURN(bcm_port_flood_block_set(master,
    617                                                      FB_HG2, FB_HG0, -1U));
    618         BCM_IF_ERROR_RETURN(bcm_port_flood_block_set(master,
    619                                                      FB_HG2, FB_HG1, -1U));
    620         BCM_IF_ERROR_RETURN(bcm_port_flood_block_set(master,
    621                                                      FB_HG3, FB_HG0, -1U));
    622         BCM_IF_ERROR_RETURN(bcm_port_flood_block_set(master,
    623                                                      FB_HG3, FB_HG1, -1U));
    624         BCM_IF_ERROR_RETURN(bcm_port_flood_block_set(partner,
    625                                                      FB_HG2, FB_HG0, -1U));
    626         BCM_IF_ERROR_RETURN(bcm_port_flood_block_set(partner,
    627                                                      FB_HG2, FB_HG1, -1U));
    628         BCM_IF_ERROR_RETURN(bcm_port_flood_block_set(partner,
    629                                                      FB_HG3, FB_HG0, -1U));
    630         BCM_IF_ERROR_RETURN(bcm_port_flood_block_set(partner,
    631                                                      FB_HG3, FB_HG1, -1U));
    632     }
    633 
    634 #ifdef BCM_BOARD_AUTO_E2E
    635     /* intra-board end to end flow control, if available */
    636     BCM_IF_ERROR_RETURN(_bcm_board_dual_xgs3_e2e_set(master,  master_modid,
    637                                                      partner, partner_modid));
    638 #endif  /* BCM_BOARD_AUTO_E2E */
    639 
    640     return BCM_E_NONE;
    641 }
    642 
    643 
    644 
    645 #else
    646 int _brd_chassis_ast_not_empty;
    647 #endif /* INCLUDE_CHASSIS */