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

extender.c (18041B)


      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:    extender.c
      8  * Purpose: Implements bcm_extender_forward_* APIs for Greyhound.
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <sal/core/libc.h>
     13 
     14 #if defined(BCM_GREYHOUND_SUPPORT) && defined(INCLUDE_L3)
     15 
     16 #include <soc/mem.h>
     17 #include <soc/ism_hash.h>
     18 
     19 #include <bcm/error.h>
     20 
     21 #include <bcm_int/esw_dispatch.h>
     22 #include <bcm_int/esw/l2.h>
     23 #include <bcm_int/common/multicast.h>
     24 #include <bcm_int/esw/greyhound.h>
     25 
     26 /*
     27  * Purpose:
     28  *	Add a downstream forwarding entry
     29  * Parameters:
     30  *	unit - (IN) Device Number
     31  *	forward_entry - (IN) Forwarding entry
     32  */
     33 int
     34 bcm_gh_extender_forward_add(int unit, bcm_extender_forward_t *forward_entry)
     35 {
     36     int rv = BCM_E_NONE;
     37     bcm_module_t mod_out;
     38     bcm_port_t port_out;
     39     bcm_trunk_t tgid_out;
     40     int id_out;
     41     l2x_entry_t l2x_entry;
     42     int lower_th, higher_th;
     43 
     44     if (forward_entry->name_space > 0xfff) {
     45         return BCM_E_PARAM;
     46     }
     47 
     48     if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) {
     49         if (forward_entry->extended_port_vid > 0x3fff) {
     50             return BCM_E_PARAM;
     51         }
     52 
     53         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit,
     54                     forward_entry->dest_port,
     55                     &mod_out, &port_out, &tgid_out, &id_out));
     56         if (-1 != id_out) {
     57             return BCM_E_PARAM;
     58         }
     59 
     60         sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
     61         soc_L2Xm_field32_set(unit, &l2x_entry, VALIDf, 1);
     62         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 
     63                              GH_L2_HASH_KEY_TYPE_PE_VID); /* PE_VID */
     64         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf,
     65                 forward_entry->name_space);
     66         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf,
     67                 forward_entry->extended_port_vid);
     68         if (-1 != tgid_out) {
     69             BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, tgid_out));
     70             soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__DEST_TYPEf, 1);
     71             soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__TGIDf, tgid_out);
     72         } else {
     73             soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__MODULE_IDf, mod_out);
     74             soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__PORT_NUMf, port_out);
     75         }
     76         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__STATIC_BITf, 1);
     77 
     78     } else { /* Multicast forward entry */
     79         BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
     80                     bcmSwitchExtenderMulticastLowerThreshold, &lower_th));
     81         BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
     82                     bcmSwitchExtenderMulticastHigherThreshold, &higher_th));
     83         if ((forward_entry->extended_port_vid < lower_th) ||
     84                (forward_entry->extended_port_vid > higher_th)) {
     85             return BCM_E_PARAM;
     86         }
     87         if (!_BCM_MULTICAST_IS_L2(forward_entry->dest_multicast)) {
     88             return BCM_E_PARAM;
     89         }
     90 
     91         sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
     92         soc_L2Xm_field32_set(unit, &l2x_entry, VALIDf, 1);
     93         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 
     94                              GH_L2_HASH_KEY_TYPE_PE_VID); /* PE_VID */
     95         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf,
     96                 forward_entry->name_space);
     97         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf,
     98                 forward_entry->extended_port_vid);
     99         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__L2MC_PTRf,
    100                 _BCM_MULTICAST_ID_GET(forward_entry->dest_multicast));
    101         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__STATIC_BITf, 1);
    102     }
    103 
    104     if (forward_entry->flags & BCM_EXTENDER_FORWARD_COPY_TO_CPU) {
    105         if (SOC_MEM_FIELD_VALID(unit, L2Xm, PE_VID__CPUf)) {
    106             soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__CPUf, 1);
    107         }
    108     }
    109 
    110     soc_mem_lock(unit, L2Xm);
    111 
    112     if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_REPLACE)) {
    113         l2x_entry_t  l2x_lookup;
    114         int l2_index;
    115 
    116         /* See if the entry already exists */
    117         rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry,
    118                                 &l2x_lookup, &l2_index);
    119         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
    120             soc_mem_unlock(unit, L2Xm);
    121             return rv;
    122         } 
    123         if (BCM_SUCCESS(rv)) {
    124             soc_mem_unlock(unit, L2Xm);
    125             return BCM_E_EXISTS;
    126         } 
    127 
    128         rv = soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
    129         if (SOC_FAILURE(rv)) {
    130             soc_mem_unlock(unit, L2Xm);
    131             return rv;
    132         }
    133     } else { /* Replace existing entry */
    134         rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
    135         if (SOC_FAILURE(rv)) {
    136             soc_mem_unlock(unit, L2Xm);
    137             return rv;
    138         }
    139         rv = soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
    140         if (SOC_FAILURE(rv)) {
    141             soc_mem_unlock(unit, L2Xm);
    142             return rv;
    143         }
    144     }
    145 
    146     soc_mem_unlock(unit, L2Xm);
    147 
    148     return rv;
    149 }
    150 
    151 /*
    152  * Purpose:
    153  *	Delete a downstream forwarding entry
    154  * Parameters:
    155  *      unit - (IN) Device Number
    156  *      forward_entry - (IN) Forwarding entry
    157  */
    158 int
    159 bcm_gh_extender_forward_delete(int unit, bcm_extender_forward_t *forward_entry)
    160 {
    161     int rv = BCM_E_NONE;
    162     l2x_entry_t l2x_entry;
    163     int lower_th, higher_th;
    164 
    165     if (forward_entry->name_space > 0xfff) {
    166         return BCM_E_PARAM;
    167     }
    168     if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) {
    169         if (forward_entry->extended_port_vid > 0x3fff) {
    170             return BCM_E_PARAM;
    171         }
    172     } else { /* Multicast forward entry */
    173         BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
    174                 bcmSwitchExtenderMulticastLowerThreshold, &lower_th));
    175         BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
    176                     bcmSwitchExtenderMulticastHigherThreshold, &higher_th));
    177         if ((forward_entry->extended_port_vid < lower_th) ||
    178                (forward_entry->extended_port_vid > higher_th)) {
    179             return BCM_E_PARAM;
    180         }
    181     }
    182 
    183     sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
    184     soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 
    185                          GH_L2_HASH_KEY_TYPE_PE_VID); /* PE_VID */
    186     soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf,
    187             forward_entry->name_space);
    188     soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf,
    189             forward_entry->extended_port_vid);
    190     soc_mem_lock(unit, L2Xm);
    191     rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
    192     soc_mem_unlock(unit, L2Xm);
    193 
    194     return rv;
    195 }
    196 
    197 int
    198 _bcm_gh_extender_forward_delete_all(int unit, bcm_extender_forward_t *forward_entry, void *data)
    199 {
    200     BCM_IF_ERROR_RETURN(bcm_gh_extender_forward_delete(unit, forward_entry));
    201 
    202     return BCM_E_NONE;
    203 }
    204 
    205 /*
    206  * Purpose:
    207  *	Delete all downstream forwarding entries
    208  * Parameters:
    209  *	unit - Device Number
    210  */
    211 int
    212 bcm_gh_extender_forward_delete_all(int unit)
    213 {
    214     int rv = BCM_E_NONE;
    215 #if 1 /* TBD */	
    216     BCM_IF_ERROR_RETURN(bcm_gh_extender_forward_traverse(unit, 
    217         _bcm_gh_extender_forward_delete_all, NULL));
    218 
    219 #else
    220     l2_bulk_match_mask_entry_t match_mask;
    221     l2_bulk_match_data_entry_t match_data;
    222     int field_len;
    223 
    224     sal_memset(&match_mask, 0, sizeof(match_mask));
    225     sal_memset(&match_data, 0, sizeof(match_data));
    226 
    227     soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, VALIDf, 1);
    228     soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, VALIDf, 1);
    229 
    230     field_len = soc_mem_field_length(unit, L2_BULK_MATCH_MASKm, KEY_TYPEf);
    231     soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, KEY_TYPEf,
    232             (1 << field_len) - 1);
    233     soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, KEY_TYPEf,
    234             TR_L2_HASH_KEY_TYPE_PE_VID);
    235 
    236     soc_mem_lock(unit, L2Xm);
    237     rv = WRITE_L2_BULK_MATCH_MASKm(unit, MEM_BLOCK_ALL, 0,
    238             &match_mask);
    239     if (BCM_SUCCESS(rv)) {
    240         rv = WRITE_L2_BULK_MATCH_DATAm(unit, MEM_BLOCK_ALL, 0,
    241                 &match_data);
    242     }
    243     if (BCM_SUCCESS(rv)) {
    244         rv = soc_reg_field32_modify(unit, L2_BULK_CONTROLr, REG_PORT_ANY,
    245                 ACTIONf, 1);
    246     }
    247     if (BCM_SUCCESS(rv)) {
    248         rv = soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr);
    249     }
    250     soc_mem_unlock(unit, L2Xm);
    251 #endif
    252     return rv;
    253 }
    254 
    255 /*
    256  * Purpose:
    257  *      Get a downstream forwarding entry
    258  * Parameters:
    259  *      unit - (IN) Device Number
    260  *      forward_entry - (IN/OUT) Forwarding entry
    261  */
    262 int
    263 bcm_gh_extender_forward_get(int unit, bcm_extender_forward_t *forward_entry)
    264 {
    265     int rv = BCM_E_NONE;
    266     l2x_entry_t l2x_entry, l2x_entry_out;
    267     int idx;
    268     _bcm_gport_dest_t dest;
    269     int l2mc_index;
    270     int lower_th, higher_th;
    271 
    272     if (forward_entry->name_space > 0xfff) {
    273         return BCM_E_PARAM;
    274     }
    275     if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) {
    276         if (forward_entry->extended_port_vid > 0x3fff) {
    277             return BCM_E_PARAM;
    278         }
    279     } else { /* Multicast forward entry */
    280         BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
    281                     bcmSwitchExtenderMulticastLowerThreshold, &lower_th));
    282         BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
    283                     bcmSwitchExtenderMulticastHigherThreshold, &higher_th));
    284         if ((forward_entry->extended_port_vid < lower_th) ||
    285                (forward_entry->extended_port_vid > higher_th)) {
    286             return BCM_E_PARAM;
    287         }
    288     }
    289 
    290     sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
    291     soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 
    292                          GH_L2_HASH_KEY_TYPE_PE_VID); /* PE_VID */
    293     soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf,
    294             forward_entry->name_space);
    295     soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf,
    296             forward_entry->extended_port_vid);
    297     soc_mem_lock(unit, L2Xm);
    298     rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ALL, &idx, &l2x_entry,
    299             &l2x_entry_out, 0);
    300     soc_mem_unlock(unit, L2Xm);
    301 
    302     if (SOC_SUCCESS(rv)) {
    303         if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) {
    304             if (soc_L2Xm_field32_get(unit, &l2x_entry_out,
    305                         PE_VID__DEST_TYPEf)) {
    306                 dest.tgid = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    307                     PE_VID__TGIDf);
    308                 dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
    309             } else {
    310                 dest.modid = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    311                         PE_VID__MODULE_IDf);
    312                 dest.port = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    313                         PE_VID__PORT_NUMf);
    314                 dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
    315             }
    316             BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest,
    317                         &(forward_entry->dest_port)));
    318         } else {
    319             l2mc_index = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    320                     PE_VID__L2MC_PTRf);
    321             _BCM_MULTICAST_GROUP_SET(forward_entry->dest_multicast,
    322                     _BCM_MULTICAST_TYPE_L2, l2mc_index);
    323         }
    324     }
    325 
    326     return rv;
    327 }
    328 
    329 /*
    330  * Purpose:
    331  *      Traverse all valid downstream forwarding entries and call the
    332  *      supplied callback routine.
    333  * Parameters:
    334  *      unit      - Device Number
    335  *      cb        - User callback function, called once per forwarding entry.
    336  *      user_data - cookie
    337  * Returns:
    338  *      BCM_E_XXX
    339  */
    340 int
    341 bcm_gh_extender_forward_traverse(int unit,
    342                              bcm_extender_forward_traverse_cb cb,
    343                              void *user_data)
    344 {
    345     int rv = BCM_E_NONE;
    346     int chunk_entries, chunk_bytes;
    347     uint8 *l2_tbl_chunk = NULL;
    348     int chunk_idx_min, chunk_idx_max;
    349     int ent_idx;
    350     l2x_entry_t *l2x_entry;
    351     bcm_extender_forward_t forward_entry;
    352     int l2mc_index;
    353     _bcm_gport_dest_t dest;
    354     int lower_th, higher_th;
    355 
    356     /* Get ETAG VID multicast range */
    357     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
    358                 bcmSwitchExtenderMulticastLowerThreshold, &lower_th));
    359     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
    360                 bcmSwitchExtenderMulticastHigherThreshold, &higher_th));
    361 
    362     chunk_entries = soc_property_get(unit, spn_L2DELETE_CHUNKS,
    363                                  L2_MEM_CHUNKS_DEFAULT);
    364     chunk_bytes = 4 * SOC_MEM_WORDS(unit, L2Xm) * chunk_entries;
    365     l2_tbl_chunk = soc_cm_salloc(unit, chunk_bytes, "extender forward traverse");
    366     if (NULL == l2_tbl_chunk) {
    367         return BCM_E_MEMORY;
    368     }
    369     for (chunk_idx_min = soc_mem_index_min(unit, L2Xm); 
    370          chunk_idx_min <= soc_mem_index_max(unit, L2Xm); 
    371          chunk_idx_min += chunk_entries) {
    372 
    373         /* Read a chunk of L2 table */
    374         sal_memset(l2_tbl_chunk, 0, chunk_bytes);
    375         chunk_idx_max = chunk_idx_min + chunk_entries - 1;
    376         if (chunk_idx_max > soc_mem_index_max(unit, L2Xm)) {
    377             chunk_idx_max = soc_mem_index_max(unit, L2Xm);
    378         }
    379         rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY,
    380                                 chunk_idx_min, chunk_idx_max, l2_tbl_chunk);
    381         if (SOC_FAILURE(rv)) {
    382             break;
    383         }
    384         for (ent_idx = 0;
    385              ent_idx <= (chunk_idx_max - chunk_idx_min);
    386              ent_idx++) {
    387             l2x_entry = soc_mem_table_idx_to_pointer(unit, L2Xm, l2x_entry_t *, 
    388                                              l2_tbl_chunk, ent_idx);
    389             if (soc_L2Xm_field32_get(unit, l2x_entry, VALIDf) == 0) {
    390                 continue;
    391             }
    392             if (soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf) != 
    393                 GH_L2_HASH_KEY_TYPE_PE_VID) {
    394                 continue;
    395             }
    396 
    397             /* Get fields of forwarding entry */
    398             bcm_extender_forward_t_init(&forward_entry);
    399             forward_entry.name_space = soc_L2Xm_field32_get(unit, l2x_entry,
    400                     PE_VID__NAMESPACEf);
    401             forward_entry.extended_port_vid = soc_L2Xm_field32_get(unit,
    402                     l2x_entry, PE_VID__ETAG_VIDf);
    403             if ((forward_entry.extended_port_vid >= lower_th) &&
    404                 (forward_entry.extended_port_vid <= higher_th)) {
    405                 /* Multicast forward entry */
    406                 forward_entry.flags |= BCM_EXTENDER_FORWARD_MULTICAST;
    407                 l2mc_index = soc_L2Xm_field32_get(unit, l2x_entry,
    408                         PE_VID__L2MC_PTRf);
    409                 _BCM_MULTICAST_GROUP_SET(forward_entry.dest_multicast,
    410                         _BCM_MULTICAST_TYPE_L2, l2mc_index);
    411             } else {
    412                 if (soc_L2Xm_field32_get(unit, l2x_entry,
    413                             PE_VID__DEST_TYPEf)) {
    414                     dest.tgid = soc_L2Xm_field32_get(unit, l2x_entry,
    415                             PE_VID__TGIDf);
    416                     dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
    417                 } else {
    418                     dest.modid = soc_L2Xm_field32_get(unit, l2x_entry,
    419                             PE_VID__MODULE_IDf);
    420                     dest.port = soc_L2Xm_field32_get(unit, l2x_entry,
    421                             PE_VID__PORT_NUMf);
    422                     dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
    423                 }
    424                 rv = _bcm_esw_gport_construct(unit, &dest,
    425                         &(forward_entry.dest_port));
    426                 if (BCM_FAILURE(rv)) {
    427                     break;
    428                 }
    429             }
    430 
    431             if (SOC_MEM_FIELD_VALID(unit, L2Xm, PE_VID__CPUf)) {
    432                 if (soc_L2Xm_field32_get(unit, l2x_entry, PE_VID__CPUf)) {
    433                     forward_entry.flags |= BCM_EXTENDER_FORWARD_COPY_TO_CPU;
    434                 }
    435             }
    436 
    437             rv = cb(unit, &forward_entry, user_data);
    438             if (BCM_FAILURE(rv)) {
    439                 break;
    440             }
    441         }
    442         if (BCM_FAILURE(rv)) {
    443             break;
    444         }
    445     }
    446     soc_cm_sfree(unit, l2_tbl_chunk);
    447 
    448     return rv;
    449 }
    450 
    451 
    452 /*
    453  * Function:
    454  *      bcm_gh_etag_ethertype_set
    455  * Purpose:
    456  *      Set ETAG Ethertype.
    457  * Parameters:
    458  *      unit      - (IN) BCM device number
    459  *      ethertype - (IN) Ethertype
    460  * Returns:
    461  *      BCM_E_XXX
    462  */
    463 int
    464 bcm_gh_etag_ethertype_set(int unit, int ethertype)
    465 {
    466 
    467     if (ethertype < 0 || ethertype > 0xffff) {
    468         return BCM_E_PARAM;
    469     }
    470 
    471     BCM_IF_ERROR_RETURN
    472         (soc_reg_field32_modify(unit, PE_ETHERTYPEr,
    473                                 REG_PORT_ANY, ETHERTYPEf, ethertype));
    474     BCM_IF_ERROR_RETURN
    475         (soc_reg_field32_modify(unit, PE_ETHERTYPEr,
    476                                 REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0));
    477 
    478     BCM_IF_ERROR_RETURN
    479         (soc_reg_field32_modify(unit, EGR_PE_ETHERTYPEr,
    480                                 REG_PORT_ANY, ETHERTYPEf, ethertype));
    481     BCM_IF_ERROR_RETURN
    482         (soc_reg_field32_modify(unit, EGR_PE_ETHERTYPEr,
    483                                 REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0));
    484 
    485     BCM_IF_ERROR_RETURN
    486         (soc_reg_field32_modify(unit, EGR_PE_ETHERTYPE_2r,
    487                                 REG_PORT_ANY, ETHERTYPEf, ethertype));
    488     BCM_IF_ERROR_RETURN
    489         (soc_reg_field32_modify(unit, EGR_PE_ETHERTYPE_2r,
    490                                 REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0));
    491 
    492     return BCM_E_NONE;
    493 }
    494 
    495 /*
    496  * Function:
    497  *      bcm_gh_etag_ethertype_get
    498  * Purpose:
    499  *      Get ETAG Ethertype.
    500  * Parameters:
    501  *      unit      - (IN) BCM device number
    502  *      ethertype - (OUT) Ethertype
    503  * Returns:
    504  *      BCM_E_XXX
    505  */
    506 int
    507 bcm_gh_etag_ethertype_get(int unit, int *ethertype)
    508 {
    509     uint32 rval;
    510 
    511     if (ethertype == NULL) {
    512         return BCM_E_PARAM;
    513     }
    514 
    515     BCM_IF_ERROR_RETURN(READ_PE_ETHERTYPEr(unit, &rval));
    516     if (soc_reg_field_get(unit, PE_ETHERTYPEr, rval, ENABLEf)) {
    517         *ethertype = soc_reg_field_get(unit, PE_ETHERTYPEr, rval, ETHERTYPEf);
    518     } else {
    519         *ethertype = 0;
    520     }
    521 
    522     return BCM_E_NONE;
    523 }
    524 
    525 #endif /* BCM_GREYHOUND_SUPPORT && INCLUDE_L3 */