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

oob.c (32920B)


      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  * OOB Flow Control and OOB Stats
      8  * Purpose: API to set different OOB Flow Control and OOB Stats registers.
      9  */
     10 #ifdef BCM_TOMAHAWK3_SUPPORT
     11 #include <sal/core/libc.h>
     12 
     13 #include <shared/bsl.h>
     14 #include <soc/defs.h>
     15 
     16 #include <soc/drv.h>
     17 #include <soc/mem.h>
     18 #include <soc/debug.h>
     19 #include <soc/tomahawk.h>
     20 
     21 #include <bcm/error.h>
     22 #include <bcm/oob.h>
     23 
     24 #include <bcm_int/esw/mbcm.h>
     25 #include <bcm_int/esw/tomahawk.h>
     26 #include <bcm_int/esw/oob.h>
     27 #include <bcm_int/esw/tomahawk3.h>
     28 #include <bcm_int/tomahawk3_dispatch.h>
     29 #include <bcm_int/esw/stat.h>
     30 
     31 #define _BCM_TH3_PORT_EN0_WIDTH 64
     32 #define _BCM_TH3_PORT_EN1_WIDTH 64
     33 #define _BCM_TH3_OOB_FC_EGR_PROFILE_MAX 4
     34 #define _BCM_TH3_PORT_EN2_BEGIN 128
     35 #define _BCM_TH3_OOB_PORT_MAX 155
     36 #define _BCM_TH3_OOB_PORT_INVALID_HW 0xff
     37 #define _BCM_TH3_OOB_PORT_VALID(port) \
     38                ((port) >= 0 && (port) < _BCM_TH3_OOB_PORT_MAX)
     39 
     40 #define _BCM_LPORT_IS_SPARE(port) ((58 == port) || (78 == port) || \
     41                                   (98 == port) || (138 == port) || (158 == port))
     42 
     43 
     44 /*
     45  * Function:
     46  *      _bcm_th3_oob_fc_tx_config_egr_mode_get
     47  * Purpose:
     48  *      Get OOB FC Tx egress congestion reporting mode
     49  * Parameters:
     50  *      unit - (IN) StrataSwitch unit number.
     51  *      config - (OUT) OOB FC Tx configuration
     52  * Returns:
     53  *      BCM_E_XXX
     54  */
     55 STATIC int
     56 _bcm_th3_oob_fc_egr_mode_get(int unit,
     57                                   int *mode)
     58 {
     59     uint32 rval;
     60 
     61     BCM_IF_ERROR_RETURN
     62         (soc_reg32_get(unit, MMU_INTFO_CONFIG0r,
     63                        REG_PORT_ANY, 0, &rval));
     64 
     65     *mode = soc_reg_field_get(unit, MMU_INTFO_CONFIG0r,
     66                                              rval, ENG_PORT_WIDTHf);
     67 
     68     return BCM_E_NONE;
     69 }
     70 
     71 STATIC
     72 int _bcm_th3_oob_port_set_hw(
     73     int unit,
     74     int port,
     75     int oob_port)
     76 {
     77     int mmu_chip_port, max_index;
     78     soc_mem_t mem;
     79     soc_field_t field = OOB_PORT_NUMf;
     80     mmu_intfo_mmu_port_to_oob_port_mapping_thdi_entry_t ingress_entry;
     81     mmu_intfo_mmu_port_to_oob_port_mapping_thdo0_entry_t egress_entry;
     82 
     83     mem = MMU_INTFO_MMU_PORT_TO_OOB_PORT_MAPPING_THDIm;
     84     max_index = soc_mem_index_max(unit, mem);
     85     mmu_chip_port = SOC_TH3_MMU_CHIP_PORT(unit, port);
     86 
     87     if(mmu_chip_port < 0 || mmu_chip_port > max_index) {
     88         return BCM_E_INTERNAL;
     89     }
     90     BCM_IF_ERROR_RETURN
     91         (soc_mem_read(unit, mem, MEM_BLOCK_ANY, mmu_chip_port, &ingress_entry));
     92     soc_mem_field32_set(unit, mem, &ingress_entry, field, oob_port);
     93     BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL,
     94                                           mmu_chip_port, &ingress_entry));
     95 
     96     mem = MMU_INTFO_MMU_PORT_TO_OOB_PORT_MAPPING_THDO0m;
     97     BCM_IF_ERROR_RETURN
     98         (soc_mem_read(unit, mem, MEM_BLOCK_ANY, mmu_chip_port, &egress_entry));
     99     soc_mem_field32_set(unit, mem, &egress_entry, field, oob_port);
    100     BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL,
    101                                           mmu_chip_port, &egress_entry));
    102 
    103     return BCM_E_NONE;
    104 }
    105 
    106 STATIC int _bcm_th3_oob_port_get_hw(
    107     int unit,
    108     int port,
    109     int *oob_port)
    110 {
    111     int mmu_chip_port, max_index;
    112     soc_mem_t mem;
    113     soc_field_t field = OOB_PORT_NUMf;
    114     mmu_intfo_mmu_port_to_oob_port_mapping_thdi_entry_t ingress_entry;
    115 
    116     if(!SOC_PORT_VALID(unit, port) || oob_port == NULL) {
    117         return BCM_E_PARAM;
    118     }
    119     mem = MMU_INTFO_MMU_PORT_TO_OOB_PORT_MAPPING_THDIm;
    120     max_index = soc_mem_index_max(unit, mem);
    121     mmu_chip_port = SOC_TH3_MMU_CHIP_PORT(unit, port);
    122 
    123     if(mmu_chip_port < 0 || mmu_chip_port > max_index) {
    124         return BCM_E_INTERNAL;
    125     }
    126     BCM_IF_ERROR_RETURN
    127         (soc_mem_read(unit, mem, MEM_BLOCK_ANY, mmu_chip_port, &ingress_entry));
    128     *oob_port = soc_mem_field32_get(unit, mem, &ingress_entry, field);
    129 
    130     return BCM_E_NONE;
    131 }
    132 
    133 int
    134 bcm_tomahawk3_oob_fc_tx_port_mapping_get(
    135     int unit,
    136     int max_count,
    137     int *port_array,
    138     int *oob_port_array,
    139     int *count)
    140 {
    141     int i;
    142     int num;
    143     if (port_array == NULL || oob_port_array == NULL ||
    144         count == NULL) {
    145         return BCM_E_PARAM;
    146     }
    147     *count = 0;
    148     num = (max_count > _TH3_DEV_PORTS_PER_DEV) ?
    149                 _TH3_DEV_PORTS_PER_DEV : max_count;
    150     for(i = 0; i < num; i++) {
    151         if(_BCM_LPORT_IS_SPARE(port_array[i])) {
    152             oob_port_array[i] = -1;
    153             continue;
    154         }
    155         BCM_IF_ERROR_RETURN(
    156                 _bcm_th3_oob_port_get_hw(unit, port_array[i],
    157                                                         &oob_port_array[i]));
    158         if(_BCM_TH3_OOB_PORT_INVALID_HW == oob_port_array[i]) {
    159             oob_port_array[i] = -1;
    160         }
    161     }
    162     *count = i;
    163     return BCM_E_NONE;
    164 }
    165 
    166 
    167 int
    168 bcm_tomahawk3_oob_fc_tx_port_mapping_set(
    169     int unit,
    170     int count,
    171     int *port_array,
    172     int *oob_port_array)
    173 {
    174     int i, port, oob_port_used[_BCM_TH3_OOB_PORT_MAX] = { 0 };
    175     int *lport_allocated = NULL;
    176 
    177     if (port_array == NULL || oob_port_array == NULL
    178         || count == 0) {
    179         return BCM_E_PARAM;
    180     }
    181     lport_allocated = sal_alloc(_TH3_DEV_PORTS_PER_DEV * sizeof(int),
    182                                         "logical port to oob mapping");
    183     if (lport_allocated == NULL) {
    184         return BCM_E_MEMORY;
    185     }
    186     for (i = 0; i < _TH3_DEV_PORTS_PER_DEV; i++) {
    187         lport_allocated[i] = -1;
    188     }
    189     /* valid input before writing to HW*/
    190     for (i = 0; i < count; i++) {
    191         if(!SOC_PORT_VALID(unit, port_array[i])
    192             || !_BCM_TH3_OOB_PORT_VALID(oob_port_array[i])) {
    193             return BCM_E_PARAM;
    194         }
    195         /* if more than one port mapped to the same oob port,
    196          * or one port is mapped to different oob ports
    197          * input is invalid
    198         */
    199         if (oob_port_used[oob_port_array[i]] ||
    200                   lport_allocated[port_array[i]] != -1) {
    201             return BCM_E_PARAM;
    202         }
    203         oob_port_used[oob_port_array[i]] = 1;
    204         lport_allocated[port_array[i]] = oob_port_array[i];
    205     }
    206     /* populate the entire table */
    207     PBMP_ALL_ITER(unit, port) {
    208         if(_BCM_LPORT_IS_SPARE(port)) {
    209             /* spare port is not mapped to any oob port */
    210             continue;
    211         }
    212         if (lport_allocated[port] != -1) {
    213             BCM_IF_ERROR_RETURN(
    214                 _bcm_th3_oob_port_set_hw(unit, port, lport_allocated[port]));
    215         } else {
    216             BCM_IF_ERROR_RETURN(
    217                 _bcm_th3_oob_port_set_hw(unit, port,
    218                                     _BCM_TH3_OOB_PORT_INVALID_HW));
    219 
    220         }
    221 
    222     }
    223     sal_free(lport_allocated);
    224     return BCM_E_NONE;
    225 }
    226 
    227 int
    228 bcm_tomahawk3_oob_fc_tx_queue_profile_get(
    229     int unit,
    230     int profile_id,
    231     int max_count,
    232     bcm_oob_fc_tx_queue_config_t *config,
    233     int *count)
    234 {
    235     int i;
    236     soc_reg_t reg;
    237     uint64 rval64;
    238     soc_reg_t profile_regs[] = {
    239                                 MMU_INTFO_OOBFC_ENG_Q_MAP0r,
    240                                 MMU_INTFO_OOBFC_ENG_Q_MAP1r,
    241                                 MMU_INTFO_OOBFC_ENG_Q_MAP2r,
    242                                 MMU_INTFO_OOBFC_ENG_Q_MAP3r
    243                                };
    244     soc_field_t offset_fields[] = {
    245                          MMUQ0_TO_OOB_BIT_OFFSETf, MMUQ1_TO_OOB_BIT_OFFSETf,
    246                          MMUQ2_TO_OOB_BIT_OFFSETf, MMUQ3_TO_OOB_BIT_OFFSETf,
    247                          MMUQ4_TO_OOB_BIT_OFFSETf, MMUQ5_TO_OOB_BIT_OFFSETf,
    248                          MMUQ6_TO_OOB_BIT_OFFSETf, MMUQ7_TO_OOB_BIT_OFFSETf,
    249                          MMUQ8_TO_OOB_BIT_OFFSETf, MMUQ9_TO_OOB_BIT_OFFSETf,
    250                          MMUQ10_TO_OOB_BIT_OFFSETf, MMUQ11_TO_OOB_BIT_OFFSETf
    251                        };
    252     soc_field_t en_fields[] = {
    253                          MMUQ0_TO_OOB_ENf, MMUQ1_TO_OOB_ENf,
    254                          MMUQ2_TO_OOB_ENf, MMUQ3_TO_OOB_ENf,
    255                          MMUQ4_TO_OOB_ENf, MMUQ5_TO_OOB_ENf,
    256                          MMUQ6_TO_OOB_ENf, MMUQ7_TO_OOB_ENf,
    257                          MMUQ8_TO_OOB_ENf, MMUQ9_TO_OOB_ENf,
    258                          MMUQ10_TO_OOB_ENf, MMUQ11_TO_OOB_ENf
    259                        };
    260 
    261     if(config == NULL || profile_id < 0 ||
    262                profile_id >= _BCM_TH3_OOB_FC_EGR_PROFILE_MAX) {
    263         return BCM_E_PARAM;
    264     }
    265     reg = profile_regs[profile_id];
    266     COMPILER_64_ZERO(rval64);
    267     BCM_IF_ERROR_RETURN(
    268        soc_reg64_get(unit, reg, REG_PORT_ANY, 0, &rval64));
    269     for(i = 0; i < max_count && i < SOC_TH3_NUM_GP_QUEUES; i++) {
    270         config[i].cosq = i;
    271         config[i].queue_enable =
    272                         soc_reg64_field32_get(unit, reg, rval64, en_fields[i]);
    273         config[i].queue_offset =
    274                         soc_reg64_field32_get(unit, reg, rval64, offset_fields[i]);
    275     }
    276     *count = i;
    277     return BCM_E_NONE;
    278 }
    279 
    280 int
    281 bcm_tomahawk3_oob_fc_tx_queue_profile_set(
    282     int unit,
    283     int profile_id,
    284     int count,
    285     bcm_oob_fc_tx_queue_config_t *config)
    286 {
    287 #define _BCM_TH3_OOB_FC_EGR_MODE0_WIDTH 8
    288 #define _BCM_TH3_OOB_FC_EGR_MODE1_WIDTH 16
    289    int i, mode, num_bit;
    290    uint64 rval64;
    291    soc_reg_t reg;
    292    bcm_oob_fc_tx_queue_config_t entire_profile[SOC_TH3_NUM_GP_QUEUES];
    293    int offset_ref[_BCM_TH3_OOB_FC_EGR_MODE1_WIDTH] = {0};
    294    int ret_count = 0;
    295    soc_reg_t profile_regs[] = {
    296                                 MMU_INTFO_OOBFC_ENG_Q_MAP0r,
    297                                 MMU_INTFO_OOBFC_ENG_Q_MAP1r,
    298                                 MMU_INTFO_OOBFC_ENG_Q_MAP2r,
    299                                 MMU_INTFO_OOBFC_ENG_Q_MAP3r
    300                                };
    301    soc_field_t offset_fields[] = {
    302                          MMUQ0_TO_OOB_BIT_OFFSETf, MMUQ1_TO_OOB_BIT_OFFSETf,
    303                          MMUQ2_TO_OOB_BIT_OFFSETf, MMUQ3_TO_OOB_BIT_OFFSETf,
    304                          MMUQ4_TO_OOB_BIT_OFFSETf, MMUQ5_TO_OOB_BIT_OFFSETf,
    305                          MMUQ6_TO_OOB_BIT_OFFSETf, MMUQ7_TO_OOB_BIT_OFFSETf,
    306                          MMUQ8_TO_OOB_BIT_OFFSETf, MMUQ9_TO_OOB_BIT_OFFSETf,
    307                          MMUQ10_TO_OOB_BIT_OFFSETf, MMUQ11_TO_OOB_BIT_OFFSETf
    308                        };
    309    soc_field_t en_fields[] = {
    310                          MMUQ0_TO_OOB_ENf, MMUQ1_TO_OOB_ENf,
    311                          MMUQ2_TO_OOB_ENf, MMUQ3_TO_OOB_ENf,
    312                          MMUQ4_TO_OOB_ENf, MMUQ5_TO_OOB_ENf,
    313                          MMUQ6_TO_OOB_ENf, MMUQ7_TO_OOB_ENf,
    314                          MMUQ8_TO_OOB_ENf, MMUQ9_TO_OOB_ENf,
    315                          MMUQ10_TO_OOB_ENf, MMUQ11_TO_OOB_ENf
    316                        };
    317    if(config == NULL || count <=0 || count > SOC_TH3_NUM_GP_QUEUES ||
    318         profile_id < 0 || profile_id >= _BCM_TH3_OOB_FC_EGR_PROFILE_MAX) {
    319         return BCM_E_PARAM;
    320    }
    321    num_bit = _BCM_TH3_OOB_FC_EGR_MODE0_WIDTH;
    322    BCM_IF_ERROR_RETURN(_bcm_th3_oob_fc_egr_mode_get(unit, &mode));
    323    if(mode == 0) {
    324         num_bit = _BCM_TH3_OOB_FC_EGR_MODE0_WIDTH;
    325    } else if (mode == 1) {
    326         /* Limit to max cos. Bits [15:12] are unused or driven to 0 */
    327         num_bit = SOC_TH3_COS_MAX;
    328    }
    329    reg = profile_regs[profile_id];
    330    COMPILER_64_ZERO(rval64);
    331    BCM_IF_ERROR_RETURN(
    332        soc_reg64_get(unit, reg, REG_PORT_ANY, 0, &rval64));
    333    /* get old profile */
    334    BCM_IF_ERROR_RETURN(
    335         bcm_tomahawk3_oob_fc_tx_queue_profile_get(unit, profile_id,
    336                 SOC_TH3_NUM_GP_QUEUES, entire_profile, &ret_count));
    337    /* overwrite existing profile with new entry */
    338    for (i = 0; i < count; i++) {
    339         int mmu_q_id;
    340         if (config[i].queue_offset >= num_bit) {
    341             return BCM_E_PARAM;
    342         }
    343         if (config[i].queue_enable != 0 && config[i].queue_enable != 1) {
    344             return BCM_E_PARAM;
    345         }
    346         if ((config[i].cosq < 0) || (config[i].cosq >= SOC_TH3_NUM_GP_QUEUES))  {
    347             return BCM_E_PARAM;
    348         }
    349         mmu_q_id = config[i].cosq;
    350         sal_memcpy(&entire_profile[mmu_q_id], &config[i],
    351                         sizeof(bcm_oob_fc_tx_queue_config_t));
    352    }
    353    /* write profile to HW */
    354    for (i = 0; i < SOC_TH3_NUM_GP_QUEUES; i++) {
    355         if (entire_profile[i].queue_enable) {
    356             offset_ref[entire_profile[i].queue_offset]++;
    357             if (offset_ref[entire_profile[i].queue_offset] > 2) {
    358                 /* at most two queues can be mapped to the same bit offset */
    359                 return BCM_E_PARAM;
    360             }
    361         }
    362         soc_reg64_field32_set(unit, reg, &rval64, offset_fields[i],
    363                                     entire_profile[i].queue_offset);
    364         soc_reg64_field32_set(unit, reg, &rval64, en_fields[i],
    365                                     entire_profile[i].queue_enable);
    366    }
    367    BCM_IF_ERROR_RETURN(
    368        soc_reg64_set(unit, reg, REG_PORT_ANY, 0, rval64));
    369 
    370 #undef _BCM_TH3_OOB_FC_EGR_MODE0_WIDTH
    371 #undef _BCM_TH3_OOB_FC_EGR_MODE1_WIDTH
    372 
    373    return BCM_E_NONE;
    374 }
    375 
    376 /*
    377  * Function:
    378  *      _bcm_th3_oob_fc_tx_port_ing_egr_set
    379  * Purpose:
    380  *      Set OOB FC Tx Port reporting configuration.
    381  * Parameters:
    382  *      unit - (IN) StrataSwitch unit number.
    383  *      port - (IN) Local port
    384  *      status - (IN) Status of Congestion State reporting
    385  *      dir - (IN) Direction 0 = Ingreess, 1 = Egress,
    386  *                           2 = Internal congestion reporting.
    387  * Returns:
    388  *      BCM_E_XXX
    389  */
    390 static int
    391 _bcm_th3_oob_fc_tx_port_ing_egr_set(int unit, bcm_port_t port,
    392                                     int status, int dir)
    393 {
    394     uint32 rval = 0;
    395     uint64 rval64;
    396     int oob_port = -1;
    397     static const soc_field_t field[3] = {ING_PORT_ENf,
    398                                          ENG_PORT_ENf, CONGST_ST_ENf};
    399     static const soc_reg_t reg[3][3] = {
    400         {MMU_INTFO_OOBFC_ING_PORT_EN0_64r, MMU_INTFO_OOBFC_ING_PORT_EN1_64r,
    401          MMU_INTFO_OOBFC_ING_PORT_EN2r},
    402         {MMU_INTFO_OOBFC_ENG_PORT_EN0_64r, MMU_INTFO_OOBFC_ENG_PORT_EN1_64r,
    403          MMU_INTFO_OOBFC_ENG_PORT_EN2r},
    404         {MMU_INTFO_OOBFC_CONGST_ST_EN0_64r, MMU_INTFO_OOBFC_CONGST_ST_EN1_64r,
    405          MMU_INTFO_OOBFC_CONGST_ST_EN2r}};
    406 
    407     if ((status != 1) && (status != 0)) {
    408         /* 0: disable
    409          * 1: enable
    410         */
    411         return BCM_E_PARAM;
    412     }
    413 
    414     if (dir > 2) {
    415         return BCM_E_PARAM;
    416     }
    417 
    418     COMPILER_64_ZERO(rval64);
    419     BCM_IF_ERROR_RETURN(
    420         _bcm_th3_oob_port_get_hw(unit, port, &oob_port));
    421     if(_BCM_TH3_OOB_PORT_INVALID_HW == oob_port) {
    422         return BCM_E_PORT;
    423     }
    424 
    425     if ((oob_port >= 0) && (oob_port < _BCM_TH3_PORT_EN0_WIDTH)) {
    426         /* For OOB port 0-63 */
    427 
    428         BCM_IF_ERROR_RETURN
    429             (soc_reg64_get(unit, reg[dir][0], REG_PORT_ANY, 0, &rval64));
    430         if (((status == 1) && (!COMPILER_64_BITTEST(rval64, oob_port))) ||
    431             ((status == 0) && (COMPILER_64_BITTEST(rval64, oob_port)))) {
    432             if (status == 1) {
    433                 COMPILER_64_BITSET(rval64, oob_port);
    434             } else {
    435                 COMPILER_64_BITCLR(rval64, oob_port);
    436             }
    437             soc_reg64_field_set(unit, reg[dir][0], &rval64,
    438                                 field[dir], rval64);
    439             BCM_IF_ERROR_RETURN
    440                 (soc_reg64_set(unit, reg[dir][0], REG_PORT_ANY, 0, rval64));
    441         }
    442     } else if ((oob_port >= _BCM_TH3_PORT_EN0_WIDTH) &&
    443                 (oob_port < _BCM_TH3_PORT_EN2_BEGIN)) {
    444         /* For OOB port 64-127 */
    445 
    446         BCM_IF_ERROR_RETURN
    447             (soc_reg64_get(unit, reg[dir][1], REG_PORT_ANY, 0, &rval64));
    448         if (((status == 1) && (!COMPILER_64_BITTEST(rval64, (oob_port % _BCM_TH3_PORT_EN0_WIDTH)))) ||
    449             ((status == 0) && (COMPILER_64_BITTEST(rval64, (oob_port % _BCM_TH3_PORT_EN0_WIDTH))))) {
    450             if (status == 1) {
    451                 COMPILER_64_BITSET(rval64, (oob_port % _BCM_TH3_PORT_EN0_WIDTH));
    452             } else {
    453                 COMPILER_64_BITCLR(rval64, (oob_port % _BCM_TH3_PORT_EN0_WIDTH));
    454             }
    455             soc_reg64_field_set(unit, reg[dir][1], &rval64,
    456                                 field[dir], rval64);
    457             BCM_IF_ERROR_RETURN
    458                 (soc_reg64_set(unit, reg[dir][1], REG_PORT_ANY, 0, rval64));
    459         }
    460     } else if ((oob_port >= _BCM_TH3_PORT_EN2_BEGIN)
    461                             && (oob_port < _BCM_TH3_OOB_PORT_MAX)) {
    462         /* For oob port 128-154 */
    463 
    464         BCM_IF_ERROR_RETURN
    465             (soc_reg32_get(unit, reg[dir][2], REG_PORT_ANY, 0, &rval));
    466         if (((status == 1) && (!(rval & (0x1 << (oob_port % _BCM_TH3_PORT_EN2_BEGIN))))) ||
    467             ((status == 0) && ((rval & (0x1 << (oob_port % _BCM_TH3_PORT_EN2_BEGIN)))))) {
    468             if (status == 1) {
    469                 rval |= 0x1 << (oob_port % _BCM_TH3_PORT_EN2_BEGIN);
    470             } else {
    471                 rval &= ~(0x1 << (oob_port % _BCM_TH3_PORT_EN2_BEGIN));
    472             }
    473             soc_reg_field_set(unit, reg[dir][2], &rval, field[dir], rval);
    474 
    475             BCM_IF_ERROR_RETURN
    476                 (soc_reg32_set(unit, reg[dir][2], REG_PORT_ANY, 0, rval));
    477         }
    478     } else {
    479         return BCM_E_PARAM;
    480     }
    481 
    482     return BCM_E_NONE;
    483 }
    484 
    485 static int
    486 _bcm_th3_oob_fc_tx_congst_set(int unit, bcm_port_t port) {
    487     int ing_status = 0, egr_status = 0;
    488 
    489     BCM_IF_ERROR_RETURN(
    490         bcm_th3_oob_fc_tx_port_control_get(unit, port, &ing_status, 0));
    491     BCM_IF_ERROR_RETURN(
    492         bcm_th3_oob_fc_tx_port_control_get(unit, port, &egr_status, 1));
    493 
    494     /* turn off congestion reporting from MMU to OOB
    495      * only when ingress and egress reporting are both turned off
    496     */
    497     if (!ing_status && !egr_status) {
    498         BCM_IF_ERROR_RETURN(
    499             _bcm_th3_oob_fc_tx_port_ing_egr_set(unit, port, 0, 2));
    500     } else {
    501         BCM_IF_ERROR_RETURN(
    502             _bcm_th3_oob_fc_tx_port_ing_egr_set(unit, port, 1, 2));
    503     }
    504 
    505     return BCM_E_NONE;
    506 }
    507 
    508 /*
    509  * Function:
    510  *      bcm_th3_oob_fc_tx_port_control_set
    511  * Purpose:
    512  *      Set OOB FC Tx Port configuration.
    513  * Parameters:
    514  *      unit - (IN) StrataSwitch unit number.
    515  *      port - (IN) Local port
    516  *      status - (IN) Status of Congestion State reporting
    517  *      dir - (IN) Direction 0 = Ingreess, 1 = Egress
    518  * Returns:
    519  *      BCM_E_XXX
    520  */
    521 int
    522 bcm_th3_oob_fc_tx_port_control_set(int unit, bcm_port_t port,
    523                               int status, int dir)
    524 {
    525     if ((status != 1) && (status != 0)) {
    526         /* 0: disable
    527          * 1: enable
    528         */
    529         return BCM_E_PARAM;
    530     }
    531     if (dir > 1) {
    532         return BCM_E_PARAM;
    533     }
    534     BCM_IF_ERROR_RETURN(
    535         _bcm_th3_oob_fc_tx_port_ing_egr_set(unit, port, status, dir));
    536     BCM_IF_ERROR_RETURN(
    537         _bcm_th3_oob_fc_tx_congst_set(unit, port));
    538     return BCM_E_NONE;
    539 }
    540 
    541 /*
    542  * Function:
    543  *      bcm_th3_oob_fc_tx_port_control_get
    544  * Purpose:
    545  *      Get OOB FC Tx side Port configuration.
    546  * Parameters:
    547  *      unit - (IN) StrataSwitch unit number.
    548  *      port - (IN) Logical port
    549  *      status - (OUT) Status of Congestion State reporting
    550  *      dir - (IN) Direction 0 = Ingreess, 1 = Egress
    551  * Returns:
    552  *      BCM_E_XXX
    553  */
    554 int
    555 bcm_th3_oob_fc_tx_port_control_get(int unit, bcm_port_t port,
    556                                  int *status, int dir)
    557 {
    558     uint32 rval = 0;
    559     uint64 rval64;
    560     int oob_port = -1;
    561     static const soc_reg_t reg[2][3] = {
    562         {MMU_INTFO_OOBFC_ING_PORT_EN0_64r, MMU_INTFO_OOBFC_ING_PORT_EN1_64r,
    563             MMU_INTFO_OOBFC_ING_PORT_EN2r},
    564         {MMU_INTFO_OOBFC_ENG_PORT_EN0_64r, MMU_INTFO_OOBFC_ENG_PORT_EN1_64r,
    565             MMU_INTFO_OOBFC_ENG_PORT_EN2r}};
    566 
    567     if (dir > 1) {
    568         return BCM_E_PARAM;
    569     }
    570     BCM_IF_ERROR_RETURN(
    571         _bcm_th3_oob_port_get_hw(unit, port, &oob_port));
    572     if(_BCM_TH3_OOB_PORT_INVALID_HW == oob_port) {
    573         return BCM_E_NOT_FOUND;
    574     }
    575     COMPILER_64_ZERO(rval64);
    576 
    577     if ((oob_port >= 0) && (oob_port < _BCM_TH3_PORT_EN0_WIDTH)) {
    578         /* For logical port 0-63 */
    579         BCM_IF_ERROR_RETURN
    580             (soc_reg64_get(unit, reg[dir][0], REG_PORT_ANY, 0, &rval64));
    581         if (COMPILER_64_BITTEST(rval64, oob_port)) {
    582             *status = 0x1;
    583         } else {
    584             *status = 0x0;
    585         }
    586     } else if ((oob_port >= _BCM_TH3_PORT_EN0_WIDTH) &&
    587                     (oob_port < _BCM_TH3_PORT_EN2_BEGIN)) {
    588         /* For logical port 64-127 */
    589         BCM_IF_ERROR_RETURN
    590             (soc_reg64_get(unit, reg[dir][1], REG_PORT_ANY, 0, &rval64));
    591 
    592         if (COMPILER_64_BITTEST(rval64, (oob_port % _BCM_TH3_PORT_EN0_WIDTH))) {
    593             *status = 0x1;
    594         } else {
    595             *status = 0x0;
    596         }
    597     } else if ((oob_port >= _BCM_TH3_PORT_EN2_BEGIN) &&
    598                     (oob_port < _BCM_TH3_OOB_PORT_MAX)) {
    599         /* For logical port 128-154 */
    600         BCM_IF_ERROR_RETURN
    601             (soc_reg32_get(unit, reg[dir][2], REG_PORT_ANY, 0, &rval));
    602         if (rval & (0x1 << (oob_port % _BCM_TH3_PORT_EN2_BEGIN))) {
    603             *status = 0x1;
    604         } else {
    605             *status = 0x0;
    606         }
    607     } else {
    608         return BCM_E_PARAM;
    609     }
    610 
    611     return BCM_E_NONE;
    612 }
    613 
    614 int bcm_th3_oob_fx_egress_profile_id_set(int unit, bcm_port_t port,
    615                                            int profile_id)
    616 {
    617     soc_mem_t mem = MMU_INTFO_OOBFC_ENG_PORT_PSELm;
    618     int max_index, mmu_chip_port;
    619     soc_field_t field = ENG_PORT_PROFILE_SELf;
    620     mmu_intfo_oobfc_eng_port_psel_entry_t entry;
    621     if(!(SOC_PORT_VALID(unit, port)) || profile_id < 0 ||
    622            profile_id > _BCM_TH3_OOB_FC_EGR_PROFILE_MAX) {
    623         return BCM_E_PARAM;
    624     }
    625     max_index = soc_mem_index_max(unit, mem);
    626     mmu_chip_port = SOC_TH3_MMU_CHIP_PORT(unit, port);
    627 
    628     if(mmu_chip_port < 0 || mmu_chip_port > max_index) {
    629         return BCM_E_INTERNAL;
    630     }
    631     BCM_IF_ERROR_RETURN(
    632         soc_mem_read(unit, mem, MEM_BLOCK_ANY, mmu_chip_port, &entry));
    633     soc_mem_field32_set(unit, mem, &entry, field, profile_id);
    634     BCM_IF_ERROR_RETURN(
    635         soc_mem_write(unit, mem, MEM_BLOCK_ALL, mmu_chip_port, &entry));
    636 
    637     return BCM_E_NONE;
    638 }
    639 
    640 int bcm_th3_oob_fx_egress_profile_id_get(int unit, bcm_port_t port,
    641                                            int *profile_id)
    642 {
    643     soc_mem_t mem = MMU_INTFO_OOBFC_ENG_PORT_PSELm;
    644     soc_field_t field = ENG_PORT_PROFILE_SELf;
    645     int max_index, mmu_chip_port;
    646     mmu_intfo_oobfc_eng_port_psel_entry_t entry;
    647     if(!(SOC_PORT_VALID(unit, port)) || profile_id == NULL) {
    648         return BCM_E_PARAM;
    649     }
    650     max_index = soc_mem_index_max(unit, mem);
    651     mmu_chip_port = SOC_TH3_MMU_CHIP_PORT(unit, port);
    652 
    653     if(mmu_chip_port < 0 || mmu_chip_port > max_index) {
    654         return BCM_E_INTERNAL;
    655     }
    656     BCM_IF_ERROR_RETURN(
    657         soc_mem_read(unit, mem, MEM_BLOCK_ANY, mmu_chip_port, &entry));
    658     *profile_id = soc_mem_field32_get(unit, mem, &entry, field);
    659 
    660     return BCM_E_NONE;
    661 }
    662 
    663 /*
    664  * Function:
    665  *      _bcm_th3_oob_fc_tx_config_flags_set
    666  * Purpose:
    667  *      Set OOB FC Tx enable flags
    668  * Parameters:
    669  *      unit - (IN) StrataSwitch unit number.
    670  *      flags - (IN) OOB FC Tx flags
    671  * Returns:
    672  *      BCM_E_XXX
    673  */
    674 STATIC int
    675 _bcm_th3_oob_fc_tx_config_flags_set(int unit, uint32 flags)
    676 {
    677     uint32 rval = 0;
    678     uint32 fval = 0;
    679     soc_reg_t reg = INVALIDr;
    680 
    681     if (flags & BCM_OOB_FC_TX_FCN_EN) {
    682         return BCM_E_UNAVAIL;
    683     }
    684 
    685     reg = MMU_INTFO_OOBFC_CHANNEL_BASE_64r;
    686     BCM_IF_ERROR_RETURN
    687         (soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval));
    688     if (flags & BCM_OOB_FC_TX_ING_EN) {
    689         fval = 1;
    690     }
    691     soc_reg_field_set(unit, reg, &rval, ING_ENf, fval);
    692 
    693     fval = 0;
    694     if (flags & BCM_OOB_FC_TX_EGR_EN) {
    695         fval = 1;
    696     }
    697     soc_reg_field_set(unit, reg, &rval, ENG_ENf, fval);
    698 
    699     fval = 0;
    700     if (flags & BCM_OOB_FC_TX_POOL_EN) {
    701         fval = 1;
    702     }
    703     soc_reg_field_set(unit, reg, &rval, POOL_ENf, fval);
    704 
    705     BCM_IF_ERROR_RETURN
    706         (soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval));
    707 
    708     return BCM_E_NONE;
    709 }
    710 
    711 /*
    712  * Function:
    713  *      _bcm_th3_oob_fc_tx_config_flags_get
    714  * Purpose:
    715  *      Get OOB FC Tx enable status
    716  * Parameters:
    717  *      unit - (IN) StrataSwitch unit number.
    718  *      config - (OUT) OOB FC Tx configuration
    719  * Returns:
    720  *      BCM_E_XXX
    721  */
    722 STATIC int
    723 _bcm_th3_oob_fc_tx_config_flags_get(int unit,
    724                               bcm_oob_fc_tx_config_t *config)
    725 {
    726     uint32 fval;
    727     uint32 rval;
    728     soc_reg_t reg = MMU_INTFO_OOBFC_CHANNEL_BASE_64r;
    729     rval = 0;
    730 
    731     config->flags = 0x0;
    732 
    733 
    734     BCM_IF_ERROR_RETURN
    735         (soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval));
    736 
    737     fval = soc_reg_field_get(unit, reg, rval, ING_ENf);
    738     if (fval) {
    739         config->flags |= BCM_OOB_FC_TX_ING_EN;
    740     }
    741 
    742     fval = soc_reg_field_get(unit, reg, rval, ENG_ENf);
    743     if (fval) {
    744         config->flags |= BCM_OOB_FC_TX_EGR_EN;
    745     }
    746 
    747     fval = soc_reg_field_get(unit, reg, rval, POOL_ENf);
    748 
    749     if (fval) {
    750         config->flags |= BCM_OOB_FC_TX_POOL_EN;
    751     }
    752 
    753     return BCM_E_NONE;
    754 }
    755 
    756 /*
    757  * Function:
    758  *      _bcm_th3_oob_fc_tx_config_gcs_id_set
    759  * Purpose:
    760  *      Set OOB FC Tx global congestion reporting
    761  *      service pool id
    762  * Parameters:
    763  *      unit - (IN) StrataSwitch unit number.
    764  *      id - (IN) OOB FC Tx global congestion service pool id
    765  * Returns:
    766  *      BCM_E_XXX
    767  */
    768 STATIC int
    769 _bcm_th3_oob_fc_tx_config_gcs_id_set(int unit,
    770                              bcm_service_pool_id_t id)
    771 {
    772     uint32 rval;
    773     soc_reg_t reg = MMU_INTFO_OOBFC_GCSr;
    774     BCM_IF_ERROR_RETURN
    775         (soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval));
    776     soc_reg_field_set(unit, reg, &rval,
    777                       GCS_IDf, id);
    778     BCM_IF_ERROR_RETURN
    779         (soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval));
    780 
    781     return BCM_E_NONE;
    782 }
    783 
    784 /*
    785  * Function:
    786  *      _bcm_th3_oob_fc_tx_config_gcs_id_get
    787  * Purpose:
    788  *      Get OOB FC Tx global congestion reporting
    789  *      service pool id
    790  * Parameters:
    791  *      unit - (IN) StrataSwitch unit number.
    792  *      config - (OUT) OOB FC Tx configuration
    793  * Returns:
    794  *      BCM_E_XXX
    795  */
    796 STATIC int
    797 _bcm_th3_oob_fc_tx_config_gcs_id_get(int unit,
    798                               bcm_oob_fc_tx_config_t *config)
    799 {
    800     uint32 rval;
    801 
    802     BCM_IF_ERROR_RETURN
    803         (soc_reg32_get(unit, MMU_INTFO_OOBFC_GCSr, REG_PORT_ANY, 0, &rval));
    804 
    805     config->gcs_id = soc_reg_field_get(unit, MMU_INTFO_OOBFC_GCSr, rval,
    806                                        GCS_IDf);
    807 
    808     return BCM_E_NONE;
    809 }
    810 
    811 /*
    812  * Function:
    813  *      _bcm_th3_oob_fc_tx_config_ipg_set
    814  * Purpose:
    815  *      Set OOB FC Tx inter packet gap
    816  * Parameters:
    817  *      unit - (IN) StrataSwitch unit number.
    818  *      ipg - (IN) OOB FC Tx inter packet gap
    819  * Returns:
    820  *      BCM_E_XXX
    821  */
    822 STATIC int
    823 _bcm_th3_oob_fc_tx_config_ipg_set(int unit, uint8 ipg)
    824 {
    825     uint32 rval;
    826     soc_reg_t reg = MMU_INTFO_OOBFC_TX_IDLEr;
    827     BCM_IF_ERROR_RETURN
    828         (soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval));
    829     soc_reg_field_set(unit, reg, &rval, IDLE_GAPf, ipg);
    830     BCM_IF_ERROR_RETURN
    831         (soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval));
    832     return BCM_E_NONE;
    833 }
    834 
    835 /*
    836  * Function:
    837  *      _bcm_th_oob_fc_tx_config_ipg_get
    838  * Purpose:
    839  *      Get OOB FC Tx inter packet gap
    840  * Parameters:
    841  *      unit - (IN) StrataSwitch unit number.
    842  *      config - (OUT) OOB FC Tx configuration
    843  * Returns:
    844  *      BCM_E_XXX
    845  */
    846 STATIC int
    847 _bcm_th3_oob_fc_tx_config_ipg_get(int unit,
    848                             bcm_oob_fc_tx_config_t *config)
    849 {
    850     uint32 rval;
    851 
    852     BCM_IF_ERROR_RETURN
    853         (soc_reg32_get(unit, MMU_INTFO_OOBFC_TX_IDLEr, REG_PORT_ANY, 0, &rval));
    854 
    855     config->inter_pkt_gap = soc_reg_field_get(unit, MMU_INTFO_OOBFC_TX_IDLEr,
    856                                               rval, IDLE_GAPf);
    857 
    858     return BCM_E_NONE;
    859 }
    860 
    861 /*
    862  * Function:
    863  *      _bcm_th3_oob_fc_tx_config_egr_mode_set
    864  * Purpose:
    865  *      Set OOB FC Tx egress congestion reporting mode
    866  * Parameters:
    867  *      unit - (IN) StrataSwitch unit number.
    868  *      mode - (IN) OOB FC Tx egress congestion reporting mode
    869  * Returns:
    870  *      BCM_E_XXX
    871  */
    872 STATIC int
    873 _bcm_th3_oob_fc_tx_config_egr_mode_set(int unit,
    874                              int mode)
    875 {
    876     uint32 rval;
    877     soc_reg_t reg = MMU_INTFO_CONFIG0r;
    878 
    879     BCM_IF_ERROR_RETURN
    880         (soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval));
    881 
    882     soc_reg_field_set(unit, reg, &rval, ENG_PORT_WIDTHf, mode);
    883     BCM_IF_ERROR_RETURN
    884         (soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval));
    885 
    886     return BCM_E_NONE;
    887 }
    888 
    889 /*
    890  * Function:
    891  *      _bcm_th3_oob_fc_tx_config_egr_mode_get
    892  * Purpose:
    893  *      Get OOB FC Tx egress congestion reporting mode
    894  * Parameters:
    895  *      unit - (IN) StrataSwitch unit number.
    896  *      config - (OUT) OOB FC Tx configuration
    897  * Returns:
    898  *      BCM_E_XXX
    899  */
    900 STATIC int
    901 _bcm_th3_oob_fc_tx_config_egr_mode_get(int unit,
    902                                   bcm_oob_fc_tx_config_t *config)
    903 {
    904     int mode = 0;
    905     BCM_IF_ERROR_RETURN(_bcm_th3_oob_fc_egr_mode_get(unit, &mode));
    906 
    907     config->egr_mode = mode;
    908 
    909     return BCM_E_NONE;
    910 }
    911 
    912 /*
    913  * Function:
    914  *      bcm_th3_oob_fc_tx_config_set
    915  * Purpose:
    916  *      Set OOB FC Tx global configuration.
    917  * Parameters:
    918  *      unit - (IN) StrataSwitch unit number.
    919  *      config - (IN) OOB FC Tx global configuration
    920  * Returns:
    921  *      BCM_E_XXX
    922  */
    923 int
    924 bcm_th3_oob_fc_tx_config_set(int unit,
    925                             bcm_oob_fc_tx_config_t *config)
    926 {
    927     if (config == NULL) {
    928         return BCM_E_PARAM;
    929     }
    930 
    931     if ((config->gcs_id < 0) || (config->gcs_id >= _TH3_MMU_NUM_POOL)) {
    932         return BCM_E_PARAM;
    933     }
    934 
    935     /* egress mode - 0: 8bit, 1: 16bit */
    936     if ((config->egr_mode < 0) || (config->egr_mode > 1)) {
    937         return BCM_E_PARAM;
    938     }
    939 
    940     /* Enabling/Disabling OOBFC Tx Ingress, Egress and Service Pool */
    941     BCM_IF_ERROR_RETURN
    942         (_bcm_th3_oob_fc_tx_config_flags_set(unit, config->flags));
    943 
    944     /* Setting Inter packet Gap between two HCFC message */
    945     BCM_IF_ERROR_RETURN
    946         (_bcm_th3_oob_fc_tx_config_ipg_set(unit, config->inter_pkt_gap));
    947 
    948     /* Setting service pool id whose congestion state will be
    949        reported in every HCFC message */
    950     BCM_IF_ERROR_RETURN
    951         (_bcm_th3_oob_fc_tx_config_gcs_id_set(unit, config->gcs_id));
    952 
    953     /* Setting Egress mode for reporting OOBFC message. */
    954     
    955     BCM_IF_ERROR_RETURN
    956         (_bcm_th3_oob_fc_tx_config_egr_mode_set(unit, config->egr_mode));
    957 
    958     return BCM_E_NONE;
    959 }
    960 
    961 /*
    962  * Function:
    963  *      bcm_th3_oob_fc_tx_config_get
    964  * Purpose:
    965  *      Get OOB FC Tx global configuration.
    966  * Parameters:
    967  *      unit - (IN) StrataSwitch unit number.
    968  *      config - (OUT) OOB FC Tx global configuration
    969  * Returns:
    970  *      BCM_E_XXX
    971  */
    972 int
    973 bcm_th3_oob_fc_tx_config_get(int unit,
    974                             bcm_oob_fc_tx_config_t *config)
    975 {
    976     if (config == NULL) {
    977         return BCM_E_PARAM;
    978     }
    979 
    980     /* Get the congestion state reporting status of FCN,
    981        OOBFC Tx Ingress, Egress and Service Pool */
    982     BCM_IF_ERROR_RETURN
    983         (_bcm_th3_oob_fc_tx_config_flags_get(unit, config));
    984 
    985     /* Get the configured Inter Packet Gap between OOBFC Tx message.*/
    986     BCM_IF_ERROR_RETURN
    987         (_bcm_th3_oob_fc_tx_config_ipg_get(unit, config));
    988 
    989     /* Setting service pool id whose congestion state will be
    990        reported in every HCFC message */
    991     BCM_IF_ERROR_RETURN
    992         (_bcm_th3_oob_fc_tx_config_gcs_id_get(unit, config));
    993 
    994     /* Get the configured Egress mode of OOBFC Tx side */
    995     BCM_IF_ERROR_RETURN
    996         (_bcm_th3_oob_fc_tx_config_egr_mode_get(unit, config));
    997 
    998     return BCM_E_NONE;
    999 }
   1000 
   1001 int
   1002 bcm_th3_oob_port_mapping_init(int unit)
   1003 {
   1004     int port, oob_port = 0;
   1005     PBMP_ALL_ITER(unit, port) {
   1006         if (_BCM_LPORT_IS_SPARE(port)) {
   1007             BCM_IF_ERROR_RETURN(
   1008                 _bcm_th3_oob_port_set_hw(unit, port, _BCM_TH3_OOB_PORT_INVALID_HW));
   1009         }
   1010         BCM_IF_ERROR_RETURN(
   1011                 _bcm_th3_oob_port_set_hw(unit, port, oob_port));
   1012         oob_port++;
   1013     }
   1014     return BCM_E_NONE;
   1015 }
   1016 
   1017 /*
   1018 * Function:
   1019 *      bcm_th3_oob_fc_tx_info_get
   1020 * Purpose:
   1021 *      Get OOB FC Tx global information.
   1022 * Parameters:
   1023 *      unit - (IN) StrataSwitch unit number.
   1024 *      info - (OUT) OOB FC Tx global information
   1025 * Returns:
   1026 *      BCM_E_XXX
   1027 */
   1028 int
   1029 bcm_th3_oob_fc_tx_info_get(int unit, bcm_oob_fc_tx_info_t *info)
   1030 {
   1031     uint32 rval;
   1032     soc_reg_t reg = MMU_INTFO_OOBFC_CHANNEL_BASE_64r; /* 32 bit reg */
   1033     if (info == NULL) {
   1034         return BCM_E_PARAM;
   1035     }
   1036 
   1037     BCM_IF_ERROR_RETURN
   1038         (soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval));
   1039 
   1040     /* Get the Channel base value for HCFC messages containing
   1041        congestion state of different resources */
   1042     /* Ingress Ports */
   1043     info->ing_base =  (uint8)soc_reg_field_get(unit, reg,
   1044                                                    rval, ING_BASEf);
   1045 
   1046     /* Egress Unicast Queue not supported in TH3*/
   1047     info->ucast_base =  0;
   1048 
   1049     /* Egress Multicast Queue not supported in TH3*/
   1050     info->mcast_base =  0;
   1051 
   1052     /* Egress OOB Class */
   1053     info->cos_base =  (uint8)soc_reg_field_get(unit, reg,
   1054                                                     rval, ENG_BASEf);
   1055 
   1056     /* Ingress and Egress Service Pool Congestion */
   1057 
   1058     info->pool_base =  (uint8)soc_reg_field_get(unit, reg,
   1059                                                       rval, POOL_BASEf);
   1060 
   1061     return BCM_E_NONE;
   1062 }
   1063 
   1064 #endif
   1065 
   1066