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 (22967B)


      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: Port Management
      9  */
     10 
     11 #include <soc/defs.h>
     12 #if defined(BCM_TRIDENT2_SUPPORT)
     13 #include <soc/drv.h>
     14 #include <bcm/port.h>
     15 #include <bcm/error.h>
     16 #include <bcm_int/esw/port.h>
     17 #include <bcm_int/esw/trident.h>
     18 #include <bcm_int/common/lock.h>
     19 #include <bcm_int/esw/trident2.h>
     20 #include <bcm_int/esw/trident2plus.h>
     21 #include <bcm_int/esw/portctrl.h>
     22 
     23 int
     24 bcm_td2_port_rate_ingress_set(int unit, bcm_port_t port, uint32 bandwidth,
     25                               uint32 burst)
     26 {
     27     int phy_port, mmu_port, index;
     28     static soc_mem_t config_mem[] = {
     29         MMU_MTRI_BKPMETERINGCONFIG_MEM_0m,
     30         MMU_MTRI_BKPMETERINGCONFIG_MEM_1m
     31     };
     32     soc_mem_t mem;
     33     uint32 rval;
     34     mmu_mtri_bkpmeteringconfig_mem_0_entry_t entry;
     35     uint32 pause, refresh_rate, bucketsize, granularity, flags;
     36     int refresh_bitsize, bucket_bitsize;
     37     soc_info_t *si;
     38 
     39     si = &SOC_INFO(unit);
     40     phy_port = SOC_INFO(unit).port_l2p_mapping[port];
     41     mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
     42     if (SOC_PBMP_MEMBER(si->ypipe_pbm, port)) {
     43         mem = config_mem[1];
     44         index = mmu_port & 0x3f;
     45     } else {
     46         mem = config_mem[0];
     47         index = mmu_port;
     48     }
     49 
     50     sal_memset(&entry, 0, sizeof(entry));
     51 
     52     /* If metering is disabled on this ingress port we are done. */
     53     if (!bandwidth || !burst) {
     54         SOC_IF_ERROR_RETURN
     55             (soc_mem_write(unit, mem, MEM_BLOCK_ANY, index, &entry));
     56         return BCM_E_NONE;
     57     }
     58 
     59     flags = 0;
     60     BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval));
     61     if (soc_reg_field_get(unit, MISCCONFIGr, rval, ITU_MODE_SELf)) {
     62         flags |= _BCM_TD_METER_FLAG_NON_LINEAR;
     63     }
     64 
     65     /* Discard threshold will be set to 12.5 % above pause threshold */
     66     pause = (burst * 8) / 9;
     67     refresh_bitsize = soc_mem_field_length(unit, mem, REFRESHCOUNTf);
     68     bucket_bitsize = soc_mem_field_length(unit, mem, PAUSE_THDf);
     69     BCM_IF_ERROR_RETURN
     70         (_bcm_td_rate_to_bucket_encoding(unit, bandwidth, pause, flags,
     71                                          refresh_bitsize, bucket_bitsize,
     72                                          &refresh_rate, &bucketsize,
     73                                          &granularity));
     74 
     75     soc_mem_field32_set(unit, mem, &entry, METER_GRANULARITYf, granularity);
     76     soc_mem_field32_set(unit, mem, &entry, REFRESHCOUNTf, refresh_rate);
     77     soc_mem_field32_set(unit, mem, &entry, PAUSE_THDf, bucketsize);
     78     soc_mem_field32_set(unit, mem, &entry, BKPDISCARD_ENf, 1);
     79     /* Set discard threshold to 12.5 % above pause threshold */
     80     soc_mem_field32_set(unit, mem, &entry, DISCARD_THDf, 3);
     81     /* Set resume threshold to 75% above pause threshold */
     82     /* RESUME_THD field in entry is 0 */
     83 
     84     SOC_IF_ERROR_RETURN
     85         (soc_mem_write(unit, mem, MEM_BLOCK_ANY, index, &entry));
     86 
     87     return BCM_E_NONE;
     88 }
     89 
     90 int
     91 bcm_td2_port_rate_ingress_get(int unit, bcm_port_t port, uint32 *bandwidth,
     92                               uint32 *burst)
     93 {
     94     int phy_port, mmu_port, index;
     95     static soc_mem_t config_mem[] = {
     96         MMU_MTRI_BKPMETERINGCONFIG_MEM_0m,
     97         MMU_MTRI_BKPMETERINGCONFIG_MEM_1m
     98     };
     99     soc_mem_t mem;
    100     uint32 rval;
    101     mmu_mtri_bkpmeteringconfig_mem_0_entry_t entry;
    102     uint32 pause, refresh_rate, bucketsize, granularity, flags;
    103     soc_info_t *si;
    104 
    105     if (bandwidth == NULL || burst == NULL) {
    106         return BCM_E_PARAM;
    107     }
    108 
    109     si = &SOC_INFO(unit);
    110     phy_port = SOC_INFO(unit).port_l2p_mapping[port];
    111     mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
    112     if (SOC_PBMP_MEMBER(si->ypipe_pbm, port)) {
    113         mem = config_mem[1];
    114         index = mmu_port & 0x3f;
    115     } else {
    116         mem = config_mem[0];
    117         index = mmu_port;
    118     }
    119 
    120     SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, &entry));
    121 
    122     if (!soc_mem_field32_get(unit, mem, &entry, BKPDISCARD_ENf)) {
    123         *bandwidth = *burst = 0;
    124         return BCM_E_NONE;
    125     }
    126 
    127     refresh_rate = soc_mem_field32_get(unit, mem, &entry, REFRESHCOUNTf);
    128     bucketsize = soc_mem_field32_get(unit, mem, &entry, PAUSE_THDf);
    129     granularity = soc_mem_field32_get(unit, mem, &entry, METER_GRANULARITYf);
    130 
    131     flags = 0;
    132     BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval));
    133     if (soc_reg_field_get(unit, MISCCONFIGr, rval, ITU_MODE_SELf)) {
    134         flags |= _BCM_TD_METER_FLAG_NON_LINEAR;
    135     }
    136 
    137     BCM_IF_ERROR_RETURN
    138         (_bcm_td_bucket_encoding_to_rate(unit, refresh_rate, bucketsize,
    139                                          granularity, flags, bandwidth,
    140                                          &pause));
    141 
    142     switch (soc_mem_field32_get(unit, mem, &entry, DISCARD_THDf)) {
    143     case 0:
    144         *burst = pause * 7 / 4; /* 75% above PAUSE_THD */
    145         break;
    146     case 1:
    147         *burst = pause * 3 / 2; /* 50% above PAUSE_THD */
    148         break;
    149     case 2:
    150         *burst = pause * 5 / 4; /* 25% above PAUSE_THD */
    151         break;
    152     case 3:
    153         *burst = pause * 9 / 8; /* 12.5% above PAUSE_THD */
    154         break;
    155     default:
    156         /* Should never happen */
    157         *burst = 0;
    158         break;
    159     }
    160 
    161     return BCM_E_NONE;
    162 }
    163 
    164 int
    165 bcm_td2_port_rate_pause_get(int unit, bcm_port_t port, uint32 *pause,
    166                             uint32 *resume)
    167 {
    168     int phy_port, mmu_port, index;
    169     static soc_mem_t config_mem[] = {
    170         MMU_MTRI_BKPMETERINGCONFIG_MEM_0m,
    171         MMU_MTRI_BKPMETERINGCONFIG_MEM_1m
    172     };
    173     soc_mem_t mem;
    174     uint32 rval;
    175     mmu_mtri_bkpmeteringconfig_mem_0_entry_t entry;
    176     uint32 burst, bandwidth, bucketsize, granularity, flags;
    177     soc_info_t *si;
    178 
    179     if (pause == NULL || resume == NULL) {
    180         return BCM_E_PARAM;
    181     }
    182 
    183     si = &SOC_INFO(unit);
    184     phy_port = SOC_INFO(unit).port_l2p_mapping[port];
    185     mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
    186     if (SOC_PBMP_MEMBER(si->ypipe_pbm, port)) {
    187         mem = config_mem[1];
    188         index = mmu_port & 0x3f;
    189     } else {
    190         mem = config_mem[0];
    191         index = mmu_port;
    192     }
    193 
    194     SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, &entry));
    195 
    196     if (!soc_mem_field32_get(unit, mem, &entry, BKPDISCARD_ENf)) {
    197         *pause = *resume = 0;
    198         return BCM_E_NONE;
    199     }
    200 
    201     bucketsize = soc_mem_field32_get(unit, mem, &entry, PAUSE_THDf);
    202     granularity = soc_mem_field32_get(unit, mem, &entry, METER_GRANULARITYf);
    203 
    204     flags = 0;
    205     BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval));
    206     if (soc_reg_field_get(unit, MISCCONFIGr, rval, ITU_MODE_SELf)) {
    207         flags |= _BCM_TD_METER_FLAG_NON_LINEAR;
    208     }
    209 
    210     BCM_IF_ERROR_RETURN
    211         (_bcm_td_bucket_encoding_to_rate(unit, 0, bucketsize, granularity,
    212                                          flags, &bandwidth, pause));
    213 
    214     switch (soc_mem_field32_get(unit, mem, &entry, RESUME_THDf)) {
    215     case 0:
    216         *resume = *pause * 3 / 4; /* 75% of PAUSE_THD */
    217         break;
    218     case 1:
    219         *resume = *pause * 1 / 2; /* 50% of PAUSE_THD */
    220         break;
    221     case 2:
    222         *resume = *pause * 1 / 4; /* 25% of PAUSE_THD */
    223         break;
    224     case 3:
    225         *resume = *pause * 1 / 8; /* 12.5% of PAUSE_THD */
    226         break;
    227     default:
    228         /* Should never happen */
    229         *resume = 0;
    230         break;
    231     }
    232 
    233     switch (soc_mem_field32_get(unit, mem, &entry, DISCARD_THDf)) {
    234     case 0:
    235         burst = *pause * 7 / 4; /* 75% above PAUSE_THD */
    236         break;
    237     case 1:
    238         burst = *pause * 3 / 2; /* 50% above PAUSE_THD */
    239         break;
    240     case 2:
    241         burst = *pause * 5 / 4; /* 25% above PAUSE_THD */
    242         break;
    243     case 3:
    244         burst = *pause * 9 / 8; /* 12.5% above PAUSE_THD */
    245         break;
    246     default:
    247         /* Should never happen */
    248         burst = 0;
    249         break;
    250     }
    251 
    252     *pause = burst - *pause;
    253     *resume = burst - *resume;
    254 
    255     return BCM_E_NONE;
    256 }
    257 
    258 /*
    259  * Function:
    260  *      bcm_td2_port_rate_egress_get
    261  * Purpose:
    262  *      Get egress metering information
    263  * Parameters:
    264  *      unit       - (IN) Unit number
    265  *      port       - (IN) Port number
    266  *      bandwidth  - (IN) Kilobits per second or packets per second
    267  *                        zero if rate limiting is disabled
    268  *      burst      - (IN) Maximum burst size in kilobits or packets
    269  *      mode       - (IN) _BCM_PORT_RATE_BYTE_MODE or _BCM_PORT_RATE_PPS_MODE
    270  * Returns:
    271  *      BCM_E_XXX
    272  */
    273 int
    274 bcm_td2_port_rate_egress_set(int unit, bcm_port_t port, uint32 bandwidth,
    275                              uint32 burst, uint32 mode)
    276 {
    277     int phy_port, mmu_port, index;
    278     static soc_mem_t config_mem[] = {
    279         MMU_MTRO_EGRMETERINGCONFIG_MEM_0m,
    280         MMU_MTRO_EGRMETERINGCONFIG_MEM_1m
    281     };
    282     soc_mem_t mem;
    283     uint32 rval;
    284     mmu_mtro_egrmeteringconfig_mem_0_entry_t entry;
    285     uint32 refresh_rate, bucketsize, granularity, flags;
    286     int refresh_bitsize, bucket_bitsize;
    287     soc_info_t *si;
    288 
    289     si = &SOC_INFO(unit);
    290     phy_port = SOC_INFO(unit).port_l2p_mapping[port];
    291     mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
    292     if (SOC_PBMP_MEMBER(si->ypipe_pbm, port)) {
    293         mem = config_mem[1];
    294         index = mmu_port & 0x3f;
    295     } else {
    296         mem = config_mem[0];
    297         index = mmu_port;
    298     }
    299     if (SOC_IS_MONTEREY(unit)) {
    300         mem = MMU_MTRO_EGRMETERINGCONFIG_MEMm;
    301     }  
    302 
    303     /*
    304      * The procedure followed is first disable the egress metering, then
    305      * re-enable the egress metering.
    306      *
    307      * NOTE: During the period of disabling and re-enabling the Egress metering
    308      * may be in-effective for couple of cycles
    309      */
    310     sal_memset(&entry, 0, sizeof(entry));
    311     SOC_IF_ERROR_RETURN
    312             (soc_mem_write(unit, mem, MEM_BLOCK_ANY, index, &entry));
    313 
    314     /* If metering is disabled on this ingress port we are done. */
    315     if (!bandwidth || !burst) {
    316         return BCM_E_NONE;
    317     }
    318 
    319     flags = mode == _BCM_PORT_RATE_PPS_MODE ?
    320         _BCM_TD_METER_FLAG_PACKET_MODE : 0;
    321     BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval));
    322     if (soc_reg_field_get(unit, MISCCONFIGr, rval, ITU_MODE_SELf)) {
    323         flags |= _BCM_TD_METER_FLAG_NON_LINEAR;
    324     }
    325 
    326     refresh_bitsize = soc_mem_field_length(unit, mem, REFRESHf);
    327     bucket_bitsize = soc_mem_field_length(unit, mem, THD_SELf);
    328     BCM_IF_ERROR_RETURN
    329         (_bcm_td_rate_to_bucket_encoding(unit, bandwidth, burst, flags,
    330                                          refresh_bitsize, bucket_bitsize,
    331                                          &refresh_rate, &bucketsize,
    332                                          &granularity));
    333     soc_mem_field32_set(unit, mem, &entry, MODEf,
    334                         mode == _BCM_PORT_RATE_PPS_MODE ? 1 : 0);
    335     soc_mem_field32_set(unit, mem, &entry, METER_GRANf, granularity);
    336     soc_mem_field32_set(unit, mem, &entry, REFRESHf, refresh_rate);
    337     soc_mem_field32_set(unit, mem, &entry, THD_SELf, bucketsize);
    338 
    339     SOC_IF_ERROR_RETURN
    340         (soc_mem_write(unit, mem, MEM_BLOCK_ANY, index, &entry));
    341 
    342     return BCM_E_NONE;
    343 }
    344 
    345 /*
    346  * Function:
    347  *      bcm_td2_port_rate_egress_get
    348  * Purpose:
    349  *      Get egress metering information
    350  * Parameters:
    351  *      unit       - (IN) Unit number
    352  *      port       - (IN) Port number
    353  *      bandwidth  - (OUT) Kilobits per second or packets per second
    354  *                         zero if rate limiting is disabled
    355  *      burst      - (OUT) Maximum burst size in kilobits or packets
    356  *      mode       - (OUT) _BCM_PORT_RATE_BYTE_MODE or _BCM_PORT_RATE_PPS_MODE
    357  * Returns:
    358  *      BCM_E_XXX
    359  */
    360 int
    361 bcm_td2_port_rate_egress_get(int unit, bcm_port_t port, uint32 *bandwidth,
    362                              uint32 *burst, uint32 *mode)
    363 {
    364     int phy_port, mmu_port, index;
    365     static soc_mem_t config_mem[] = {
    366         MMU_MTRO_EGRMETERINGCONFIG_MEM_0m,
    367         MMU_MTRO_EGRMETERINGCONFIG_MEM_1m
    368     };
    369     soc_mem_t mem;
    370     uint32 rval;
    371     mmu_mtri_bkpmeteringconfig_mem_0_entry_t entry;
    372     uint32 refresh_rate, bucketsize, granularity, flags;
    373     soc_info_t *si;
    374 
    375 
    376     if (bandwidth == NULL || burst == NULL) {
    377         return BCM_E_PARAM;
    378     }
    379 
    380     si = &SOC_INFO(unit);
    381     phy_port = SOC_INFO(unit).port_l2p_mapping[port];
    382     mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
    383 
    384     if (SOC_PBMP_MEMBER(si->ypipe_pbm, port)) {
    385         mem = config_mem[1];
    386         index = mmu_port & 0x3f;
    387     } else {
    388         mem = config_mem[0];
    389         index = mmu_port;
    390     }
    391 
    392     if (SOC_IS_MONTEREY(unit)) {
    393         mem = MMU_MTRO_EGRMETERINGCONFIG_MEMm;
    394     }  
    395     SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, &entry));
    396 
    397     refresh_rate = soc_mem_field32_get(unit, mem, &entry, REFRESHf);
    398     bucketsize = soc_mem_field32_get(unit, mem, &entry, THD_SELf);
    399     granularity = soc_mem_field32_get(unit, mem, &entry, METER_GRANf);
    400 
    401     flags = soc_mem_field32_get(unit, mem, &entry, MODEf) ?
    402         _BCM_TD_METER_FLAG_PACKET_MODE : 0;
    403     BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval));
    404     if (soc_reg_field_get(unit, MISCCONFIGr, rval, ITU_MODE_SELf)) {
    405         flags |= _BCM_TD_METER_FLAG_NON_LINEAR;
    406     }
    407 
    408     BCM_IF_ERROR_RETURN
    409         (_bcm_td_bucket_encoding_to_rate(unit, refresh_rate, bucketsize,
    410                                          granularity, flags, bandwidth,
    411                                          burst));
    412     *mode = flags & _BCM_TD_METER_FLAG_PACKET_MODE ?
    413         _BCM_PORT_RATE_PPS_MODE : _BCM_PORT_RATE_BYTE_MODE;
    414 
    415     return BCM_E_NONE;
    416 }
    417 
    418 /*
    419  * Function:
    420  *     _bcm_td2_port_drain_cells
    421  * Purpose:
    422  *     To drain cells associated to the port.
    423  * Parameters:
    424  *     unit       - (IN) unit number
    425  *     port       - (IN) Port
    426  * Returns:
    427  *     BCM_E_XXX
    428  */
    429 int _bcm_td2_port_drain_cells(int unit, int port)
    430 {
    431     mac_driver_t *macd;
    432     int rv = BCM_E_NONE;
    433 
    434     /* Call Port Control module */
    435     if (SOC_USE_PORTCTRL(unit)) {
    436         return bcmi_esw_portctrl_egress_queue_drain(unit, port);
    437     }
    438 
    439     if (IS_CPU_PORT(unit, port)) {
    440         return BCM_E_PORT;
    441     }
    442     
    443     PORT_LOCK(unit);
    444     rv = soc_mac_probe(unit, port, &macd);
    445 
    446     if (BCM_SUCCESS(rv)) {
    447         rv = MAC_CONTROL_SET(macd, unit, port, SOC_MAC_CONTROL_EGRESS_DRAIN, 1);
    448 
    449     }
    450     PORT_UNLOCK(unit);
    451     return rv;
    452 }
    453 
    454 int bcm_td2_port_drain_cells(int unit, int port)
    455 {
    456     BCM_IF_ERROR_RETURN
    457         (_bcm_td2_port_drain_cells(unit, port));
    458 
    459     BCM_IF_ERROR_RETURN
    460         (_bcm_td2_cosq_port_queue_state_check(unit, port));
    461 
    462     return BCM_E_NONE;
    463 }
    464 
    465 /* Port table field programming - assumes PORT_LOCK is taken */
    466 int
    467 _bcm_td2_egr_port_set(int unit, bcm_port_t port,
    468                       soc_field_t field, int value)
    469 
    470 {
    471     egr_port_entry_t pent;
    472     soc_mem_t mem = EGR_PORTm;
    473     int rv, cur_val;
    474 
    475     if (!SOC_MEM_FIELD_VALID(unit, mem, field)) {
    476         return (BCM_E_UNAVAIL);
    477     }
    478     sal_memset(&pent, 0, sizeof(egr_port_entry_t));
    479     rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, port, &pent);
    480 
    481     if (BCM_SUCCESS(rv)) {
    482         cur_val = soc_EGR_PORTm_field32_get(unit, &pent, field);
    483         if (value != cur_val) {
    484             soc_EGR_PORTm_field32_set(unit, &pent, field, value);
    485             rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, port, &pent);
    486         }
    487     }
    488     return rv;
    489 }
    490 
    491 int
    492 _bcm_td2_egr_port_get(int unit, bcm_port_t port,
    493                       soc_field_t field, int *value)
    494 
    495 {
    496     egr_port_entry_t pent;
    497     soc_mem_t mem = EGR_PORTm;
    498 
    499     if (!SOC_MEM_FIELD_VALID(unit, mem, field)) {
    500         return (BCM_E_UNAVAIL);
    501     }
    502     if (value == NULL) {
    503         return (BCM_E_PARAM);
    504     }
    505 
    506     sal_memset(&pent, 0, sizeof(egr_port_entry_t));
    507     BCM_IF_ERROR_RETURN
    508         (READ_EGR_PORTm(unit, MEM_BLOCK_ANY, port, &pent));
    509     *value = soc_EGR_PORTm_field32_get(unit, &pent, field);
    510 
    511     return BCM_E_NONE;
    512 }
    513 
    514 int 
    515 bcm_td2p_port_coe_e2ecc(int unit, bcm_port_t port,
    516         bcm_port_congestion_config_t *config)
    517 {
    518     uint32 regval = 0;
    519     int e2ecc_enable = 0;
    520     uint32 field_val;
    521     int index;
    522     int copy_to_cpu = 0; 
    523     mmu_intfi_st_trans_tbl_entry_t st_trans_entry;
    524 
    525     if (config->flags & BCM_PORT_CONGESTION_CONFIG_E2ECC_COE_FLEX_MODE) {
    526         return BCM_E_UNAVAIL;
    527     }
    528      /*
    529       * e2ecc_enable here denotes the coe flow control mode we are operating 
    530       * 0 = flow control messages treated as normal data frames.
    531       * 1 = subtending ports send E2ECC pause frames only (only strict mode is supported)
    532       * 2 = subtending ports send VLAN pause frames .
    533       * 3 = reserved
    534       */
    535     if ((config->flags &
    536          BCM_PORT_CONGESTION_CONFIG_E2ECC_COE_STRICT_MODE) && 
    537         (config->flags & BCM_PORT_CONGESTION_CONFIG_RX)) {
    538         e2ecc_enable = 1;
    539     } else if ((config->flags &
    540          BCM_PORT_CONGESTION_CONFIG_VLAN_PAUSE_COE) && 
    541         (config->flags & BCM_PORT_CONGESTION_CONFIG_RX)) {
    542         e2ecc_enable = 2;
    543     }  
    544 
    545     if (config->flags &
    546          BCM_PORT_CONGESTION_CONFIG_COPY_TO_CPU) {
    547          copy_to_cpu = 1 ;
    548     }
    549   
    550     SOC_IF_ERROR_RETURN(
    551                READ_COE_FLOW_CONTROL_CONFIGr (unit, port, &regval));
    552     /* Enable the Flow control and E2ECC mode
    553      * 1. When there is enable request
    554      */
    555     soc_reg_field_set(unit, COE_FLOW_CONTROL_CONFIGr, &regval,
    556                     FLOW_CONTROL_FORMATf, e2ecc_enable);
    557     soc_reg_field_set(unit, COE_FLOW_CONTROL_CONFIGr, &regval,
    558                     COPY_TO_CPUf, copy_to_cpu);
    559     SOC_IF_ERROR_RETURN(
    560       WRITE_COE_FLOW_CONTROL_CONFIGr (unit, port, regval));
    561 
    562     if (e2ecc_enable == 1) {
    563         /* Configure E2ECC-FC to receive MAC-DA, Length/Type, and Opcode.
    564          * HW will match these settings so that we can get the subport tag
    565          * from 12 bits of MAC SA 
    566          */ 
    567         field_val = (config->dest_mac[0] << 8) |    /* MAC-DA[47:40] */
    568                     (config->dest_mac[1]);          /* MAC-DA[39:32] */
    569         SOC_IF_ERROR_RETURN(READ_ING_VOQFC_MACDA_MSr(unit, &regval));
    570         soc_reg_field_set(unit, ING_VOQFC_MACDA_MSr, &regval, DAf, field_val);
    571         SOC_IF_ERROR_RETURN(WRITE_ING_VOQFC_MACDA_MSr(unit, regval));
    572 
    573         field_val = (config->dest_mac[2] << 24) |   /* MAC-DA[31:24] */
    574                     (config->dest_mac[3] << 16) |   /* MAC-DA[23:16] */
    575                     (config->dest_mac[4] << 8) |    /* MAC-DA[15:8] */ 
    576                     (config->dest_mac[5]);          /* MAC-DA[7:0] */  
    577 
    578         SOC_IF_ERROR_RETURN(READ_ING_VOQFC_MACDA_LSr(unit, &regval));
    579         soc_reg_field_set(unit, ING_VOQFC_MACDA_LSr, &regval, DAf, field_val);
    580         SOC_IF_ERROR_RETURN(WRITE_ING_VOQFC_MACDA_LSr(unit, regval));
    581 
    582 
    583         SOC_IF_ERROR_RETURN(READ_ING_VOQFC_IDr(unit, &regval));
    584         soc_reg_field_set(unit, ING_VOQFC_IDr, &regval,
    585                           LENGTH_TYPEf, config->ethertype);
    586         soc_reg_field_set(unit, ING_VOQFC_IDr, &regval,
    587                           OPCODEf, config->opcode);
    588         SOC_IF_ERROR_RETURN(WRITE_ING_VOQFC_IDr(unit, regval));
    589 
    590 
    591         /*
    592          * Hardcoding the MMU_INTFI_ST_TRANS_TBL so the
    593          * congestion data is written as it is
    594          * in FC_ST_TABLE, This we are doing so that
    595          * congestion data is updated as it is
    596          * it recevied
    597          */
    598 
    599         for (index=0 ; index < soc_mem_index_count(unit,
    600                     MMU_INTFI_ST_TRANS_TBLm); index++) {
    601             SOC_IF_ERROR_RETURN(READ_MMU_INTFI_ST_TRANS_TBLm(
    602                         unit, MEM_BLOCK_ALL,index,
    603                         &st_trans_entry));
    604             soc_mem_field32_set(unit, MMU_INTFI_ST_TRANS_TBLm,
    605                     &st_trans_entry, FC_ST_XLATEf,index%16);
    606             SOC_IF_ERROR_RETURN(WRITE_MMU_INTFI_ST_TRANS_TBLm(
    607                         unit, MEM_BLOCK_ALL, index,
    608                         &st_trans_entry));
    609         }
    610         /*
    611          *  FC_WIDTH is set to 2 so that 4 bits of i
    612          * congestion data is read on each cycle
    613          */
    614         SOC_IF_ERROR_RETURN
    615             (soc_reg_field32_modify(unit, INTFI_CFGr, REG_PORT_ANY,
    616                                     FC_WIDTHf, 2));
    617         /*
    618          * MERGE_EN is set to 0, for COE messages 
    619          * to bypass the DMVOQ merge block
    620          */
    621 
    622         SOC_IF_ERROR_RETURN
    623             (soc_reg_field32_modify(unit, INTFI_CFGr, REG_PORT_ANY,
    624                                     MERGE_ENf, 0));
    625         /* MODE_SEL is set to 1 to specify the message is of type
    626          *  DMVOQ/E2ECC
    627          */
    628         SOC_IF_ERROR_RETURN
    629             (soc_reg_field32_modify(unit, INTFI_CFGr, REG_PORT_ANY,
    630                                     MODE_SELf, 1));
    631 
    632         /* Setting VOQFC_Enable to false so that it will identify CoE
    633          * E2ECC messsages rather than VOQFC
    634          */
    635         SOC_IF_ERROR_RETURN(READ_IE2E_CONTROLr(unit, port, &regval));
    636         if (soc_reg_field_get(unit, IE2E_CONTROLr, regval,
    637                             VOQFC_ENABLEf)) {
    638             soc_reg_field_set(unit, IE2E_CONTROLr, &regval,
    639                           VOQFC_ENABLEf, 0);
    640             SOC_IF_ERROR_RETURN(WRITE_IE2E_CONTROLr(unit, port, regval));
    641         }
    642 
    643         /* set CONGESTION_STATE_BYTES to 1 because we're only expecting 1
    644          * byte per interface */
    645         for (index = 0 ; index < SOC_REG_NUMELS(unit, CONGESTION_STATE_BYTESr)
    646                 ; index++) {
    647             soc_reg_field_set(unit, CONGESTION_STATE_BYTESr, &regval,
    648                     DATAf, 1);
    649             SOC_IF_ERROR_RETURN(WRITE_CONGESTION_STATE_BYTESr(unit,
    650                         index, regval));
    651         }
    652     } else if(e2ecc_enable == 2){ 
    653 
    654         field_val = (config->dest_mac[0] << 8) |    /* MAC-DA[47:40] */
    655                     (config->dest_mac[1]);          /* MAC-DA[39:32] */
    656 
    657         SOC_IF_ERROR_RETURN(READ_COE_VLAN_PAUSE_MACDA_MSr(unit, &regval));
    658         soc_reg_field_set(unit, COE_VLAN_PAUSE_MACDA_MSr, &regval, DAf, field_val);
    659         SOC_IF_ERROR_RETURN(WRITE_COE_VLAN_PAUSE_MACDA_MSr(unit, regval));
    660 
    661         field_val = (config->dest_mac[2] << 24) |   /* MAC-DA[31:24] */
    662                     (config->dest_mac[3] << 16) |   /* MAC-DA[23:16] */
    663                     (config->dest_mac[4] << 8) |    /* MAC-DA[15:8] */ 
    664                     (config->dest_mac[5]);          /* MAC-DA[7:0] */  
    665 
    666         SOC_IF_ERROR_RETURN(READ_COE_VLAN_PAUSE_MACDA_LSr(unit, &regval));
    667         soc_reg_field_set(unit, COE_VLAN_PAUSE_MACDA_LSr, &regval, DAf, field_val);
    668         SOC_IF_ERROR_RETURN(WRITE_COE_VLAN_PAUSE_MACDA_LSr(unit, regval));
    669         SOC_IF_ERROR_RETURN(READ_COE_VLAN_PAUSE_IDr(unit, &regval));
    670         soc_reg_field_set(unit, COE_VLAN_PAUSE_IDr, &regval,
    671                           LENGTH_TYPEf, config->ethertype);
    672         soc_reg_field_set(unit, COE_VLAN_PAUSE_IDr, &regval,
    673                           OPCODEf, config->opcode);
    674         SOC_IF_ERROR_RETURN(WRITE_COE_VLAN_PAUSE_IDr(unit, regval));
    675 
    676         SOC_IF_ERROR_RETURN
    677             (soc_reg_field32_modify(unit, INTFI_CFGr, REG_PORT_ANY,
    678                                     FC_WIDTHf, 2));
    679     }
    680 
    681     return BCM_E_NONE;
    682 }
    683 
    684 #else /* BCM_TRIDENT2_SUPPORT */
    685 int _td2_port_not_empty;
    686 #endif  /* BCM_TRIDENT2_SUPPORT */