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

niv.c (18272B)


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