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

switch.c (50586B)


      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:        switch.c
      8  * Purpose:
      9  */
     10 #if defined(BCM_TOMAHAWK3_SUPPORT)
     11 #include <soc/debug.h>
     12 #include <soc/drv.h>
     13 #include <soc/mem.h>
     14 #include <bcm/switch.h>
     15 #include <bcm/error.h>
     16 #include <bcm_int/esw/switch.h>
     17 #include <bcm_int/esw/port.h>
     18 #include <bcm_int/esw/flex_ctr.h>
     19 #if defined(BCM_INSTRUMENTATION_SUPPORT)
     20 #include <bcm_int/esw/instrumentation.h>
     21 #endif
     22 #if defined(INCLUDE_L3)
     23 #include <bcm/l3.h>
     24 #include <bcm_int/esw/firebolt.h>
     25 #include <bcm_int/tomahawk3_dispatch.h>
     26 #endif /* INCLUDE_L3 */
     27 
     28 #define AGM_LOCK(unit)      soc_mem_lock(unit, AGM_MONITOR_TABLEm)
     29 #define AGM_UNLOCK(unit)    soc_mem_unlock(unit, AGM_MONITOR_TABLEm)
     30 
     31 /* Helper routines for argument translation */
     32 static int
     33 _th3_bool_invert(int unit, int arg, int set)
     34 {
     35     /* Same for both set/get */
     36     return !arg;
     37 }
     38 
     39 bcm_switch_binding_t tomahawk3_bindings[] =
     40 {
     41     { bcmSwitchUnknownVlanToCpu, 0,
     42         CPU_CONTROL_0r, UVLAN_TOCPUf,
     43         NULL, 0 },
     44     { bcmSwitchArpReplyToCpu, 0,
     45         PROTOCOL_PKT_CONTROLr, ARP_REPLY_TO_CPUf,
     46         NULL, 0 },
     47     { bcmSwitchArpReplyDrop, 0,
     48         PROTOCOL_PKT_CONTROLr, ARP_REPLY_DROPf,
     49         NULL, 0 },
     50     { bcmSwitchArpRequestToCpu, 0,
     51         PROTOCOL_PKT_CONTROLr, ARP_REQUEST_TO_CPUf,
     52         NULL, 0 },
     53     { bcmSwitchArpRequestDrop, 0,
     54         PROTOCOL_PKT_CONTROLr, ARP_REQUEST_DROPf,
     55         NULL, 0 },
     56     { bcmSwitchNdPktToCpu, 0,
     57         PROTOCOL_PKT_CONTROLr, ND_PKT_TO_CPUf,
     58         NULL, 0 },
     59     { bcmSwitchNdPktDrop, 0,
     60         PROTOCOL_PKT_CONTROLr, ND_PKT_DROPf,
     61         NULL, 0 },
     62     { bcmSwitchDhcpPktToCpu, 0,
     63         PROTOCOL_PKT_CONTROLr, DHCP_PKT_TO_CPUf,
     64         NULL, 0 },
     65     { bcmSwitchDhcpPktDrop, 0,
     66         PROTOCOL_PKT_CONTROLr, DHCP_PKT_DROPf,
     67         NULL, 0 },
     68     { bcmSwitchL2StaticMoveToCpu, 0,
     69         CPU_CONTROL_1r, STATICMOVE_TOCPUf,
     70         NULL, 0 },
     71     { bcmSwitchL2NonStaticMoveToCpu, 0,
     72         CPU_CONTROL_1r, NONSTATICMOVE_TOCPUf,
     73         NULL, 0 },
     74     { bcmSwitchSharedVlanEnable, 0,
     75         ING_CONFIG_64r, SVL_ENABLEf,
     76         NULL, 0},
     77     { bcmSwitchSharedVlanMismatchToCpu, 0,
     78         CPU_CONTROL_0r, PVLAN_VID_MISMATCH_TOCPUf ,
     79         NULL, 0},
     80     { bcmSwitchSharedVlanL2McastEnable, 0,
     81         ING_CONFIG_64r, LOOKUP_L2MC_WITH_FID_IDf,
     82         NULL, 0},
     83     { bcmSwitchBpduInvalidVlanDrop, 0,
     84         EGR_CONFIG_1r, BPDU_INVALID_VLAN_DROPf,
     85         NULL, soc_feature_igmp_mld_support },
     86     { bcmSwitchMirrorInvalidVlanDrop, 0,
     87         EGR_CONFIG_1r, MIRROR_INVALID_VLAN_DROPf,
     88         NULL, soc_feature_igmp_mld_support },
     89     { bcmSwitchMcastFloodBlocking, 0,
     90         IGMP_MLD_PKT_CONTROLr, PFM_RULE_APPLYf,
     91         NULL, soc_feature_igmp_mld_support },
     92     { bcmSwitchMldUcastEnable,  0,
     93         ING_CONFIG_64r, MLD_PKTS_UNICAST_IGNOREf,
     94         _th3_bool_invert, soc_feature_igmp_mld_support },
     95     { bcmSwitchMldDirectAttachedOnly,   0,
     96         ING_CONFIG_64r, MLD_CHECKS_ENABLEf,
     97         NULL, soc_feature_igmp_mld_support },
     98     { bcmSwitchIgmpReservedMcastEnable,    0,
     99         ING_CONFIG_64r, IPV4_RESERVED_MC_ADDR_IGMP_ENABLEf,
    100         NULL, soc_feature_igmp_mld_support },
    101     { bcmSwitchMldReservedMcastEnable,     0,
    102         ING_CONFIG_64r, IPV6_RESERVED_MC_ADDR_MLD_ENABLEf,
    103         NULL, soc_feature_igmp_mld_support },
    104     { bcmSwitchIgmpUcastEnable,            0,
    105         ING_CONFIG_64r, IGMP_PKTS_UNICAST_IGNOREf,
    106         _th3_bool_invert, soc_feature_igmp_mld_support },
    107     { bcmSwitchPortEgressBlockL2,          0,
    108         ING_CONFIG_64r, APPLY_EGR_MASK_ON_L2f,
    109         NULL, 0},
    110     { bcmSwitchIp4McastL2DestCheck,        0,
    111         ING_CONFIG_64r, IPV4_MC_MACDA_CHECK_ENABLEf,
    112         NULL, 0},
    113     { bcmSwitchIp6McastL2DestCheck,        0,
    114         ING_CONFIG_64r, IPV6_MC_MACDA_CHECK_ENABLEf,
    115         NULL, 0},
    116     { bcmSwitchUnknownIpmcAsMcast, 0,
    117         ING_MISC_CONFIG2r, IPMC_MISS_AS_L2MCf,
    118         NULL, 0 },
    119     { bcmSwitchIpmcSameVlanL3Route, 0,
    120         EGR_CONFIG_1r, IPMC_ROUTE_SAME_VLANf,
    121         NULL, 0},
    122     { bcmSwitchHashUseFlowSelMplsEcmp, 0,
    123         RTAG7_HASH_SELr, USE_FLOW_SEL_MPLS_ECMPf,
    124         NULL, 0},
    125     { bcmSwitchHashMPLSUseLabelStack, 0,
    126        RTAG7_HASH_CONTROL_2r, USE_MPLS_STACK_FOR_HASHINGf,
    127         NULL, 0},
    128     { bcmSwitchMplsPortIndependentLowerRange1, 0,
    129         GLOBAL_MPLS_RANGE_1_LOWERr, LABELf,
    130         NULL, 0},
    131     { bcmSwitchMplsPortIndependentUpperRange1, 0,
    132         GLOBAL_MPLS_RANGE_1_UPPERr, LABELf,
    133         NULL, 0},
    134     { bcmSwitchMplsPortIndependentLowerRange2, 0,
    135        GLOBAL_MPLS_RANGE_2_LOWERr, LABELf,
    136        NULL, 0},
    137     { bcmSwitchMplsPortIndependentUpperRange2, 0,
    138         GLOBAL_MPLS_RANGE_2_UPPERr, LABELf,
    139         NULL, 0},
    140     { bcmSwitchEcmpMacroFlowHashEnable, 0,
    141         RTAG7_HASH_SELr, USE_FLOW_SEL_ECMPf,
    142         NULL, 0},
    143     { bcmSwitchDosAttackV4FirstFrag, 0,
    144         DOS_CONTROLr, IPV4_FIRST_FRAG_CHECK_ENABLEf,
    145         NULL, 0 },
    146     { bcmSwitchDosAttackSipEqualDip, 0,
    147         DOS_CONTROLr, DROP_IF_SIP_EQUALS_DIPf,
    148         NULL, 0 },
    149     { bcmSwitchDosAttackMACSAEqualMACDA, 0,
    150         DOS_CONTROLr, MACSA_EQUALS_MACDA_DROPf,
    151         NULL, soc_feature_enhanced_dos_ctrl },
    152     { bcmSwitchDosAttackFlagZeroSeqZero, 0,
    153         DOS_CONTROLr, TCP_FLAGS_CTRL0_SEQ0_ENABLEf,
    154         NULL, 0 },
    155     { bcmSwitchDosAttackSynFrag, 0,
    156         DOS_CONTROLr, TCP_FLAGS_SYN_FRAG_ENABLEf,
    157         NULL, 0},
    158     { bcmSwitchDosAttackIcmpFragments, 0,
    159         DOS_CONTROL_2r, ICMP_FRAG_PKTS_ENABLEf,
    160         NULL, soc_feature_enhanced_dos_ctrl },
    161     { bcmSwitchDosAttackIcmpV4, 0,
    162         DOS_CONTROL_2r, ICMP_V4_PING_SIZE_ENABLEf,
    163         NULL, 0 },
    164     { bcmSwitchDosAttackIcmpV6, 0,
    165         DOS_CONTROL_2r, ICMP_V6_PING_SIZE_ENABLEf,
    166         NULL, 0 },
    167     { bcmSwitchDosAttackTcpOffset, 0,
    168         DOS_CONTROL_2r, TCP_HDR_OFFSET_EQ1_ENABLEf,
    169         NULL, soc_feature_enhanced_dos_ctrl },
    170     { bcmSwitchDosAttackUdpPortsEqual, 0,
    171         DOS_CONTROL_2r, UDP_SPORT_EQ_DPORT_ENABLEf,
    172         NULL, soc_feature_enhanced_dos_ctrl },
    173     { bcmSwitchDosAttackTcpPortsEqual, 0,
    174         DOS_CONTROL_2r, TCP_SPORT_EQ_DPORT_ENABLEf,
    175         NULL, soc_feature_enhanced_dos_ctrl },
    176     { bcmSwitchDosAttackTcpFlagsSF, 0,
    177         DOS_CONTROL_2r, TCP_FLAGS_SYN_FIN_ENABLEf,
    178         NULL, soc_feature_enhanced_dos_ctrl },
    179     { bcmSwitchDosAttackTcpFlagsFUP, 0,
    180         DOS_CONTROL_2r, TCP_FLAGS_FIN_URG_PSH_SEQ0_ENABLEf,
    181         NULL, soc_feature_enhanced_dos_ctrl },
    182     { bcmSwitchDosAttackTcpHdrPartial, 0,
    183         DOS_CONTROL_2r, TCP_HDR_PARTIAL_ENABLEf,
    184         NULL, soc_feature_enhanced_dos_ctrl },
    185     { bcmSwitchDosAttackV6MinFragEnable, 0,
    186         DOS_CONTROL_2r, IPV6_MIN_FRAG_SIZE_ENABLEf,
    187         NULL, soc_feature_enhanced_dos_ctrl },
    188     { bcmSwitchDosAttackIcmpPktOversize, 0,
    189         DOS_CONTROL_3r, BIG_ICMP_PKT_SIZEf,
    190         NULL, 0 },
    191     { bcmSwitchDosAttackIcmpV6PingSize, 0,
    192         DOS_CONTROL_3r, BIG_ICMPV6_PKT_SIZEf,
    193         NULL, soc_feature_big_icmpv6_ping_check },
    194     { bcmSwitchDosAttackMinTcpHdrSize, 0,
    195         DOS_CONTROL_3r, MIN_TCPHDR_SIZEf,
    196         NULL, 0 },
    197     { bcmSwitchDosAttackToCpu, 0,
    198         CPU_CONTROL_0r, DOSATTACK_TOCPUf,
    199         NULL, 0 },
    200     { bcmSwitchTunnelIp4IdShared, 0,
    201         EGR_TUNNEL_ID_MASKr, SHARED_FRAG_ID_ENABLEf,
    202         NULL, 0},
    203     { bcmSwitchPortEgressBlockL3,          0,
    204         ING_CONFIG_64r, APPLY_EGR_MASK_ON_L3f,
    205         NULL, 0},
    206     { bcmSwitchParityErrorToCpu, 0,
    207         CPU_CONTROL_0r, PARITY_ERR_TOCPUf,
    208         NULL, soc_feature_parity_err_tocpu },
    209     { bcmSwitchSourceMacZeroDrop, 0,
    210         CPU_CONTROL_0r, MACSA_ALL_ZERO_DROPf,
    211         NULL, 0},
    212     { bcmSwitchMplsSequenceErrToCpu, 0,
    213         ING_MISC_CONFIGr, MPLS_SEQ_NUM_FAIL_TOCPUf,
    214         NULL, 0},
    215     { bcmSwitchMplsLabelMissToCpu, 0,
    216         CPU_CONTROL_Mr, MPLS_LABEL_MISSf,
    217         NULL, 0},
    218     { bcmSwitchMplsTtlErrToCpu, 0,
    219         CPU_CONTROL_Mr, MPLS_TTL_CHECK_FAILf,
    220         NULL, 0},
    221     { bcmSwitchMplsInvalidL3PayloadToCpu, 0,
    222         CPU_CONTROL_Mr, MPLS_INVALID_PAYLOADf,
    223         NULL, 0},
    224     { bcmSwitchMplsInvalidActionToCpu, 0,
    225         CPU_CONTROL_Mr, MPLS_INVALID_ACTIONf,
    226         NULL, 0},
    227     { bcmSwitchMplsPortIndependentLowerRange1, 0,
    228         GLOBAL_MPLS_RANGE_1_LOWERr, LABELf,
    229         NULL, 0},
    230     { bcmSwitchMplsPortIndependentUpperRange1, 0,
    231         GLOBAL_MPLS_RANGE_1_UPPERr, LABELf,
    232         NULL, 0},
    233     { bcmSwitchMplsPortIndependentLowerRange2, 0,
    234        GLOBAL_MPLS_RANGE_2_LOWERr, LABELf,
    235        NULL, 0},
    236     { bcmSwitchMplsPortIndependentUpperRange2, 0,
    237         GLOBAL_MPLS_RANGE_2_UPPERr, LABELf,
    238         NULL, 0},
    239     { bcmSwitchMplsPWControlWordToCpu, 0,
    240        ING_MISC_CONFIGr, PWACH_TOCPUf,
    241        NULL, soc_feature_mpls},
    242     { bcmSwitchCpuToCpuEnable, 0,
    243         ING_MISC_CONFIGr, DO_NOT_COPY_FROM_CPU_TO_CPUf,
    244         _th3_bool_invert, 0 },
    245     { bcmSwitchIpmcTtl1ToCpu, 0,
    246         CPU_CONTROL_1r, IPMC_TTL1_ERR_TOCPUf,
    247         NULL, 0 },
    248     { bcmSwitchL3UcastTtl1ToCpu, 0,
    249         CPU_CONTROL_1r, L3UC_TTL1_ERR_TOCPUf,
    250         NULL, 0 },
    251     { bcmSwitchDhcpLearn, 0,
    252         ING_MISC_CONFIG2r, DO_NOT_LEARN_DHCPf,
    253         NULL, 0 },
    254     { bcmSwitchTunnelUnknownIpmcDrop, 0,
    255         ING_MISC_CONFIG2r, UNKNOWN_TUNNEL_IPMC_DROPf,
    256         NULL, 0 },
    257     { bcmSwitchMcastUnknownErrToCpu, 0,
    258         CPU_CONTROL_1r, MC_INDEX_ERROR_TOCPUf,
    259         NULL,0},
    260     { bcmSwitchDosAttackV6MinFragSize, 0,
    261         IPV6_MIN_FRAG_SIZEr, PKT_LENGTHf,
    262         NULL, soc_feature_enhanced_dos_ctrl },
    263     { bcmSwitchEgressBlockUcast, 0,
    264         ING_MISC_CONFIGr, APPLY_EGR_MASK_ON_UC_ONLYf,
    265         NULL, soc_feature_egress_blk_ucast_override },
    266     { bcmSwitchHgHdrMcastFloodOverride, 0,
    267         EGR_CONFIG_1r, FORCE_STATIC_MH_PFMf,
    268         NULL, soc_feature_static_pfm },
    269     { bcmSwitchShaperAdjust, 0,
    270         EGR_SHAPING_CONTROLr, PACKET_IFG_BYTESf,
    271         NULL, soc_feature_meter_adjust },
    272     { bcmSwitchUnknownMcastToCpu, 0,
    273         CPU_CONTROL_1r, UMC_TOCPUf,
    274         NULL, 0 },
    275     { bcmSwitchUnknownUcastToCpu, 0,
    276         CPU_CONTROL_1r, UUCAST_TOCPUf,
    277         NULL, 0 },
    278     { bcmSwitchL3HeaderErrToCpu, 0,
    279         CPU_CONTROL_1r, V4L3ERR_TOCPUf,
    280         NULL, 0 },
    281     { bcmSwitchUnknownL3DestToCpu, 0,
    282         CPU_CONTROL_1r, V4L3DSTMISS_TOCPUf,
    283         NULL, 0 },
    284     { bcmSwitchIpmcPortMissToCpu, 0,
    285         CPU_CONTROL_1r, IPMCPORTMISS_TOCPUf,
    286         NULL, 0 },
    287     { bcmSwitchIpmcErrorToCpu, 0,
    288         CPU_CONTROL_1r, IPMCERR_TOCPUf,
    289         NULL, 0 },
    290     { bcmSwitchV6L3ErrToCpu, 0,
    291         CPU_CONTROL_1r, V6L3ERR_TOCPUf,
    292         NULL, 0 },
    293     { bcmSwitchV6L3DstMissToCpu, 0,
    294         CPU_CONTROL_1r, V6L3DSTMISS_TOCPUf,
    295         NULL, 0 },
    296     { bcmSwitchV4L3ErrToCpu, 0,
    297         CPU_CONTROL_1r, V4L3ERR_TOCPUf,
    298         NULL, 0 },
    299     { bcmSwitchV4L3DstMissToCpu, 0,
    300         CPU_CONTROL_1r, V4L3DSTMISS_TOCPUf,
    301         NULL, 0 },
    302     { bcmSwitchTunnelErrToCpu, 0,
    303         CPU_CONTROL_1r, TUNNEL_ERR_TOCPUf,
    304         NULL, 0 },
    305     { bcmSwitchMartianAddrToCpu, 0,
    306         CPU_CONTROL_1r, MARTIAN_ADDR_TOCPUf,
    307         NULL, 0 },
    308     { bcmSwitchL3UcTtlErrToCpu, 0,
    309         CPU_CONTROL_1r, L3UC_TTL_ERR_TOCPUf,
    310         NULL, 0 },
    311     { bcmSwitchL3SlowpathToCpu, 0,
    312         CPU_CONTROL_1r, L3_SLOWPATH_TOCPUf,
    313         NULL, 0 },
    314     { bcmSwitchIpmcTtlErrToCpu, 0,
    315         CPU_CONTROL_1r, IPMC_TTL_ERR_TOCPUf,
    316         NULL, 0 },
    317     { bcmSwitchSampleIngressRandomSeed, 0,
    318         SFLOW_ING_RAND_SEEDr, SEEDf,
    319         NULL, 0 },
    320     { bcmSwitchSampleEgressRandomSeed, 0,
    321         SFLOW_EGR_RAND_SEEDr, SEEDf,
    322         NULL, 0 },
    323     { bcmSwitchNonIpL3ErrToCpu, 0,
    324         CPU_CONTROL_1r, NIP_L3ERR_TOCPUf,
    325         NULL, soc_feature_nip_l3_err_tocpu },
    326     { bcmSwitchSourceRouteToCpu, 0,
    327         CPU_CONTROL_1r, SRCROUTE_TOCPUf,
    328         NULL, 0 },
    329     { bcmSwitchL3MtuFailToCpu, 0,
    330         CPU_CONTROL_1r, L3_MTU_FAIL_TOCPUf,
    331         NULL, soc_feature_l3mtu_fail_tocpu },
    332     { bcmSwitchV6L3LocalLinkDrop,0,
    333         ING_MISC_CONFIG2r, IPV6_SIP_LINK_LOCAL_DROPf,
    334         NULL, 0},
    335     { bcmSwitchMplsGalAlertLabelToCpu, 0,
    336         CPU_CONTROL_Mr, MPLS_GAL_EXPOSED_TO_CPUf,
    337         NULL, 0},
    338     { bcmSwitchMplsRalAlertLabelToCpu, 0,
    339         CPU_CONTROL_Mr, MPLS_RAL_EXPOSED_TO_CPUf,
    340         NULL, 0},
    341     { bcmSwitchMplsIllegalReservedLabelToCpu, 0,
    342         CPU_CONTROL_Mr, MPLS_ILLEGAL_RSVD_LABEL_TO_CPUf,
    343         NULL, 0},
    344     { bcmSwitchMplsUnknownAchTypeToCpu, 0,
    345         CPU_CONTROL_Mr, MPLS_UNKNOWN_ACH_TYPE_TO_CPUf,
    346         NULL, 0},
    347     { bcmSwitchMplsUnknownAchVersionToCpu, 0,
    348         CPU_CONTROL_Mr, MPLS_UNKNOWN_ACH_VERSION_TOCPUf,
    349         NULL, 0},
    350     { bcmSwitchTimesyncUnknownVersionToCpu, 0,
    351         CPU_CONTROL_Mr, UNKNOWN_1588_VERSION_TO_CPUf,
    352         NULL, 0},
    353     { bcmSwitchTimesyncIngressVersion, 0,
    354         ING_1588_PARSING_CONTROLr, VERSION_CONTROLf,
    355         NULL, 0},
    356     { bcmSwitchTimesyncEgressVersion, 0,
    357         EGR_1588_PARSING_CONTROLr, VERSION_CONTROLf,
    358         NULL, 0},
    359     { bcmSwitchL2GreTunnelMissToCpu, 0,
    360         CPU_CONTROL_Mr, L2GRE_SIP_LOOKUP_FAIL_COPY_TOCPUf,
    361         NULL, 0},
    362     { bcmSwitchVxlanTunnelMissToCpu, 0,
    363         CPU_CONTROL_Mr, VXLAN_SIP_LOOKUP_FAIL_COPY_TOCPUf,
    364         NULL, 0},
    365     { bcmSwitchHashL2GreKeyMask0, 0,
    366         RTAG7_HASH_CONTROL_L2GRE_MASK_Ar, L2GRE_TUNNEL_GRE_KEY_MASK_Af,
    367         NULL, soc_feature_l2gre},
    368     { bcmSwitchHashL2GreKeyMask1, 0,
    369         RTAG7_HASH_CONTROL_L2GRE_MASK_Br, L2GRE_TUNNEL_GRE_KEY_MASK_Bf,
    370         NULL, soc_feature_l2gre},
    371     { bcmSwitchHashSctpL4Port, 0,
    372         ING_SCTP_CONTROLr, PARSE_SCTPf,
    373         NULL, 0},
    374     { bcmSwitchHashUseL2GreTunnelGreKey0, 0,
    375         RTAG7_HASH_CONTROL_2r, L2GRE_TUNNEL_USE_GRE_KEY_Af,
    376         NULL, soc_feature_l2gre},
    377     { bcmSwitchHashUseL2GreTunnelGreKey1, 0,
    378         RTAG7_HASH_CONTROL_2r, L2GRE_TUNNEL_USE_GRE_KEY_Bf,
    379         NULL, soc_feature_l2gre},
    380     { bcmSwitchHashField0Ip6FlowLabel,0,
    381        RTAG7_HASH_CONTROL_2r, ENABLE_FLOW_LABEL_IPV6_Af,
    382         NULL, 0},
    383     { bcmSwitchHashField1Ip6FlowLabel,0,
    384        RTAG7_HASH_CONTROL_2r, ENABLE_FLOW_LABEL_IPV6_Bf,
    385         NULL, 0},
    386     { bcmSwitchMacroFlowHashUseMSB, 0,
    387        RTAG7_HASH_CONTROL_2r, MACRO_FLOW_HASH_BYTE_SELf,
    388         NULL, 0},
    389     { bcmSwitchHashField0OverlayCntagRpidEnable, 0,
    390        RTAG7_HASH_CONTROL_2r, ENABLE_BIN_12_OVERLAY_Af,
    391         NULL, 0},
    392     { bcmSwitchHashField1OverlayCntagRpidEnable, 0,
    393        RTAG7_HASH_CONTROL_2r, ENABLE_BIN_12_OVERLAY_Bf,
    394         NULL, 0},
    395     { bcmSwitchHashMPLSUseLabelStack, 0,
    396        RTAG7_HASH_CONTROL_2r, USE_MPLS_STACK_FOR_HASHINGf,
    397         NULL, 0},
    398     { bcmSwitchHashMPLSExcludeReservedLabel, 0,
    399        RTAG7_HASH_CONTROL_2r, EXCLUDE_ALL_RESERVED_LABELS_FROM_MPLS_HASHf,
    400         NULL, 0},
    401     { bcmSwitchHashUseFlowSelTrunkUc , 0,
    402        RTAG7_HASH_SELr, USE_FLOW_SEL_TRUNK_UCf,
    403         NULL, 0},
    404     { bcmSwitchHashUseFlowSelEcmp, 0,
    405        RTAG7_HASH_SELr, USE_FLOW_SEL_ECMPf,
    406         NULL, 0},
    407     { bcmSwitchV6L3SrcDstLocalLinkDropCancel, 0,
    408         ING_MISC_CONFIG2r, IPV6_SIP_AND_DIP_LINK_LOCAL_DO_NOT_DROPf,
    409         NULL, 0},
    410     { bcmSwitchHashUseFlowSelTrunkNonUnicast, 0,
    411        RTAG7_HASH_SELr, USE_FLOW_SEL_TRUNK_NONUCf,
    412         NULL, 0},
    413     { bcmSwitchHashUseFlowSelEntropy, 0,
    414        RTAG7_HASH_SELr, USE_FLOW_SEL_ENTROPY_LABELf,
    415         NULL, 0},
    416     { bcmSwitchFieldMultipathHashSeed, 0,
    417         FP_ECMP_HASH_CONTROLr, ECMP_HASH_SALTf,
    418         NULL, 0},
    419     { bcmSwitchRateLimitLinear,            0,
    420         MMU_MTRO_CONFIGr, ITU_MODE_SELf,
    421         _th3_bool_invert, 0}
    422 };
    423 
    424 
    425 int
    426 _bcm_th3_switch_control_port_binding_set(int unit,
    427                                 bcm_port_t port,
    428                                 bcm_switch_control_t type,
    429                                 int arg, int *found)
    430 {
    431     uint64 oval64, val64;
    432     int i;
    433     bcm_switch_binding_t *b;
    434     uint32 max;
    435     int fval, fwidth, prt, idx;
    436 
    437     *found = 0;
    438     /*
    439      * Tomahawk3_bindings can only handle switch type that requires
    440      * configuration in one field within one/multiple register. If the switch
    441      * type need to configure multiple fields, it need to be processed with
    442      * switch case method:
    443      */
    444     switch (type) {
    445         case bcmSwitchDosAttackIcmp:
    446             if (arg >= 0) {
    447                 SOC_IF_ERROR_RETURN(
    448                     soc_reg_get(unit, DOS_CONTROL_2r, port, 0, &val64));
    449                 oval64 = val64;
    450                 soc_reg64_field32_set(unit,
    451                     DOS_CONTROL_2r, &val64, ICMP_V4_PING_SIZE_ENABLEf, !!arg);
    452                 soc_reg64_field32_set(unit,
    453                     DOS_CONTROL_2r, &val64, ICMP_V6_PING_SIZE_ENABLEf, !!arg);
    454                 if (COMPILER_64_NE(val64, oval64)) {
    455                     SOC_IF_ERROR_RETURN(
    456                         soc_reg_set(unit, DOS_CONTROL_2r, port, 0, val64));
    457                 }
    458                 *found = 1;
    459                 return BCM_E_NONE;
    460             } else {
    461                 return BCM_E_PARAM;
    462             }
    463 
    464         case bcmSwitchMeterAdjust:
    465             if (soc_feature(unit, soc_feature_meter_adjust)) {
    466                 if (arg < 0) {
    467                     return BCM_E_PARAM;
    468                 }
    469 
    470                 /* EGR_COUNTER_CONTROLr */
    471                 SOC_IF_ERROR_RETURN(
    472                     soc_reg_get(unit, EGR_COUNTER_CONTROLr, port, 0, &val64));
    473                 oval64 = val64;
    474                 fwidth = soc_reg_field_length(
    475                                 unit, EGR_COUNTER_CONTROLr, PACKET_IFG_BYTESf);
    476                 max = (fwidth < 32) ? ((1 << fwidth)) - 1 : -1;
    477                 soc_reg64_field32_set(unit, EGR_COUNTER_CONTROLr, &val64,
    478                     PACKET_IFG_BYTESf, ((uint32)arg > max) ? max : (uint32)arg);
    479                 if (COMPILER_64_NE(val64, oval64)) {
    480                     SOC_IF_ERROR_RETURN(
    481                        soc_reg_set(unit, EGR_COUNTER_CONTROLr, port, 0, val64));
    482                 }
    483 
    484                 /* EGR_SHAPING_CONTROLr */
    485                 SOC_IF_ERROR_RETURN(
    486                     soc_reg_get(unit, EGR_SHAPING_CONTROLr, port, 0, &val64));
    487                 oval64 = val64;
    488                 fwidth = soc_reg_field_length(
    489                                 unit, EGR_SHAPING_CONTROLr, PACKET_IFG_BYTESf);
    490                 max = (fwidth < 32) ? ((1 << fwidth)) - 1 : -1;
    491                 soc_reg64_field32_set(unit, EGR_SHAPING_CONTROLr, &val64,
    492                     PACKET_IFG_BYTESf, ((uint32)arg > max) ? max : (uint32)arg);
    493                 if (COMPILER_64_NE(val64, oval64)) {
    494                     SOC_IF_ERROR_RETURN(
    495                        soc_reg_set(unit, EGR_SHAPING_CONTROLr, port, 0, val64));
    496                 }
    497 
    498                 /* IFP_METER_CONTROLr */
    499                 SOC_IF_ERROR_RETURN(
    500                     soc_reg_get(unit, IFP_METER_CONTROLr, port, 0, &val64));
    501                 oval64 = val64;
    502                 fwidth = soc_reg_field_length(
    503                                 unit, IFP_METER_CONTROLr, PACKET_IFG_BYTESf);
    504                 max = (fwidth < 32) ? ((1 << fwidth)) - 1 : -1;
    505                 soc_reg64_field32_set(unit, IFP_METER_CONTROLr, &val64,
    506                     PACKET_IFG_BYTESf, ((uint32)arg > max) ? max : (uint32)arg);
    507                 if (COMPILER_64_NE(val64, oval64)) {
    508                     SOC_IF_ERROR_RETURN(
    509                         soc_reg_set(unit, IFP_METER_CONTROLr, port, 0, val64));
    510                 }
    511                 *found = 1;
    512             }
    513             return BCM_E_NONE;
    514 
    515         case bcmSwitchRemoteLearnTrust:
    516             arg = _th3_bool_invert(unit, arg, 1);
    517             if (arg < 0) {
    518                 return BCM_E_PARAM;
    519             }
    520 
    521             /* ING_CONFIG_64r */
    522             SOC_IF_ERROR_RETURN(
    523                 soc_reg_get(unit, ING_CONFIG_64r, port, 0, &val64));
    524             oval64 = val64;
    525             soc_reg64_field32_set(
    526                 unit, ING_CONFIG_64r, &val64, IGNORE_HG_HDR_DONOT_LEARNf, arg);
    527             if (COMPILER_64_NE(val64, oval64)) {
    528                 SOC_IF_ERROR_RETURN(
    529                     soc_reg_set(unit, ING_CONFIG_64r, port, 0, val64));
    530             }
    531 
    532             /* EGR_CONFIG_1r */
    533             SOC_IF_ERROR_RETURN(
    534                 soc_reg_get(unit, EGR_CONFIG_1r, port, 0, &val64));
    535             oval64 = val64;
    536             soc_reg64_field32_set(
    537                 unit, EGR_CONFIG_1r, &val64, IGNORE_HG_HDR_DONOT_LEARNf, arg);
    538             if (COMPILER_64_NE(val64, oval64)) {
    539                 SOC_IF_ERROR_RETURN(
    540                     soc_reg_set(unit, EGR_CONFIG_1r, port, 0, val64));
    541             }
    542             *found = 1;
    543             return BCM_E_NONE;
    544 
    545         default:
    546             break;
    547     }
    548 
    549     for (i = 0; i < COUNTOF(tomahawk3_bindings); i++) {
    550         b = &tomahawk3_bindings[i];
    551         if (b->type == type) {
    552             /* We don't check the b->chip since the table is specific for TH3 */
    553             if (b->feature && !soc_feature(unit, b->feature)) {
    554                 continue;
    555             }
    556             if (!SOC_REG_FIELD_VALID(unit, b->reg, b->field)) {
    557                 continue;
    558             }
    559             if (b->xlate_arg) {
    560                 if ((fval = (b->xlate_arg)(unit, arg, 1)) < 0) {
    561                     return fval;
    562                 }
    563             } else {
    564                 fval = arg;
    565             }
    566             /* Negative values should be treated as errors */
    567             if (fval < 0) {
    568                 return BCM_E_PARAM;
    569             }
    570             if ((b->reg == PROTOCOL_PKT_CONTROLr) ||
    571                 (b->reg == IGMP_MLD_PKT_CONTROLr)) {
    572                 int index;
    573 
    574                 BCM_IF_ERROR_RETURN
    575                     (_bcm_esw_port_tab_get(unit, port,
    576                     PROTOCOL_PKT_INDEXf, &index));
    577                 prt = port;
    578                 idx = index;
    579             } else {
    580                 prt = port;
    581                 idx = 0;
    582             }
    583 
    584             fwidth = soc_reg_field_length(unit, b->reg, b->field);
    585             if (fwidth < 32) {
    586                 max = (1 << fwidth) - 1;
    587             } else {
    588                 max = -1;
    589             }
    590             SOC_IF_ERROR_RETURN(soc_reg_get(unit, b->reg, prt, idx, &val64));
    591             oval64 = val64;
    592             soc_reg64_field32_set(unit, b->reg, &val64, b->field,
    593                                 ((uint32)fval > max) ? max : (uint32)fval);
    594             if (COMPILER_64_NE(val64, oval64)) {
    595                 SOC_IF_ERROR_RETURN(soc_reg_set(unit, b->reg, prt, idx, val64));
    596             }
    597 
    598             *found = 1;
    599             break;
    600         }
    601     }
    602     return BCM_E_NONE;
    603 }
    604 
    605 
    606 int
    607 _bcm_th3_switch_control_port_binding_get(int unit,
    608                                 bcm_port_t port,
    609                                 bcm_switch_control_t type,
    610                                 int *arg, int *found)
    611 {
    612     uint64 val64;
    613     int i;
    614     bcm_switch_binding_t *b;
    615     int prt, idx;
    616 
    617     *found = 0;
    618 
    619     /*
    620      * Tomahawk3_bindings can only handle switch type that requires
    621      * configuration in one field within one/multiple register. If the switch
    622      * type need to configure multiple fields, it need to be processed with
    623      * switch case method:
    624      */
    625     switch (type) {
    626         case bcmSwitchDosAttackIcmp:
    627             SOC_IF_ERROR_RETURN(
    628                 soc_reg_get(unit, DOS_CONTROL_2r, port, 0, &val64));
    629             *arg = soc_reg64_field32_get(
    630                         unit, DOS_CONTROL_2r, val64, ICMP_V4_PING_SIZE_ENABLEf);
    631             *found = 1;
    632             return BCM_E_NONE;
    633 
    634         case bcmSwitchMeterAdjust:
    635             if (soc_feature(unit, soc_feature_meter_adjust)) {
    636                 SOC_IF_ERROR_RETURN(
    637                     soc_reg_get(unit, EGR_COUNTER_CONTROLr, port, 0, &val64));
    638                 *arg = soc_reg64_field32_get(
    639                         unit, EGR_COUNTER_CONTROLr, val64, PACKET_IFG_BYTESf);
    640                 *found = 1;
    641             }
    642             return BCM_E_NONE;
    643 
    644         case bcmSwitchRemoteLearnTrust:
    645             SOC_IF_ERROR_RETURN(
    646                 soc_reg_get(unit, ING_CONFIG_64r, port, 0, &val64));
    647             *arg = soc_reg64_field32_get(
    648                     unit, ING_CONFIG_64r, val64, IGNORE_HG_HDR_DONOT_LEARNf);
    649             *arg = _th3_bool_invert(unit, *arg, 0);
    650             *found = 1;
    651             return BCM_E_NONE;
    652 
    653         default:
    654             break;
    655     }
    656 
    657     for (i = 0; i < COUNTOF(tomahawk3_bindings); i++) {
    658         b = &tomahawk3_bindings[i];
    659         if (b->type == type) {
    660             if (b->feature && !soc_feature(unit, b->feature)) {
    661                 continue;
    662             }
    663 
    664             if (!SOC_REG_FIELD_VALID(unit, b->reg, b->field)) {
    665                 continue;
    666             }
    667             if ((b->reg == PROTOCOL_PKT_CONTROLr) ||
    668                 (b->reg == IGMP_MLD_PKT_CONTROLr)) {
    669                 int index;
    670 
    671                 BCM_IF_ERROR_RETURN
    672                     (_bcm_esw_port_tab_get(unit, port,
    673                     PROTOCOL_PKT_INDEXf, &index));
    674                 prt = port;
    675                 idx = index;
    676             } else {
    677                 prt = port;
    678                 idx = 0;
    679             }
    680             SOC_IF_ERROR_RETURN(soc_reg_get(unit, b->reg, prt, idx, &val64));
    681             *arg = soc_reg64_field32_get(unit, b->reg, val64, b->field);
    682 
    683             if (b->xlate_arg) {
    684                 *arg = (b->xlate_arg)(unit, *arg, 0);
    685             }
    686             *found = 1;
    687             break;
    688         }
    689     }
    690     return BCM_E_NONE;
    691 }
    692 
    693 /*
    694  * Function:
    695  *      bcm_tomahawk3_switch_pkt_trace_info_clear
    696  *
    697  * Purpose:
    698  *      This API is used to clear the existing SDK states for the visibility
    699  *      capture on the given port. It also clears the HW capture buffers for
    700  *      the pipe on which the given port resides.
    701  *      If the port parameter is passed in as -1 then SDK will reset the SW
    702  *      and HW capture states respective to all the pipes.
    703  *
    704  * Parameters:
    705  *      unit - (IN) Unit number.
    706  *      port - (IN) Logical port number
    707  *
    708  * Returns:
    709  *      BCM_E_xxx
    710  *
    711  * Notes:
    712  */
    713 int bcm_tomahawk3_switch_pkt_trace_info_clear(int unit, bcm_port_t port)
    714 {
    715     int rv = BCM_E_UNAVAIL;
    716 #ifdef BCM_INSTRUMENTATION_SUPPORT
    717     int pipe = -1;
    718 
    719     /* Extract the pipe information from the given valid port */
    720     if (-1 != port) {
    721         if (!SOC_PORT_VALID(unit, port) ||
    722             SOC_FAILURE(soc_port_pipe_get(unit, port, &pipe))) {
    723             return BCM_E_PORT;
    724         }
    725     }
    726 
    727     /* There are no SW states so just reset the HW states */
    728     rv = _bcm_th3_pkt_trace_hw_reset(unit, pipe);
    729 #endif
    730     return rv;
    731 }
    732 
    733 #if defined(INCLUDE_L3)
    734 /*
    735  * Function:
    736  *      bcmi_th3_switch_agm_l3_ecmp_get_entries_per_period
    737  *
    738  * Purpose:
    739  *      This helper function determines the number of counter entries needed
    740  *      or already allocated for an ECMP group. For ECMP groups which are
    741  *      configured with dynamic mode RESILIENT HASH, dynamic size of the grp
    742  *      is the number of counters. For all other ECMP groups it is the number
    743  *      of actual members in the group.
    744  *
    745  * Parameters:
    746  *      unit - (IN) Unit number.
    747  *      agm_id - (IN) AGM identifier
    748  *      ecmp_id - (IN) ECMP Group identifier
    749  *      num_entries - (OUT) Number of entries to be returned to caller
    750  *
    751  * Returns:
    752  *      BCM_E_xxx
    753  *
    754  * Notes:
    755  *      This helper routine does not take any locks. It is assumed the caller
    756  *      would lock approriate resources before calling it.
    757  */
    758 static int
    759 bcmi_th3_switch_agm_l3_ecmp_get_entries_per_period(int unit,
    760    bcm_switch_agm_id_t agm_id, bcm_if_t ecmp_id, uint32 *num_entries) {
    761 
    762     int rv = BCM_E_NONE;
    763     int mbr_cnt;
    764     agm_monitor_t   agm_mnt;
    765     bcm_l3_egress_ecmp_t ecmp_info;
    766 
    767     if (!num_entries) {
    768         return BCM_E_PARAM;
    769     }
    770 
    771     BCM_IF_ERROR_RETURN(_bcm_th_switch_agm_info(unit, agm_id, &agm_mnt));
    772     *num_entries = agm_mnt.attr.num_members;
    773     bcm_l3_egress_ecmp_t_init(&ecmp_info);
    774 
    775     ecmp_info.ecmp_intf = ecmp_id;
    776     rv = bcm_esw_l3_ecmp_get(unit, &ecmp_info, 0, NULL, &mbr_cnt);
    777     if (BCM_SUCCESS(rv)) {
    778         if (BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT == ecmp_info.dynamic_mode) {
    779             if (ecmp_info.dynamic_size > *num_entries) {
    780                 *num_entries = ecmp_info.dynamic_size;
    781             }
    782         }
    783     } else {
    784         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    785                 "L3 ECMP ID %d info get failed (%d)\n"), ecmp_id, rv));
    786     }
    787     return rv;
    788 }
    789 
    790 /*
    791  * Function:
    792  *      bcm_th3_switch_agm_l3_ecmp_stat_destroy
    793  *
    794  * Purpose:
    795  *      This function  detaches and de-allocates the flex stat counter
    796  *      associated with the AGM with the given AGM ID. Once flex stat APIs
    797  *      successfully complete the counter ID in the AGM is reset to 0.
    798  *
    799  * Parameters:
    800  *      unit - (IN) Unit number.
    801  *      agm_id - (IN) AGM identifier
    802  *
    803  * Returns:
    804  *      BCM_E_xxx
    805  *
    806  * Notes:
    807  *      This function takes AGM_LOCK, so the caller does not need to lock
    808  */
    809 int bcm_th3_switch_agm_l3_ecmp_stat_destroy(int unit,
    810                                             bcm_switch_agm_id_t agm_id) {
    811 
    812     int             rv = BCM_E_NONE;
    813     agm_monitor_t   agm_mnt;
    814 
    815     AGM_LOCK(unit);
    816     rv = _bcm_th_switch_agm_info(unit, agm_id, &agm_mnt);
    817 
    818     if (BCM_SUCCESS(rv)) {
    819         /* Detach the flex stat counter */
    820         rv = bcm_th_agm_stat_detach(unit, agm_mnt.attr.agm_id,
    821                     agm_mnt.agm_pool_id, (uint32)agm_mnt.counter_id);
    822 
    823         if (BCM_SUCCESS(rv)) {
    824             /* Destroy flex counter */
    825             rv = bcm_th_agm_stat_id_clear(unit, agm_mnt.counter_id);
    826 
    827             if (BCM_SUCCESS(rv)) {
    828                 /* Update software bookkeeping information */
    829                 _bcm_th_switch_agm_update_counter_id(unit, agm_id, 0);
    830             } else {
    831                 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    832                   "AGM %d destroy counter id failed, rv = %d.\n"), agm_id, rv));
    833             }
    834         } else {
    835             LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    836                 "AGM %d detach failed, rv = %d.\n"), agm_id, rv));
    837         }
    838     }
    839     AGM_UNLOCK(unit);
    840     return rv;
    841 }
    842 
    843 /*
    844  * Function:
    845  *      bcm_th3_switch_agm_l3_ecmp_stat_create
    846  *
    847  * Purpose:
    848  *      This function allocates and attaches a flex stat counter associated
    849  *      with an AGM with the given ID for given ECMP group ID. The number of
    850  *      counter indexes to be allocated is determined based on the ECMP group
    851  *      type. If the ECMP group was created with dynamic mode RESILIENT, the
    852  *      number of counter entries would be (dynamic_size * agm_periods), else
    853  *      it would be (ecmp_grp_member_count * agm_periods). Once flex stat APIs
    854  *      successfully complete, the counter ID in the AGM is set to Flex stat
    855  *      given counter ID.
    856  *
    857  * Parameters:
    858  *      unit - (IN) Unit number.
    859  *      agm_id - (IN) AGM identifier
    860  *      l3_ecmp_id - (IN) ECMP group identifier
    861  *
    862  * Returns:
    863  *      BCM_E_xxx
    864  *
    865  * Notes:
    866  *      This function takes AGM_LOCK, so the caller does not need to lock
    867  */
    868 int bcm_th3_switch_agm_l3_ecmp_stat_create(int unit,
    869         bcm_switch_agm_id_t agm_id, bcm_if_t l3_ecmp_id) {
    870 
    871     int             rv = BCM_E_NONE;
    872     uint32          counter_id = 0;
    873     uint32          stat_cnt_per_period = 0;
    874     agm_monitor_t   agm_mnt;
    875 
    876     AGM_LOCK(unit);
    877     rv = _bcm_th_switch_agm_info(unit, agm_id, &agm_mnt);
    878 
    879     if (BCM_SUCCESS(rv)) {
    880         /* Get number of counter entries to be created for one AGM period */
    881         rv = bcmi_th3_switch_agm_l3_ecmp_get_entries_per_period(
    882                         unit, agm_id, l3_ecmp_id, &stat_cnt_per_period);
    883 
    884         if (BCM_SUCCESS(rv)) {
    885             /* Allocate a flex stat counter ID */
    886             rv = bcm_th_agm_stat_id_get(unit,
    887                              agm_id,
    888                              agm_mnt.agm_pool_id,
    889                              stat_cnt_per_period*(agm_mnt.attr.period_num + 1),
    890                              &counter_id);
    891 
    892             if (BCM_SUCCESS(rv)) {
    893                 LOG_VERBOSE(BSL_LS_BCM_SWITCH,
    894                     (BSL_META_U(unit, "Allocated counter id %d for AGM %d.\n"),
    895                     counter_id, agm_id));
    896 
    897                 /* Attach the counter */
    898                 rv = bcm_th_agm_stat_attach(
    899                         unit, agm_id, agm_mnt.agm_pool_id, counter_id);
    900                 if (BCM_FAILURE(rv)) {
    901                     AGM_UNLOCK(unit);
    902                     return rv;
    903                 }
    904 
    905                 if (BCM_SUCCESS(rv)) {
    906                     LOG_VERBOSE(BSL_LS_BCM_SWITCH,
    907                         (BSL_META_U(unit, "Attached counter id %d to AGM %d\n"),
    908                         counter_id, agm_id));
    909 
    910                     /* Update software bookkeeping information */
    911                     _bcm_th_switch_agm_update_counter_id(
    912                                                     unit, agm_id, counter_id);
    913                 } else {
    914                     LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    915                         "Attach failed of counter %d for AGM %d failed\n"),
    916                         counter_id, agm_id));
    917                     bcm_th_agm_stat_id_clear(unit, counter_id);
    918                 }
    919             } else {
    920                 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    921                     "Allocation of counter with count %d for AGM %d failed\n"),
    922                     stat_cnt_per_period*(agm_mnt.attr.period_num + 1), agm_id));
    923             }
    924         }
    925     }
    926 
    927     AGM_UNLOCK(unit);
    928     return rv;
    929 }
    930 #endif /* INCLUDE_L3 */
    931 
    932 /*
    933  * Function:
    934  *      _bcmi_th3_agm_stat_retrieve
    935  *
    936  * Purpose:
    937  *      This helper function retrieves the packet stat count and byte stat count
    938  *      for the given flex stat counter index. At first pkt count is retrieved.
    939  *      Only if it is non zero byte count is retrieved else byte count is
    940  *      assumed to be zero.
    941  *
    942  * Parameters:
    943  *      unit - (IN) Unit number.
    944  *      agm_id - (IN) AGM identifier
    945  *      ctr_idx - (IN) Flex stat counter index
    946  *      ctr_val - (OUT) counter value to be sent back to caller
    947  *
    948  * Returns:
    949  *      BCM_E_xxx
    950  *
    951  * Notes:
    952  *      This helper routine does not take any locks. It is assumed the caller
    953  *      would lock approriate resources before calling it.
    954  */
    955 static int
    956 _bcmi_th3_agm_stat_retrieve(int unit,
    957                            bcm_switch_agm_id_t agm_id,
    958                            uint32 ctr_idx,
    959                            bcm_stat_value_t *ctr_val) {
    960 
    961     int                         rv = BCM_E_NONE;
    962     uint32                      num_table;
    963     bcm_stat_flex_table_info_t  tbl_info;
    964 
    965     if (!ctr_val) {
    966         return BCM_E_PARAM;
    967     }
    968 
    969     /* Initialize to 0 */
    970     sal_memset(ctr_val, 0, sizeof(bcm_stat_value_t));
    971 
    972     BCM_IF_ERROR_RETURN(
    973         bcm_th_agm_stat_get_table_info(unit, agm_id, &num_table, &tbl_info));
    974     if (bcmStatFlexDirectionIngress != tbl_info.direction) {
    975         return BCM_E_NONE;
    976     }
    977 
    978     /* Get Pkt count */
    979     rv = _bcm_esw_stat_counter_get(unit, TRUE,
    980                 tbl_info.index, tbl_info.table, 0,
    981                 0 /* packet flag*/, ctr_idx, ctr_val);
    982 
    983     if (BCM_FAILURE(rv)) {
    984         sal_memset(ctr_val, 0, sizeof(bcm_stat_value_t));
    985         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    986             "AGM %d collected pkt counter %d failed, rv = %d.\n"),
    987             agm_id, ctr_idx, rv));
    988     } else if (!COMPILER_64_IS_ZERO(ctr_val->packets64)) {
    989 
    990         /* Get byte count */
    991         rv = _bcm_esw_stat_counter_get(unit, TRUE,
    992                     tbl_info.index, tbl_info.table, 0,
    993                     1 /* byte flag */, ctr_idx, ctr_val);
    994 
    995         if (BCM_FAILURE(rv)) {
    996             sal_memset(ctr_val, 0, sizeof(bcm_stat_value_t));
    997             LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    998                 "AGM %d collected byte counter %d failed, rv = %d.\n"),
    999                 agm_id, ctr_idx, rv));
   1000         }
   1001     }
   1002 
   1003     return rv;
   1004 }
   1005 
   1006 /*
   1007  * Function:
   1008  *      _bcmi_th3_switch_agm_trunk_stat_get
   1009  *
   1010  * Purpose:
   1011  *      This internal function gets the AGM stats for Trunk.
   1012  *
   1013  * Parameters:
   1014  *      unit - (IN) Unit number.
   1015  *      agm_mnt - (IN) AGM monitor
   1016  *      member_arr - (IN) array to hold Trunk member gport IDs
   1017  *      nstat - (IN) size of the stat array passed in
   1018  *      stat_arr - (OUT) retrieved flex stat values
   1019  *
   1020  * Returns:
   1021  *      BCM_E_xxx
   1022  *
   1023  * Notes:
   1024  *      This function does not check validity of given parameters, as it is
   1025  *      meant to be called after doing such validations. Hence it also does
   1026  *      not takes appr. locks,  Caller need to take locks before calling it
   1027  */
   1028 static int
   1029 _bcmi_th3_switch_agm_trunk_stat_get(int unit,
   1030                             agm_monitor_t *agm_mnt,
   1031                             void *member_arr,
   1032                             int nstat,
   1033                             bcm_switch_agm_stat_t *stat_arr) {
   1034     int     i;
   1035     int     mbr_cnt;
   1036     bcm_trunk_member_t *mbr_arr = (bcm_trunk_member_t *)member_arr;
   1037     bcm_trunk_info_t tinfo;
   1038     bcm_stat_value_t ctr_val;
   1039 
   1040     LOG_VERBOSE(BSL_LS_BCM_SWITCH, (
   1041         BSL_META_U(unit, "AGM %d(Trunk) stat get: mbr cnt %d, period %d.\n"),
   1042         agm_mnt->attr.agm_id, agm_mnt->attr.num_members,
   1043         (nstat / agm_mnt->attr.num_members) + 1));
   1044 
   1045 
   1046     BCM_IF_ERROR_RETURN(
   1047         bcm_esw_trunk_get(unit, (bcm_trunk_t)agm_mnt->group_id,
   1048                 &tinfo, agm_mnt->attr.num_members, mbr_arr, &mbr_cnt));
   1049 
   1050     if (0 == mbr_cnt) {
   1051         return BCM_E_FAIL;
   1052     }
   1053 
   1054     /* Fill in the nstat array with available data */
   1055     for (i = 0; i < nstat ; i++) {
   1056         stat_arr[i].period = i / agm_mnt->attr.num_members;
   1057         stat_arr[i].intf_id = BCM_IF_INVALID;
   1058         stat_arr[i].gport_id = mbr_arr[i % mbr_cnt].gport;
   1059 
   1060         BCM_IF_ERROR_RETURN(
   1061           _bcmi_th3_agm_stat_retrieve(unit, agm_mnt->attr.agm_id, i, &ctr_val));
   1062 
   1063         stat_arr[i].packets = ctr_val.packets64;
   1064         stat_arr[i].bytes = ctr_val.bytes;
   1065     }
   1066 
   1067     return BCM_E_NONE;
   1068 }
   1069 
   1070 #if defined(INCLUDE_L3)
   1071 /*
   1072  * Function:
   1073  *      _bcmi_th3_switch_agm_l3_ecmp_stat_get
   1074  *
   1075  * Purpose:
   1076  *      This internal function gets the AGM stats for ECMP group.
   1077  *
   1078  * Parameters:
   1079  *      unit - (IN) Unit number.
   1080  *      agm_mnt - (IN) AGM monitor
   1081  *      member_arr - (IN) array to hold ECMP Egr obj intf IDs
   1082  *      nstat - (IN) size of the stat array passed in
   1083  *      stat_arr - (OUT) retrieved flex stat values
   1084  *
   1085  * Returns:
   1086  *      BCM_E_xxx
   1087  *
   1088  * Notes:
   1089  *      This function does not check validity of given parameters, as it is
   1090  *      meant to be called after doing such validations. Hence it also does
   1091  *      not takes appr. locks,  Caller need to take locks before calling it
   1092  */
   1093 static int
   1094 _bcmi_th3_switch_agm_l3_ecmp_stat_get(int unit,
   1095                             agm_monitor_t *agm_mnt,
   1096                             void *member_arr,
   1097                             int nstat,
   1098                             bcm_switch_agm_stat_t *stat_arr) {
   1099 
   1100     int     i, j;
   1101     int     stat_arr_idx;
   1102     int     num_periods = 0;
   1103     int     mbr, mbr_cnt = 0;
   1104     int     nhop_to_intf_offset = 0;
   1105     uint32  nhop_idx;
   1106     uint32  counter_idx;
   1107     uint32  ecmp_base_ptr = 0;
   1108     uint32  entries_per_period = agm_mnt->attr.num_members;
   1109     bcm_if_t    egr_obj_intf;
   1110     bcm_if_t    *mbr_arr = (bcm_if_t *)member_arr;
   1111     bcm_if_t    ecmp_intf = (bcm_if_t)agm_mnt->group_id;
   1112     soc_mem_t   ecmp_mem = INVALIDm;
   1113     ecmp_entry_t         ecmp_entry;
   1114     bcm_stat_value_t     counter_val;
   1115     ecmp_count_entry_t   ecmp_grp_entry;
   1116     bcm_l3_egress_ecmp_t ecmp_info;
   1117 
   1118 
   1119     /* Calculate number of periods based on given nstat parameter */
   1120     num_periods =
   1121         (nstat + agm_mnt->attr.num_members - 1) / agm_mnt->attr.num_members;
   1122 
   1123     LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1124         "AGM %d(ECMP) stat get: group member count %d, period %d.\n"),
   1125         agm_mnt->attr.agm_id, agm_mnt->attr.num_members, num_periods));
   1126 
   1127     /* Retrieve and validate the members of the ECMP group */
   1128     bcm_l3_egress_ecmp_t_init(&ecmp_info);
   1129     ecmp_info.ecmp_intf = ecmp_intf;
   1130     BCM_IF_ERROR_RETURN(
   1131         bcm_esw_l3_egress_ecmp_get(unit, &ecmp_info, 0, NULL, &mbr_cnt));
   1132     BCM_IF_ERROR_RETURN(bcm_esw_l3_egress_multipath_get(
   1133         unit, ecmp_intf, agm_mnt->attr.num_members, mbr_arr, &mbr_cnt));
   1134     if (0 == mbr_cnt) {
   1135         return BCM_E_FAIL;
   1136     }
   1137 
   1138     /* For RH ECMPs find out the base address for L3_ECMP memory and offset
   1139      * which will be used to covert nhop to corresponding egr obj interface ID.
   1140      * Also adjust the counter entries per AGM period values based on dyn size.
   1141      */
   1142     if (BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT == ecmp_info.dynamic_mode) {
   1143         if (ecmp_info.dynamic_size > agm_mnt->attr.num_members) {
   1144             entries_per_period = ecmp_info.dynamic_size;
   1145         }
   1146 
   1147         if (bcmSwitchAgmTypeL3EcmpOverlay == agm_mnt->attr.agm_type) {
   1148             ecmp_mem = ECMP_GROUP_HIERARCHICALm;
   1149             nhop_to_intf_offset = BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   1150         } else {
   1151             ecmp_mem = L3_ECMP_COUNTm;
   1152             nhop_to_intf_offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
   1153         }
   1154         SOC_IF_ERROR_RETURN(soc_mem_read(unit, ecmp_mem,
   1155             MEM_BLOCK_ANY, ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit),
   1156             &ecmp_grp_entry));
   1157         ecmp_base_ptr =
   1158             soc_mem_field32_get(unit, ecmp_mem, &ecmp_grp_entry, BASE_PTRf);
   1159     }
   1160 
   1161     /* Initialize the stat arr with known rese values */
   1162     for (i = 0; i < nstat ; i++) {
   1163         stat_arr[i].period = i / agm_mnt->attr.num_members;
   1164         COMPILER_64_ZERO(stat_arr[i].packets);
   1165         COMPILER_64_ZERO(stat_arr[i].bytes);
   1166         stat_arr[i].gport_id = BCM_GPORT_INVALID;
   1167         stat_arr[i].intf_id = mbr_arr[i % mbr_cnt];
   1168     }
   1169 
   1170     for (i = 0; i < num_periods; i++) {
   1171         for (j = 0; j < entries_per_period; j++) {
   1172             counter_idx = (i * entries_per_period) + j;
   1173 
   1174             /* Retrieve the stat counts */
   1175             BCM_IF_ERROR_RETURN(
   1176                 _bcmi_th3_agm_stat_retrieve(unit,
   1177                     agm_mnt->attr.agm_id, counter_idx, &counter_val));
   1178 
   1179             /* If there are no packets on this counter then skip to next ctr */
   1180             if (COMPILER_64_IS_ZERO(counter_val.packets64)) {
   1181                 continue;
   1182             }
   1183 
   1184             /* Calculate the index into arr where the stats are to be updated */
   1185             if (BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT == ecmp_info.dynamic_mode) {
   1186 
   1187                 /* For RH ECMPs, index into stat arr is derived indirectly.
   1188                  * First next hop index is retrieved from L3 ECMP memory which
   1189                  * is then used to deduce the egr object interface ID. This egr
   1190                  * intf is further searched into the member array. The offset of
   1191                  * member array where the intf is found is used directly to
   1192                  * derive the index into USer given stat array.
   1193                  */
   1194                 SOC_IF_ERROR_RETURN(READ_L3_ECMPm(
   1195                     unit, MEM_BLOCK_ANY, j + ecmp_base_ptr, &ecmp_entry));
   1196 
   1197                 nhop_idx =
   1198                     soc_L3_ECMPm_field32_get(
   1199                         unit, &ecmp_entry, NEXT_HOP_INDEXf);
   1200 
   1201                 egr_obj_intf = nhop_to_intf_offset + (bcm_if_t)nhop_idx;
   1202 
   1203                 for (mbr=0 ; mbr<mbr_cnt ; mbr++) {
   1204                     if (mbr_arr[mbr] == egr_obj_intf) {
   1205                         stat_arr_idx = mbr + (i * agm_mnt->attr.num_members);
   1206                         break;
   1207                     }
   1208                 }
   1209 
   1210                 if (mbr >= mbr_cnt) {
   1211                     LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1212                         "AGM %d ECMP egr obj %d not found.\n"),
   1213                         agm_mnt->attr.agm_id, egr_obj_intf));
   1214                     return BCM_E_FAIL;
   1215                 }
   1216             } else {
   1217                 /* For non RH ECMPs, derive the index into stat arr directly */
   1218                 stat_arr_idx = (i * agm_mnt->attr.num_members) + j;
   1219             }
   1220 
   1221             /* Update the stat arr if the index is within the max arr size */
   1222             if (stat_arr_idx < nstat) {
   1223                 COMPILER_64_ADD_64( stat_arr[stat_arr_idx].packets,
   1224                                     counter_val.packets64 );
   1225                 COMPILER_64_ADD_64( stat_arr[stat_arr_idx].bytes,
   1226                                     counter_val.bytes );
   1227             } else {
   1228                 /* If the calculated index is out of range then assert, however
   1229                  * for last AGM period there could be possibility that User did
   1230                  * not provide enough space to accomodate data for all members,
   1231                  * hence in this case only assert if calculated index is out of
   1232                  * range provided if the given array was of sufficient size.
   1233                  */
   1234                 if (i != (num_periods-1)) {
   1235                     assert(stat_arr_idx < nstat);
   1236                 } else if (stat_arr_idx >= ((i+1)*agm_mnt->attr.num_members)) {
   1237                     assert(stat_arr_idx < ((i+1)*agm_mnt->attr.num_members));
   1238                 }
   1239             }
   1240         }
   1241     }
   1242 
   1243     return BCM_E_NONE;
   1244 }
   1245 #endif /* INCLUDE_L3 */
   1246 
   1247 /*
   1248  * Function:
   1249  *      bcm_th3_switch_agm_stat_get
   1250  *
   1251  * Purpose:
   1252  *      This function initializes the given stat array with reset values. It
   1253  *      allocates an array to hold ECMP or Trunk member information based on
   1254  *      the AGM type. Then it calls appr. function based on AGM type to
   1255  *      retrieve the flex stats.
   1256  *
   1257  * Parameters:
   1258  *      unit - (IN) Unit number.
   1259  *      agm_id - (IN) AGM identifier
   1260  *      nstat - (IN) size of the stat array passed in
   1261  *      stat_arr - (OUT) retrieved flex stat values
   1262  *
   1263  * Returns:
   1264  *      BCM_E_xxx
   1265  *
   1266  * Notes:
   1267  *      This function checks validity of all the given parameters, as it is
   1268  *      meant to be called from API dispatch layer. It also takes appr. locks
   1269  *      so caller need not take locks.
   1270  */
   1271 int bcm_th3_switch_agm_stat_get(int unit,
   1272                            bcm_switch_agm_id_t agm_id,
   1273                            int nstat,
   1274                            bcm_switch_agm_stat_t *stat_arr) {
   1275 
   1276     int             elm_size = 0;
   1277     int             rv = BCM_E_UNAVAIL;
   1278     void            *mbr_arr = NULL;
   1279     agm_monitor_t   agm_mnt;
   1280     int (*func_p)(int, agm_monitor_t *, void *, int, bcm_switch_agm_stat_t *);
   1281 
   1282     /* Validate parameters */
   1283     if (!SOC_UNIT_VALID(unit)) {
   1284         return BCM_E_UNIT;
   1285     }
   1286     if (NULL == stat_arr || nstat <= 0) {
   1287         return BCM_E_PARAM;
   1288     }
   1289     BCM_IF_ERROR_RETURN(bcm_th_switch_agm_id_validate(unit, agm_id));
   1290 
   1291     func_p = NULL;
   1292     AGM_LOCK(unit);
   1293 
   1294     /* Get hold of AGM monitor info */
   1295     rv = _bcm_th_switch_agm_info(unit, agm_id, &agm_mnt);
   1296 
   1297     if (BCM_SUCCESS(rv)) {
   1298         /* Validate the nstat supported by the AGM. If the user has
   1299          * provided larger than needed buffer, return BCM_E_PARAM
   1300          */
   1301         if (nstat > ((agm_mnt.attr.period_num+1) * agm_mnt.attr.num_members)) {
   1302             AGM_UNLOCK(unit);
   1303             return BCM_E_PARAM;
   1304         }
   1305 
   1306         if ((bcmSwitchAgmTypeL3Ecmp == agm_mnt.attr.agm_type) ||
   1307             (bcmSwitchAgmTypeL3EcmpOverlay == agm_mnt.attr.agm_type)) {
   1308 #if defined(INCLUDE_L3)
   1309             if (soc_feature(unit, soc_feature_l3)) {
   1310                 elm_size = sizeof(bcm_if_t);
   1311                 func_p = _bcmi_th3_switch_agm_l3_ecmp_stat_get;
   1312             } else
   1313 #endif
   1314             {
   1315                 AGM_UNLOCK(unit);
   1316                 return BCM_E_UNAVAIL;
   1317             }
   1318         } else if (bcmSwitchAgmTypeTrunk == agm_mnt.attr.agm_type) {
   1319             elm_size = sizeof(bcm_trunk_member_t);
   1320             func_p = _bcmi_th3_switch_agm_trunk_stat_get;
   1321         } else {
   1322             AGM_UNLOCK(unit);
   1323             return BCM_E_UNAVAIL;
   1324         }
   1325 
   1326         /* Allocate member array */
   1327         mbr_arr = sal_alloc(elm_size * agm_mnt.attr.num_members, "mbr_arr");
   1328         if (mbr_arr) {
   1329             /* Call AGM type specific function to get the stats */
   1330             rv = func_p(unit, &agm_mnt, mbr_arr, nstat, stat_arr);
   1331 
   1332             /* Free the member array */
   1333             sal_free(mbr_arr);
   1334         } else {
   1335             rv = BCM_E_MEMORY;
   1336         }
   1337     }
   1338 
   1339     AGM_UNLOCK(unit);
   1340     return rv;
   1341 }
   1342 
   1343 /*
   1344  * Function:
   1345  *      bcm_th3_switch_agm_stat_clear
   1346  *
   1347  * Purpose:
   1348  *      This function calls appr. flex stat APIs to clear the counter value for
   1349  *      counter associated with the given AGM ID.
   1350  *
   1351  * Parameters:
   1352  *      unit - (IN) Unit number.
   1353  *      agm_id - (IN) AGM identifier
   1354  *
   1355  * Returns:
   1356  *      BCM_E_xxx
   1357  *
   1358  * Notes:
   1359  *      This function checks validity of all the given parameters, as it is
   1360  *      meant to be called from API dispatch layer. It also takes appr. locks
   1361  *      so caller need not take locks.
   1362  */
   1363 int bcm_th3_switch_agm_stat_clear(int unit,
   1364                            bcm_switch_agm_id_t agm_id) {
   1365 
   1366     int     i, j;
   1367     int     num_periods;
   1368     int     rv = BCM_E_NONE;
   1369     uint32  num_table;
   1370     uint32  entries_per_period;
   1371     agm_monitor_t agm_mnt;
   1372     bcm_stat_value_t counter_val;
   1373     bcm_stat_flex_table_info_t tbl_info;
   1374 
   1375     /* Validate parameters */
   1376     if (!SOC_UNIT_VALID(unit)) {
   1377         return BCM_E_UNIT;
   1378     }
   1379 
   1380     BCM_IF_ERROR_RETURN(bcm_th_switch_agm_id_validate(unit, agm_id));
   1381 
   1382     AGM_LOCK(unit);
   1383     rv = bcm_th_agm_stat_get_table_info(unit, agm_id, &num_table, &tbl_info);
   1384     if (BCM_FAILURE(rv) || bcmStatFlexDirectionIngress != tbl_info.direction) {
   1385         goto _exit_stat_cl;
   1386     }
   1387 
   1388     rv = _bcm_th_switch_agm_info(unit, agm_id, &agm_mnt);
   1389     if (BCM_FAILURE(rv)) {
   1390         goto _exit_stat_cl;
   1391     }
   1392 
   1393     num_periods = agm_mnt.attr.period_num + 1;
   1394     entries_per_period = agm_mnt.attr.num_members;
   1395 
   1396     if ((bcmSwitchAgmTypeL3Ecmp == agm_mnt.attr.agm_type) ||
   1397         (bcmSwitchAgmTypeL3EcmpOverlay == agm_mnt.attr.agm_type)) {
   1398 #if defined(INCLUDE_L3)
   1399         if (soc_feature(unit, soc_feature_l3)) {
   1400             rv = bcmi_th3_switch_agm_l3_ecmp_get_entries_per_period(unit,
   1401                     agm_id, (bcm_if_t)agm_mnt.group_id, &entries_per_period);
   1402         } else
   1403 #endif
   1404         {
   1405             rv = BCM_E_UNAVAIL;
   1406         }
   1407         if (BCM_FAILURE(rv)) {
   1408             goto _exit_stat_cl;
   1409         }
   1410     }
   1411 
   1412     sal_memset(&counter_val, 0, sizeof(bcm_stat_value_t));
   1413 
   1414     for (i = 0; i < num_periods; i++) {
   1415         for (j = 0; j < entries_per_period; j++) {
   1416 
   1417             /* Clear packet and byte count, both at once */
   1418             rv = _bcm_esw_stat_counter_set(
   1419                     unit, tbl_info.index, tbl_info.table,
   1420                         0, -1, ((i * entries_per_period) + j), &counter_val);
   1421             if (BCM_FAILURE(rv)) {
   1422                 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1423                     "AGM %d clear packet/byte counter %d failed, rv = %d.\n"),
   1424                     agm_id, ((i * entries_per_period) + j), rv));
   1425                 goto _exit_stat_cl;
   1426             }
   1427         }
   1428     }
   1429 
   1430 _exit_stat_cl:
   1431     AGM_UNLOCK(unit);
   1432     return rv;
   1433 }
   1434 #endif /* BCM_TOMAHAWK3_SUPPORT */