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_common.c (46076B)


      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_common.c
      8  * Purpose:     Common XGS board programming functions
      9  */
     10 #include <shared/bsl.h>
     11 #include <shared/alloc.h>
     12 
     13 #include <sdk_config.h>
     14 #include <sal/core/sync.h>
     15 
     16 #include <bcm/error.h>
     17 #include <bcm/port.h>
     18 #include <bcm/stack.h>
     19 #include <bcm/init.h>               /* bcm_info_get */
     20 #include <bcm/trunk.h>
     21 #include <bcm/topo.h>
     22 #include <bcm/mirror.h>
     23 #include <bcm/switch.h>
     24 #include <bcm_int/esw/mirror.h>
     25 
     26 #include <appl/cputrans/nh_tx.h>    /* nh_tx_src_get */
     27 #include <appl/cputrans/cpu2cpu.h>    /* nh_tx_src_get */
     28 #include <appl/stktask/topology.h>
     29 #include <appl/stktask/topo_brd.h>
     30 #include <appl/stktask/stktask.h>       /* bcm_st_reserved_modid_enable_get */
     31 
     32 #include "topo_int.h"
     33 
     34 #if defined(BCM_BOARD_AUTO_TRUNK)
     35 #define AUTO_TRUNK_DEFAULT TRUE
     36 #else
     37 #define AUTO_TRUNK_DEFAULT FALSE
     38 #endif
     39 
     40 typedef struct _trunk_info_s {
     41     int num_ports;
     42     bcm_trunk_member_t member[BCM_TRUNK_FABRIC_MAX_PORTCNT];
     43     bcm_trunk_info_t info;
     44 } _trunk_info_t;
     45 
     46 static int _bcm_board_auto_trunk_enable = AUTO_TRUNK_DEFAULT;
     47 
     48 #ifndef BCM_BOARD_MAX_MODID
     49 #define BCM_BOARD_MAX_MODID   32
     50 #endif
     51 
     52 static int _bcm_board_num_modids = BCM_BOARD_MAX_MODID;
     53 
     54 /*
     55  * Function:
     56  *     bcm_board_auto_trunk_set
     57  * Purpose:
     58  *     Sets the auto trunk state for this CPU subsystem
     59  * Parameters:
     60  *     flag - FALSE=no automatic trunking !FALSE=automatic trunking
     61  * Returns:
     62  *     BCM_E_NONE
     63  * Notes:
     64  */
     65 
     66 int
     67 bcm_board_auto_trunk_set(int flag)
     68 {
     69     _bcm_board_auto_trunk_enable = flag;
     70 
     71     return BCM_E_NONE;
     72 }
     73 
     74 /*
     75  * Function:
     76  *     bcm_board_auto_trunk_get
     77  * Purpose:
     78  *     Gets the current auto trunk state for this CPU subsystem
     79  * Parameters:
     80  *     flag - pointer to state variable
     81  * Returns:
     82  *     BCM_E_NONE
     83  * Notes:
     84  *      See bcm_board_auto_trunk_set for the meaning of the flag variable
     85  */
     86 
     87 int
     88 bcm_board_auto_trunk_get(int *flag)
     89 {
     90     if (flag) {
     91         *flag = _bcm_board_auto_trunk_enable;
     92     }
     93 
     94     return BCM_E_NONE;
     95 }
     96 
     97 
     98 /*
     99  * Function:
    100  *     bcm_board_num_modid_set
    101  * Purpose:
    102  *     Gets the maximum number of modids for this CPU subsystem
    103  * Parameters:
    104  *     num - maximum number of modids
    105  * Returns:
    106  *     BCM_E_NONE
    107  * Notes:
    108  */
    109 
    110 int
    111 bcm_board_num_modid_set(int num)
    112 {
    113     _bcm_board_num_modids = num;
    114 
    115     return BCM_E_NONE;
    116 }
    117 
    118 /*
    119  * Function: bcm_board_num_modid_get
    120  *     
    121  * Purpose:
    122  *     Gets the maximum number of modids for this CPU subsystem
    123  * Parameters:
    124  *     num - pointer to variable
    125  * Returns:
    126  *     BCM_E_NONE
    127  */
    128 
    129 int
    130 bcm_board_num_modid_get(int *num)
    131 {
    132     if (num) {
    133         *num = _bcm_board_num_modids;
    134     }
    135 
    136     return BCM_E_NONE;
    137 }
    138 
    139 STATIC bcm_board_trunk_cb_f bcm_board_trunk_callback_func;
    140 STATIC void *               bcm_board_trunk_callback_cookie;
    141 
    142 int bcm_board_trunk_callback_add(bcm_board_trunk_cb_f func,
    143                                  void *cookie)
    144 {
    145     bcm_board_trunk_callback_func   = func;
    146     bcm_board_trunk_callback_cookie = cookie;
    147 
    148     return BCM_E_NONE;
    149 }
    150 
    151 int bcm_board_trunk_callback_remove(bcm_board_trunk_cb_f func,
    152                                     void *cookie)
    153 {
    154     bcm_board_trunk_callback_func   = NULL;
    155     bcm_board_trunk_callback_cookie = NULL;
    156 
    157     return BCM_E_NONE;
    158 }
    159 
    160 #define TRUNK_STATUS_FREE 1
    161 #define TRUNK_STATUS_BUSY 2
    162 
    163 STATIC int
    164 _to_devport(int unit, bcm_gport_t gport)
    165 {
    166     return (BCM_GPORT_IS_DEVPORT(gport)) ?
    167             gport : BCM_GPORT_DEVPORT(unit, gport);
    168 }
    169 
    170 STATIC int
    171 _bcm_board_port_match(int unit, bcm_trunk_member_t *a, bcm_trunk_member_t *b)
    172 {
    173     bcm_gport_t ga, gb;
    174 
    175     ga = _to_devport(unit, a->gport);
    176     gb = _to_devport(unit, b->gport);
    177 
    178     if (ga != gb) {
    179         return FALSE;
    180     }
    181 
    182     if (a->flags != b->flags) {
    183         return FALSE;
    184     }
    185 
    186     return TRUE;
    187                      
    188 }
    189 STATIC int
    190 _bcm_board_trunk_match(int unit,
    191                        _trunk_info_t *a, _trunk_info_t *b)
    192 {
    193     int i;
    194 
    195     if (a->num_ports != b->num_ports) {
    196         return FALSE;
    197     }
    198 
    199     for (i=0; i<a->num_ports; i++) {
    200         if (!_bcm_board_port_match(unit, a->member + i, b->member + i)) {
    201             return FALSE;
    202         }
    203     }
    204 
    205     return TRUE;
    206 }
    207 
    208 STATIC int
    209 _bcm_board_trunk_make(int unit, _trunk_info_t *trunk,
    210                       int start_tid, int *status, int trunk_maxnum)
    211 {
    212     int tid_offset;
    213     int tid_available;
    214     int tid;
    215     int rv;
    216     _trunk_info_t current;
    217 
    218     tid_available = -1;
    219     for (tid_offset = 0; tid_offset < trunk_maxnum; tid_offset++) {
    220         if (status[tid_offset] == 0) {
    221             tid = start_tid + tid_offset;
    222             rv = bcm_trunk_get(unit, tid, &current.info,
    223                                COUNTOF(current.member), current.member,
    224                                &current.num_ports);
    225 
    226             if (BCM_FAILURE(rv)) {
    227                 if (rv == BCM_E_NOT_FOUND) {
    228                     if (tid_available < 0) {
    229                         tid_available = tid_offset;
    230                         LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    231                                     (BSL_META_U(unit,
    232                                     "Available trunk %d\n"),
    233                                      tid));
    234                     } else {
    235                         LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    236                                     (BSL_META_U(unit,
    237                                     "Free trunk %d\n"),
    238                                      tid));
    239                     }
    240                     status[tid_offset] = TRUNK_STATUS_FREE;
    241                 } else if (rv == BCM_E_PARAM) {
    242                     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    243                                 (BSL_META_U(unit,
    244                                 "Illegal trunk %d\n"),
    245                                  tid));
    246                     break;
    247                 } else {
    248                     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    249                                 (BSL_META_U(unit,
    250                                 "Trunk %d error %d\n"),
    251                                  tid, rv));
    252                     return rv;
    253                 }
    254             } else if (_bcm_board_trunk_match(unit, trunk, &current)) {
    255                 /* have a trunk that matches requirements */
    256                 status[tid_offset] = TRUNK_STATUS_BUSY;
    257                 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    258                             (BSL_META_U(unit,
    259                             "Reusing trunk %d\n"),
    260                              tid));
    261                 return BCM_E_NONE;
    262             }
    263         } else if (status[tid_offset] == TRUNK_STATUS_FREE &&
    264                    tid_available < 0) {
    265             tid_available = tid_offset;
    266         }
    267     }
    268 
    269     if (tid_available < 0) {
    270         LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    271                     (BSL_META_U(unit,
    272                     "No free trunk was found\n")));
    273         return BCM_E_UNAVAIL;
    274     }
    275     tid = start_tid + tid_available;
    276     BCM_IF_ERROR_RETURN
    277         (bcm_trunk_create(unit, BCM_TRUNK_FLAG_WITH_ID, &tid));
    278     BCM_IF_ERROR_RETURN(bcm_trunk_set(unit, tid, &trunk->info,
    279                                       trunk->num_ports,
    280                                       trunk->member));
    281     status[tid_available] = TRUNK_STATUS_BUSY;
    282     LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    283                 (BSL_META_U(unit,
    284                 "Created trunk %d\n"),
    285                  tid));
    286     return BCM_E_NONE;
    287 }
    288 
    289 STATIC int
    290 _bcm_board_trunk_remove(int unit, 
    291                         int start_tid, int *status, int trunk_maxnum)
    292 {
    293     int tid_offset;
    294     int tid;
    295     int rv;
    296 
    297     for (tid_offset = 0; tid_offset < trunk_maxnum; tid_offset++) {
    298         if (status[tid_offset] == 0) {
    299             tid = start_tid + tid_offset;
    300             rv = bcm_trunk_destroy(unit, tid);
    301             if (BCM_FAILURE(rv) && (BCM_E_NOT_FOUND != rv)) {
    302                 break;
    303             }
    304             LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    305                         (BSL_META_U(unit,
    306                         "Destroyed trunk %d\n"),
    307                          tid));
    308         }
    309     }
    310 
    311     return BCM_E_NONE;
    312 }
    313 
    314 
    315 /*
    316  * Function:
    317  * _bcm_board_trunk_interconnect_mark
    318  *
    319  * Purpose:
    320  * Iterate through all the existing fabric trunks and find out the
    321  * one's which are interconnect trunks. For these trunks mark the
    322  * status as 'TRUNK_STATUS_BUSY' in the given status array.
    323  *
    324  * Parameters:
    325  *     unit   - device of fabric unit
    326  *     entry  - local board's cpudb entry
    327  *     start  - starting tid
    328  *     status  - array to maintain trunk status
    329  *     trunk_maxnum - max number of fabric trunks
    330  * Returns:
    331  *      BCM_E_NONE
    332  */
    333 STATIC int
    334 _bcm_board_trunk_interconnect_mark(int unit, cpudb_entry_t *entry,
    335                                    int start, int *status, int trunk_maxnum)
    336 {
    337     int             rv;
    338     int             tid_offset;
    339     int             member_prt;
    340     int             cpudb_prt;
    341     _trunk_info_t   trunk;
    342 
    343     /*
    344      * Check the status of the interconnect/internal trunk and if exists then
    345      * do not destroy the interconnects while setting up External Stack Links
    346      */
    347     for (tid_offset = 0; tid_offset < trunk_maxnum; tid_offset++) {
    348         if (status[tid_offset] == 0) {
    349             rv = bcm_trunk_get(unit, (start + tid_offset), &trunk.info,
    350                                COUNTOF(trunk.member), trunk.member,
    351                                &trunk.num_ports);
    352             if (BCM_SUCCESS(rv)) {
    353 
    354                 /*
    355                  * Check whether this trunk is an interconnect trunk by
    356                  * comparing the IC trunk ports with the external stacking ports
    357                  */
    358                 for (member_prt = 0, cpudb_prt = 0;
    359                     member_prt < trunk.num_ports; member_prt++) {
    360 
    361                     /* Iterate through the ports in CPUDB */
    362                     for (; cpudb_prt < entry->base.num_stk_ports; cpudb_prt++) {
    363                         /* Skip if port unit is not the one being processed */
    364                         if (entry->base.stk_ports[cpudb_prt].unit != unit) {
    365                             continue;
    366                         }
    367 
    368                         /*
    369                          * Here stk_ports are external stacking ports only, They
    370                          * do not  include interconnect  stacking links.  If the
    371                          * member of this trunk matches with any stacking ports,
    372                          * then mark the current trunk as non-interconnect.
    373                          */
    374                         if (trunk.member[member_prt].gport
    375                              == BCM_GPORT_DEVPORT(unit,
    376                                     entry->base.stk_ports[cpudb_prt].port)) {
    377                             break;
    378                         }
    379                     }
    380 
    381                     /*
    382                      * If the trunk port is external stack port then
    383                      * do not continue with other ports of the trunk.
    384                      */
    385                     if (cpudb_prt < entry->base.num_stk_ports) break;
    386                 }
    387 
    388                 /* If it is interconnect trunk, then update the status */
    389                 if ((member_prt >= trunk.num_ports)
    390                     && (cpudb_prt >= entry->base.num_stk_ports)) {
    391                     status[tid_offset] = TRUNK_STATUS_BUSY;
    392                 }
    393             }
    394         }
    395     }
    396 
    397     return BCM_E_NONE;
    398 }
    399 
    400 /*
    401  * Function:
    402  *     _bcm_board_trunk_unit
    403  * Purpose:
    404  *     Program fabric trunks for external stack ports (unit specific).
    405  *     External stack ports for the specified unit are trunked if
    406  *     the following conditions are met:
    407  *     - TX CPU keys are the same, and
    408  *     - If stack-port information for the remote TX CPU entry is valid,
    409  *       check that the remote stack-port units are the same.
    410  *
    411  *     This routine can be used to create/destroy trunks that are 
    412  *     symmetric as well as asymmetric.
    413  *
    414  *     Symmetric trunks are defined when stack links on a unit are
    415  *     connected to the same remote unit, or, if different remote units,
    416  *     these must reside in different CPUs.
    417  *
    418  *     Asymmetric trunks are defined when stack links on a unit are
    419  *     connected to two different remote units that reside on the
    420  *     same CPU.  To set the trunks correctly, the CPU database must
    421  *     contain valid stack-port information for remote CPU entries.
    422  *
    423  *     If stack-port information for remote CPU entries is not
    424  *     available, perform old behavior.
    425  *
    426  *     If a trunk create callback is set, the the callback will be
    427  *     called with the constructed trunk parameters; the application
    428  *     must then call bcm_trunk_set(). This allows the application
    429  *     to affect trunk setup (before trunk creation) and also
    430  *     perform trunk post processing.
    431  *
    432  *     If there is no callback, then this function will call
    433  *     bcm_trunk_set() to construct the trunk.
    434  *
    435  * Parameters:
    436  *     unit   - device of fabric unit
    437  *     entry  - local board's cpudb entry
    438  *     db_ref - database of current configuration
    439  *     start  - starting tid
    440  *     flags  - control flags
    441  * Returns:
    442  *      BCM_E_XXX
    443  * Notes:
    444  *     Some early discovery versions do not carry stack-port information
    445  *     for remote CPU entries.
    446  */
    447 
    448 
    449 STATIC int
    450 _bcm_board_trunk_unit(int unit, cpudb_entry_t *entry, cpudb_ref_t db_ref,
    451                       int start, int flags)
    452 {
    453     int                     tid, rv = BCM_E_NONE, i, j;
    454     int                     idx;
    455     _trunk_info_t           trunk;
    456     cpudb_entry_t           *tx_entry;
    457     cpudb_key_t             tx_key;   /* TX key, unit on master port to .. */
    458     int                     tx_unit;  /* .. compare against */
    459     cpudb_key_t             pkey;     /* TX key, unit on other ports being ..*/
    460     int                     punit;    /* .. compare to master port */
    461     bcm_gport_t             devport;
    462     SHR_BITDCLNAME(pseen, CPUDB_CXN_MAX);
    463     int                     *trunk_status;
    464     bcm_trunk_chip_info_t   ti;
    465     int                     trunk_maxnum;
    466 
    467     /* Destroy any pre-existing fabric trunks */
    468     if (flags & BCM_BOARD_TRUNK_DESTROY) {
    469         for (tid = start;; tid++) {
    470             rv = bcm_trunk_destroy(unit, tid);
    471             if (BCM_FAILURE(rv) && (BCM_E_NOT_FOUND != rv)) {
    472                 break;
    473             }
    474         }
    475         if (tid != start) {
    476             LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    477                         (BSL_META_U(unit,
    478                         "TOPO: destroyed %d trunks\n"),
    479                          tid-start));
    480         }
    481         return BCM_E_NONE;
    482     }
    483 
    484 
    485     BCM_IF_ERROR_RETURN(bcm_trunk_chip_info_get(unit, &ti));
    486     trunk_maxnum = (ti.trunk_fabric_id_max - ti.trunk_fabric_id_min + 1);
    487     trunk_status = sal_alloc(trunk_maxnum * sizeof(int), "trunk_status_ptr");
    488     sal_memset(trunk_status, 0, trunk_maxnum * sizeof(int));
    489     
    490     sal_memset(pseen, 0, SHR_BITALLOCSIZE(CPUDB_CXN_MAX));
    491     sal_memset(&trunk, 0, sizeof(trunk));
    492     trunk.info.psc = -1; /* Default hash algorithm */
    493     trunk.info.dlf_index = -1;
    494     trunk.info.mc_index = -1;
    495     trunk.info.ipmc_index = -1;
    496     tid = start;
    497 
    498     /*
    499      * For each external stack port in entry (this is
    500      * the master port to compare against
    501      */
    502     for (i = 0; i < entry->base.num_stk_ports; i++) {
    503         /* Skip if stack port was already analyzed */
    504         if (SHR_BITGET(pseen, i)) {
    505             continue;
    506         }
    507 
    508         /* Set flag to indicate stack port is being analyzed */
    509         SHR_BITSET(pseen, i);
    510 
    511         /* Skip if TX is not known */
    512         if (!(entry->sp_info[i].flags & CPUDB_SPF_TX_RESOLVED)) {
    513             continue;
    514         }
    515 
    516         /* Skip if stack-port unit is not the one being processed */
    517         if (entry->base.stk_ports[i].unit != unit) {
    518             continue;
    519         }
    520 
    521         /*
    522          * Get the remote TX CPU key and unit for the master port
    523          */
    524         CPUDB_KEY_COPY(tx_key, entry->sp_info[i].tx_cpu_key);
    525         tx_entry = NULL;
    526         tx_unit = -1;
    527         if (db_ref) {
    528             CPUDB_KEY_SEARCH(db_ref, tx_key, tx_entry);
    529             if (tx_entry) {
    530                 idx = entry->sp_info[i].tx_stk_idx;
    531                 if ((idx >= 0) && (idx < CPUDB_CXN_MAX)) {
    532                     tx_unit = tx_entry->base.stk_ports[idx].unit;
    533                 }
    534             }
    535         }
    536 
    537         /*
    538          * Trunk only stack ports with same TX CPU key and
    539          * same remote stack-port unit.
    540          *
    541          * Note: If stack-port information for remote CPU entries
    542          *       is not available, then check for CPU key only
    543          *       (old behavior).
    544          */
    545         trunk.num_ports = 0;
    546         devport = BCM_GPORT_DEVPORT(unit, entry->base.stk_ports[i].port);
    547         bcm_trunk_member_t_init(&trunk.member[trunk.num_ports]);
    548         trunk.member[trunk.num_ports].gport = devport;
    549         trunk.num_ports++;
    550         for (j = i+1; j < entry->base.num_stk_ports; j++) {
    551             /*
    552              * Skip if: stack port was already analyzed, or
    553              *          TX is not known
    554              *          stack-port unit is not the one being processed
    555              */
    556             if (SHR_BITGET(pseen, j)) {
    557                 continue;
    558             }
    559             if (!(entry->sp_info[j].flags & CPUDB_SPF_TX_RESOLVED)) {
    560                 continue;
    561             }
    562             if (entry->base.stk_ports[j].unit != unit) {
    563                 continue;
    564             }
    565 
    566             /*
    567              * Get other stack port TX CPU key and unit to
    568              * compare against master port
    569              */
    570 
    571             if ((flags & BCM_BOARD_TRUNK_ALL) == 0) {
    572                 CPUDB_KEY_COPY(pkey, entry->sp_info[j].tx_cpu_key);
    573                 punit = -1;
    574                 if (tx_unit >= 0) {
    575                     idx = entry->sp_info[j].tx_stk_idx;
    576                     if ((idx >= 0) && (idx < CPUDB_CXN_MAX) && tx_entry) {
    577                         punit = tx_entry->base.stk_ports[idx].unit;
    578                     }
    579                 }
    580 
    581                 /* Skip port if TX CPU key or unit are different */
    582                 if (!CPUDB_KEY_EQUAL(tx_key, pkey) || (tx_unit != punit)) {
    583                     continue;
    584                 }
    585 
    586             }
    587 
    588             /* Mark stack port as analyzed, add to trunk group */
    589             SHR_BITSET(pseen, j);
    590             devport = BCM_GPORT_DEVPORT(unit, entry->base.stk_ports[j].port);
    591             bcm_trunk_member_t_init(trunk.member + trunk.num_ports);
    592             trunk.member[trunk.num_ports].gport = devport;
    593             trunk.num_ports++;
    594         }
    595 
    596         if (trunk.num_ports > 1) {
    597             if (bcm_board_trunk_callback_func) {
    598                 rv = bcm_trunk_create(unit, BCM_TRUNK_FLAG_WITH_ID, &tid);
    599                 if (BCM_FAILURE(rv) && (BCM_E_EXISTS != rv)) {
    600                     goto cleanup;
    601                 }
    602                 rv = bcm_board_trunk_callback_func(
    603                         unit, tid, &trunk.info, trunk.num_ports, 
    604                         trunk.member, bcm_board_trunk_callback_cookie);
    605                 if (BCM_FAILURE(rv)) {
    606                     goto cleanup;
    607                 }
    608                 trunk_status[tid - start] = TRUNK_STATUS_BUSY;
    609             } else {
    610                 rv = _bcm_board_trunk_make(
    611                         unit, &trunk, start, trunk_status, trunk_maxnum);
    612                 if (BCM_FAILURE(rv)) {
    613                     goto cleanup;
    614                 }
    615             }
    616             tid++;
    617         }
    618     }
    619 
    620     _bcm_board_trunk_interconnect_mark(unit, entry, start,
    621                                         trunk_status, trunk_maxnum);
    622 
    623     /* destroy any left over fabric trunks */
    624     rv = _bcm_board_trunk_remove(unit, start, trunk_status, trunk_maxnum);
    625 cleanup:
    626     sal_free(trunk_status);
    627 
    628     return rv;
    629 }
    630 
    631 /*
    632  * Function:
    633  *     bcm_board_trunk_system
    634  * Purpose:
    635  *     Program fabric trunks for stack ports using system information
    636  *     provided by CPU database.  This routine can be used
    637  *     to create/destroy trunks that are symmetric as well as asymmetric.
    638  *
    639  *     Symmetric trunks are defined when stack links on a unit are
    640  *     connected to the same remote unit, or, if different remote units,
    641  *     these must reside in different CPUs.
    642  *
    643  *     Asymmetric trunks are defined when stack links on a unit are
    644  *     connected to two different remote units that reside on the
    645  *     same CPU.  To set the trunks correctly, the CPU database must
    646  *     contain valid stack-port information for remote CPU entries.
    647  *
    648  * Parameters:
    649  *     entry  - local board's cpudb entry
    650  *     db_ref - database of current configuration
    651  *     flags  - trunk flags
    652  * Returns:
    653  *     BCM_E_XXX
    654  * Note:
    655  *     Some early discovery versions do not carry stack-port information
    656  *     for remote CPU entries.
    657  */
    658 int
    659 bcm_board_trunk_system(cpudb_entry_t *entry, cpudb_ref_t db_ref, int flags)
    660 {
    661     int                    unit;
    662     bcm_trunk_chip_info_t  ti;
    663     int                    auto_trunk;
    664 
    665     
    666     BCM_IF_ERROR_RETURN(bcm_board_auto_trunk_get(&auto_trunk));
    667     if (auto_trunk) {
    668         /* scan for board fabric units */
    669         for (unit = 0; unit < entry->base.num_units; unit++) {
    670             BCM_IF_ERROR_RETURN(bcm_trunk_chip_info_get(unit, &ti));
    671             if (ti.trunk_fabric_id_min >= 0) {
    672                 BCM_IF_ERROR_RETURN
    673                     (_bcm_board_trunk_unit(unit, entry, db_ref, 
    674                                            ti.trunk_fabric_id_min, 
    675                                            flags));
    676             }
    677         }
    678     }
    679     return BCM_E_NONE;
    680 }
    681 
    682 /*
    683  * Function:
    684  *     bcm_board_trunk_local
    685  * Purpose:
    686  *     Program fabric trunks for stack ports using local information.
    687  *     When creating trunks, this routine should be used for
    688  *     symmetric trunks only (see bcm_board_trunk_system for more
    689  *     information).
    690  *
    691  * Parameters:
    692  *     entry  - local board's cpudb entry
    693  *     flags  - trunk flags
    694  * Returns:
    695  *     BCM_E_XXX
    696  */
    697 int
    698 bcm_board_trunk_local(cpudb_entry_t *entry, int flags)
    699 {
    700     return bcm_board_trunk_system(entry, NULL, flags);
    701 }
    702 
    703 /*
    704  * Function:
    705  *     bcm_board_trunk_destroy
    706  * Purpose:
    707  *     Destroy all fabric trunks on board
    708  *
    709  * Parameters:
    710  *     entry  - local board's cpudb entry
    711  * Returns:
    712  *     BCM_E_XXX
    713  */
    714 int
    715 bcm_board_trunk_destroy(cpudb_entry_t *entry)
    716 {
    717     return bcm_board_trunk_system(entry, NULL, BCM_BOARD_TRUNK_DESTROY);
    718 }
    719 
    720 /*
    721  * Function:
    722  *    bcm_board__unknown_src_modid_setup
    723  * Purpose:
    724  *    Iterate over local stack ports and set NH src mod ID appropriately
    725  * Parameters:
    726  *    entry  - local board's cpudb entry
    727  * Returns:
    728  *    BCM_E_XXX
    729  */
    730 int
    731 bcm_board_unknown_src_modid_setup(cpudb_entry_t *entry)
    732 {
    733     int i;
    734     bcm_port_t port;
    735     int unit, modid;
    736 
    737     nh_tx_unknown_modid_get(&modid);
    738     for (i = 0; i < entry->base.num_stk_ports; i++) {
    739         unit = entry->base.stk_ports[i].unit;
    740         port = entry->base.stk_ports[i].port;
    741 
    742         if (!(entry->sp_info[i].flags & CPUDB_SPF_RX_RESOLVED) &&
    743             !(entry->sp_info[i].flags & CPUDB_SPF_TX_RESOLVED) &&
    744             !(entry->sp_info[i].flags & CPUDB_SPF_ETHERNET)) {
    745             BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit,
    746                          port, modid, TRUE));
    747         }
    748     }
    749 
    750     return BCM_E_NONE;
    751 }
    752 
    753 
    754 /*
    755  * Function:
    756  *     bcm_board_module_filter
    757  * Purpose:
    758  *     Program fabric source module filtering to prevent
    759  *     fabric loops.  Also programs egress port masking.
    760  * Parameters:
    761  *     unit   - fabric device
    762  *     tp_cpu - topology programming structure
    763  *     db_ref - database of current configuration
    764  *     config - port configuration for fabric device
    765  * Returns:
    766  *     BCM_E_XXX
    767  * Notes:
    768  *     Must be called once per board fabric device.
    769  *
    770  *     Some early discovery versions do not carry stack-port information
    771  *     for remote CPU entries.  This is needed for cases where stack
    772  *     links on a unit are connected to two different remote units 
    773  *     that reside on the same CPU and are interconnected through
    774  *     their internal stack links.
    775  *
    776  *     If stack-port information for remote CPU entries is not
    777  *     available, perform old behavior.
    778  *
    779  *     Also, verify that device has the corresponding support
    780  *     for SOURCE MODID BLOCKING.
    781  */
    782 
    783 
    784 int
    785 bcm_board_module_filter(int unit,
    786                         topo_cpu_t *tp_cpu,
    787                         cpudb_ref_t db_ref,
    788                         bcm_port_config_t *config)
    789 {
    790     cpudb_entry_t    *entry;
    791     int              i, j, m, rv, enable;
    792     bcm_port_t       port, eport;
    793     bcm_module_t     mod;
    794     bcm_pbmp_t       intports, extports, disports, enaports, ethports;
    795     topo_stk_port_t  *tsp;
    796     int              nhmod = -1, nhport;
    797     int              idx;
    798     cpudb_entry_t    *rx_entry;
    799     cpudb_key_t      rx_key;   /* RX key, unit on master port to .. */
    800     int              rx_unit;  /* .. compare against */
    801     cpudb_key_t      pkey;     /* RX key, unit on other ports being ..*/
    802     int              punit;    /* .. compare to master port */
    803     int              num_modids;
    804     SHR_BITDCLNAME(rxmod, BCM_BOARD_MAX_MODID);
    805 
    806     entry = &tp_cpu->local_entry;
    807     BCM_PBMP_ASSIGN(intports, config->stack_ext);
    808     BCM_PBMP_CLEAR(extports);
    809     BCM_PBMP_CLEAR(disports);
    810     BCM_PBMP_CLEAR(ethports);
    811 
    812     BCM_IF_ERROR_RETURN(bcm_board_num_modid_get(&num_modids));
    813     for (i = 0; i < entry->base.num_stk_ports; i++) {
    814         if (entry->base.stk_ports[i].unit != unit) {
    815             continue;
    816         }
    817         port = entry->base.stk_ports[i].port;
    818         
    819         if ((entry->sp_info[i].flags & CPUDB_SPF_ETHERNET)) {
    820             BCM_PBMP_PORT_ADD(ethports, port);
    821             continue;
    822         }
    823 
    824         /* If we're using a reserved NH modid, or there's no
    825            nhmod defined for this stack port, or there was a nhmod
    826            for this stack port but it was was less than zero, then get the
    827            default */
    828 
    829         if (bcm_st_reserved_modid_enable_get() ||
    830             nh_tx_src_mod_port_get(unit, port, &nhmod, &nhport) < 0 ||
    831             nhmod < 0) {
    832             if (nh_tx_src_get(&nhmod, &nhport) < 0 || nhmod < 0) {
    833                 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY,
    834                             (BSL_META_U(unit,
    835                             "TOPO: Could not get default NH src modid.\n")));
    836             }
    837         }
    838         
    839         sal_memset(rxmod, 0, SHR_BITALLOCSIZE(BCM_BOARD_MAX_MODID));
    840         if (nhmod >= 0 && nhmod < num_modids) {
    841             SHR_BITSET(rxmod, nhmod);    /* add nexthop module */
    842         }
    843 
    844         /*
    845          * Get the remote RX CPU key and unit for the master port
    846          */
    847         CPUDB_KEY_COPY(rx_key, entry->sp_info[i].rx_cpu_key);
    848         rx_entry = NULL;
    849         rx_unit = -1;
    850         if (db_ref) {
    851             CPUDB_KEY_SEARCH(db_ref, rx_key, rx_entry);
    852             if (rx_entry) {
    853                 idx = entry->sp_info[i].rx_stk_idx;
    854                 if ((idx >= 0) && (idx < CPUDB_CXN_MAX)) {
    855                     rx_unit = rx_entry->base.stk_ports[idx].unit;
    856                 }
    857             }
    858         }
    859 
    860         /*
    861          * Allow only mod IDs of those stack ports with same RX CPU key
    862          * and same remote stack-port unit.
    863          *
    864          * Note: If stack-port information for remote CPU entries
    865          *       is not available, then check for CPU key only
    866          *       (old behavior).
    867          */
    868         for (j = 0; j < entry->base.num_stk_ports; j++) {
    869             if (entry->base.stk_ports[j].unit != unit) {
    870                 continue;
    871             }
    872             if (!(entry->sp_info[j].flags & CPUDB_SPF_RX_RESOLVED)) {
    873                 continue;
    874             }
    875 
    876             /*
    877              * Get other stack port RX CPU key and unit to
    878              * compare against master port
    879              */
    880             CPUDB_KEY_COPY(pkey, entry->sp_info[j].rx_cpu_key);
    881             punit = -1;
    882             if (rx_unit >= 0) {
    883                 idx = entry->sp_info[j].rx_stk_idx;
    884                 if ((idx >= 0) && (idx < CPUDB_CXN_MAX) && rx_entry) {
    885                     punit = rx_entry->base.stk_ports[idx].unit;
    886                 }
    887             }
    888 
    889             /* Skip port if RX CPU key or unit are different */
    890             if (!CPUDB_KEY_EQUAL(rx_key, pkey) || (rx_unit != punit)) {
    891                 continue;
    892             }
    893 
    894             /* add modules that are rxable on this stack port */
    895             tsp = &tp_cpu->tp_stk_port[j];
    896             for (m = 0; m < tsp->rx_mod_num; m++) {
    897                 SHR_BITSET(rxmod, tsp->rx_mods[m]);
    898             }
    899         }
    900         
    901         for (mod = 0; mod < BCM_BOARD_MAX_MODID; mod++) {
    902             enable = SHR_BITGET(rxmod, mod) ? TRUE : FALSE;
    903             rv = bcm_port_modid_enable_set(unit, port, mod, enable);
    904             if (rv < 0) {
    905                 break;
    906             }
    907         }
    908         BCM_PBMP_PORT_REMOVE(intports, port);
    909         if (entry->sp_info[i].flags &
    910             (CPUDB_SPF_TX_RESOLVED|CPUDB_SPF_RX_RESOLVED)) {
    911             BCM_PBMP_PORT_ADD(extports, port);
    912         } else {
    913             BCM_PBMP_PORT_ADD(disports, port);
    914         }
    915     }
    916     
    917     /*
    918      * HG ports are now partitioned into three bitmaps:
    919      * extports - external stack ports that have connectivity
    920      * disports - external stack ports with no connectivity
    921      * intports - internal ports to other switches on the board
    922      *
    923      * enaports is a bitmap of all enabled ports (intports | extports)
    924      */
    925 
    926     BCM_PBMP_ASSIGN(enaports, intports);
    927     BCM_PBMP_OR(enaports, extports);
    928 
    929     /*
    930      * Egress port masking works in two classes:
    931      * - disabled ingress ports (disports) cannot send to any egress port
    932      *   (other than the cpu)
    933      * - enabled ingress ports (enaports) can send to any other enabled
    934      *   port
    935      */
    936     
    937     BCM_PBMP_ITER(disports, port) {
    938         BCM_PBMP_ITER(config->stack_ext, eport) {
    939             rv = bcm_port_flood_block_set(unit, port, eport, -1U);
    940             if (rv < 0) {
    941                 break;
    942             }
    943         }
    944     }
    945 
    946     BCM_PBMP_ITER(enaports, port) {
    947         BCM_PBMP_ITER(config->stack_ext, eport) {
    948             int flag = BCM_PBMP_MEMBER(enaports, eport) ? 0 : -1;
    949             rv = bcm_port_flood_block_set(unit, port, eport, flag);
    950             if (rv < 0) {
    951                 break;
    952             }
    953         }
    954     }
    955 
    956     /*
    957      * internal and Ethernet ports allow any module ids
    958      */
    959     enable = TRUE;
    960     BCM_PBMP_OR(intports, ethports);
    961     BCM_PBMP_ITER(intports, port) {
    962         rv = bcm_port_modid_enable_set(unit, port, -1, enable);
    963     }
    964 
    965     return BCM_E_NONE;
    966 }
    967 
    968 
    969 /*
    970  * Add stack ports according to configuration;
    971  * Adds internal ports assuming:
    972  *    Single fabric (funit >= 0)
    973  *    Each device attached to the fabric has an IPIC port specified.
    974  *    unitport is indexed by unit number and gives port on fabric
    975  */
    976 
    977 int
    978 bcm_board_internal_stk_port_add(int unit, int port)
    979 {
    980     uint32 flags;
    981 
    982     BCM_IF_ERROR_RETURN(bcm_stk_port_get(unit, port, &flags));
    983     if (!(flags & BCM_STK_ENABLE)) {
    984         BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, port,
    985                                              BCM_BOARD_INT_STK_FLAGS));
    986     }
    987 
    988     return BCM_E_NONE;
    989 }
    990 
    991 STATIC int
    992 _bcm_board_xgs_stk_port_add(int funit, topo_cpu_t *tp_cpu, int *unitport)
    993 {
    994     int unit, port;
    995     cpudb_entry_t *l_entry;
    996     uint32 flags;
    997 
    998     l_entry = &tp_cpu->local_entry;
    999 
   1000     /* First, make sure internal ports have been added */
   1001     for (unit = 0; unit < l_entry->base.num_units; unit++) {
   1002         port = unitport[unit];
   1003         if (port < 0) { /* Skip device (eg fabric module) */
   1004             continue;
   1005         }
   1006         BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(funit, port));
   1007 
   1008         if (bcm_stk_port_get(unit, BCM_STK_USE_HG_IF, &flags) < 0) {
   1009             LOG_WARN(BSL_LS_TKS_TOPOLOGY,
   1010                      (BSL_META_U(unit,
   1011                      "Could not get IPIC stack info for unit %d\n"),
   1012                       unit));
   1013             continue;
   1014         }
   1015         if (!(flags & BCM_STK_ENABLE)) {
   1016             BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, BCM_STK_USE_HG_IF,
   1017                                                  BCM_BOARD_INT_STK_FLAGS));
   1018         }
   1019     }
   1020 
   1021     return BCM_E_NONE;
   1022 }
   1023 
   1024 
   1025 /* Program stack port mod IDs */
   1026 int
   1027 bcm_board_fab_mod_map(int funit, topo_cpu_t *tp_cpu, cpudb_entry_t *l_entry)
   1028 {
   1029     int i, m;
   1030     topo_stk_port_t *tsp;
   1031     bcm_port_t port;
   1032     bcm_module_t mod;
   1033 
   1034     /* set up module routing for fabric ports */
   1035     for (i = 0; i < l_entry->base.num_stk_ports; i++) {
   1036         tsp = &tp_cpu->tp_stk_port[i];
   1037         port = l_entry->base.stk_ports[i].port;
   1038 
   1039         for (m = 0; m < tsp->tx_mod_num; m++) {
   1040             mod = tsp->tx_mods[m];
   1041             BCM_IF_ERROR_RETURN(bcm_stk_modport_set(funit, mod, port));
   1042         }
   1043     }
   1044 
   1045     return BCM_E_NONE;
   1046 }
   1047 
   1048 /*
   1049  * Common code for XGS boards with
   1050  * a single fabric device (5670, 5671) and
   1051  * 0 or more switch devices (5690, 5673, etc)
   1052  */
   1053 
   1054 STATIC int
   1055 _bcm_board_xgs_connection_add(int funit, 
   1056                               bcm_board_port_connection_t *connection,
   1057                               int num_connections)
   1058 {
   1059     int unit, fport, sport;
   1060     uint32 flags;
   1061 
   1062     /* First, make sure internal ports have been added */
   1063     for (unit = 0; unit < num_connections; unit++) {
   1064         fport = connection[unit].to;
   1065         if (fport < 0) { /* Skip device (eg fabric module) */
   1066             continue;
   1067         }
   1068         BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(funit, fport));
   1069 
   1070         sport = connection[unit].from;
   1071         if (bcm_stk_port_get(unit, sport, &flags) < 0) {
   1072             LOG_WARN(BSL_LS_TKS_TOPOLOGY,
   1073                      (BSL_META_U(unit,
   1074                      "Could not get stack info for (%d,%d)\n"),
   1075                       unit, sport));
   1076             continue;
   1077         }
   1078         if (!(flags & BCM_STK_ENABLE)) {
   1079             BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, sport,
   1080                                                  BCM_BOARD_INT_STK_FLAGS));
   1081         }
   1082     }
   1083 
   1084     return BCM_E_NONE;
   1085 }
   1086 
   1087 
   1088 int
   1089 bcm_board_xgs_local_switch(int funit,
   1090                            topo_cpu_t *tp_cpu,
   1091                            bcm_port_config_t *config,
   1092                            bcm_board_port_connection_t *connection)
   1093 {
   1094     int                i, m, unit;
   1095     cpudb_entry_t      *l_entry;
   1096     bcm_port_t         hport, port;
   1097     bcm_pbmp_t         pbm, empty;
   1098     bcm_module_t       mod;
   1099 
   1100     l_entry = &tp_cpu->local_entry;
   1101 
   1102     BCM_IF_ERROR_RETURN(
   1103         _bcm_board_xgs_connection_add(funit,
   1104                                       connection,
   1105                                       l_entry->base.num_units));
   1106 
   1107     /* program fabric for how to get to local units */
   1108     BCM_PBMP_CLEAR(empty);
   1109     for (unit = 0; unit < l_entry->base.num_units; unit++) {
   1110         port = connection[unit].to;
   1111         if (port < 0) {
   1112             continue;
   1113         }
   1114         mod = l_entry->mod_ids[unit];
   1115         if (mod < 0) {
   1116             continue;
   1117         }
   1118         m = l_entry->base.mod_ids_req[unit];
   1119         BCM_PBMP_PORT_SET(pbm, port);
   1120         BCM_PBMP_ITER(config->hg, hport) {
   1121             for (i = 0; i < m; i++) {
   1122                 BCM_IF_ERROR_RETURN
   1123                     (bcm_stk_ucbitmap_set(funit, hport, mod+i,
   1124                                           hport == port ? empty : pbm));
   1125             }
   1126         }
   1127     }
   1128 
   1129     for (unit = 0; unit < l_entry->base.num_units; unit++) {
   1130         if (unit == funit) {    /* skip fabric */
   1131             continue;
   1132         }
   1133         mod = l_entry->mod_ids[unit];
   1134         if (mod >= 0) {
   1135             BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, mod));
   1136             BCM_IF_ERROR_RETURN(bcm_stk_modport_clear_all(unit));
   1137         }
   1138     }
   1139 
   1140     return BCM_E_NONE;
   1141 }
   1142 
   1143 
   1144 int
   1145 bcm_board_xgs_local_fabric(int funit,
   1146                            topo_cpu_t *tp_cpu,
   1147                            bcm_port_config_t *config)
   1148 {
   1149     int                i, m;
   1150     topo_stk_port_t    *tsp;
   1151     cpudb_entry_t      *l_entry;
   1152     bcm_module_t       mod;
   1153     bcm_info_t         info;
   1154     bcm_port_t         port, hport;
   1155     bcm_pbmp_t         pbm;
   1156 
   1157     /*
   1158      * Module programming for fabric
   1159      * (usually only occurs if board is fabric only)
   1160      */
   1161     l_entry = &tp_cpu->local_entry;
   1162     mod = l_entry->mod_ids[funit];
   1163     if (mod >= 0) {
   1164         BCM_IF_ERROR_RETURN(bcm_info_get(funit, &info));
   1165         if (info.capability & BCM_INFO_FABRIC) {
   1166             BCM_PBMP_ITER(config->hg, hport) {
   1167                 BCM_IF_ERROR_RETURN
   1168                     (bcm_stk_ucbitmap_set(funit, hport, mod, config->cpu));
   1169             }
   1170         }
   1171     }
   1172 
   1173     for (i = 0; i < l_entry->base.num_stk_ports; i++) {
   1174         tsp = &tp_cpu->tp_stk_port[i];
   1175         port = l_entry->base.stk_ports[i].port;
   1176 
   1177         for (m = 0; m < tsp->tx_mod_num; m++) {
   1178             mod = tsp->tx_mods[m];
   1179 
   1180             BCM_PBMP_ITER(config->hg, hport) {
   1181                 BCM_PBMP_CLEAR(pbm);
   1182                 if (hport != port) {
   1183                     BCM_PBMP_PORT_ADD(pbm, port);
   1184                 }
   1185 #ifdef BCM_ESW_SUPPORT
   1186                 BCM_IF_ERROR_RETURN
   1187                     (_bcm_esw_mirror_stk_update(funit, mod, hport, pbm));
   1188 #endif
   1189             }
   1190         }
   1191     }
   1192 
   1193     return BCM_E_NONE;
   1194 }
   1195 
   1196 /*
   1197  * Common code for XGS boards with
   1198  * a single fabric device (5670, 5671) and
   1199  * 0 or more switch devices (5690, 5673, etc)
   1200  */
   1201 
   1202 
   1203 
   1204 int
   1205 bcm_board_xgs_common(int funit, topo_cpu_t *tp_cpu, cpudb_ref_t db_ref,
   1206                      int *unitport)
   1207 {
   1208     int                i, m, unit;
   1209     topo_stk_port_t    *tsp;
   1210     bcm_pbmp_t         pbm, empty;
   1211     cpudb_entry_t      *l_entry;
   1212     bcm_port_t         port, hport;
   1213     bcm_module_t       mod;
   1214     bcm_port_config_t  config;
   1215     bcm_info_t         info;
   1216 
   1217     /* Notify BCM layer of internal stack ports */
   1218     BCM_IF_ERROR_RETURN(_bcm_board_xgs_stk_port_add(funit, tp_cpu, unitport));
   1219 
   1220     l_entry = &tp_cpu->local_entry;
   1221 
   1222     BCM_IF_ERROR_RETURN(bcm_port_config_get(funit, &config));
   1223 
   1224     /* program fabric for how to get to local units */
   1225     BCM_PBMP_CLEAR(empty);
   1226     for (unit = 0; unit < l_entry->base.num_units; unit++) {
   1227         port = unitport[unit];
   1228         if (port < 0) {
   1229             continue;
   1230         }
   1231         mod = l_entry->mod_ids[unit];
   1232         if (mod < 0) {
   1233             continue;
   1234         }
   1235         m = l_entry->base.mod_ids_req[unit];
   1236         BCM_PBMP_PORT_SET(pbm, port);
   1237         BCM_PBMP_ITER(config.hg, hport) {
   1238             for (i = 0; i < m; i++) {
   1239                 BCM_IF_ERROR_RETURN
   1240                     (bcm_stk_ucbitmap_set(funit, hport, mod+i,
   1241                                           hport == port ? empty : pbm));
   1242             }
   1243         }
   1244     }
   1245     
   1246     unit = funit;  /* board fabric unit */
   1247 
   1248     /*
   1249      * Module programming for fabric
   1250      * (usually only occurs if board is fabric only)
   1251      */
   1252     mod = l_entry->mod_ids[unit];
   1253     if (mod >= 0) {
   1254         BCM_IF_ERROR_RETURN(bcm_info_get(unit, &info));
   1255         if (info.capability & BCM_INFO_FABRIC) {
   1256             BCM_PBMP_ITER(config.hg, hport) {
   1257                 BCM_IF_ERROR_RETURN
   1258                     (bcm_stk_ucbitmap_set(unit, hport, mod, config.cpu));
   1259             }
   1260         }
   1261     }
   1262 
   1263     for (i = 0; i < l_entry->base.num_stk_ports; i++) {
   1264          tsp = &tp_cpu->tp_stk_port[i];
   1265          port = l_entry->base.stk_ports[i].port;
   1266 
   1267          for (m = 0; m < tsp->tx_mod_num; m++) {
   1268               mod = tsp->tx_mods[m];
   1269 
   1270               BCM_PBMP_ITER(config.hg, hport) {
   1271                  BCM_PBMP_CLEAR(pbm);
   1272                  if (hport != port) {
   1273                      BCM_PBMP_PORT_ADD(pbm, port);
   1274                  }
   1275 #ifdef BCM_ESW_SUPPORT
   1276                  BCM_IF_ERROR_RETURN
   1277                     (_bcm_esw_mirror_stk_update(unit, mod, hport, pbm));
   1278 #endif
   1279               }
   1280          }
   1281     }
   1282 
   1283     BCM_IF_ERROR_RETURN(bcm_board_fab_mod_map(funit, tp_cpu, l_entry));
   1284     BCM_IF_ERROR_RETURN(bcm_board_module_filter(unit, tp_cpu, db_ref,
   1285                                                 &config));
   1286     BCM_IF_ERROR_RETURN(bcm_board_trunk_system(l_entry, db_ref, TRUE));
   1287 
   1288     /*
   1289      * Transient state setup: program  dflt modid if ports
   1290      * are not resolved
   1291      */
   1292     bcm_board_unknown_src_modid_setup(l_entry);
   1293 
   1294     /*
   1295      * Module programming for switches
   1296      */
   1297     for (unit = 0; unit < l_entry->base.num_units; unit++) {
   1298         if (unit == funit) {    /* skip fabric */
   1299             continue;
   1300         }
   1301         mod = l_entry->mod_ids[unit];
   1302         if (mod >= 0) {
   1303             BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, mod));
   1304             BCM_IF_ERROR_RETURN(bcm_stk_modport_clear_all(unit));
   1305         }
   1306     }
   1307 
   1308 #ifdef BCM_BOARD_AUTO_E2E
   1309     /* intra-board end to end flow control, if available */
   1310     BCM_IF_ERROR_RETURN(bcm_board_e2e_set());
   1311 #endif  /* BCM_BOARD_AUTO_E2E */
   1312 
   1313     return BCM_E_NONE;
   1314 }
   1315 
   1316 /*
   1317  * Find output stack port on src_unit to get to a remote modid
   1318  */
   1319 int
   1320 bcm_board_topomap_stk(int src_unit, int dest_modid, bcm_port_t *exit_port)
   1321 {
   1322     cpudb_unit_port_t *stk_port;
   1323     topo_cpu_t *tp_cpu;
   1324     int sp_idx, m_idx;
   1325     int mod_id;
   1326 
   1327     /* Remote module ID; look up in CPU database */
   1328     bcm_board_topo_get(&tp_cpu);
   1329     if (tp_cpu == NULL) {
   1330         return BCM_E_INIT;
   1331     }
   1332 
   1333     /* Search topo info for the stack port with the given mod id */
   1334     TOPO_FOREACH_STK_PORT(stk_port, tp_cpu, sp_idx) {
   1335         TOPO_FOREACH_TX_MODID(mod_id, tp_cpu, sp_idx, m_idx) {
   1336             if (dest_modid == mod_id && stk_port->unit == src_unit) {
   1337                 *exit_port = stk_port->port;
   1338                 return BCM_E_NONE;
   1339             }
   1340         }
   1341     }
   1342 
   1343     return BCM_E_NOT_FOUND;
   1344 }
   1345 
   1346 int
   1347 bcm_board_untrunkable_stack_ports(int unit, topo_cpu_t *tp_cpu)
   1348 {
   1349     int                 i, punit;
   1350     bcm_port_t          port;
   1351     cpudb_entry_t       *l_entry;
   1352 
   1353     l_entry = &tp_cpu->local_entry;
   1354     for (i=0; i < l_entry->base.num_stk_ports; i++) {
   1355         punit = l_entry->base.stk_ports[i].unit;
   1356         port = l_entry->base.stk_ports[i].port;
   1357 
   1358         if (unit != punit) {
   1359             continue;
   1360         }
   1361 
   1362         if (l_entry->sp_info[i].flags & CPUDB_SPF_CUT_PORT) {
   1363             BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit,
   1364                                                           port,
   1365                                                           -1,
   1366                                                           0)); 
   1367         }
   1368     }
   1369 
   1370     return BCM_E_NONE;
   1371 }
   1372 
   1373 /*
   1374  * Rapid Recovery
   1375  */
   1376 
   1377 /*
   1378  * Function:
   1379  *     bcm_board_topo_trunk_failover
   1380  * Purpose:
   1381  *     Re-programs the local board to recover from a trunk link failure
   1382  *     case.
   1383  * Parameters:
   1384  *     topo_cpu     - Local topology
   1385  *     unit         - Unit of failed stack port
   1386  *     fail_sp      - Failed stack port
   1387  *     faiL_sp_idx  - Failed stack port index
   1388  *     tid          - Trunk id of failed stack port
   1389  *     trunk        - New trunk information; should NOT contain the failed
   1390  *                    stack port
   1391  *     member_count - Number of trunk members in member_array
   1392  *     member_array - Array of trunk members
   1393  * Returns:
   1394  *     BCM_E_NONE  - Success
   1395  *     BCM_E_XXX   - System cannot perform rapid recovery
   1396  *
   1397  * Note:
   1398  *     Caller MUST provide new trunk information in argument.
   1399  */
   1400 int
   1401 bcm_board_topo_trunk_failover(topo_cpu_t *topo_cpu,
   1402                               int unit, bcm_port_t fail_sp, int fail_sp_idx,
   1403                               bcm_trunk_t tid, bcm_trunk_info_t *trunk,
   1404                               int member_count,
   1405                               bcm_trunk_member_t *member_array)
   1406 {
   1407     int              i, rv;
   1408     bcm_module_t     mod;
   1409     bcm_port_t       port;
   1410     bcm_port_t       repl_sp;        /* Port to replace failed port */
   1411     topo_stk_port_t  *fail_topo_sp;  /* Topo info for failed port */
   1412     int              mirr_dir;       /* True if mode is directed mirroring */
   1413 
   1414     
   1415     /* Get first active port of trunk to replace failed port */
   1416     if (member_count <= 0) {    /* Trunk should contain at least 1 port */
   1417         return BCM_E_FAIL;
   1418     }
   1419     BCM_IF_ERROR_RETURN
   1420         (bcm_port_local_get(unit, member_array[0].gport, &repl_sp));
   1421     
   1422     /*
   1423      * Destination-module port table
   1424      */
   1425     fail_topo_sp = &topo_cpu->tp_stk_port[fail_sp_idx];
   1426 
   1427     for (i = 0; i < fail_topo_sp->tx_mod_num; i++) {
   1428         mod = fail_topo_sp->tx_mods[i];
   1429         BCM_IF_ERROR_RETURN(bcm_stk_modport_get(unit, mod, &port));
   1430         if (port == fail_sp) {
   1431             BCM_IF_ERROR_RETURN(bcm_stk_modport_set(unit, mod, repl_sp));
   1432         }
   1433     }
   1434     
   1435     /*
   1436      * Fabric trunk
   1437      *
   1438      * Note: The trunk is kept with 1 additional port member left
   1439      */
   1440     BCM_IF_ERROR_RETURN
   1441         (bcm_trunk_set(unit, tid, trunk, member_count, member_array));
   1442 
   1443     /*
   1444      * Mirror
   1445      */
   1446     rv = bcm_switch_control_get(unit, bcmSwitchDirectedMirroring, &mirr_dir);
   1447     if (BCM_FAILURE(rv)) {
   1448         mirr_dir = 0;
   1449     }
   1450     /* Non-directed mirroring or Draco compat mode requires update */
   1451     if (!mirr_dir) {
   1452         bcm_port_config_t  config;
   1453         bcm_port_t         hport;
   1454         bcm_pbmp_t         mtp_pbmp;
   1455         
   1456         /* MTP bitmap on HG ports */
   1457         BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config));
   1458         BCM_PBMP_ITER(config.hg, hport) {
   1459             BCM_PBMP_CLEAR(mtp_pbmp);
   1460             rv = bcm_mirror_to_pbmp_get(unit, hport, &mtp_pbmp);
   1461             if (rv == BCM_E_UNAVAIL) {
   1462                 continue;
   1463             }
   1464             BCM_IF_ERROR_RETURN(rv);
   1465             
   1466             /* Update if failed port is part of the mirror mtp pbmp */
   1467             if (BCM_PBMP_MEMBER(mtp_pbmp, fail_sp)) {
   1468                 BCM_PBMP_PORT_REMOVE(mtp_pbmp, fail_sp);
   1469                 BCM_PBMP_PORT_ADD(mtp_pbmp, repl_sp);
   1470                 BCM_IF_ERROR_RETURN(bcm_mirror_to_pbmp_set(unit, hport,
   1471                                                            mtp_pbmp));
   1472             }
   1473         }
   1474 
   1475         /* MTP port */
   1476         BCM_IF_ERROR_RETURN(bcm_mirror_to_get(unit, &port));
   1477         if (port == fail_sp) {
   1478             if (BCM_FAILURE(bcm_mirror_to_set(unit, repl_sp))) {
   1479                 LOG_ERROR(BSL_LS_TKS_TOPOLOGY,
   1480                           (BSL_META_U(unit,
   1481                           "Cannot set MTP on unit %d, port %d\n"),
   1482                            unit, repl_sp));
   1483                 return BCM_E_FAIL;
   1484             }
   1485         }
   1486     }
   1487     
   1488     return BCM_E_NONE;
   1489 }