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

port.c (32001B)


      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:        port.c
      8  * Purpose:     Manages untagged priority setting for port
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <assert.h>
     14 
     15 #include <soc/mem.h>
     16 #include <soc/debug.h>
     17 #include <soc/drv.h>
     18 #include <soc/memory.h>
     19 #include <bcm/error.h>
     20 
     21 #include <bcm_int/esw_dispatch.h>
     22 #include <bcm_int/esw/port.h>
     23 #include <bcm_int/esw/firebolt.h>
     24 #include <bcm_int/esw/xgs3.h>
     25 
     26 
     27 /*
     28  * Function:
     29  *      bcm_port_untagged_priority_set
     30  * Purpose:
     31  *      Set the 802.1P priority for untagged packets coming in on a
     32  *      port.  This value will be written into the priority field of the
     33  *      tag that is added at the ingress.
     34  * Parameters:
     35  *      unit      - StrataSwitch Unit #.
     36  *      port      - StrataSwitch port #.
     37  *      priority  - Priority to be set in 802.1p priority tag, from 0 to 7.
     38  *                  A negative priority leaves the ingress port priority as
     39  *                  is, but disables it from overriding ARL-based priorities.
     40  *                  (on those devices that support ARL-based priority).
     41  * Returns:
     42  *      BCM_E_NONE
     43  *      BCM_E_XXX
     44  */
     45 
     46 int
     47 bcm_shadow_port_untagged_priority_set(int unit, bcm_port_t port, int priority)
     48 {
     49     port_tab_entry_t ptab_entry;   /* Port table entry.             */
     50     int rv = BCM_E_NONE;
     51 
     52     if (priority > 7 || priority < 0) {
     53         return BCM_E_PARAM;
     54     }
     55 
     56     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
     57 
     58     soc_mem_lock(unit, PORT_TABm);
     59 
     60     rv = BCM_XGS3_MEM_READ(unit, PORT_TABm, port, &ptab_entry);
     61     if (BCM_FAILURE(rv)) {
     62        soc_mem_unlock(unit, PORT_TABm);
     63        return (rv);
     64     }
     65 
     66     soc_mem_field32_set(unit, PORT_TABm, &ptab_entry, PORT_INT_PRIf, 
     67                     priority);
     68     rv = BCM_XGS3_MEM_WRITE(unit, PORT_TABm, port, &ptab_entry);
     69     if (BCM_FAILURE(rv)) {
     70        soc_mem_unlock(unit, PORT_TABm);
     71        return (rv);
     72     }
     73 
     74     soc_mem_unlock(unit, PORT_TABm);
     75 
     76     LOG_INFO(BSL_LS_BCM_PORT,
     77              (BSL_META_U(unit,
     78                          "bcm_shadow_port_untagged_priority_set: u=%d p=%d pri=%d rv=%d\n"),
     79               unit, port, priority, rv));
     80 
     81     return rv;
     82 }
     83 
     84 /*
     85  * Function:
     86  *      bcm_port_untagged_priority_get
     87  * Purpose:
     88  *      Returns priority being assigned to untagged receive packets
     89  * Parameters:
     90  *      unit      - StrataSwitch Unit #.
     91  *      port      - StrataSwitch port #.
     92  *      priority  - Pointer to an int in which priority value is returned.
     93  * Returns:
     94  *      BCM_E_NONE
     95  *      BCM_E_XXX
     96  */
     97 
     98 int
     99 bcm_shadow_port_untagged_priority_get(int unit, bcm_port_t port, int *priority)
    100 {
    101     port_tab_entry_t ptab_entry;   /* Port table entry.             */
    102     int rv = BCM_E_NONE;
    103 
    104     if (priority != NULL) {
    105         soc_mem_lock(unit, PORT_TABm);
    106         rv = BCM_XGS3_MEM_READ(unit, PORT_TABm, port, &ptab_entry);
    107         if (BCM_FAILURE(rv)) {
    108            soc_mem_unlock(unit, PORT_TABm);
    109            return (rv);
    110         }
    111         soc_mem_unlock(unit, PORT_TABm);
    112 
    113         *priority = soc_mem_field32_get(unit, PORT_TABm, &ptab_entry, PORT_INT_PRIf);
    114         LOG_INFO(BSL_LS_BCM_PORT,
    115                  (BSL_META_U(unit,
    116                              "bcm_shadow_port_untagged_priority_get: u=%d p=%d pri=%d\n"),
    117                   unit, port, *priority));
    118     }
    119 
    120     return BCM_E_NONE;
    121 }
    122 
    123 /*
    124  * Function:
    125  *      _bcm_shadow_port_dscp_map_set
    126  * Purpose:
    127  *      Internal implementation for bcm_port_dscp_map_set
    128  * Parameters:
    129  *      unit - switch device
    130  *      port - switch port or -1 for global table
    131  *      srccp - src code point or -1
    132  *      mapcp - mapped code point or -1
    133  *      prio - priority value for mapped code point
    134  *              -1 to use port default untagged priority
    135  *              BCM_PRIO_RED    can be or'ed into the priority
    136  *              BCM_PRIO_YELLOW can be or'ed into the priority
    137  * Returns:
    138  *      BCM_E_XXX
    139  */
    140 
    141 STATIC int
    142 _bcm_shadow_port_dscp_map_set(int unit, bcm_port_t port,
    143                        int srccp, int mapcp, int prio)
    144 {
    145     int                  i, cng;
    146     dscp_table_entry_t   de;
    147     int                  max_index;   
    148     int                  min_index;
    149 
    150 #define DSCP_CODE_POINT_CNT 256  /* for IPV6 */
    151 #define DSCP_CODE_POINT_MAX (DSCP_CODE_POINT_CNT - 1)
    152 
    153     if (mapcp < -1 || mapcp > DSCP_CODE_POINT_MAX) {
    154         return BCM_E_PARAM;
    155     }
    156 
    157 
    158     if (srccp < -1 || srccp > DSCP_CODE_POINT_MAX) {
    159         return BCM_E_PARAM;
    160     }
    161     /* Extract cng bits and check for valid priority. */
    162     
    163     cng = 0; /* Green */
    164     if (prio < 0) {
    165         return BCM_E_PARAM;
    166     }
    167     if (prio & BCM_PRIO_RED) {
    168         cng = 0x01;  /* Red */
    169         prio &= ~BCM_PRIO_RED;
    170     } else if (prio & BCM_PRIO_YELLOW) {
    171         cng = 0x03;  /* Yellow  */
    172         prio &= ~BCM_PRIO_YELLOW;
    173     }
    174     if ((prio & ~BCM_PRIO_MASK) != 0) {
    175         return BCM_E_PARAM;
    176     }
    177     if (srccp < 0 && mapcp < 0) {
    178         /* No mapping */
    179         return BCM_E_NONE;
    180     } else if (srccp < 0) {
    181         /* fill all entries in DSCP_TABLEm with mapcp */
    182         sal_memset(&de, 0, sizeof(de));
    183         soc_DSCP_TABLEm_field32_set(unit, &de, PRIf, prio);
    184         soc_DSCP_TABLEm_field32_set(unit, &de, CNGf, cng);
    185         min_index = port * 512;
    186         max_index = min_index + DSCP_CODE_POINT_MAX;
    187         for (i = min_index; i < max_index; i++) {
    188             SOC_IF_ERROR_RETURN
    189                 (WRITE_DSCP_TABLEm(unit, MEM_BLOCK_ALL, i, &de));
    190         }
    191     } else {
    192         sal_memset(&de, 0, sizeof(de));
    193         /* fill specific srccp entry/entries in DSCP_TABLEm with mapcp */
    194         soc_DSCP_TABLEm_field32_set(unit, &de, PRIf, prio);
    195         soc_DSCP_TABLEm_field32_set(unit, &de, CNGf, cng);
    196         /* The table storage is, 256 for IPv4 + 256 for IPv6 per port */
    197         if (srccp < 64) {
    198             SOC_IF_ERROR_RETURN
    199               (WRITE_DSCP_TABLEm(unit, MEM_BLOCK_ALL, 
    200                                  (port * 512) + (srccp << 2), &de));  /* IPV4 */
    201         }
    202         SOC_IF_ERROR_RETURN
    203           (WRITE_DSCP_TABLEm(unit, MEM_BLOCK_ALL, 
    204                              (port * 512) + 256 + srccp, &de)); /* IPV6 */
    205     }
    206     return BCM_E_NONE;
    207 }
    208 
    209 /*
    210  * Function:
    211  *      bcm_port_dscp_map_set
    212  * Purpose:
    213  *      Define a mapping for diffserv code points
    214  *      The mapping enable/disable is controlled by a seperate API
    215  *      bcm_port_dscp_map_enable_set/get
    216  *      Also Enable/Disable control for DSCP mapping for tunnels
    217  *      are available in the respective tunnel create APIs.
    218  * Parameters:
    219  *      unit - switch device
    220  *      port - switch port      or -1 to setup global mapping table.
    221  *      srccp - src code point or -1
    222  *      mapcp - mapped code point or -1
    223  *      prio - priority value for mapped code point
    224  *              -1 to use port default untagged priority
    225  *              BCM_PRIO_DROP_FIRST can be or'ed into the priority
    226  * Returns:
    227  *      BCM_E_XXX
    228  * Notes:
    229  *      On most xgs switches there are a limited set
    230  *      of mappings that are possible:
    231  *              srccp -1, mapcp -1:     no mapping
    232  *              srccp -1, mapcp 0..63:  map all packets
    233  *              srccp 0, mapcp 0..63:   map packets with cp 0
    234  *      On Firebolt/Helix/Felix, there is no per port mapping table.
    235  *      Only a global mapping table is available.
    236  */
    237 
    238 int
    239 bcm_shadow_port_dscp_map_set(int unit, bcm_port_t port, int srccp, int mapcp,
    240                              int prio)
    241 {
    242     int rv = BCM_E_NONE;
    243 
    244     if (port != -1) {
    245         BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    246     }
    247 
    248     soc_mem_lock(unit, PORT_TABm);
    249 
    250     if (port < 0) {
    251         for (port = 0; port <= 16; port++) {  /* for all ports */
    252             rv = _bcm_shadow_port_dscp_map_set(unit, port, srccp, mapcp, prio);
    253             if (BCM_FAILURE(rv)) {
    254                 soc_mem_unlock(unit, PORT_TABm);
    255                 return rv;
    256             }
    257         }
    258     } else {
    259         if ((port >= 1) && (port <= 16)) { /*Specific port */
    260             rv = _bcm_shadow_port_dscp_map_set(unit, port, srccp, mapcp, prio);
    261         } else {
    262             rv = BCM_E_PORT;
    263         }
    264     }
    265     soc_mem_unlock(unit, PORT_TABm);
    266 
    267     return rv;
    268 }
    269 
    270 /*
    271  * Function:
    272  *      _bcm_shadow_port_dscp_map_get
    273  * Purpose:
    274  *      Get a mapping for diffserv code points
    275  * Parameters:
    276  *      unit - switch device
    277  *      port - switch port
    278  *      srccp - src code point or -1
    279  *      mapcp - (OUT) pointer to returned mapped code point
    280  *      prio - (OUT) Priority value for mapped code point or -1
    281  *                      May have BCM_PRIO_DROP_FIRST or'ed into it
    282  * Returns:
    283  *      BCM_E_XXX
    284  */
    285 
    286 STATIC int
    287 _bcm_shadow_port_dscp_map_get(int unit, bcm_port_t port, int srccp, int *mapcp,
    288                       int *prio)
    289 {
    290     int                     base;
    291     dscp_table_entry_t      de;
    292 
    293     if (srccp < -1 || srccp > DSCP_CODE_POINT_MAX || 
    294         mapcp == NULL || prio == NULL) {
    295         return BCM_E_PARAM;
    296     }
    297 
    298     /* look up in DSCP_TABLEm */
    299     if (srccp < 0) {
    300         srccp = 0;
    301     }
    302     base = (port * 512) + 256; /* Always retrive IPV6 settings */
    303     /* IPv4 and IPv6 are both set to same value */
    304     SOC_IF_ERROR_RETURN
    305         (READ_DSCP_TABLEm(unit, MEM_BLOCK_ANY, base + srccp, &de));
    306     *prio = soc_DSCP_TABLEm_field32_get(unit, &de, PRIf);
    307     if (soc_DSCP_TABLEm_field32_get(unit, &de, CNGf)) {
    308         
    309         *prio |= BCM_PRIO_DROP_FIRST;
    310     }
    311     return BCM_E_NONE;
    312 
    313 }
    314 
    315 /*
    316  * Function:
    317  *      bcm_port_dscp_map_get
    318  * Purpose:
    319  *      Get a mapping for diffserv code points
    320  * Parameters:
    321  *      unit - switch device
    322  *      port - switch port
    323  *      srccp - src code point or -1
    324  *      mapcp - (OUT) pointer to returned mapped code point
    325  *      prio - (OUT) Priority value for mapped code point or -1
    326  *                      May have BCM_PRIO_DROP_FIRST or'ed into it
    327  * Returns:
    328  *      BCM_E_XXX
    329  */
    330 
    331 int
    332 bcm_shadow_port_dscp_map_get(int unit, bcm_port_t port, int srccp, int *mapcp,
    333                       int *prio)
    334 {
    335     int rv;
    336 
    337     if (port != -1) {
    338         BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    339     }
    340 
    341     soc_mem_lock(unit, PORT_TABm);
    342 
    343     /* Get device port configuration. */
    344     if ((port >= 1) && (port <=16)) {
    345         rv = _bcm_shadow_port_dscp_map_get(unit, port, srccp, mapcp, prio);
    346     } else {
    347         rv = BCM_E_PORT;
    348     }
    349 
    350     soc_mem_unlock(unit, PORT_TABm);
    351     return rv;
    352 }
    353 
    354 
    355 /*
    356  * Function:
    357  *      bcm_shadow_port_vlan_priority_map_set
    358  * Description:
    359  *      Define the mapping of incomming port, packet priority, and cfi bit to
    360  *      switch internal priority and color.
    361  * Parameters:
    362  *      unit         - (IN) Device number
    363  *      port         - (IN) Port number
    364  *      pkt_pri      - (IN) Packet priority
    365  *      cfi          - (IN) Packet CFI
    366  *      internal_pri - (IN) Internal priority
    367  *      color        - (IN) color
    368  * Return Value:
    369  *      BCM_E_XXX
    370  * Note:
    371  *      This API programs only the mapping table. 
    372  */
    373 int
    374 bcm_shadow_port_vlan_priority_map_set(int unit, bcm_port_t port, int pkt_pri,
    375                                    int cfi, int internal_pri, bcm_color_t color)
    376 {
    377     int                      index;
    378     ing_pri_cng_map_entry_t  pri_map;
    379 
    380     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    381     if (pkt_pri < 0 || pkt_pri > 7 || cfi < 0 || cfi > 1 || internal_pri < 0 ||
    382         internal_pri >=
    383         (1 << soc_mem_field_length(unit, ING_PRI_CNG_MAPm, PRIf))) {
    384         return BCM_E_PARAM;
    385     }
    386 
    387     /* ING_PRI_CNG_MAP table is indexed with
    388      * port[0:4] incoming priority[2:0] incoming CFI[0]
    389      */
    390     index = (port << 4) | (pkt_pri << 1) | cfi;
    391 
    392     memset(&pri_map, 0, sizeof(pri_map));
    393     soc_mem_field32_set(unit, ING_PRI_CNG_MAPm, &pri_map, PRIf, 
    394                         internal_pri);
    395     soc_mem_field32_set(unit, ING_PRI_CNG_MAPm, &pri_map, CNGf, 
    396                         _BCM_COLOR_ENCODING(unit, color));
    397     SOC_IF_ERROR_RETURN
    398         (WRITE_ING_PRI_CNG_MAPm(unit, MEM_BLOCK_ALL, index, &pri_map));
    399     return BCM_E_NONE;
    400 }
    401 
    402 /*
    403  * Function:
    404  *      bcm_shadow_port_vlan_priority_map_get
    405  * Description:
    406  *      Get the mapping of incomming port, packet priority, and cfi bit to
    407  *      switch internal priority and color.
    408  * Parameters:
    409  *      unit         - (IN) Device number
    410  *      port         - (IN) Port number
    411  *      pkt_pri      - (IN) Packet priority
    412  *      cfi          - (IN) Packet CFI
    413  *      internal_pri - (OUT) Internal priority
    414  *      color        - (OUT) color
    415  * Return Value:
    416  *      BCM_E_XXX
    417  * Note:
    418  *      This API programs only the mapping table. 
    419  */
    420 int
    421 bcm_shadow_port_vlan_priority_map_get(int unit, bcm_port_t port, int pkt_pri,
    422                                    int cfi, int *internal_pri, 
    423                                    bcm_color_t *color)
    424 {
    425 
    426     int index, hw_color;
    427     ing_pri_cng_map_entry_t pri_map;
    428 
    429     /* Input parameters check. */
    430     if ((NULL == internal_pri) || (NULL == color)) {
    431         return (BCM_E_PARAM);
    432     }
    433 
    434     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    435 
    436     if (pkt_pri < 0 || pkt_pri > 7 || cfi < 0 || cfi > 1) {
    437         return BCM_E_PARAM;
    438     }
    439 
    440     /* ING_PRI_CNG_MAP table is indexed with
    441      * port[4:0] incoming priority[2:0] incoming CFI[0]
    442      */
    443     index = (port << 4) | (pkt_pri << 1) | cfi;
    444     LOG_INFO(BSL_LS_BCM_PORT,
    445              (BSL_META_U(unit,
    446                          "bcm_shadow_port_vlan_priority_map_get: u=%d p=%d index=%d\n"),
    447               unit, port, index));
    448 
    449     SOC_IF_ERROR_RETURN
    450         (READ_ING_PRI_CNG_MAPm(unit, MEM_BLOCK_ANY, index, &pri_map));
    451     *internal_pri = soc_mem_field32_get(unit, ING_PRI_CNG_MAPm, &pri_map, 
    452                                        PRIf);
    453     hw_color = soc_mem_field32_get(unit, ING_PRI_CNG_MAPm, &pri_map, CNGf);
    454     *color = _BCM_COLOR_DECODING(unit, hw_color);
    455     return BCM_E_NONE;
    456 }
    457 
    458 /*
    459  * Function:
    460  *      bcm_shadow_port_management_packet_config_set
    461  * Description:
    462  *      Set Management packet classification for Ethertype and/or Dest MAC
    463  * Parameters:
    464  *      unit         - (IN) Device number
    465  *      port         - (IN) Port number
    466  *      config      -  (IN) Pointer to bcm_port_management_packet_config_t
    467  * Return Value:
    468  *      BCM_E_XXX
    469  * Note:
    470  *      This API programs MGMT_FRAME_CTRL register
    471  */
    472 int
    473 bcm_shadow_port_management_packet_config_set(int unit, bcm_port_t port,
    474                                    bcm_port_management_packet_config_t *config)
    475 {
    476     int rv = BCM_E_NONE;
    477     bcm_mac_t   dest_mac;
    478     soc_reg_t reg[5] = {CTRL_DA1r, CTRL_DA2r, CTRL_DA3r, CTRL_DA4r,
    479                        CTRL_DA5r};
    480     soc_field_t field[5] = {CTRL_DA1f, CTRL_DA2f, CTRL_DA3f, CTRL_DA4f,
    481                        CTRL_DA5f};
    482     uint64 mac_field;
    483     bcm_ethertype_t etype;
    484     uint32 val;
    485     uint64 val64;
    486     int enable, i, p, empty = 0;
    487 
    488     if (config == NULL) {
    489         return BCM_E_PARAM;
    490     }
    491     if (port < 0 || port > 16) {
    492         return BCM_E_PARAM;
    493     }
    494     soc_mem_lock(unit, PORT_TABm);
    495     if ((config->flags & 
    496                     (BCM_PORT_MANAGEMENT_PACKET_DEST_MAC |
    497                      BCM_PORT_MANAGEMENT_PACKET_ETHERTYPE)) ==
    498                     (BCM_PORT_MANAGEMENT_PACKET_DEST_MAC |
    499                      BCM_PORT_MANAGEMENT_PACKET_ETHERTYPE)) {
    500         if (config->flags & BCM_PORT_MANAGEMENT_PACKET_CLEAR) { 
    501             /* Clear the config */
    502             rv = READ_CTRL_ETHERTYPE2r(unit, &val);
    503             etype = soc_reg_field_get(unit, CTRL_ETHERTYPE2r, val, 
    504                                       ETHERTYPEf);
    505             if (BCM_SUCCESS(rv)) {
    506                 rv = soc_reg_get(unit, CTRL_DA6r, port, 0, &mac_field);
    507                 SAL_MAC_ADDR_FROM_UINT64(dest_mac, mac_field);
    508                 if (BCM_SUCCESS(rv)) {
    509                     if ((ENET_CMP_MACADDR(dest_mac, config->dest_mac) == 0) &&
    510                                         (etype == config->ethertype)) {
    511                         rv = (soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    512                                            CTRL_ETHERTYPE2f, 0));
    513                         rv = (soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    514                                            CTRL_DA6f, 0));
    515                         for (i = 0; i <= 16; i++) { 
    516                             /* check if any other ports are still using ethtype */
    517                             rv = READ_MGMT_FRAME_ENABLEr(unit, i, &val);
    518                             if (BCM_SUCCESS(rv)) {
    519                                 enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, CTRL_ETHERTYPE2f);
    520                                 if (enable) {
    521                                     break;
    522                                 }
    523                             }
    524                         }
    525                         if (BCM_SUCCESS(rv) && i >= 16) { /* No ports using ethertype, clear it */
    526                             rv = soc_reg_field32_modify(unit, CTRL_ETHERTYPE2r, port, 
    527                                                     ETHERTYPEf, 0);
    528                             COMPILER_64_ZERO(val64);
    529                             rv = soc_reg_set(unit, CTRL_DA6r, port, 0, val64);
    530                         }
    531                     } else {
    532                         rv = BCM_E_NOT_FOUND;
    533                     }
    534                 }
    535             }
    536         } else {
    537             rv = READ_CTRL_ETHERTYPE2r(unit, &val);
    538             etype = soc_reg_field_get(unit, CTRL_ETHERTYPE2r, val, 
    539                                       ETHERTYPEf);
    540             if (BCM_SUCCESS(rv)) {
    541                 rv = soc_reg_get(unit, CTRL_DA6r, port, 0, &mac_field);
    542                 SAL_MAC_ADDR_FROM_UINT64(dest_mac, mac_field);
    543                 if (BCM_SUCCESS(rv)) {
    544                    if ((ENET_CMP_MACADDR(dest_mac, config->dest_mac) == 0) &&
    545                        (etype == config->ethertype)) {
    546                         rv = (soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    547                                            CTRL_ETHERTYPE2f, 1));
    548                         rv = (soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    549                                            CTRL_DA6f, 1));
    550                     } else if ((etype == 0) && COMPILER_64_IS_ZERO(mac_field)) {
    551                         rv = (soc_reg_field32_modify(unit, CTRL_ETHERTYPE2r, port, 
    552                                            ETHERTYPEf, config->ethertype));
    553                         SAL_MAC_ADDR_TO_UINT64(config->dest_mac, mac_field);
    554                         rv = soc_reg_set(unit, CTRL_DA6r, port, 0, mac_field);
    555 
    556                         rv = (soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    557                                            CTRL_ETHERTYPE2f, 1));
    558                         rv = (soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    559                                            CTRL_DA6f, 1));
    560                     } else {
    561                         rv = BCM_E_RESOURCE;
    562                     }
    563                 }
    564             }
    565         }
    566     } else if ((config->flags & BCM_PORT_MANAGEMENT_PACKET_ETHERTYPE) ==
    567                          BCM_PORT_MANAGEMENT_PACKET_ETHERTYPE) {
    568         if (config->flags & BCM_PORT_MANAGEMENT_PACKET_CLEAR) { 
    569             /* Clear the config */
    570             rv = READ_CTRL_ETHERTYPE1r(unit, &val);
    571             etype = soc_reg_field_get(unit, CTRL_ETHERTYPE1r, val, 
    572                                       ETHERTYPEf);
    573             if (BCM_SUCCESS(rv)) { 
    574                 if (etype == config->ethertype) {
    575                     rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    576                                                 CTRL_ETHERTYPE1f, 0);
    577                     for (i = 0; i <= 16; i++) { 
    578                         /* check if any other ports are still using ethtype */
    579                         rv = READ_MGMT_FRAME_ENABLEr(unit, i, &val);
    580                         if (BCM_SUCCESS(rv)) {
    581                             enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, CTRL_ETHERTYPE1f);
    582                             if (enable) {
    583                                 break;
    584                             }
    585                         }
    586                     }
    587                     if (BCM_SUCCESS(rv) && i >= 16) { /* No ports using ethertype, clear it */
    588                         rv = soc_reg_field32_modify(unit, CTRL_ETHERTYPE1r, port, 
    589                                                     ETHERTYPEf, 0);
    590                     }
    591                 } else {
    592                     rv = BCM_E_NOT_FOUND;
    593                 }
    594             }
    595         } else {
    596             /* Only Ether type is valid */
    597             rv = READ_MGMT_FRAME_ENABLEr(unit, port, &val);
    598             if (BCM_SUCCESS(rv)) {
    599                 enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, CTRL_ETHERTYPE1f);
    600                 rv = READ_CTRL_ETHERTYPE1r(unit, &val);
    601                 etype = soc_reg_field_get(unit, CTRL_ETHERTYPE1r, val, ETHERTYPEf);
    602                 if (BCM_SUCCESS(rv)) {
    603                     if ((etype == config->ethertype)) { 
    604                         /* Other ports have already added the ether type */
    605                         rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    606                                             CTRL_ETHERTYPE1f, 1);
    607                     } else if ((etype == 0x0)) {
    608                         BCM_IF_ERROR_RETURN
    609                             (soc_reg_field32_modify(unit, CTRL_ETHERTYPE1r, port, 
    610                                                 ETHERTYPEf, config->ethertype));
    611                         BCM_IF_ERROR_RETURN
    612                             (soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    613                                                 CTRL_ETHERTYPE1f, 1));
    614                     } else {
    615                         rv = BCM_E_RESOURCE;
    616                     }
    617                 }
    618             }
    619         }
    620     } else if ((config->flags & BCM_PORT_MANAGEMENT_PACKET_DEST_MAC) ==
    621                          BCM_PORT_MANAGEMENT_PACKET_DEST_MAC) {
    622         /* check if the DA is CDP multicast */
    623         bcm_mac_t neigh_disc_da = {0x33, 0x33, 0x00, 0x00, 0x00, 0x00};
    624         bcm_mac_t cdp_da = {0x01, 0x00, 0x0C, 0xCC, 0xCC, 0xCC};
    625         bcm_mac_t sstp_da = {0x01, 0x00, 0x0C, 0xCC, 0xCC, 0xCD};
    626         if (config->flags & BCM_PORT_MANAGEMENT_PACKET_CLEAR) { 
    627 
    628             if (ENET_CMP_MACADDR(cdp_da, config->dest_mac) == 0) {
    629                 /* Clear the MGMT Frame classification */
    630                 rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    631                                             C_MC_DMAC_Af, 0);
    632             } else if (ENET_CMP_MACADDR(sstp_da, config->dest_mac) == 0) {
    633                 /* Clear the MGMT Frame classification */
    634                 rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    635                                             C_MC_DMAC_Bf, 0);
    636             } else if (ENET_CMP_MACADDR(neigh_disc_da, config->dest_mac) == 0) {
    637                 /* Clear the MGMT Frame classification */
    638                 rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    639                                             NEIGHBOR_DISCf, 0);
    640             } else  {
    641                 /* Clear the config */
    642                 for (i = 0; i < 5; i++) {
    643                     rv = soc_reg_get(unit, reg[i], port, 0, &mac_field);
    644                     SAL_MAC_ADDR_FROM_UINT64(dest_mac, mac_field);
    645                     if (BCM_SUCCESS(rv) && (ENET_CMP_MACADDR(dest_mac,
    646                     config->dest_mac) == 0)) {
    647                         rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    648                                                 field[i], 0);
    649                         for (p = 0; p <= 16; p++) { 
    650                             /* check if any other ports are still using ethtype */
    651                             rv = READ_MGMT_FRAME_ENABLEr(unit, p, &val);
    652                             if (BCM_SUCCESS(rv)) {
    653                                 enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, field[i]);
    654                                 if (enable) {
    655                                     break;
    656                                 }
    657                             }
    658                         }
    659                         if (BCM_SUCCESS(rv) && i >= 16) { /* No ports using dest-da, clear it */
    660                             COMPILER_64_ZERO(val64);
    661                             rv = soc_reg_set(unit, reg[i], port, 0, val64);
    662                         }
    663                         break;
    664                     }
    665                 }
    666                 if (i >= 5) {
    667                     rv = BCM_E_NOT_FOUND;
    668                 }
    669             }
    670         } else {
    671             if (ENET_CMP_MACADDR(cdp_da, config->dest_mac) == 0) {
    672                 /* Clear the MGMT Frame classification */
    673                 rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    674                                             C_MC_DMAC_Af, 1);
    675             } else if (ENET_CMP_MACADDR(sstp_da, config->dest_mac) == 0) {
    676                 /* Clear the MGMT Frame classification */
    677                 rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    678                                             C_MC_DMAC_Bf, 1);
    679             } else if (ENET_CMP_MACADDR(neigh_disc_da, config->dest_mac) == 0) {
    680                 /* Clear the MGMT Frame classification */
    681                 rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    682                                             NEIGHBOR_DISCf, 1);
    683             } else {
    684                 empty = -1;
    685                 for (i = 0; i < 5; i++) { /* find a matching Dest-DA */
    686                     rv = soc_reg_get(unit, reg[i], port, 0, &mac_field);
    687                     SAL_MAC_ADDR_FROM_UINT64(dest_mac, mac_field);
    688                     if (BCM_SUCCESS(rv) && (ENET_CMP_MACADDR(dest_mac, config->dest_mac) == 0)) {
    689                         rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    690                                                     field[i], 1);
    691                         break;
    692                     }
    693                     if (BCM_SUCCESS(rv) && COMPILER_64_IS_ZERO(mac_field)) {
    694                         empty = i; /* found an empty slot */
    695                     }
    696                 }
    697 
    698                 if (i >= 5 && empty != -1) { /* no match found, but found an empty slot */
    699                     SAL_MAC_ADDR_TO_UINT64(config->dest_mac, mac_field);
    700                     rv = soc_reg64_set(unit, reg[empty], port, 0, mac_field);
    701                     if (BCM_SUCCESS(rv)) {
    702                         rv = soc_reg_field32_modify(unit, MGMT_FRAME_ENABLEr, port, 
    703                                                     field[empty], 1);
    704                     }
    705                 } else if (i >= 5 && empty == -1) {   /* no empty slot found */
    706                     rv = BCM_E_RESOURCE;
    707                 }
    708             } 
    709         }
    710     } else {
    711         rv = BCM_E_PARAM;
    712     }
    713     soc_mem_unlock(unit, PORT_TABm);
    714 
    715     return rv;
    716 }
    717 
    718 /*
    719  * Function:
    720  *      bcm_shadow_port_management_packet_config_get
    721  * Description:
    722  *      Get Management packet classification for Ethertype and/or Dest MAC
    723  * Parameters:
    724  *      unit         - (IN) Device number
    725  *      port         - (IN) Port number
    726  *      config_array -  (OUT) Pointer to bcm_port_management_packet_config_t
    727  *      max_config   - (IN) Max number of Management Packet classifications requested
    728  *      config_count  -  (OUT) Actual number of Management Packet classifcations
    729  * Return Value:
    730  *      BCM_E_XXX
    731  * Note:
    732  */
    733 int
    734 bcm_shadow_port_management_packet_config_get(int unit, bcm_port_t port,
    735                                    bcm_port_management_packet_config_t *config,
    736                                    int max_config, int *config_count)
    737 
    738 {
    739     int rv = BCM_E_NONE;
    740     bcm_mac_t   dest_mac;
    741     soc_reg_t reg[5] = {CTRL_DA1r, CTRL_DA2r, CTRL_DA3r, CTRL_DA4r,
    742                        CTRL_DA5r};
    743     soc_field_t field[5] = {CTRL_DA1f, CTRL_DA2f, CTRL_DA3f, CTRL_DA4f,
    744                        CTRL_DA5f};
    745     uint64 mac_field;
    746     bcm_ethertype_t etype;
    747     uint32 val;
    748     int enable, i = 0, cnt = 0;
    749     bcm_mac_t neigh_disc_da = {0x33, 0x33, 0x00, 0x00, 0x00, 0x00};
    750     bcm_mac_t cdp_da = {0x01, 0x00, 0x0C, 0xCC, 0xCC, 0xCC};
    751     bcm_mac_t sstp_da = {0x01, 0x00, 0x0C, 0xCC, 0xCC, 0xCD};
    752 
    753     if ((config == NULL) || (max_config == 0)) {
    754         return BCM_E_PARAM;
    755     }
    756     if (port < 0 || port > 16) {
    757         return BCM_E_PARAM;
    758     }
    759     *config_count = 0;
    760     soc_mem_lock(unit, PORT_TABm);
    761     rv = READ_MGMT_FRAME_ENABLEr(unit, port, &val);
    762     if (BCM_SUCCESS(rv)) {
    763         enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, CTRL_ETHERTYPE1f);
    764         if (enable) {
    765             rv = READ_CTRL_ETHERTYPE1r(unit, &val);
    766             etype = soc_reg_field_get(unit, CTRL_ETHERTYPE1r, val, 
    767                                       ETHERTYPEf);
    768             config[cnt].ethertype = etype;
    769             config[cnt].flags = BCM_PORT_MANAGEMENT_PACKET_ETHERTYPE;
    770             cnt++;
    771             if (cnt >= max_config) {
    772                 soc_mem_unlock(unit, PORT_TABm);
    773                 *config_count = cnt;
    774                 return BCM_E_NONE;
    775             }
    776         }
    777         enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, CTRL_ETHERTYPE2f);
    778         if (enable) {
    779             rv = READ_CTRL_ETHERTYPE2r(unit, &val);
    780             etype = soc_reg_field_get(unit, CTRL_ETHERTYPE2r, val, 
    781                                       ETHERTYPEf);
    782             config[cnt].ethertype = etype;
    783             config[cnt].flags = BCM_PORT_MANAGEMENT_PACKET_ETHERTYPE;
    784 
    785             rv = soc_reg_get(unit, CTRL_DA6r, port, 0, &mac_field);
    786             SAL_MAC_ADDR_FROM_UINT64(dest_mac, mac_field);
    787             ENET_SET_MACADDR(config[cnt].dest_mac, dest_mac);
    788             config[cnt].flags = BCM_PORT_MANAGEMENT_PACKET_ETHERTYPE | 
    789                               BCM_PORT_MANAGEMENT_PACKET_DEST_MAC;
    790             cnt++;
    791             if (cnt >= max_config) {
    792                 soc_mem_unlock(unit, PORT_TABm);
    793                 *config_count = cnt;
    794                 return BCM_E_NONE;
    795             }
    796         }
    797         enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, NEIGHBOR_DISCf);
    798         if (enable) {
    799             ENET_SET_MACADDR(config[cnt].dest_mac, neigh_disc_da);
    800             config[cnt].flags = BCM_PORT_MANAGEMENT_PACKET_DEST_MAC;
    801             cnt++;
    802             if (cnt >= max_config) {
    803                 soc_mem_unlock(unit, PORT_TABm);
    804                 *config_count = cnt;
    805                 return BCM_E_NONE;
    806             }
    807         }
    808         enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, C_MC_DMAC_Af);
    809         if (enable) {
    810             ENET_SET_MACADDR(config[cnt].dest_mac, cdp_da);
    811             config[cnt].flags = BCM_PORT_MANAGEMENT_PACKET_DEST_MAC;
    812             cnt++;
    813             if (cnt >= max_config) {
    814                 soc_mem_unlock(unit, PORT_TABm);
    815                 *config_count = cnt;
    816                 return BCM_E_NONE;
    817             }
    818         }
    819         enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, C_MC_DMAC_Bf);
    820         if (enable) {
    821             ENET_SET_MACADDR(config[cnt].dest_mac, sstp_da);
    822             config[cnt].flags = BCM_PORT_MANAGEMENT_PACKET_DEST_MAC;
    823             cnt++;
    824             if (cnt >= max_config) {
    825                 soc_mem_unlock(unit, PORT_TABm);
    826                 *config_count = cnt;
    827                 return BCM_E_NONE;
    828             }
    829         }
    830 
    831         for (i = 0; i < 5; i++) {
    832             enable = soc_reg_field_get(unit, MGMT_FRAME_ENABLEr, val, field[i]);
    833             if (enable) {
    834                 rv = soc_reg_get(unit, reg[i], port, 0, &mac_field);
    835                 SAL_MAC_ADDR_FROM_UINT64(dest_mac, mac_field);
    836                 ENET_SET_MACADDR(config[cnt].dest_mac, dest_mac);
    837                 config[cnt].flags = BCM_PORT_MANAGEMENT_PACKET_DEST_MAC;
    838                 cnt++;
    839                 if (cnt >= max_config) {
    840                     *config_count = cnt;
    841                     break;
    842                 }
    843             }
    844         }
    845     }
    846     soc_mem_unlock(unit, PORT_TABm);
    847     return rv;
    848 }