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

l2x.c (16372B)


      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  * XGS GH L2 Table Manipulation API routines.
      8  *
      9  * A low-level L2 shadow table is optionally kept in soc->arlShadow by
     10  * using a callback to get all inserts/deletes from the l2xmsg task. It
     11  * can be disabled by setting the l2xmsg_avl property to 0.
     12  */
     13 
     14 #include <sal/core/libc.h>
     15 #include <shared/bsl.h>
     16 #include <soc/drv.h>
     17 #include <soc/l2x.h>
     18 #include <soc/ptable.h>
     19 #include <soc/debug.h>
     20 #include <soc/util.h>
     21 #include <soc/mem.h>
     22 #include <soc/greyhound.h>
     23 
     24 #ifdef BCM_GREYHOUND_SUPPORT
     25 
     26 #define _SOC_GH_L2_TABLE_DMA_CHUNK_SIZE 1024
     27 
     28 /*
     29  * Function:
     30  *    _soc_gh_l2_entry_limit_update
     31  * Purpose:
     32  *    Update the mac limits per l2 entry
     33  * Parameters:
     34  *    unit         - unit number
     35  *    l2_entry     - l2 entry
     36  *    ptm_tbl      - port or trumk mac limit table
     37  *    ptm_entry_dw - entry length of port or trumk mac limit table
     38  *    vvm_tbl      - vlan or vfi mac limit table
     39  *    vvm_entry_dw - entry length of vlan or vfi mac limit table
     40  *    s_count      - system mac limit count
     41  * Returns:
     42  *    SOC_E_XXX.
     43  */
     44 STATIC int
     45 _soc_gh_l2_entry_limit_update(
     46     int unit,
     47     uint32 *l2_entry,
     48     uint32 *ptm_tbl,
     49     uint32 ptm_entry_dw,
     50     uint32 *vvm_tbl,
     51     uint32 vvm_entry_dw,
     52     uint32 *s_count)
     53 {
     54     uint32 dest_type, key_type;
     55     uint32 is_valid, is_limit_counted = 0;
     56     soc_mem_t mem;
     57     uint32 entry[SOC_MAX_MEM_WORDS];
     58     int32 v_index = -1;  /* vlan index */
     59     int32 p_index = -1;  /* port index */
     60     uint32 p_count = 0;  /* port or trunk mac count */
     61     uint32 v_count = 0;  /* vlan or vfi mac count */
     62     uint32 *v_entry;     /* vlan or vfi count entry */
     63     uint32 *p_entry;     /* port or trunk count entry */
     64 
     65     mem = L2Xm;
     66 
     67     /* check if entry is valid */
     68     is_valid = soc_mem_field32_get(unit, mem, l2_entry, VALIDf);
     69     if (!is_valid) {
     70         /* not valid entry skip it */
     71         return SOC_E_NONE;
     72     }
     73 
     74     /* check if entry is limit counted */
     75     if (soc_mem_field_valid(unit, mem, LIMIT_COUNTEDf)) {
     76         is_limit_counted = soc_mem_field32_get(unit, mem, l2_entry,
     77                                                LIMIT_COUNTEDf);
     78         if (!is_limit_counted) {
     79             /* entry not limit counted skip it */
     80             return SOC_E_NONE;
     81         }
     82     }
     83 
     84     /*
     85     * Get the key type of the entries. Process entries with only key_type
     86     * GH_L2_HASH_KEY_TYPE_BRIDGE
     87     */
     88     key_type = soc_mem_field32_get(unit, mem, l2_entry, KEY_TYPEf);
     89 
     90     if (key_type != GH_L2_HASH_KEY_TYPE_BRIDGE) {
     91         return SOC_E_NONE;
     92     }
     93 
     94     dest_type = soc_mem_field32_get(unit, mem, l2_entry, L2__DEST_TYPEf);
     95 
     96     switch (dest_type) {
     97         case 0: /* mod port */
     98             SOC_IF_ERROR_RETURN(soc_mem_read(unit, PORT_TABm,
     99                                              MEM_BLOCK_ANY, 0, &entry));
    100             if (soc_mem_field32_get(unit, PORT_TABm, &entry, MY_MODIDf) ==
    101                 soc_mem_field32_get(unit, mem, l2_entry, L2__MODULE_IDf)) {
    102                 p_index = soc_mem_field32_get(unit, mem, l2_entry, PORT_NUMf) +
    103                           soc_mem_index_count(unit, TRUNK_GROUPm);
    104             }
    105             break;
    106         case 1: /* trunk */
    107             p_index = soc_mem_field32_get(unit, mem, l2_entry, L2__TGIDf);
    108             break;
    109         default:
    110             /* if VFI based key then break else continue? */
    111             break;
    112     }
    113 
    114     /*
    115     * based on key_type get vlan or vfi
    116     * to index into VLAN_OR_VFI_MAC_COUNTm
    117     */
    118     v_index = soc_mem_field32_get(unit, mem, l2_entry, L2__VLAN_IDf);
    119 
    120     /*
    121     * read and update vlan or vfi mac count
    122     * in buffer also update the sys mac count.
    123     */
    124     v_count = 0;
    125     if (v_index >= 0) {
    126         v_entry = (vvm_tbl + (v_index * vvm_entry_dw));
    127         v_count = soc_mem_field32_get(unit, VLAN_OR_VFI_MAC_COUNTm,
    128                                       v_entry, COUNTf);
    129         *s_count = *s_count + 1;
    130         v_count++;
    131         soc_mem_field32_set(unit, VLAN_OR_VFI_MAC_COUNTm,
    132                             v_entry, COUNTf, v_count);
    133     }
    134 
    135     /* read and update port or trunk mac count in buffer. */
    136     p_count = 0;
    137     if (p_index >= 0) {
    138         p_entry = ptm_tbl + (p_index * ptm_entry_dw);
    139         p_count = soc_mem_field32_get(unit, PORT_OR_TRUNK_MAC_COUNTm,
    140                                       p_entry, COUNTf);
    141         p_count++;
    142         soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_COUNTm,
    143                             p_entry, COUNTf, p_count);
    144     }
    145 
    146     return SOC_E_NONE;
    147 }
    148 
    149 
    150 /**************************************************
    151  * @function soc_gh_l2_entry_limit_count_update
    152  *
    153  *
    154  * @purpose Read L2 table from hardware, calculate
    155  *          and restore port/trunk and vlan/vfi
    156  *          mac counts.
    157  *
    158  * @param  unit   @b{(input)}  unit number
    159  *
    160  * @returns BCM_E_NONE
    161  * @returns BCM_E_FAIL
    162  *
    163  * @comments This rountine gets called for an
    164  *           L2 table SER event, if any of the
    165  *           mac limits(system, port, vlan) are
    166  *           enabled on the device.
    167  *
    168  * @end
    169  */
    170 int
    171 soc_gh_l2_entry_limit_count_update(int unit)
    172 {
    173     uint32 rval;
    174     uint32 *l2_entry;    /* l2 entry */
    175     uint32 s_count = 0;  /* system mac count */
    176 
    177     /* l2 table */
    178     int index_min, index_max;
    179     int entry_dw, entry_sz;
    180     int chnk_idx, chnk_idx_max, table_chnk_sz, idx;
    181     int chunk_size = _SOC_GH_L2_TABLE_DMA_CHUNK_SIZE;
    182 
    183     /* port or trunk mac count table */
    184     int ptm_index_min, ptm_index_max;
    185     int ptm_table_sz, ptm_entry_dw, ptm_entry_sz;
    186 
    187     /* vlan or vfi mac count table */
    188     int vvm_index_min, vvm_index_max;
    189     int vvm_table_sz, vvm_entry_dw, vvm_entry_sz;
    190 
    191     uint32 *l2_buf = NULL;
    192     uint32 *ptm_buf = NULL;
    193     uint32 *vvm_buf = NULL;
    194 
    195     soc_mem_t mem;
    196     int rv;
    197 #ifdef BCM_HURRICANE3_SUPPORT
    198     uint32 l2_learn;
    199 #endif /* BCM_HURRICANE3_SUPPORT */
    200 
    201     /* If MAC learn limit not enabled do nothing */
    202     SOC_IF_ERROR_RETURN(READ_SYS_MAC_LIMIT_CONTROLr(unit, &rval));
    203     if (!soc_reg_field_get(unit, SYS_MAC_LIMIT_CONTROLr,
    204                            rval, ENABLEf)) {
    205         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    206                     (BSL_META_U(unit,
    207                                 "\nMAC limits not enabled.\n")));
    208         return SOC_E_NONE;
    209     }
    210 
    211     /*
    212      * Mac limits are enabled.
    213      * 1. Read (DMA) L2 table to recalculate mac count
    214      * 2. Iterate through all the entries.
    215      * 3. if the entry is limit_counted
    216      * Check if KEY_TYPE is BRIDGE, VLAN or VFI
    217      * based on DEST_TYPE determine if Trunk or ModPort
    218      * Get port index into port_or_trunk_mac_count table
    219      * Get vlan/vfi index into vlan_or_vfi_mac_count table
    220      * update the port, vlan/vfi, system mac count.
    221      * Write(slam) port_or_trunk_mac count and
    222      * vlan_or_vfi_mac_count tables.
    223      */
    224 
    225     /*
    226      * Allocate memory for port/trunk mac count table to store
    227      * the updated count.
    228      */
    229     mem = PORT_OR_TRUNK_MAC_COUNTm;
    230     ptm_entry_dw = soc_mem_entry_words(unit, mem);
    231     ptm_entry_sz = ptm_entry_dw * sizeof(uint32);
    232     ptm_index_min = soc_mem_index_min(unit, mem);
    233     ptm_index_max = soc_mem_index_max(unit, mem);
    234     ptm_table_sz = (ptm_index_max - ptm_index_min + 1) * ptm_entry_sz;
    235 
    236     ptm_buf = soc_cm_salloc(unit, ptm_table_sz, "ptm_tmp");
    237     if (ptm_buf == NULL) {
    238         LOG_ERROR(BSL_LS_SOC_L2,
    239                   (BSL_META_U(unit,
    240                               "soc_gh_l2_entry_limit_count_update: "
    241                               "Memory allocation failed for %s\n"),
    242                   SOC_MEM_NAME(unit, mem)));
    243         return SOC_E_MEMORY;
    244     }
    245 
    246     sal_memset(ptm_buf, 0, ptm_table_sz);
    247 
    248     /*
    249      * Allocate memory for vlan/vfi mac count table to store
    250      * the updated count.
    251      */
    252     mem = VLAN_OR_VFI_MAC_COUNTm;
    253     vvm_entry_dw = soc_mem_entry_words(unit, mem);
    254     vvm_entry_sz = vvm_entry_dw * sizeof(uint32);
    255     vvm_index_min = soc_mem_index_min(unit, mem);
    256     vvm_index_max = soc_mem_index_max(unit, mem);
    257     vvm_table_sz = (vvm_index_max - vvm_index_min + 1) * vvm_entry_sz;
    258 
    259     vvm_buf = soc_cm_salloc(unit, vvm_table_sz, "vvm_tmp");
    260     if (vvm_buf == NULL) {
    261         soc_cm_sfree(unit, ptm_buf);
    262         LOG_ERROR(BSL_LS_SOC_L2,
    263                   (BSL_META_U(unit,
    264                               "soc_gh_l2_entry_limit_count_update: "
    265                               "Memory allocation failed for %s\n"),
    266                   SOC_MEM_NAME(unit, mem)));
    267         return SOC_E_MEMORY;
    268     }
    269 
    270     sal_memset(vvm_buf, 0, vvm_table_sz);
    271 
    272     /* Create a copy L2Xm table for calculating mac count */
    273     mem = L2Xm;
    274     entry_dw = soc_mem_entry_words(unit, mem);
    275     entry_sz = entry_dw * sizeof(uint32);
    276     index_min = soc_mem_index_min(unit, mem);
    277     index_max = soc_mem_index_max(unit, mem);
    278     table_chnk_sz = chunk_size * entry_sz;
    279 
    280     l2_buf = soc_cm_salloc(unit, table_chnk_sz, "l2x_tmp");
    281     if (l2_buf == NULL) {
    282         soc_cm_sfree(unit, ptm_buf);
    283         soc_cm_sfree(unit, vvm_buf);
    284         LOG_ERROR(BSL_LS_SOC_L2,
    285                   (BSL_META_U(unit,
    286                               "soc_gh_l2_entry_limit_count_update: "
    287                               "Memory allocation failed for %s\n"),
    288                   SOC_MEM_NAME(unit, mem)));
    289         return SOC_E_MEMORY;
    290     }
    291 
    292     SOC_L2X_MEM_LOCK(unit);
    293     for (chnk_idx = index_min; chnk_idx <= index_max; chnk_idx += chunk_size) {
    294         sal_memset(l2_buf, 0, table_chnk_sz);
    295 
    296         chnk_idx_max = ((chnk_idx + chunk_size) <= index_max) ?
    297                        (chnk_idx + chunk_size - 1) : index_max;
    298 
    299          /* DMA L2 Table */
    300         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, chnk_idx,
    301                                 chnk_idx_max, l2_buf);
    302         if (SOC_FAILURE(rv)) {
    303             soc_cm_sfree(unit, ptm_buf);
    304             soc_cm_sfree(unit, vvm_buf);
    305             soc_cm_sfree(unit, l2_buf);
    306             SOC_L2X_MEM_UNLOCK(unit);
    307             LOG_ERROR(BSL_LS_SOC_L2,
    308                       (BSL_META_U(unit,
    309                                   "DMA failed: %s, mac limts not synced!\n"),
    310                       soc_errmsg(rv)));
    311             return SOC_E_FAIL;
    312         }
    313 
    314         /* Iter through all l2 entries in the chunk */
    315         for (idx = 0; idx <= (chnk_idx_max - chnk_idx); idx++) {
    316             l2_entry = (l2_buf + (idx * entry_dw));
    317 
    318             rv = _soc_gh_l2_entry_limit_update(unit, l2_entry,
    319                                                ptm_buf, ptm_entry_dw,
    320                                                vvm_buf, vvm_entry_dw,
    321                                                &s_count);
    322             if (SOC_FAILURE(rv)) {
    323                 soc_cm_sfree(unit, ptm_buf);
    324                 soc_cm_sfree(unit, vvm_buf);
    325                 soc_cm_sfree(unit, l2_buf);
    326                 SOC_L2X_MEM_UNLOCK(unit);
    327                 LOG_ERROR(BSL_LS_SOC_L2,
    328                           (BSL_META_U(unit,
    329                                       "L2 MAC count update failed: %s, "
    330                                       "for L2 Entry\n"),
    331                           soc_errmsg(rv)));
    332                 return SOC_E_FAIL;
    333             }
    334         } /* End for index */
    335     } /* End for chnk_idx */
    336 
    337     /* Free memory */
    338     soc_cm_sfree(unit, l2_buf);
    339 
    340 #ifdef BCM_HURRICANE3_SUPPORT
    341     if (soc_feature(unit, soc_feature_l2_overflow_bucket)) {
    342         /* check if l2 overflow table is enabled */
    343         rv = READ_L2_LEARN_CONTROLr(unit, &l2_learn);
    344         if (SOC_FAILURE(rv)) {
    345             soc_cm_sfree(unit, ptm_buf);
    346             soc_cm_sfree(unit, vvm_buf);
    347             SOC_L2X_MEM_UNLOCK(unit);
    348             LOG_ERROR(BSL_LS_SOC_L2,
    349                       (BSL_META_U(unit,
    350                                   "Register read failed: %s, "
    351                                   "for L2 Learn Control\n"),
    352                       soc_errmsg(rv)));
    353             return SOC_E_FAIL;
    354         }
    355         if (soc_reg_field_get(unit, L2_LEARN_CONTROLr,
    356                               l2_learn, OVERFLOW_BUCKET_ENABLEf)) {
    357             /* L2 overflow table is enabled */
    358             mem = L2_ENTRY_OVERFLOWm;
    359             entry_dw = soc_mem_entry_words(unit, mem);
    360             entry_sz = entry_dw * sizeof(uint32);
    361             index_min = soc_mem_index_min(unit, mem);
    362             index_max = soc_mem_index_max(unit, mem);
    363             table_chnk_sz = (index_max + 1) * entry_sz;
    364 
    365             l2_buf = soc_cm_salloc(unit, table_chnk_sz, "l2x_overflow");
    366             if (l2_buf == NULL) {
    367                 soc_cm_sfree(unit, ptm_buf);
    368                 soc_cm_sfree(unit, vvm_buf);
    369                 SOC_L2X_MEM_UNLOCK(unit);
    370                 LOG_ERROR(BSL_LS_SOC_L2,
    371                           (BSL_META_U(unit,
    372                                       "soc_gh_l2_entry_limit_count_update: "
    373                                       "Memory allocation failed for %s\n"),
    374                           SOC_MEM_NAME(unit, mem)));
    375                 return SOC_E_MEMORY;
    376             }
    377 
    378             sal_memset(l2_buf, 0, table_chnk_sz);
    379 
    380             /* DMA L2 overflow Table */
    381             rv =  soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
    382                                      index_min, index_max, l2_buf);
    383             if (SOC_FAILURE(rv)) {
    384                 soc_cm_sfree(unit, ptm_buf);
    385                 soc_cm_sfree(unit, vvm_buf);
    386                 soc_cm_sfree(unit, l2_buf);
    387                 SOC_L2X_MEM_UNLOCK(unit);
    388                 LOG_ERROR(BSL_LS_SOC_L2,
    389                           (BSL_META_U(unit,
    390                                       "DMA failed: %s, "
    391                                       "mac limts not synced!\n"),
    392                           soc_errmsg(rv)));
    393                 return SOC_E_FAIL;
    394             }
    395 
    396             /* Iter through all l2 overflow entries */
    397             for (idx = 0; idx <= index_max; idx++) {
    398                 l2_entry = (l2_buf + (idx * entry_dw));
    399 
    400                 rv = _soc_gh_l2_entry_limit_update(unit, l2_entry,
    401                                                    ptm_buf, ptm_entry_dw,
    402                                                    vvm_buf, vvm_entry_dw,
    403                                                    &s_count);
    404                 if (SOC_FAILURE(rv)) {
    405                     soc_cm_sfree(unit, ptm_buf);
    406                     soc_cm_sfree(unit, vvm_buf);
    407                     soc_cm_sfree(unit, l2_buf);
    408                     SOC_L2X_MEM_UNLOCK(unit);
    409                     LOG_ERROR(BSL_LS_SOC_L2,
    410                               (BSL_META_U(unit,
    411                                           "L2 MAC count update failed: %s, "
    412                                           "for L2 Overflow Entry\n"),
    413                               soc_errmsg(rv)));
    414                     return SOC_E_FAIL;
    415                 }
    416             }
    417 
    418             /* Free memory */
    419             soc_cm_sfree(unit, l2_buf);
    420         }
    421     }
    422 #endif /* BCM_HURRICANE3_SUPPORT */
    423 
    424     /* Write the tables to hardware */
    425     mem = PORT_OR_TRUNK_MAC_COUNTm;
    426     rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY,
    427                              ptm_index_min, ptm_index_max, (void *)ptm_buf);
    428     if (SOC_FAILURE(rv)) {
    429         soc_cm_sfree(unit, ptm_buf);
    430         soc_cm_sfree(unit, vvm_buf);
    431         SOC_L2X_MEM_UNLOCK(unit);
    432         LOG_ERROR(BSL_LS_SOC_L2,
    433                   (BSL_META_U(unit,
    434                               "PORT_OR_TRUNK_MAC_COUNT write failed: "
    435                               "%s, mac limts not synced!\n"),
    436                    soc_errmsg(rv)));
    437         return SOC_E_FAIL;
    438     }
    439 
    440     mem = VLAN_OR_VFI_MAC_COUNTm;
    441     rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY,
    442                              vvm_index_min, vvm_index_max, (void *)vvm_buf);
    443     if (SOC_FAILURE(rv)) {
    444         soc_cm_sfree(unit, ptm_buf);
    445         soc_cm_sfree(unit, vvm_buf);
    446         SOC_L2X_MEM_UNLOCK(unit);
    447         LOG_ERROR(BSL_LS_SOC_L2,
    448                   (BSL_META_U(unit,
    449                               "VLAN_OR_VFI_MAC_COUNT write failed: "
    450                               "%s, mac limts not synced!\n"),
    451                    soc_errmsg(rv)));
    452         return SOC_E_FAIL;
    453     }
    454 
    455     /* Update system count */
    456     soc_reg_field_set(unit, SYS_MAC_COUNTr, &rval, COUNTf, s_count);
    457     rv = WRITE_SYS_MAC_COUNTr(unit, rval);
    458 
    459     /* Free memory */
    460     soc_cm_sfree(unit, ptm_buf);
    461     soc_cm_sfree(unit, vvm_buf);
    462 
    463     SOC_L2X_MEM_UNLOCK(unit);
    464 
    465     return rv;
    466 }
    467 
    468 #endif /* BCM_GREYHOUND_SUPPORT */