tsn_stat.c (97426B)
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 * Purpose: 8 * Manage chip specific functionality for TSN Statistics implementation on GH2. 9 */ 10 11 #include <sal/core/libc.h> 12 #include <soc/drv.h> 13 #include <bcm/error.h> 14 #include <bcm/types.h> 15 #include <bcm/tsn.h> 16 #include <bcm_int/esw/tsn_stat.h> 17 #include <bcm_int/esw/tsn.h> 18 #include <bcm_int/esw/tsn_taf.h> 19 #include <soc/profile_mem.h> 20 #include <shared/bsl.h> 21 #include <shared/shr_res_bitmap.h> 22 23 #if defined(BCM_GREYHOUND2_SUPPORT) && defined(BCM_TSN_SUPPORT) 24 /* TSN stat portcnt table contents for GH2 */ 25 STATIC const tsn_stat_portcnt_table_info_t portcnt_table[] = 26 { 27 {bcmTsnStatIngressSrTaggedPackets, 28 SR_PORT_COUNT_RX_TAGGEDm, COUNTf}, 29 {bcmTsnStatIngressNonLinkLocalPackets, 30 SR_PORT_COUNT_RXm, COUNTf}, 31 {bcmTsnStatIngressSrWrongLanPackets, 32 SR_PORT_COUNT_RX_WRONG_LANm, COUNTf}, 33 {bcmTsnStatIngressSrRxErrorPackets, 34 SR_PORT_COUNT_RX_ERRORm, COUNTf}, 35 {bcmTsnStatIngressSrTagErrorPackets, 36 SR_PORT_COUNT_RX_TAG_ERRORm, COUNTf}, 37 {bcmTsnStatIngressSrDuplicatePackets, 38 SR_PORT_COUNT_RX_DUPLICATESm, COUNTf}, 39 {bcmTsnStatIngressSrOutOfOrderSrPackets, 40 SR_PORT_COUNT_RX_OUTOFORDERm, COUNTf}, 41 {bcmTsnStatIngressSrOwnRxPackets, 42 SR_PORT_COUNT_OWN_RXm, COUNTf}, 43 {bcmTsnStatIngressSrUnexpectedPackets, 44 SR_PORT_COUNT_UNEXPECTED_FRAMEm, COUNTf}, 45 {bcmTsnStatIngressMtuErrorPackets, 46 SR_PORT_MTU_ERRORm, COUNTf}, 47 {bcmTsnStatIngressStuErrorPackets, 48 SR_PORT_STU_ERRORm, COUNTf}, 49 {bcmTsnStatIngressSrAcceptedSrPackets, 50 SR_PORT_COUNT_RX_PASSEDm, COUNTf}, 51 {bcmTsnStatIngressSrSaSrcFilteredPackets, 52 SR_PORT_PROXY_MAC_ERRORm, COUNTf}, 53 {bcmTsnStatEgressSrTaggedPackets, 54 SR_PORT_COUNT_TX_TAGGEDm, COUNTf}, 55 {bcmTsnStatEgressNonLinkLocalPackets, 56 SR_PORT_COUNT_TXm, COUNTf}, 57 {bcmTsnStatEgressMtuErrorPackets, 58 SR_PORT_TX_MTU_ERRORm, COUNTf}, 59 {bcmTsnStatEgressStuErrorPackets, 60 SR_PORT_TX_STU_ERRORm, COUNTf} 61 }; 62 63 #define GH2_TSN_STAT_PORTCNT_TABLE_SIZE (COUNTOF(portcnt_table)) 64 65 /* TSN stat flowcnt table contents for GH2 */ 66 STATIC const soc_mem_t flowcnt_group_mem[bcmTsnStatGroupTypeCount] = 67 {SR_ING_COUNTER_PROFILEm, 68 SR_EGR_COUNTER_PROFILEm}; 69 STATIC const uint32 flowcnt_group_num[bcmTsnStatGroupTypeCount] = {8, 8}; 70 STATIC const soc_mem_t flowcnt_flow_mem[bcmTsnStatGroupTypeCount] = 71 {SR_FLOW_ING_COUNTER_CONTROLm, 72 SR_FLOW_EGR_COUNTER_CONTROLm}; 73 STATIC const uint32 flowcnt_flow_num[bcmTsnStatGroupTypeCount] = {8192, 8192}; 74 STATIC const soc_field_t flowcnt_flow_profile_field[bcmTsnStatGroupTypeCount] = 75 {SR_ING_COUNTER_PROFILEf, 76 SR_EGR_COUNTER_PROFILEf}; 77 STATIC const soc_mem_t flowcnt_pool_mem[bcmTsnStatGroupTypeCount] 78 [bcmTsnStatCount] = 79 {{SR_FLOW_COUNT_POOL0m, SR_FLOW_COUNT_POOL1m, 80 SR_FLOW_COUNT_POOL2m, SR_FLOW_COUNT_POOL3m, 81 SR_FLOW_COUNT_POOL4m, SR_FLOW_COUNT_POOL5m, 82 SR_FLOW_COUNT_POOL6m, SR_FLOW_COUNT_POOL7m}, 83 {EGR_SR_FLOW_COUNT_POOL0m, 84 EGR_SR_FLOW_COUNT_POOL1m}}; 85 86 STATIC const uint32 flowcnt_pool_num[bcmTsnStatGroupTypeCount] = {8, 2}; 87 STATIC uint32 flowcnt_enable_value_mapping_cnt[SOC_MAX_NUM_DEVICES] 88 [bcmTsnStatGroupTypeCount]; 89 STATIC const bcm_tsn_stat_t flowcnt_enable_value_mapping 90 [bcmTsnStatGroupTypeCount][bcmTsnStatCount] = 91 {{bcmTsnStatIngressSrSaSrcFilteredPackets, 92 bcmTsnStatIngressSrAcceptedSrPackets, 93 bcmTsnStatCount /* bit 2: reserved */ , 94 bcmTsnStatIngressStuErrorPackets, 95 bcmTsnStatIngressMtuErrorPackets, 96 bcmTsnStatIngressSrUnexpectedPackets, 97 bcmTsnStatIngressSrOwnRxPackets, 98 bcmTsnStatIngressSrOutOfOrderSrPackets, 99 bcmTsnStatCount/* bit 8: reserved */, 100 bcmTsnStatIngressSrDuplicatePackets, 101 bcmTsnStatIngressSrTagErrorPackets, 102 bcmTsnStatIngressSrRxErrorPackets, 103 bcmTsnStatIngressSrWrongLanPackets, 104 bcmTsnStatIngressNonLinkLocalPackets, 105 bcmTsnStatIngressSrTaggedPackets, 106 bcmTsnStatIngressTafMtuPass, 107 bcmTsnStatIngressTafGatePass, 108 bcmTsnStatIngressTafGateCloseDrop, 109 bcmTsnStatIngressTafGateNoByteDrop, 110 bcmTsnStatIngressTafMeterDrop}, 111 {bcmTsnStatEgressStuErrorPackets, 112 bcmTsnStatEgressMtuErrorPackets, 113 bcmTsnStatEgressNonLinkLocalPackets, 114 bcmTsnStatEgressSrTaggedPackets}}; 115 /* 116 * sw database for flowcnt : counter 117 */ 118 STATIC uint64 *flowcnt_counter_sw[SOC_MAX_NUM_DEVICES] 119 [bcmTsnStatGroupTypeCount][bcmTsnStatCount]; 120 STATIC uint64 *flowcnt_counter_hw[SOC_MAX_NUM_DEVICES] 121 [bcmTsnStatGroupTypeCount][bcmTsnStatCount]; 122 123 STATIC uint8 *flowcnt_counter_dma_buffer[SOC_MAX_NUM_DEVICES] 124 [bcmTsnStatGroupTypeCount]; 125 STATIC uint64 flowcnt_counter_max[SOC_MAX_NUM_DEVICES] 126 [bcmTsnStatGroupTypeCount][bcmTsnStatCount]; 127 STATIC uint64 flowcnt_counter_mask[SOC_MAX_NUM_DEVICES] 128 [bcmTsnStatGroupTypeCount][bcmTsnStatCount]; 129 130 /* 131 * sw database for flowcnt : group 132 */ 133 STATIC soc_profile_mem_t *flowcnt_group_mem_profile[SOC_MAX_NUM_DEVICES] 134 [bcmTsnStatGroupTypeCount]; 135 /* for each group, mapping between statType and pool_id */ 136 STATIC int32 **flowcnt_group_stat2pool[SOC_MAX_NUM_DEVICES] 137 [bcmTsnStatGroupTypeCount]; 138 139 /* the relationship between "statType" and "flow_id bitmap" 140 * ex. Given a specific statType, 141 * 1. we can traverse and find which groupId contains this statType 142 * 2. Then we can get flow_id bitmap attached to this groupId 143 * (1. is impacted when the group's enable_value changes) 144 * (2. is impacted when flow attach/detach the group) 145 * 146 * If we want to keep the cache between "statType" and "flow_id bitmap" 147 * we need to update the cache value when event 1 or 2 occurs. 148 * However before the user wants to change group's enable_value, 149 * he/she needs to detach all flows that attached to this group first. 150 * According to this assumption, we only need to care about event 2. 151 */ 152 STATIC SHR_BITDCL *flowcnt_stat_fbmp_cache[SOC_MAX_NUM_DEVICES] 153 [bcmTsnStatGroupTypeCount] 154 [bcmTsnStatCount]; 155 156 /* 157 * sw database for flowcnt : pool 158 */ 159 STATIC int32 flowcnt_pool_bitmap_alloc_min[SOC_MAX_NUM_DEVICES] 160 [bcmTsnStatGroupTypeCount]; 161 STATIC int32 flowcnt_pool_bitmap_alloc_max[SOC_MAX_NUM_DEVICES] 162 [bcmTsnStatGroupTypeCount]; 163 STATIC shr_res_bitmap_handle_t flowcnt_pool_bitmap[SOC_MAX_NUM_DEVICES] 164 [bcmTsnStatGroupTypeCount]; 165 STATIC uint8 *flowcnt_mem_entry_buf[SOC_MAX_NUM_DEVICES]; 166 167 168 typedef int (*bcmi_gh2_tsn_stat_flowcnt_group_traverse_cb)( 169 int unit, 170 bcm_tsn_stat_group_type_t group_type, 171 uint32 group_id, 172 void *user_data); 173 174 typedef struct bcmi_gh2_tsn_stat_flowcnt_group_traverse_userdata_s { 175 bcm_tsn_stat_group_traverse_cb cb; 176 void *cb_user_data; 177 } bcmi_gh2_tsn_stat_flowcnt_group_traverse_userdata_t; 178 179 /* helper macro */ 180 #define BCMI_TSN_FLOWCNT_MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) 181 #define BCMI_TSN_FLOWCNT_STAT_ID_EGRESS_BIT (20) 182 #define ERROR_RETURN_WITH_EXTRA_CLEAN(_op_, _extra_clean_) \ 183 do { \ 184 int _rv_ = (_op_); \ 185 if (BCM_FAILURE(_rv_)) { \ 186 (_extra_clean_); \ 187 return (_rv_); \ 188 } \ 189 } while (0) 190 191 #define INIT_ERROR_RETURN_WITH_CLEAN(_op_) \ 192 do { \ 193 int _rv_ = (_op_); \ 194 if (BCM_FAILURE(_rv_)) { \ 195 bcmi_gh2_tsn_stat_flowcnt_cleanup(unit);\ 196 return (_rv_); \ 197 } \ 198 } while (0) 199 200 #define INIT_ERROR_RETURN_WITH_EXTRA_CLEAN(_op_, _extra_clean_) \ 201 do { \ 202 int _rv_ = (_op_); \ 203 if (BCM_FAILURE(_rv_)) { \ 204 (_extra_clean_); \ 205 bcmi_gh2_tsn_stat_flowcnt_cleanup(unit); \ 206 return (_rv_); \ 207 } \ 208 } while (0) 209 210 #define WRITE_PTR(__ptr__, __type__, __data__) \ 211 do { \ 212 *((__type__*)(__ptr__)) = (__data__); \ 213 (__ptr__) += sizeof(__type__); \ 214 } while (0) 215 216 #define READ_PTR(__ptr__, __type__, __dest__) \ 217 do { \ 218 (__dest__) = *((__type__*)(__ptr__)); \ 219 (__ptr__) += sizeof(__type__); \ 220 } while (0) 221 222 223 /**************** TSN Stat Threshold ****************/ 224 225 /* 226 * TSN Stat Threshold Select Structure on GH2 227 */ 228 typedef struct bcmi_gh2_tsn_stat_threshold_select_s { 229 bcm_tsn_stat_t stat_type; /* TSN Statistics type */ 230 soc_reg_t reg; /* Counter Threshold register */ 231 soc_field_t threshold_field; /* Counter threshold field */ 232 soc_field_t interrupt_field; /* Interrupt field */ 233 soc_field_t copy_to_cpu_field; /* Copy to cpu field */ 234 } bcmi_gh2_tsn_stat_threshold_select_t; 235 236 /* 237 * TSN Stat Threshold Select info structure for Source Port on GH2 238 */ 239 STATIC const bcmi_gh2_tsn_stat_threshold_select_t 240 gh2_port_count_threshold_info[] = 241 { 242 {bcmTsnStatIngressSrTaggedPackets, 243 SR_PORT_COUNT_THRESHOLD_RX_TAGGEDr, COUNTER_THRESHOLDf, 244 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 245 {bcmTsnStatIngressNonLinkLocalPackets, 246 SR_PORT_COUNT_THRESHOLD_RXr, COUNTER_THRESHOLDf, 247 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 248 {bcmTsnStatIngressSrWrongLanPackets, 249 SR_PORT_COUNT_THRESHOLD_RX_WRONG_LANr, COUNTER_THRESHOLDf, 250 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 251 {bcmTsnStatIngressSrRxErrorPackets, 252 SR_PORT_COUNT_THRESHOLD_RX_ERRORr, COUNTER_THRESHOLDf, 253 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 254 {bcmTsnStatIngressSrTagErrorPackets, 255 SR_PORT_COUNT_THRESHOLD_RX_TAG_ERRORr, COUNTER_THRESHOLDf, 256 INTERRUPT_ENABLEf, INVALIDf}, 257 {bcmTsnStatIngressSrDuplicatePackets, 258 SR_PORT_COUNT_THRESHOLD_RX_DUPLICATESr, COUNTER_THRESHOLDf, 259 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 260 {bcmTsnStatIngressSrOutOfOrderSrPackets, 261 SR_PORT_COUNT_THRESHOLD_RX_OUTOFORDERr, COUNTER_THRESHOLDf, 262 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 263 {bcmTsnStatIngressSrOwnRxPackets, 264 SR_PORT_COUNT_THRESHOLD_OWN_RXr, COUNTER_THRESHOLDf, 265 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 266 {bcmTsnStatIngressSrUnexpectedPackets, 267 SR_PORT_COUNT_THRESHOLD_UNEXPECTED_FRAMEr, COUNTER_THRESHOLDf, 268 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 269 {bcmTsnStatIngressMtuErrorPackets, 270 SR_PORT_THRESHOLD_MTU_ERRORr, COUNTER_THRESHOLDf, 271 INTERRUPT_ENABLEf, INVALIDf}, 272 {bcmTsnStatIngressStuErrorPackets, 273 SR_PORT_THRESHOLD_STU_ERRORr, COUNTER_THRESHOLDf, 274 INTERRUPT_ENABLEf, INVALIDf}, 275 {bcmTsnStatIngressSrAcceptedSrPackets, 276 SR_PORT_COUNT_THRESHOLD_RX_PASSEDr, COUNTER_THRESHOLDf, 277 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 278 {bcmTsnStatIngressSrSaSrcFilteredPackets, 279 SR_PORT_COUNT_THRESHOLD_PROXY_MAC_ERRORr, COUNTER_THRESHOLDf, 280 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 281 {bcmTsnStatEgressSrTaggedPackets, 282 SR_PORT_COUNT_THRESHOLD_TX_TAGGEDr, COUNTER_THRESHOLDf, 283 INTERRUPT_ENABLEf, INVALIDf}, 284 {bcmTsnStatEgressNonLinkLocalPackets, 285 SR_PORT_COUNT_THRESHOLD_TXr, COUNTER_THRESHOLDf, 286 INTERRUPT_ENABLEf, INVALIDf}, 287 {bcmTsnStatEgressMtuErrorPackets, 288 SR_PORT_THRESHOLD_TX_MTU_ERRORr, COUNTER_THRESHOLDf, 289 INTERRUPT_ENABLEf, INVALIDf}, 290 {bcmTsnStatEgressStuErrorPackets, 291 SR_PORT_THRESHOLD_TX_STU_ERRORr, COUNTER_THRESHOLDf, 292 INTERRUPT_ENABLEf, INVALIDf} 293 }; 294 295 /* 296 * TSN Stat Threshold Select info structure for Source SR Flow on GH2 297 */ 298 STATIC const bcmi_gh2_tsn_stat_threshold_select_t 299 gh2_flow_count_threshold_info[] = 300 { 301 {bcmTsnStatIngressSrTaggedPackets, 302 SR_FLOW_COUNT_THRESHOLD_RX_TAGGEDr, COUNTER_THRESHOLDf, 303 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 304 {bcmTsnStatIngressNonLinkLocalPackets, 305 SR_FLOW_COUNT_THRESHOLD_RXr, COUNTER_THRESHOLDf, 306 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 307 {bcmTsnStatIngressSrWrongLanPackets, 308 SR_FLOW_COUNT_THRESHOLD_RX_WRONG_LANr, COUNTER_THRESHOLDf, 309 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 310 {bcmTsnStatIngressSrRxErrorPackets, 311 SR_FLOW_COUNT_THRESHOLD_RX_ERRORr, COUNTER_THRESHOLDf, 312 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 313 {bcmTsnStatIngressSrTagErrorPackets, 314 SR_FLOW_COUNT_THRESHOLD_RX_TAG_ERRORr, COUNTER_THRESHOLDf, 315 INTERRUPT_ENABLEf, INVALIDf}, 316 {bcmTsnStatIngressSrDuplicatePackets, 317 SR_FLOW_COUNT_THRESHOLD_RX_DUPLICATESr, COUNTER_THRESHOLDf, 318 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 319 {bcmTsnStatIngressSrOutOfOrderSrPackets, 320 SR_FLOW_COUNT_THRESHOLD_RX_OUTOFORDERr, COUNTER_THRESHOLDf, 321 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 322 {bcmTsnStatIngressSrOwnRxPackets, 323 SR_FLOW_COUNT_THRESHOLD_OWN_RXr, COUNTER_THRESHOLDf, 324 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 325 {bcmTsnStatIngressSrUnexpectedPackets, 326 SR_FLOW_COUNT_THRESHOLD_UNEXPECTED_FRAMEr, COUNTER_THRESHOLDf, 327 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 328 {bcmTsnStatIngressMtuErrorPackets, 329 SR_FLOW_THRESHOLD_MTU_ERRORr, COUNTER_THRESHOLDf, 330 INTERRUPT_ENABLEf, INVALIDf}, 331 {bcmTsnStatIngressStuErrorPackets, 332 SR_FLOW_THRESHOLD_STU_ERRORr, COUNTER_THRESHOLDf, 333 INTERRUPT_ENABLEf, INVALIDf}, 334 {bcmTsnStatIngressSrAcceptedSrPackets, 335 SR_FLOW_COUNT_THRESHOLD_RX_PASSEDr, COUNTER_THRESHOLDf, 336 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 337 {bcmTsnStatIngressSrSaSrcFilteredPackets, 338 SR_FLOW_THRESHOLD_PROXY_MAC_ERRORr, COUNTER_THRESHOLDf, 339 INTERRUPT_ENABLEf, COPY_TO_CPUf}, 340 {bcmTsnStatEgressSrTaggedPackets, 341 SR_FLOW_COUNT_THRESHOLD_TX_TAGGEDr, COUNTER_THRESHOLDf, 342 INTERRUPT_ENABLEf, INVALIDf}, 343 {bcmTsnStatEgressNonLinkLocalPackets, 344 SR_FLOW_COUNT_THRESHOLD_TXr, COUNTER_THRESHOLDf, 345 INTERRUPT_ENABLEf, INVALIDf}, 346 {bcmTsnStatEgressMtuErrorPackets, 347 SR_FLOW_THRESHOLD_TX_MTU_ERRORr, COUNTER_THRESHOLDf, 348 INTERRUPT_ENABLEf, INVALIDf}, 349 {bcmTsnStatEgressStuErrorPackets, 350 SR_FLOW_THRESHOLD_TX_STU_ERRORr, COUNTER_THRESHOLDf, 351 INTERRUPT_ENABLEf, INVALIDf} 352 }; 353 354 /* TSN Stat threshold default value for initialization */ 355 #define GH2_TSN_STAT_THRESHOLD_DEFAULT_VALUE 0xffffffff 356 357 /* TSN Stat threshold valid check for SR */ 358 #define GH2_TSN_STAT_THRESHOLD_SR_IS_VALID(unit, type) \ 359 (soc_feature(unit, soc_feature_tsn_sr) && \ 360 ((type >= bcmTsnStatIngressSrTaggedPackets && \ 361 type <= bcmTsnStatIngressSrUnexpectedPackets) || \ 362 (type >= bcmTsnStatIngressSrAcceptedSrPackets && \ 363 type <= bcmTsnStatEgressNonLinkLocalPackets))) 364 365 /* TSN Stat threshold valid check for MTU/STU */ 366 #define GH2_TSN_STAT_THRESHOLD_MTU_STU_IS_VALID(unit, type) \ 367 (soc_feature(unit, soc_feature_tsn_mtu_stu) && \ 368 ((type >= bcmTsnStatIngressMtuErrorPackets && \ 369 type <= bcmTsnStatIngressStuErrorPackets) || \ 370 (type >= bcmTsnStatEgressMtuErrorPackets && \ 371 type <= bcmTsnStatEgressStuErrorPackets))) 372 373 /* TSN Stat threshold valid check */ 374 #define GH2_TSN_STAT_THRESHOLD_IS_VALID(unit, type) \ 375 (GH2_TSN_STAT_THRESHOLD_SR_IS_VALID(unit, type) || \ 376 GH2_TSN_STAT_THRESHOLD_MTU_STU_IS_VALID(unit, type)) 377 378 /************** End of TSN Stat Threshold **************/ 379 380 /* check parameter valid or not */ 381 STATIC int 382 bcmi_gh2_tsn_stat_flowcnt_group_valid_check( 383 int unit, 384 bcm_tsn_stat_group_type_t group_type, 385 const uint32 *group_id, 386 const uint32 *group_enable_values) 387 { 388 soc_mem_t mem; 389 390 if (group_type < 0 || group_type >= bcmTsnStatGroupTypeCount) { 391 return BCM_E_PARAM; 392 } 393 394 mem = flowcnt_group_mem[group_type]; 395 /* check group_id valid */ 396 if (NULL != group_id) { 397 if (!soc_mem_index_valid(unit, mem, *group_id)) { 398 return BCM_E_PARAM; 399 } 400 } 401 402 /* check group_enable_values valid */ 403 if (NULL != group_enable_values) { 404 if (0 == *group_enable_values) { 405 return BCM_E_PARAM; 406 } 407 BCM_IF_ERROR_RETURN(soc_mem_field32_fit(unit, mem, 408 SR_COUNTER_ENABLESf, 409 *group_enable_values)); 410 } 411 return BCM_E_NONE; 412 } 413 414 /* update sw cache : mapping statType to poolId in for some specific group */ 415 STATIC int 416 bcmi_gh2_tsn_stat_flowcnt_group_update_stat2pool( 417 int unit, 418 bcm_tsn_stat_group_type_t group_type, 419 uint32 group_id, 420 uint32 group_enable_values) 421 { 422 int i, pool_index, enable_values_count_max; 423 const bcm_tsn_stat_t *enable_values_mapping; 424 425 assert(group_type >= 0 && group_type < bcmTsnStatGroupTypeCount); 426 assert(group_id < flowcnt_group_num[group_type]); 427 428 /* init flowcnt_group_stat2pool as all invalid first */ 429 for (i = 0; i < bcmTsnStatCount; i++) { 430 flowcnt_group_stat2pool[unit][group_type][group_id][i] = -1; 431 } 432 433 enable_values_mapping = flowcnt_enable_value_mapping[group_type]; 434 enable_values_count_max = flowcnt_enable_value_mapping_cnt[unit] 435 [group_type]; 436 437 /* starting from MSB, the first bit that is set to 1 corresponds 438 * to pool 0, the next bit set to 1 corresponds to pool 1, etc 439 */ 440 pool_index = 0; 441 for (i = enable_values_count_max - 1; i >= 0; i--) { 442 if (group_enable_values & (1 << i)) { 443 if (bcmTsnStatCount == enable_values_mapping[i]) { 444 /* should not happen */ 445 return BCM_E_INTERNAL; 446 } 447 flowcnt_group_stat2pool 448 [unit][group_type][group_id] 449 [enable_values_mapping[i]] = pool_index; 450 pool_index++; 451 } 452 } 453 454 return BCM_E_NONE; 455 } 456 457 /* get enable value for a given (group_type+group_id) */ 458 STATIC int 459 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_get( 460 int unit, 461 bcm_tsn_stat_group_type_t group_type, 462 uint32 group_id, 463 uint32 *ret_enable_values) 464 { 465 soc_mem_t mem; 466 soc_profile_mem_t *profile_mem; 467 void *profile_mem_ptr; 468 469 if (NULL == ret_enable_values) { 470 return BCM_E_PARAM; 471 } 472 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == group_id) { 473 /* should not query reserved group's enable value */ 474 return BCM_E_PARAM; 475 } 476 477 BCM_IF_ERROR_RETURN( 478 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 479 &group_id, NULL)); 480 481 profile_mem = flowcnt_group_mem_profile[unit][group_type]; 482 mem = flowcnt_group_mem[group_type]; 483 484 profile_mem_ptr = SOC_PROFILE_MEM_ENTRY(unit, profile_mem, 485 void *, group_id); 486 *ret_enable_values = soc_mem_field32_get(unit, mem, profile_mem_ptr, 487 SR_COUNTER_ENABLESf); 488 489 return BCM_E_NONE; 490 } 491 492 /* set enable value for a given (group_type+group_id) */ 493 STATIC int 494 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_set( 495 int unit, 496 bcm_tsn_stat_group_type_t group_type, 497 uint32 group_id, 498 uint32 group_enable_values) 499 { 500 soc_mem_t mem; 501 soc_profile_mem_t *profile_mem; 502 void *entry_buf = flowcnt_mem_entry_buf[unit]; 503 void *entries[1]; 504 int rv = BCM_E_NONE; 505 506 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == group_id) { 507 /* should not set reserved group's enable value */ 508 return BCM_E_PARAM; 509 } 510 511 BCM_IF_ERROR_RETURN( 512 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, &group_id, 513 &group_enable_values)); 514 profile_mem = flowcnt_group_mem_profile[unit][group_type]; 515 mem = flowcnt_group_mem[group_type]; 516 517 sal_memset(entry_buf, 0, WORDS2BYTES(soc_mem_entry_words(unit, mem))); 518 soc_mem_field32_set(unit, mem, entry_buf, 519 SR_COUNTER_ENABLESf, group_enable_values); 520 521 entries[0] = entry_buf; 522 rv = soc_profile_mem_set(unit, profile_mem, entries, group_id); 523 BCM_IF_ERROR_RETURN(rv); 524 525 BCM_IF_ERROR_RETURN( 526 bcmi_gh2_tsn_stat_flowcnt_group_update_stat2pool( 527 unit, group_type, group_id, group_enable_values)); 528 529 return BCM_E_NONE; 530 } 531 532 /* find enable value in one specific group 533 * return BCM_E_NONE : not exited 534 * return BCM_E_EXISTS : has already exited 535 */ 536 STATIC int 537 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_exist_check( 538 int unit, 539 bcm_tsn_stat_group_type_t group_type, 540 uint32 find_enable_values) 541 { 542 soc_mem_t mem; 543 soc_profile_mem_t *profile_mem; 544 int idx; 545 546 BCM_IF_ERROR_RETURN( 547 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 548 NULL, NULL)); 549 profile_mem = flowcnt_group_mem_profile[unit][group_type]; 550 mem = flowcnt_group_mem[group_type]; 551 552 for (idx = 0; idx < flowcnt_group_num[group_type]; idx++) { 553 void *profile_mem_ptr; 554 uint32 enable_values; 555 int ref_count; 556 557 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == idx) { 558 continue; 559 } 560 BCM_IF_ERROR_RETURN( 561 soc_profile_mem_ref_count_get(unit, profile_mem, idx, &ref_count)); 562 if (0 == ref_count) { 563 /* just need to find the enable value "in use", 564 * so skip the entry with ref_cnt = 0 565 */ 566 continue; 567 } 568 profile_mem_ptr = SOC_PROFILE_MEM_ENTRY(unit, profile_mem, void *, idx); 569 enable_values = soc_mem_field32_get(unit, mem, profile_mem_ptr, 570 SR_COUNTER_ENABLESf); 571 if (enable_values == find_enable_values) { 572 return BCM_E_EXISTS; 573 } 574 } 575 return BCM_E_NONE; 576 } 577 578 /* add a enable value into the given group, and return the new added group_id */ 579 STATIC int 580 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_insert( 581 int unit, 582 bcm_tsn_stat_group_type_t group_type, 583 uint32 insert_enable_values, 584 uint32 *ret_group_id) 585 { 586 soc_mem_t mem; 587 soc_profile_mem_t *profile_mem; 588 void *entry_buf = flowcnt_mem_entry_buf[unit]; 589 int group_id; 590 591 if (NULL == ret_group_id) { 592 return BCM_E_PARAM; 593 } 594 595 BCM_IF_ERROR_RETURN( 596 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, NULL, 597 &insert_enable_values)); 598 profile_mem = flowcnt_group_mem_profile[unit][group_type]; 599 mem = flowcnt_group_mem[group_type]; 600 /* check the new value not duplicate */ 601 BCM_IF_ERROR_RETURN( 602 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_exist_check( 603 unit, group_type, insert_enable_values)); 604 605 /* insert */ 606 sal_memset(entry_buf, 0, WORDS2BYTES(soc_mem_entry_words(unit, mem))); 607 soc_mem_field32_set(unit, mem, entry_buf, 608 SR_COUNTER_ENABLESf, insert_enable_values); 609 610 BCM_IF_ERROR_RETURN( 611 soc_profile_mem_single_table_add(unit, profile_mem, entry_buf, 612 1, &group_id)); 613 BCM_IF_ERROR_RETURN( 614 bcmi_gh2_tsn_stat_flowcnt_group_update_stat2pool( 615 unit, group_type, group_id, insert_enable_values)); 616 617 *ret_group_id = (uint32)group_id; 618 619 return BCM_E_NONE; 620 } 621 622 /* delete a enable value from the given group */ 623 STATIC int 624 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_delete( 625 int unit, 626 bcm_tsn_stat_group_type_t group_type, 627 uint32 group_id) 628 { 629 soc_profile_mem_t *profile_mem; 630 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == group_id) { 631 /* should not delete reserved group's enable value */ 632 return BCM_E_PARAM; 633 } 634 635 BCM_IF_ERROR_RETURN( 636 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 637 &group_id, NULL)); 638 profile_mem = flowcnt_group_mem_profile[unit][group_type]; 639 640 BCM_IF_ERROR_RETURN( 641 soc_profile_mem_delete(unit, profile_mem, group_id)); 642 643 BCM_IF_ERROR_RETURN( 644 bcmi_gh2_tsn_stat_flowcnt_group_update_stat2pool( 645 unit, group_type, group_id, 0)); 646 647 return BCM_E_NONE; 648 } 649 650 /* encode multiple stat types to a enable_values */ 651 STATIC int 652 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_encode( 653 int unit, 654 bcm_tsn_stat_group_type_t group_type, 655 bcm_tsn_stat_t *stat_arr, 656 uint32 stat_arr_cnt, 657 uint32 *ret_enable_values) 658 { 659 int i, j, enable_values_count_limit, enable_values_count_max; 660 const bcm_tsn_stat_t *enable_values_mapping; 661 662 if (NULL == ret_enable_values || NULL == stat_arr) { 663 return BCM_E_PARAM; 664 } 665 666 BCM_IF_ERROR_RETURN( 667 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 668 NULL, NULL)); 669 670 enable_values_count_limit = flowcnt_pool_num[group_type]; 671 enable_values_count_max = flowcnt_enable_value_mapping_cnt[unit] 672 [group_type]; 673 enable_values_mapping = flowcnt_enable_value_mapping[group_type]; 674 675 if (stat_arr_cnt <= 0 || stat_arr_cnt > enable_values_count_limit) { 676 return BCM_E_PARAM; 677 } 678 679 *ret_enable_values = 0; 680 for (i = 0; i < stat_arr_cnt; i++) { 681 int found_out = 0; 682 683 if (bcmTsnStatCount == stat_arr[i]) { 684 return BCM_E_PARAM; 685 } 686 for (j = 0; j < enable_values_count_max; j++) { 687 if (stat_arr[i] == enable_values_mapping[j]) { 688 *ret_enable_values |= (1 << j); 689 found_out = 1; 690 break; 691 } 692 } 693 if (0 == found_out) { 694 return BCM_E_PARAM; 695 } 696 } 697 if (0 == *ret_enable_values) { 698 return BCM_E_PARAM; 699 } 700 701 return BCM_E_NONE; 702 } 703 704 /* decode enable_values to multiple stat types */ 705 STATIC int 706 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_decode( 707 int unit, 708 bcm_tsn_stat_group_type_t group_type, 709 uint32 enable_values, 710 bcm_tsn_stat_t *stat_arr, 711 uint32 stat_arr_len, 712 int *ret_stat_arr_cnt) 713 { 714 int write_ptr, i, enable_values_count_max, actual_count; 715 const bcm_tsn_stat_t *enable_values_mapping; 716 717 if (0 == enable_values || NULL == ret_stat_arr_cnt) { 718 return BCM_E_PARAM; 719 } 720 721 if (0 == stat_arr_len) { 722 /* user just want to get the "needed count" 723 * for returned ret_stat_arr_cnt 724 * so need not check stat_arr here 725 */ 726 } else { 727 /* user want we write the result into stat_arr 728 * and get "written count" for returned ret_stat_arr_cnt 729 */ 730 if (NULL == stat_arr) { 731 return BCM_E_PARAM; 732 } 733 } 734 735 BCM_IF_ERROR_RETURN( 736 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 737 NULL, NULL)); 738 739 enable_values_mapping = flowcnt_enable_value_mapping[group_type]; 740 enable_values_count_max = flowcnt_enable_value_mapping_cnt[unit] 741 [group_type]; 742 743 write_ptr = 0; 744 actual_count = 0; 745 for (i = 0; i < enable_values_count_max; i++) { 746 if (enable_values & (1 << i)) { 747 if (write_ptr < stat_arr_len) { 748 stat_arr[write_ptr] = enable_values_mapping[i]; 749 write_ptr++; 750 } 751 actual_count++; 752 } 753 } 754 if (0 == stat_arr_len) { 755 *ret_stat_arr_cnt = actual_count; 756 } else { 757 *ret_stat_arr_cnt = write_ptr; 758 } 759 return BCM_E_NONE; 760 } 761 762 /* set the reference count for the given group_id in one group */ 763 STATIC int 764 bcmi_gh2_tsn_stat_flowcnt_group_refcnt_set( 765 int unit, 766 bcm_tsn_stat_group_type_t group_type, 767 uint32 group_id, 768 int refcnt_diff) 769 { 770 soc_profile_mem_t *profile_mem; 771 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == group_id) { 772 /* should not modify reserved group's ref count */ 773 return BCM_E_PARAM; 774 } 775 776 BCM_IF_ERROR_RETURN( 777 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 778 &group_id, NULL)); 779 profile_mem = flowcnt_group_mem_profile[unit][group_type]; 780 SOC_PROFILE_MEM_REFERENCE(unit, profile_mem, group_id, refcnt_diff); 781 return BCM_E_NONE; 782 } 783 784 /* get the reference count for the given group_id in one group */ 785 STATIC int 786 bcmi_gh2_tsn_stat_flowcnt_group_refcnt_get( 787 int unit, 788 bcm_tsn_stat_group_type_t group_type, 789 uint32 group_id, 790 int *ret_refcnt) 791 { 792 soc_profile_mem_t *profile_mem; 793 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == group_id) { 794 /* should not modify reserved group's ref count */ 795 return BCM_E_PARAM; 796 } 797 798 BCM_IF_ERROR_RETURN( 799 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 800 &group_id, NULL)); 801 profile_mem = flowcnt_group_mem_profile[unit][group_type]; 802 return soc_profile_mem_ref_count_get(unit, profile_mem, group_id, 803 ret_refcnt); 804 } 805 806 /* encode "group_type, group_id" to "stat_id" */ 807 STATIC int 808 bcmi_gh2_tsn_stat_flowcnt_group_id_encode( 809 int unit, 810 bcm_tsn_stat_group_type_t group_type, 811 uint32 group_id, 812 bcm_tsn_stat_group_t *ret_stat_id) 813 { 814 if (NULL == ret_stat_id) { 815 return BCM_E_PARAM; 816 } 817 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == group_id) { 818 /* should not encode reserved group's to stat_id */ 819 return BCM_E_PARAM; 820 } 821 822 BCM_IF_ERROR_RETURN( 823 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 824 &group_id, NULL)); 825 826 *ret_stat_id = group_id; 827 if (bcmTsnStatGroupTypeEgress == group_type) { 828 *ret_stat_id |= (1 << BCMI_TSN_FLOWCNT_STAT_ID_EGRESS_BIT); 829 } 830 831 return BCM_E_NONE; 832 } 833 834 /* decode "stat_id" to "group_type, group_id" */ 835 STATIC int 836 bcmi_gh2_tsn_stat_flowcnt_group_id_decode( 837 int unit, 838 bcm_tsn_stat_group_t stat_id, 839 bcm_tsn_stat_group_type_t *ret_group_type, 840 uint32 *ret_group_id) 841 { 842 if (NULL == ret_group_id || NULL == ret_group_type) { 843 return BCM_E_PARAM; 844 } 845 if (stat_id < 0) { 846 return BCM_E_PARAM; 847 } 848 849 if (stat_id & (1 << BCMI_TSN_FLOWCNT_STAT_ID_EGRESS_BIT)) { 850 *ret_group_type = bcmTsnStatGroupTypeEgress; 851 } else { 852 *ret_group_type = bcmTsnStatGroupTypeIngress; 853 } 854 855 *ret_group_id = stat_id & ((1 << BCMI_TSN_FLOWCNT_STAT_ID_EGRESS_BIT) - 1); 856 857 BCM_IF_ERROR_RETURN( 858 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, *ret_group_type, 859 ret_group_id, NULL)); 860 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == *ret_group_id) { 861 /* should not decode reserved stat_id */ 862 return BCM_E_PARAM; 863 } 864 865 return BCM_E_NONE; 866 } 867 868 /* for each valid "group_type, group_id", invoke cb with userdata */ 869 STATIC int 870 bcmi_gh2_tsn_stat_flowcnt_group_internal_traverse( 871 int unit, 872 bcmi_gh2_tsn_stat_flowcnt_group_traverse_cb cb, 873 void *user_data) 874 { 875 bcm_tsn_stat_group_type_t group_type; 876 877 if (NULL == cb) { 878 return BCM_E_PARAM; 879 } 880 881 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 882 soc_mem_t mem; 883 int group_id; 884 885 BCM_IF_ERROR_RETURN( 886 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 887 NULL, NULL)); 888 mem = flowcnt_group_mem[group_type]; 889 890 for (group_id = 0; group_id < flowcnt_group_num[group_type]; 891 group_id++) { 892 uint32 enable_values; 893 void *entry_buf = flowcnt_mem_entry_buf[unit]; 894 895 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == group_id) { 896 continue; 897 } 898 899 BCM_IF_ERROR_RETURN( 900 soc_mem_read(unit, mem, MEM_BLOCK_ANY, group_id, entry_buf)); 901 enable_values = soc_mem_field32_get(unit, mem, entry_buf, 902 SR_COUNTER_ENABLESf); 903 if (0 == enable_values) { 904 continue; 905 } 906 BCM_IF_ERROR_RETURN(cb(unit, group_type, group_id, user_data)); 907 } 908 } 909 return BCM_E_NONE; 910 } 911 912 /* helper function for bcmi_gh2_tsn_stat_flowcnt_group_traverse() */ 913 STATIC int 914 bcmi_gh2_tsn_stat_flowcnt_group_traverse_cb_user( 915 int unit, 916 bcm_tsn_stat_group_type_t group_type, 917 uint32 group_id, 918 void *user_data) 919 { 920 bcmi_gh2_tsn_stat_flowcnt_group_traverse_userdata_t *ori_user_data; 921 bcm_tsn_stat_group_t stat_id; 922 923 if (NULL == user_data) { 924 return BCM_E_PARAM; 925 } 926 927 ori_user_data = 928 (bcmi_gh2_tsn_stat_flowcnt_group_traverse_userdata_t *)user_data; 929 if (NULL == ori_user_data->cb) { 930 return BCM_E_PARAM; 931 } 932 933 BCM_IF_ERROR_RETURN( 934 bcmi_gh2_tsn_stat_flowcnt_group_id_encode( 935 unit, group_type, group_id, &stat_id)); 936 return ori_user_data->cb(unit, stat_id, ori_user_data->cb_user_data); 937 } 938 939 #if defined(BCM_WARM_BOOT_SUPPORT) 940 /* recover mem profile when warm boot */ 941 STATIC int 942 bcmi_gh2_tsn_stat_flowcnt_group_traverse_cb_recover( 943 int unit, 944 bcm_tsn_stat_group_type_t group_type, 945 uint32 group_id, 946 void *user_data) 947 { 948 soc_profile_mem_t *profile_mem = 949 flowcnt_group_mem_profile[unit][group_type]; 950 void *buf = SOC_PROFILE_MEM_ENTRY(unit, profile_mem, void *, group_id); 951 uint32 enable_values; 952 953 BCM_IF_ERROR_RETURN( 954 soc_profile_mem_sw_state_set( 955 unit, profile_mem, &buf, 1, group_id)); 956 957 enable_values = soc_mem_field32_get(unit, flowcnt_group_mem[group_type], 958 buf, SR_COUNTER_ENABLESf); 959 BCM_IF_ERROR_RETURN( 960 bcmi_gh2_tsn_stat_flowcnt_group_update_stat2pool( 961 unit, group_type, group_id, enable_values)); 962 963 return BCM_E_NONE; 964 } 965 966 STATIC int 967 bcmi_gh2_tsn_stat_flowcnt_get_scache_size( 968 int unit, int *size) 969 { 970 bcm_tsn_stat_group_type_t group_type; 971 972 if (NULL == size) { 973 return BCM_E_PARAM; 974 } 975 *size = 0; 976 977 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 978 uint32 pool_index; 979 980 for (pool_index = 0; pool_index < flowcnt_pool_num[group_type]; 981 pool_index++) { 982 983 soc_mem_t mem = flowcnt_pool_mem[group_type][pool_index]; 984 *size += sizeof(uint32) * 2 * soc_mem_index_count(unit, mem); 985 } 986 } 987 return BCM_E_NONE; 988 } 989 990 /* sync data to scache */ 991 STATIC int 992 bcmi_gh2_tsn_stat_flowcnt_sync( 993 int unit, uint8 *scache_ptr) 994 { 995 bcm_tsn_stat_group_type_t group_type; 996 997 if (NULL == scache_ptr) { 998 return BCM_E_PARAM; 999 } 1000 1001 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1002 uint32 pool_index; 1003 1004 for (pool_index = 0; pool_index < flowcnt_pool_num[group_type]; 1005 pool_index++) { 1006 1007 uint32 entry_index; 1008 soc_mem_t mem = flowcnt_pool_mem[group_type][pool_index]; 1009 1010 for (entry_index = 0; 1011 entry_index < soc_mem_index_count(unit, mem); 1012 entry_index++) { 1013 1014 WRITE_PTR(scache_ptr, uint32, 1015 COMPILER_64_LO(flowcnt_counter_sw[unit][group_type] 1016 [pool_index] 1017 [entry_index])); 1018 WRITE_PTR(scache_ptr, uint32, 1019 COMPILER_64_HI(flowcnt_counter_sw[unit][group_type] 1020 [pool_index] 1021 [entry_index])); 1022 } 1023 } 1024 } 1025 return BCM_E_NONE; 1026 } 1027 1028 /* layer-1 warmboot : reload data from hw */ 1029 STATIC int 1030 bcmi_gh2_tsn_stat_flowcnt_reload_l1(int unit) 1031 { 1032 /* if there is no scache, just copy hw counter to sw counter */ 1033 bcm_tsn_stat_group_type_t group_type; 1034 1035 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1036 uint32 pool_index; 1037 1038 for (pool_index = 0; pool_index < flowcnt_pool_num[group_type]; 1039 pool_index++) { 1040 1041 uint32 entry_index; 1042 soc_mem_t mem = flowcnt_pool_mem[group_type][pool_index]; 1043 1044 for (entry_index = 0; 1045 entry_index < soc_mem_index_count(unit, mem); 1046 entry_index++) { 1047 1048 COMPILER_64_COPY(flowcnt_counter_sw[unit][group_type] 1049 [pool_index][entry_index], 1050 flowcnt_counter_hw[unit][group_type] 1051 [pool_index][entry_index]); 1052 } 1053 } 1054 } 1055 return BCM_E_NONE; 1056 } 1057 1058 /* layer-2 warmboot : reload data from scache */ 1059 STATIC int 1060 bcmi_gh2_tsn_stat_flowcnt_reload_l2( 1061 int unit, uint8 *scache_ptr) 1062 { 1063 bcm_tsn_stat_group_type_t group_type; 1064 1065 if (NULL == scache_ptr) { 1066 return BCM_E_PARAM; 1067 } 1068 1069 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1070 uint32 pool_index; 1071 1072 for (pool_index = 0; pool_index < flowcnt_pool_num[group_type]; 1073 pool_index++) { 1074 1075 uint32 entry_index; 1076 soc_mem_t mem = flowcnt_pool_mem[group_type][pool_index]; 1077 1078 for (entry_index = 0; 1079 entry_index < soc_mem_index_count(unit, mem); 1080 entry_index++) { 1081 1082 uint32 sec_lo, sec_hi; 1083 1084 READ_PTR(scache_ptr, uint32, sec_lo); 1085 READ_PTR(scache_ptr, uint32, sec_hi); 1086 COMPILER_64_SET(flowcnt_counter_sw[unit][group_type] 1087 [pool_index][entry_index], 1088 sec_hi, sec_lo); 1089 } 1090 } 1091 } 1092 return BCM_E_NONE; 1093 } 1094 1095 #endif /* BCM_WARM_BOOT_SUPPORT */ 1096 1097 /* traverse TSN stat groups */ 1098 STATIC int 1099 bcmi_gh2_tsn_stat_flowcnt_group_traverse( 1100 int unit, 1101 bcm_tsn_stat_group_traverse_cb cb, 1102 void *user_data) 1103 { 1104 bcmi_gh2_tsn_stat_flowcnt_group_traverse_userdata_t ori_user_data; 1105 ori_user_data.cb = cb; 1106 ori_user_data.cb_user_data = user_data; 1107 1108 BCM_IF_ERROR_RETURN( 1109 bcmi_gh2_tsn_stat_flowcnt_group_internal_traverse( 1110 unit, bcmi_gh2_tsn_stat_flowcnt_group_traverse_cb_user, 1111 &ori_user_data)); 1112 return BCM_E_NONE; 1113 } 1114 1115 /* alloc a index of counter pool 1116 * if is_index_assign = 0 : parameter "index" is for output a available index 1117 * if is_index_assign = 1 : parameter "index" is for input, warmboot usage 1118 */ 1119 STATIC int 1120 bcmi_gh2_tsn_stat_flowcnt_pool_counter_alloc( 1121 int unit, 1122 bcm_tsn_stat_group_type_t group_type, 1123 int *index, 1124 int is_index_assign) 1125 { 1126 shr_res_bitmap_handle_t pool_bitmap; 1127 int new_index; 1128 1129 if (index == NULL) { 1130 return BCM_E_PARAM; 1131 } 1132 1133 BCM_IF_ERROR_RETURN( 1134 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 1135 NULL, NULL)); 1136 1137 pool_bitmap = flowcnt_pool_bitmap[unit][group_type]; 1138 if (0 == is_index_assign) { 1139 /* allocate a new available index */ 1140 BCM_IF_ERROR_RETURN( 1141 shr_res_bitmap_alloc(pool_bitmap, 0, 1, &new_index)); 1142 *index = new_index; 1143 } else { 1144 /* for warm boot, alloc a specified index */ 1145 BCM_IF_ERROR_RETURN( 1146 shr_res_bitmap_alloc(pool_bitmap, 1147 SHR_RES_BITMAP_ALLOC_WITH_ID, 1, 1148 index)); 1149 } 1150 1151 /* update min/max */ 1152 if (-1 == flowcnt_pool_bitmap_alloc_min[unit][group_type]) { 1153 flowcnt_pool_bitmap_alloc_min[unit][group_type] = *index; 1154 flowcnt_pool_bitmap_alloc_max[unit][group_type] = *index; 1155 } else if (*index < flowcnt_pool_bitmap_alloc_min[unit][group_type]) { 1156 flowcnt_pool_bitmap_alloc_min[unit][group_type] = *index; 1157 } else if (*index > flowcnt_pool_bitmap_alloc_max[unit][group_type]) { 1158 flowcnt_pool_bitmap_alloc_max[unit][group_type] = *index; 1159 } 1160 1161 return BCM_E_NONE; 1162 } 1163 1164 /* free the index in counter pool */ 1165 STATIC int 1166 bcmi_gh2_tsn_stat_flowcnt_pool_counter_free( 1167 int unit, 1168 bcm_tsn_stat_group_type_t group_type, 1169 int index) 1170 { 1171 shr_res_bitmap_handle_t pool_bitmap; 1172 1173 BCM_IF_ERROR_RETURN( 1174 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 1175 NULL, NULL)); 1176 1177 pool_bitmap = flowcnt_pool_bitmap[unit][group_type]; 1178 BCM_IF_ERROR_RETURN(shr_res_bitmap_free(pool_bitmap, 1, index)); 1179 1180 /* update min/max */ 1181 if (index == flowcnt_pool_bitmap_alloc_min[unit][group_type] && 1182 index == flowcnt_pool_bitmap_alloc_max[unit][group_type]) { 1183 /* if there is only one index has been allocated 1184 * (and it is the index that user want to free) 1185 * let the min/max value back to initial value 1186 */ 1187 flowcnt_pool_bitmap_alloc_min[unit][group_type] = -1; 1188 flowcnt_pool_bitmap_alloc_max[unit][group_type] = -1; 1189 } else if (index == flowcnt_pool_bitmap_alloc_min[unit][group_type]) { 1190 int new_min; 1191 int found = 0; 1192 1193 /* ex. the min of allocated index is 3 1194 * the max of allocated index is 10 1195 * when the user want to free index 3 (which is the min) 1196 * we need to find the new min from bitmap 1197 */ 1198 for (new_min = index + 1; 1199 new_min <= flowcnt_pool_bitmap_alloc_max[unit][group_type]; 1200 new_min++) { 1201 int rv; 1202 1203 rv = shr_res_bitmap_check( 1204 flowcnt_pool_bitmap[unit][group_type], 1205 1, new_min); 1206 if (BCM_E_EXISTS == rv) { 1207 flowcnt_pool_bitmap_alloc_min[unit][group_type] = new_min; 1208 found = 1; 1209 break; 1210 } 1211 } 1212 if (0 == found) { 1213 return BCM_E_INTERNAL; /* should not happen */ 1214 } 1215 } else if (index == flowcnt_pool_bitmap_alloc_max[unit][group_type]) { 1216 int new_max; 1217 int found = 0; 1218 1219 /* ex. the min of allocated index is 3 1220 * the max of allocated index is 10 1221 * when the user want to free index 10 (which is the max) 1222 * we need to find the new max from bitmap 1223 */ 1224 for (new_max = index - 1; 1225 new_max >= flowcnt_pool_bitmap_alloc_min[unit][group_type]; 1226 new_max--) { 1227 int rv; 1228 1229 rv = shr_res_bitmap_check( 1230 flowcnt_pool_bitmap[unit][group_type], 1231 1, new_max); 1232 if (BCM_E_EXISTS == rv) { 1233 flowcnt_pool_bitmap_alloc_max[unit][group_type] = new_max; 1234 found = 1; 1235 break; 1236 } 1237 } 1238 if (0 == found) { 1239 return BCM_E_INTERNAL; /* should not happen */ 1240 } 1241 } 1242 return BCM_E_NONE; 1243 } 1244 1245 /* update sw cache : hw flow_id(s) bitmap attached to some specific statType 1246 * is_attached - (IN) 1: hw_flow_id attach on this group_id 1247 * 0: hw_flow_id deattach from this group_id 1248 */ 1249 STATIC int 1250 bcmi_gh2_tsn_stat_flowcnt_group_update_attached_flow( 1251 int unit, 1252 bcm_tsn_stat_group_type_t group_type, 1253 uint32 group_id, 1254 uint32 hw_flow_id, 1255 uint32 is_attached) 1256 { 1257 uint32 enable_values; 1258 bcm_tsn_stat_t stat_array[bcmTsnStatCount]; 1259 int stat_count, i; 1260 1261 BCM_IF_ERROR_RETURN( 1262 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_get( 1263 unit, group_type, group_id, &enable_values)); 1264 1265 BCM_IF_ERROR_RETURN( 1266 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_decode( 1267 unit, group_type, enable_values, 1268 stat_array, bcmTsnStatCount, &stat_count)); 1269 1270 assert(stat_count < bcmTsnStatCount); 1271 for (i = 0; i < stat_count; i++) { 1272 if (is_attached) { 1273 SHR_BITSET( 1274 flowcnt_stat_fbmp_cache[unit][group_type][stat_array[i]], 1275 hw_flow_id); 1276 } else { 1277 SHR_BITCLR( 1278 flowcnt_stat_fbmp_cache[unit][group_type][stat_array[i]], 1279 hw_flow_id); 1280 } 1281 } 1282 return BCM_E_NONE; 1283 } 1284 1285 /* get the group id that attached on the given flow_id */ 1286 STATIC int 1287 bcmi_gh2_tsn_stat_flowcnt_flow_get( 1288 int unit, 1289 bcm_tsn_sr_flow_t flow_id, 1290 bcm_tsn_stat_group_type_t group_type, 1291 uint32 *ret_group_id) 1292 { 1293 soc_mem_t mem; 1294 uint32 hw_flow_id; 1295 void *buff; 1296 1297 if (NULL == ret_group_id) { 1298 return BCM_E_PARAM; 1299 } 1300 BCM_IF_ERROR_RETURN( 1301 bcmi_gh2_tsn_stat_flowcnt_group_valid_check( 1302 unit, group_type, NULL, NULL)); 1303 BCM_IF_ERROR_RETURN( 1304 bcmi_esw_tsn_sr_hw_flow_id_get( 1305 unit, flow_id, &hw_flow_id)); 1306 1307 mem = flowcnt_flow_mem[group_type]; 1308 buff = flowcnt_mem_entry_buf[unit]; 1309 1310 BCM_IF_ERROR_RETURN( 1311 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_flow_id, buff)); 1312 1313 *ret_group_id = soc_mem_field32_get(unit, mem, buff, 1314 flowcnt_flow_profile_field[group_type]); 1315 return BCM_E_NONE; 1316 } 1317 1318 /* attach the specified group_id to given flow_id */ 1319 STATIC int 1320 bcmi_gh2_tsn_stat_flowcnt_flow_set( 1321 int unit, 1322 bcm_tsn_sr_flow_t flow_id, 1323 bcm_tsn_stat_group_type_t group_type, 1324 uint32 group_id) 1325 { 1326 soc_mem_t mem; 1327 uint32 hw_flow_id; 1328 uint32 pre_group_id, pre_counter_idx; 1329 void *buff; 1330 1331 BCM_IF_ERROR_RETURN( 1332 bcmi_gh2_tsn_stat_flowcnt_group_valid_check( 1333 unit, group_type, &group_id, NULL)); 1334 BCM_IF_ERROR_RETURN( 1335 bcmi_esw_tsn_sr_hw_flow_id_get( 1336 unit, flow_id, &hw_flow_id)); 1337 1338 mem = flowcnt_flow_mem[group_type]; 1339 buff = flowcnt_mem_entry_buf[unit]; 1340 1341 /* get the previous attached group_id and counter_idx */ 1342 BCM_IF_ERROR_RETURN( 1343 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_flow_id, buff)); 1344 1345 pre_group_id = soc_mem_field32_get(unit, mem, buff, 1346 flowcnt_flow_profile_field[group_type]); 1347 pre_counter_idx = soc_mem_field32_get(unit, mem, buff, 1348 SR_COUNTER_INDEXf); 1349 1350 /* switch to new group id */ 1351 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED != group_id) { 1352 int alloc_new_counter_idx; 1353 1354 if (group_id == pre_group_id) { 1355 /* return success directly if group_id does not change */ 1356 return BCM_E_NONE; 1357 } 1358 1359 /* alloc new pool index */ 1360 BCM_IF_ERROR_RETURN( 1361 bcmi_gh2_tsn_stat_flowcnt_pool_counter_alloc( 1362 unit, group_type, &alloc_new_counter_idx, 0)); 1363 1364 /* increase ref count for this group id */ 1365 ERROR_RETURN_WITH_EXTRA_CLEAN( 1366 bcmi_gh2_tsn_stat_flowcnt_group_refcnt_set( 1367 unit, group_type, group_id, 1), 1368 bcmi_gh2_tsn_stat_flowcnt_pool_counter_free( 1369 unit, group_type, alloc_new_counter_idx)); 1370 1371 soc_mem_field32_set(unit, mem, buff, SR_COUNTER_INDEXf, 1372 alloc_new_counter_idx); 1373 soc_mem_field32_set(unit, mem, buff, 1374 flowcnt_flow_profile_field[group_type], 1375 group_id); 1376 1377 ERROR_RETURN_WITH_EXTRA_CLEAN( 1378 soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_flow_id, buff), 1379 bcmi_gh2_tsn_stat_flowcnt_pool_counter_free( 1380 unit, group_type, alloc_new_counter_idx)); 1381 1382 ERROR_RETURN_WITH_EXTRA_CLEAN( 1383 bcmi_gh2_tsn_stat_flowcnt_group_update_attached_flow( 1384 unit, group_type, group_id, hw_flow_id, 1), 1385 bcmi_gh2_tsn_stat_flowcnt_pool_counter_free( 1386 unit, group_type, alloc_new_counter_idx)); 1387 } else { 1388 /* detach */ 1389 soc_mem_field32_set(unit, mem, buff, 1390 flowcnt_flow_profile_field[group_type], 1391 BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED); 1392 BCM_IF_ERROR_RETURN 1393 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_flow_id, buff)); 1394 } 1395 1396 /* de-refer previous group and pool index */ 1397 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED != pre_group_id) { 1398 BCM_IF_ERROR_RETURN( 1399 bcmi_gh2_tsn_stat_flowcnt_pool_counter_free( 1400 unit, group_type, pre_counter_idx)); 1401 1402 BCM_IF_ERROR_RETURN( 1403 bcmi_gh2_tsn_stat_flowcnt_group_refcnt_set( 1404 unit, group_type, pre_group_id, -1)); 1405 1406 BCM_IF_ERROR_RETURN( 1407 bcmi_gh2_tsn_stat_flowcnt_group_update_attached_flow( 1408 unit, group_type, pre_group_id, hw_flow_id, 0)); 1409 } 1410 return BCM_E_NONE; 1411 } 1412 1413 /* given a stat type, return all hw flow_id(s) been attached on it */ 1414 STATIC int 1415 bcmi_gh2_tsn_stat_flowcnt_flow_get_fbmp( 1416 int unit, 1417 bcm_tsn_stat_t stat, 1418 SHR_BITDCL *fbmp, 1419 uint32 fbmp_size) 1420 { 1421 bcm_tsn_stat_group_type_t group_type; 1422 1423 if (stat < 0 || stat >= bcmTsnStatCount || NULL == fbmp) { 1424 return BCM_E_PARAM; 1425 } 1426 1427 SHR_BITCLR_RANGE(fbmp, 0, fbmp_size * SHR_BITWID); 1428 1429 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1430 1431 if (fbmp_size < _SHR_BITDCLSIZE(flowcnt_flow_num[group_type])) { 1432 return BCM_E_PARAM; 1433 } 1434 1435 SHR_BITOR_RANGE(fbmp, 1436 flowcnt_stat_fbmp_cache[unit][group_type][stat], 1437 0, flowcnt_flow_num[group_type], fbmp); 1438 } 1439 return BCM_E_NONE; 1440 } 1441 1442 /* 1443 * sync flow counter from chip to sw database (flowcnt_counter_hw/sw) 1444 * 1. read chip actual value from chip, and write it to flowcnt_counter_hw 1445 * 2. according to the difference with previous value in flowcnt_counter_hw, 1446 * increase this difference to flowcnt_counter_sw 1447 * 1448 * ex. flowcnt_counter_hw = 100, flowcnt_counter_sw = 300 1449 * if chip actual counter is 102 1450 * ==> flowcnt_counter_hw = 102, flowcnt_counter_sw = 302 1451 * 1452 * pool_index_min/max : the range of counter pool 1453 * index_index_min/max : the range of counter index 1454 */ 1455 STATIC int 1456 bcmi_gh2_tsn_stat_flowcnt_counter_sync( 1457 int unit, 1458 bcm_tsn_stat_group_type_t group_type, 1459 uint32 pool_index_min, 1460 uint32 pool_index_max, 1461 uint32 entry_index_min, 1462 uint32 entry_index_max) 1463 { 1464 uint32 pool_index; 1465 1466 BCM_IF_ERROR_RETURN( 1467 bcmi_gh2_tsn_stat_flowcnt_group_valid_check(unit, group_type, 1468 NULL, NULL)); 1469 1470 if (pool_index_min >= flowcnt_pool_num[group_type] || 1471 pool_index_max >= flowcnt_pool_num[group_type]) { 1472 return BCM_E_PARAM; 1473 } 1474 1475 for (pool_index = pool_index_min; pool_index <= pool_index_max; 1476 pool_index++) { 1477 soc_mem_t mem = flowcnt_pool_mem[group_type][pool_index]; 1478 soc_memacc_t memacc_count; 1479 uint32 entry_byte; 1480 uint8 *buffer_ptr; 1481 uint32 entry_index; 1482 1483 if (!soc_mem_index_valid(unit, mem, entry_index_min) || 1484 !soc_mem_index_valid(unit, mem, entry_index_max)) { 1485 return BCM_E_PARAM; 1486 } 1487 1488 BCM_IF_ERROR_RETURN(soc_memacc_init(unit, mem, COUNTf, &memacc_count)); 1489 entry_byte = WORDS2BYTES(soc_mem_entry_words(unit, mem)); 1490 buffer_ptr = &(flowcnt_counter_dma_buffer[unit][group_type] 1491 [entry_index_min * entry_byte]); 1492 BCM_IF_ERROR_RETURN( 1493 soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 1494 entry_index_min, entry_index_max, 1495 buffer_ptr)); 1496 1497 /* update sw counter for each entry */ 1498 for (entry_index = entry_index_min; entry_index <= entry_index_max; 1499 entry_index++) { 1500 1501 uint64 last_count, diff_count, new_count; 1502 uint64 *array_ptr_sw = 1503 flowcnt_counter_sw[unit][group_type][pool_index]; 1504 uint64 *array_ptr_hw = 1505 flowcnt_counter_hw[unit][group_type][pool_index]; 1506 1507 if (NULL == array_ptr_sw || NULL == array_ptr_hw) { 1508 return BCM_E_INIT; 1509 } 1510 1511 /* update sw counter from buffer */ 1512 buffer_ptr = &(flowcnt_counter_dma_buffer[unit][group_type] 1513 [entry_index * entry_byte]); 1514 COMPILER_64_COPY(last_count, array_ptr_hw[entry_index]); 1515 soc_memacc_field64_get(&memacc_count, buffer_ptr, &new_count); 1516 if (COMPILER_64_GT(last_count, new_count)) { 1517 /* diff_count = new_count + count_max - last_count */ 1518 LOG_VERBOSE(BSL_LS_BCM_TSN, 1519 (BSL_META_U(unit, 1520 "Roll over happened\n"))); 1521 LOG_VERBOSE(BSL_LS_BCM_TSN, 1522 (BSL_META_U(unit, 1523 ".Read Packet64 Count: %x:%x\n"), 1524 COMPILER_64_HI(new_count), 1525 COMPILER_64_LO(new_count))); 1526 COMPILER_64_COPY(diff_count, new_count); 1527 COMPILER_64_ADD_64(diff_count, flowcnt_counter_max[unit] 1528 [group_type] 1529 [pool_index]); 1530 COMPILER_64_SUB_64(diff_count, last_count); 1531 LOG_VERBOSE(BSL_LS_BCM_TSN, 1532 (BSL_META_U(unit, 1533 ".Diffed 64-Packet Count: %x:%x\n"), 1534 COMPILER_64_HI(diff_count), 1535 COMPILER_64_LO(diff_count))); 1536 } else { 1537 /* diff_count = new_count - last_count */ 1538 COMPILER_64_COPY(diff_count, new_count); 1539 COMPILER_64_SUB_64(diff_count, last_count); 1540 } 1541 1542 /* update flowcnt_counter_hw */ 1543 COMPILER_64_COPY(array_ptr_hw[entry_index], new_count); 1544 1545 /* Add difference (if it is) */ 1546 if (!COMPILER_64_IS_ZERO(diff_count)) { 1547 LOG_VERBOSE(BSL_LS_BCM_TSN, 1548 (BSL_META_U(unit, 1549 "port:%d==>" 1550 "Old 64-Packet Count Value%x:%x\t"), 1551 entry_index, 1552 COMPILER_64_HI( 1553 array_ptr_sw[entry_index]), 1554 COMPILER_64_LO( 1555 array_ptr_sw[entry_index]))); 1556 COMPILER_64_ADD_64(array_ptr_sw[entry_index], 1557 diff_count); 1558 LOG_VERBOSE(BSL_LS_BCM_TSN, 1559 (BSL_META_U(unit, 1560 "New 64-Packet Value : %x:%x\n"), 1561 COMPILER_64_HI( 1562 array_ptr_sw[entry_index]), 1563 COMPILER_64_LO( 1564 array_ptr_sw[entry_index]))); 1565 } 1566 } 1567 } 1568 return BCM_E_NONE; 1569 } 1570 1571 /* helper function for flow counter update */ 1572 STATIC int 1573 bcmi_gh2_tsn_stat_flowcnt_counter_update( 1574 int unit, 1575 soc_mem_t mem, 1576 int mem_idx, 1577 uint64 new_count) 1578 { 1579 bcm_tsn_stat_group_type_t group_type; 1580 bcm_tsn_stat_t stat_type; 1581 1582 /* search the memory and set counter */ 1583 for (stat_type = 0; stat_type < bcmTsnStatCount; stat_type++) { 1584 uint64 *array_ptr_sw, *array_ptr_hw; 1585 1586 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; 1587 group_type++) { 1588 soc_mem_t flowcnt_mem = flowcnt_pool_mem[group_type] 1589 [stat_type]; 1590 if (mem != flowcnt_mem) { 1591 continue; 1592 } 1593 array_ptr_sw = flowcnt_counter_sw[unit][group_type] 1594 [stat_type]; 1595 array_ptr_hw = flowcnt_counter_hw[unit][group_type] 1596 [stat_type]; 1597 COMPILER_64_COPY( 1598 array_ptr_sw[mem_idx], 1599 new_count); 1600 COMPILER_64_COPY( 1601 array_ptr_hw[mem_idx], 1602 new_count); 1603 return BCM_E_NONE; 1604 } 1605 } 1606 return BCM_E_NOT_FOUND; 1607 } 1608 1609 /* helper function for flow counter access */ 1610 STATIC int 1611 bcmi_gh2_tsn_stat_flowcnt_counter_access( 1612 int unit, 1613 bcm_tsn_sr_flow_t flow_id, 1614 bcmi_tsn_stat_counter_action_t action, 1615 uint32 arr_cnt, 1616 bcm_tsn_stat_t *stat_type_arr, 1617 uint64 *stat_sw_value_arr, 1618 uint64 *stat_hw_value_arr) 1619 { 1620 int arr_idx; 1621 bcm_tsn_stat_group_type_t group_type; 1622 uint32 group_id[bcmTsnStatGroupTypeCount]; 1623 uint32 counter_idx[bcmTsnStatGroupTypeCount]; 1624 uint32 hw_flow_id; 1625 1626 BCM_IF_ERROR_RETURN( 1627 bcmi_esw_tsn_sr_hw_flow_id_get( 1628 unit, flow_id, &hw_flow_id)); 1629 1630 if (NULL == stat_type_arr) { 1631 return BCM_E_PARAM; 1632 } 1633 for (arr_idx = 0; arr_idx < arr_cnt; arr_idx++) { 1634 if (stat_type_arr[arr_idx] >= bcmTsnStatCount) { 1635 return BCM_E_PARAM; 1636 } 1637 } 1638 1639 /* get group_id and counter_idx */ 1640 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1641 soc_mem_t mem = flowcnt_flow_mem[group_type]; 1642 void *buff = flowcnt_mem_entry_buf[unit]; 1643 1644 BCM_IF_ERROR_RETURN( 1645 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_flow_id, buff)); 1646 1647 group_id[group_type] = soc_mem_field32_get( 1648 unit, mem, buff, 1649 flowcnt_flow_profile_field[group_type]); 1650 counter_idx[group_type] = soc_mem_field32_get(unit, mem, buff, 1651 SR_COUNTER_INDEXf); 1652 } 1653 1654 /* for each stat type that user specify, set/get counter */ 1655 for (arr_idx = 0; arr_idx < arr_cnt; arr_idx++) { 1656 int found = 0; 1657 int select_pool_index; 1658 int select_counter_index; 1659 bcm_tsn_stat_group_type_t select_group_type = bcmTsnStatGroupTypeCount; 1660 uint64 *array_ptr_sw, *array_ptr_hw; 1661 1662 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; 1663 group_type++) { 1664 1665 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED == group_id[group_type]) { 1666 continue; 1667 } 1668 select_pool_index = 1669 flowcnt_group_stat2pool[unit][group_type] 1670 [group_id[group_type]] 1671 [stat_type_arr[arr_idx]]; 1672 if (-1 != select_pool_index) { 1673 select_group_type = group_type; 1674 found = 1; 1675 break; 1676 } 1677 } 1678 1679 if (0 == found) { 1680 /* the user has not install this stat type before */ 1681 BCM_IF_ERROR_RETURN(BCM_E_NOT_FOUND); 1682 } 1683 1684 assert(select_group_type >= 0 && 1685 select_group_type < bcmTsnStatGroupTypeCount); 1686 assert(select_pool_index >= 0 && 1687 select_pool_index < flowcnt_pool_num[select_group_type]); 1688 array_ptr_sw = flowcnt_counter_sw[unit][select_group_type] 1689 [select_pool_index]; 1690 array_ptr_hw = flowcnt_counter_hw[unit][select_group_type] 1691 [select_pool_index]; 1692 select_counter_index = counter_idx[select_group_type]; 1693 /* get flow counter */ 1694 switch (action) { 1695 case bcmiTsnStatCounterActionReadSync: 1696 BCM_IF_ERROR_RETURN( 1697 bcmi_gh2_tsn_stat_flowcnt_counter_sync( 1698 unit, select_group_type, 1699 select_pool_index, select_pool_index, 1700 select_counter_index, 1701 select_counter_index)); 1702 /* fall through */ 1703 case bcmiTsnStatCounterActionRead: 1704 if (NULL != stat_sw_value_arr) { 1705 COMPILER_64_COPY( 1706 stat_sw_value_arr[arr_idx], 1707 array_ptr_sw[select_counter_index]); 1708 } 1709 if (NULL != stat_hw_value_arr) { 1710 COMPILER_64_COPY( 1711 stat_hw_value_arr[arr_idx], 1712 array_ptr_hw[select_counter_index]); 1713 } 1714 break; 1715 case bcmiTsnStatCounterActionWrite: 1716 if (NULL != stat_sw_value_arr) { 1717 COMPILER_64_COPY( 1718 array_ptr_sw[select_counter_index], 1719 stat_sw_value_arr[arr_idx]); 1720 } 1721 if (NULL != stat_hw_value_arr) { 1722 uint8 *buffer_ptr; 1723 uint64 new_count; 1724 soc_mem_t mem = flowcnt_pool_mem[select_group_type] 1725 [select_pool_index]; 1726 1727 COMPILER_64_COPY(new_count, stat_hw_value_arr[arr_idx]); 1728 COMPILER_64_AND(new_count, 1729 flowcnt_counter_mask[unit] 1730 [select_group_type] 1731 [select_pool_index]); 1732 1733 /* write masked value into chip actual data and 1734 * update flowcnt_counter_hw 1735 */ 1736 COMPILER_64_COPY( 1737 array_ptr_hw[select_counter_index], 1738 new_count); 1739 buffer_ptr = &(flowcnt_counter_dma_buffer 1740 [unit][select_group_type][0]); 1741 BCM_IF_ERROR_RETURN( 1742 soc_mem_read(unit, mem, MEM_BLOCK_ANY, 1743 select_counter_index, buffer_ptr)); 1744 soc_mem_field64_set( 1745 unit, mem, buffer_ptr, COUNTf, new_count); 1746 BCM_IF_ERROR_RETURN( 1747 soc_mem_write(unit, mem, MEM_BLOCK_ALL, 1748 select_counter_index, buffer_ptr)); 1749 } 1750 break; 1751 default: 1752 return BCM_E_PARAM; 1753 } 1754 } 1755 1756 return BCM_E_NONE; 1757 } 1758 1759 /* callback for flow counter, sync all stat types 1760 * (just need to update the counter index has been in use) 1761 */ 1762 STATIC int 1763 bcmi_gh2_tsn_stat_flowcnt_counter_sync_all(int unit) 1764 { 1765 bcm_tsn_stat_group_type_t group_type; 1766 1767 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1768 if (-1 == flowcnt_pool_bitmap_alloc_min[unit][group_type]) { 1769 continue; 1770 } 1771 bcmi_gh2_tsn_stat_flowcnt_counter_sync( 1772 unit, group_type, 1773 0, flowcnt_pool_num[group_type] - 1, 1774 flowcnt_pool_bitmap_alloc_min[unit][group_type], 1775 flowcnt_pool_bitmap_alloc_max[unit][group_type]); 1776 } 1777 1778 return BCM_E_NONE; 1779 } 1780 1781 /* callback for flow counter, sync one specific stat type 1782 * (just need to update the counter index has been in use) 1783 */ 1784 STATIC int 1785 bcmi_gh2_tsn_stat_flowcnt_counter_sync_stat(int unit, bcm_tsn_stat_t stat) 1786 { 1787 bcm_tsn_stat_group_type_t group_type; 1788 int pool_idx; 1789 1790 if (stat < 0 || stat >= bcmTsnStatCount) { 1791 return BCM_E_PARAM; 1792 } 1793 1794 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1795 SHR_BITDCL select_pool[1]; 1796 int pool_num = flowcnt_pool_num[group_type]; 1797 int group_id; 1798 1799 if (-1 == flowcnt_pool_bitmap_alloc_min[unit][group_type]) { 1800 continue; 1801 } 1802 assert(pool_num <= SHR_BITWID); 1803 SHR_BITCLR_RANGE(&(select_pool[0]), 0, pool_num); 1804 for (group_id = 0; group_id < flowcnt_group_num[group_type]; 1805 group_id++) { 1806 pool_idx = flowcnt_group_stat2pool[unit][group_type] 1807 [group_id][stat]; 1808 if (-1 == pool_idx) { 1809 continue; 1810 } 1811 assert(pool_idx >= 0 && pool_idx < pool_num); 1812 SHR_BITSET(&(select_pool[0]), pool_idx); 1813 } 1814 1815 SHR_BIT_ITER(&(select_pool[0]), pool_num, pool_idx) { 1816 bcmi_gh2_tsn_stat_flowcnt_counter_sync( 1817 unit, group_type, pool_idx, pool_idx, 1818 flowcnt_pool_bitmap_alloc_min[unit][group_type], 1819 flowcnt_pool_bitmap_alloc_max[unit][group_type]); 1820 } 1821 } 1822 1823 return BCM_E_NONE; 1824 } 1825 1826 /* clean the resource for tsn flow counter */ 1827 STATIC int 1828 bcmi_gh2_tsn_stat_flowcnt_cleanup(int unit) 1829 { 1830 bcm_tsn_stat_group_type_t group_type; 1831 1832 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1833 int i; 1834 1835 if (NULL != flowcnt_group_mem_profile[unit][group_type]) { 1836 soc_profile_mem_destroy( 1837 unit, flowcnt_group_mem_profile[unit][group_type]); 1838 sal_free(flowcnt_group_mem_profile[unit][group_type]); 1839 flowcnt_group_mem_profile[unit][group_type] = NULL; 1840 } 1841 if (NULL != flowcnt_group_stat2pool[unit][group_type]) { 1842 for (i = 0; i < flowcnt_group_num[group_type]; i++) { 1843 if (NULL != flowcnt_group_stat2pool[unit][group_type][i]) { 1844 sal_free(flowcnt_group_stat2pool[unit][group_type][i]); 1845 flowcnt_group_stat2pool[unit][group_type][i] = NULL; 1846 } 1847 } 1848 sal_free(flowcnt_group_stat2pool[unit][group_type]); 1849 flowcnt_group_stat2pool[unit][group_type] = NULL; 1850 } 1851 if (NULL != flowcnt_pool_bitmap[unit][group_type]) { 1852 shr_res_bitmap_destroy(flowcnt_pool_bitmap[unit][group_type]); 1853 flowcnt_pool_bitmap[unit][group_type] = NULL; 1854 } 1855 if (NULL != flowcnt_counter_dma_buffer[unit][group_type]) { 1856 soc_cm_sfree(unit, flowcnt_counter_dma_buffer[unit][group_type]); 1857 flowcnt_counter_dma_buffer[unit][group_type] = NULL; 1858 } 1859 for (i = 0; 1860 i < flowcnt_pool_num[group_type]; 1861 i++) { 1862 1863 if (NULL != flowcnt_counter_sw[unit][group_type][i]) { 1864 sal_free(flowcnt_counter_sw[unit][group_type][i]); 1865 flowcnt_counter_sw[unit][group_type][i] = NULL; 1866 } 1867 if (NULL != flowcnt_counter_hw[unit][group_type][i]) { 1868 sal_free(flowcnt_counter_hw[unit][group_type][i]); 1869 flowcnt_counter_hw[unit][group_type][i] = NULL; 1870 } 1871 } 1872 for (i = 0; i < bcmTsnStatCount; i++) { 1873 if (NULL != flowcnt_stat_fbmp_cache[unit][group_type][i]) { 1874 sal_free(flowcnt_stat_fbmp_cache[unit][group_type][i]); 1875 flowcnt_stat_fbmp_cache[unit][group_type][i] = NULL; 1876 } 1877 } 1878 flowcnt_pool_bitmap_alloc_min[unit][group_type] = -1; 1879 flowcnt_pool_bitmap_alloc_max[unit][group_type] = -1; 1880 } 1881 1882 if (NULL != flowcnt_mem_entry_buf[unit]) { 1883 sal_free(flowcnt_mem_entry_buf[unit]); 1884 flowcnt_mem_entry_buf[unit] = NULL; 1885 } 1886 return BCM_E_NONE; 1887 } 1888 1889 /* init the resource for tsn flow counter */ 1890 STATIC int 1891 bcmi_gh2_tsn_stat_flowcnt_init(int unit) 1892 { 1893 bcm_tsn_stat_group_type_t group_type; 1894 uint32 max_entry_size = 0; 1895 void *entry_buf; 1896 1897 /* parameter setup */ 1898 if (soc_feature(unit, soc_feature_tsn_taf)) { 1899 flowcnt_enable_value_mapping_cnt[unit][bcmTsnStatGroupTypeIngress] = 20; 1900 flowcnt_enable_value_mapping_cnt[unit][bcmTsnStatGroupTypeEgress] = 4; 1901 } else { 1902 flowcnt_enable_value_mapping_cnt[unit][bcmTsnStatGroupTypeIngress] = 15; 1903 flowcnt_enable_value_mapping_cnt[unit][bcmTsnStatGroupTypeEgress] = 4; 1904 } 1905 1906 /* handle flow mem */ 1907 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1908 soc_mem_t mem = flowcnt_flow_mem[group_type]; 1909 1910 max_entry_size = 1911 BCMI_TSN_FLOWCNT_MAX(max_entry_size, 1912 WORDS2BYTES(soc_mem_entry_words(unit, mem))); 1913 1914 /* verify flowcnt_flow_num */ 1915 if (flowcnt_flow_num[group_type] != 1916 soc_mem_index_count(unit, mem)) { 1917 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_INTERNAL); 1918 } 1919 } 1920 1921 /* handle group mem */ 1922 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1923 soc_mem_t group_mem = flowcnt_group_mem[group_type]; 1924 soc_profile_mem_t *profile_mem; 1925 int mem_word, group_id; 1926 1927 /* verify flowcnt_group_num */ 1928 if (flowcnt_group_num[group_type] != 1929 soc_mem_index_count(unit, group_mem)) { 1930 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_INTERNAL); 1931 } 1932 1933 /* because we use bit 20 for egress bit in encoding stat id 1934 * , so the number of entries cannot excess 1 << 20 1935 */ 1936 if (flowcnt_group_num[group_type] >= 1937 (1 << BCMI_TSN_FLOWCNT_STAT_ID_EGRESS_BIT)) { 1938 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_INTERNAL); 1939 } 1940 1941 max_entry_size = 1942 BCMI_TSN_FLOWCNT_MAX(max_entry_size, 1943 WORDS2BYTES(soc_mem_entry_words(unit, 1944 group_mem))); 1945 1946 /* profile mem */ 1947 mem_word = soc_mem_entry_words(unit, group_mem); 1948 flowcnt_group_mem_profile[unit][group_type] = 1949 sal_alloc(sizeof(soc_profile_mem_t), "TSN Group Profile Mem"); 1950 profile_mem = flowcnt_group_mem_profile[unit][group_type]; 1951 if (NULL == profile_mem) { 1952 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 1953 } 1954 soc_profile_mem_t_init(profile_mem); 1955 INIT_ERROR_RETURN_WITH_CLEAN( 1956 soc_profile_mem_create(unit, &group_mem, &mem_word, 1957 1, profile_mem)); 1958 1959 /* for each gorup_id 1960 * alloc flowcnt_group_stat2pool 1961 */ 1962 flowcnt_group_stat2pool[unit][group_type] = 1963 sal_alloc(flowcnt_group_num[group_type] * sizeof(int32 *), 1964 "flowcnt_group_stat2pool"); 1965 if (NULL == flowcnt_group_stat2pool[unit][group_type]) { 1966 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 1967 } 1968 1969 for (group_id = 0; group_id < flowcnt_group_num[group_type]; 1970 group_id++) { 1971 1972 int stat_id; 1973 1974 flowcnt_group_stat2pool[unit][group_type][group_id] = 1975 sal_alloc(bcmTsnStatCount * sizeof(int32), 1976 "flowcnt_group_stat2pool"); 1977 if (NULL == flowcnt_group_stat2pool[unit][group_type][group_id]) { 1978 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 1979 } 1980 for (stat_id = 0; stat_id < bcmTsnStatCount; stat_id++) { 1981 flowcnt_group_stat2pool[unit][group_type] 1982 [group_id][stat_id] = -1; 1983 } 1984 } 1985 } 1986 1987 /* handle pool mem */ 1988 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 1989 int index, pool_entry_count; 1990 soc_mem_t mem; 1991 1992 1993 for (index = 0; 1994 index < flowcnt_pool_num[group_type]; 1995 index++) { 1996 1997 mem = flowcnt_pool_mem[group_type][index]; 1998 max_entry_size = 1999 BCMI_TSN_FLOWCNT_MAX(max_entry_size, 2000 WORDS2BYTES( 2001 soc_mem_entry_words(unit, mem))); 2002 } 2003 2004 /* allocate bitmap */ 2005 mem = flowcnt_pool_mem[group_type][0]; 2006 pool_entry_count = soc_mem_index_count(unit, mem); 2007 INIT_ERROR_RETURN_WITH_CLEAN( 2008 shr_res_bitmap_create(&flowcnt_pool_bitmap[unit][group_type], 2009 0, pool_entry_count)); 2010 flowcnt_pool_bitmap_alloc_min[unit][group_type] = -1; 2011 flowcnt_pool_bitmap_alloc_max[unit][group_type] = -1; 2012 2013 /* allocate counter sw database */ 2014 for (index = 0; 2015 index < flowcnt_pool_num[group_type]; index++) { 2016 2017 flowcnt_counter_sw[unit][group_type][index] = 2018 sal_alloc(pool_entry_count * sizeof(uint64), 2019 "tsn flow sw counter"); 2020 if (NULL == flowcnt_counter_sw[unit][group_type][index]) { 2021 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 2022 } 2023 sal_memset(flowcnt_counter_sw[unit][group_type][index], 2024 0, pool_entry_count * sizeof(uint64)); 2025 2026 flowcnt_counter_hw[unit][group_type][index] = 2027 sal_alloc(pool_entry_count * sizeof(uint64), 2028 "tsn flow hw counter"); 2029 if (NULL == flowcnt_counter_hw[unit][group_type][index]) { 2030 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 2031 } 2032 sal_memset(flowcnt_counter_hw[unit][group_type][index], 2033 0, pool_entry_count * sizeof(uint64)); 2034 2035 /* setup max/mask for counter */ 2036 COMPILER_64_SET(flowcnt_counter_max[unit][group_type][index], 0, 1); 2037 COMPILER_64_SHL(flowcnt_counter_max[unit][group_type][index], 2038 soc_mem_field_length( 2039 unit, flowcnt_pool_mem[group_type][index], 2040 COUNTf)); 2041 COMPILER_64_COPY(flowcnt_counter_mask[unit][group_type][index], 2042 flowcnt_counter_max[unit][group_type][index]); 2043 COMPILER_64_SUB_32(flowcnt_counter_mask[unit][group_type][index], 2044 1); 2045 } 2046 2047 /* allocate dma buffer */ 2048 flowcnt_counter_dma_buffer[unit][group_type] = 2049 soc_cm_salloc(unit, pool_entry_count * 2050 WORDS2BYTES(soc_mem_entry_words(unit, mem)), 2051 "tsn flowctr counter buffer"); 2052 if (NULL == flowcnt_counter_dma_buffer[unit][group_type]) { 2053 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 2054 } 2055 2056 /* setup cache for statType and fbmp */ 2057 for (index = 0; index < bcmTsnStatCount; index++) { 2058 flowcnt_stat_fbmp_cache[unit][group_type][index] = 2059 sal_alloc(SHR_BITALLOCSIZE(flowcnt_flow_num[group_type]), 2060 "flowcnt_stat_fbmp_cache"); 2061 if (NULL == flowcnt_stat_fbmp_cache[unit][group_type][index]) { 2062 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 2063 } 2064 SHR_BITCLR_RANGE( 2065 flowcnt_stat_fbmp_cache[unit][group_type][index], 2066 0, flowcnt_flow_num[group_type]); 2067 } 2068 } 2069 2070 /* allocate mem entry buf */ 2071 flowcnt_mem_entry_buf[unit] = sal_alloc(max_entry_size, "tsn mem buf"); 2072 entry_buf = flowcnt_mem_entry_buf[unit]; 2073 if (NULL == entry_buf) { 2074 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 2075 } 2076 2077 /* reserve profile entry 0 for invalid usage */ 2078 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; group_type++) { 2079 soc_mem_t mem = flowcnt_group_mem[group_type]; 2080 int group_id; 2081 2082 soc_mem_field32_set(unit, mem, entry_buf, SR_COUNTER_ENABLESf, 0); 2083 INIT_ERROR_RETURN_WITH_CLEAN( 2084 soc_profile_mem_single_table_add( 2085 unit, flowcnt_group_mem_profile[unit][group_type], 2086 entry_buf, 1, &group_id)); 2087 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED != group_id) { 2088 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_INTERNAL); 2089 } 2090 } 2091 2092 #if defined(BCM_WARM_BOOT_SUPPORT) 2093 if (SOC_WARM_BOOT(unit)) { 2094 /* warmboot : recover group profile, 2095 * traverse each valid "group_type, group_id", recover its refcnt 2096 * back to 1 2097 */ 2098 INIT_ERROR_RETURN_WITH_CLEAN( 2099 bcmi_gh2_tsn_stat_flowcnt_group_internal_traverse( 2100 unit, bcmi_gh2_tsn_stat_flowcnt_group_traverse_cb_recover, 2101 NULL)); 2102 2103 /* warmboot : recover reference count and pool alloc bitmap, 2104 * traverse each flow, if it attached to some group 2105 * ==> group's refcnt++ , setup alloc bitmap 2106 */ 2107 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; 2108 group_type++) { 2109 int entry_byte, alloc_size, index; 2110 soc_mem_t mem = flowcnt_flow_mem[group_type]; 2111 int entry_num = flowcnt_flow_num[group_type]; 2112 uint8 *dma_entry_buf; 2113 2114 entry_byte = WORDS2BYTES(soc_mem_entry_words(unit, mem)); 2115 alloc_size = entry_num * entry_byte; 2116 dma_entry_buf = soc_cm_salloc(unit, alloc_size, 2117 "tsn counter dmabuf"); 2118 if (NULL == dma_entry_buf) { 2119 INIT_ERROR_RETURN_WITH_CLEAN(BCM_E_MEMORY); 2120 } 2121 2122 INIT_ERROR_RETURN_WITH_EXTRA_CLEAN( 2123 soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 2124 0, entry_num -1, dma_entry_buf), 2125 soc_cm_sfree(unit, dma_entry_buf)); 2126 2127 for (index = 0; index < entry_num; index++) { 2128 uint32 group_id; 2129 int counter_idx; 2130 2131 group_id = 2132 soc_mem_field32_get(unit, mem, 2133 &dma_entry_buf[index * entry_byte], 2134 flowcnt_flow_profile_field[group_type]); 2135 counter_idx = 2136 soc_mem_field32_get(unit, mem, 2137 &dma_entry_buf[index * entry_byte], 2138 SR_COUNTER_INDEXf); 2139 2140 if (BCMI_TSN_FLOWCNT_GROUP_ID_RESERVED != group_id) { 2141 SOC_PROFILE_MEM_REFERENCE( 2142 unit, flowcnt_group_mem_profile[unit][group_type], 2143 group_id, 1); 2144 2145 INIT_ERROR_RETURN_WITH_EXTRA_CLEAN( 2146 bcmi_gh2_tsn_stat_flowcnt_pool_counter_alloc( 2147 unit, group_type, &counter_idx, 1), 2148 soc_cm_sfree(unit, dma_entry_buf)); 2149 2150 INIT_ERROR_RETURN_WITH_EXTRA_CLEAN( 2151 bcmi_gh2_tsn_stat_flowcnt_group_update_attached_flow( 2152 unit, group_type, group_id, index, 1), 2153 soc_cm_sfree(unit, dma_entry_buf)); 2154 } 2155 } 2156 soc_cm_sfree(unit, dma_entry_buf); 2157 } 2158 2159 /* warmboot : recover counter 2160 * recover flowcnt_counter_hw by hw data 2161 * (flowcnt_counter_sw will be recoved in reload) 2162 */ 2163 for (group_type = 0; group_type < bcmTsnStatGroupTypeCount; 2164 group_type++) { 2165 2166 uint32 pool_index; 2167 for (pool_index = 0; pool_index < flowcnt_pool_num[group_type]; 2168 pool_index++) { 2169 2170 soc_mem_t mem = flowcnt_pool_mem[group_type][pool_index]; 2171 soc_memacc_t memacc_count; 2172 int entry_byte, entry_index; 2173 uint8 *buffer_ptr; 2174 2175 INIT_ERROR_RETURN_WITH_CLEAN( 2176 soc_memacc_init(unit, mem, COUNTf, &memacc_count)); 2177 2178 entry_byte = WORDS2BYTES(soc_mem_entry_words(unit, mem)); 2179 buffer_ptr = flowcnt_counter_dma_buffer[unit][group_type]; 2180 2181 INIT_ERROR_RETURN_WITH_CLEAN( 2182 soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 2183 0, soc_mem_index_count(unit, mem) - 1, 2184 buffer_ptr)); 2185 2186 for (entry_index = 0; 2187 entry_index < soc_mem_index_count(unit, mem); 2188 entry_index++) { 2189 uint64 new_count; 2190 uint64 *array_ptr_hw = 2191 flowcnt_counter_hw[unit][group_type][pool_index]; 2192 2193 buffer_ptr = 2194 &(flowcnt_counter_dma_buffer[unit][group_type] 2195 [entry_index * entry_byte]); 2196 soc_memacc_field64_get(&memacc_count, buffer_ptr, 2197 &new_count); 2198 COMPILER_64_COPY(array_ptr_hw[entry_index], new_count); 2199 } 2200 } 2201 } 2202 } 2203 #endif /* BCM_WARM_BOOT_SUPPORT */ 2204 return BCM_E_NONE; 2205 } 2206 2207 /* 2208 * Function: 2209 * bcmi_gh2_tsn_stat_threshold_select_set 2210 * Purpose: 2211 * Configure threshold for a specific stat type based on source 2212 * Parameters: 2213 * unit - (IN) Unit number 2214 * select_info - (IN) TSN stat threshold selected source 2215 * count - (IN) count of TSN stat threshold selected source 2216 * stat - (IN) TSN statistic type (see tsn.h) 2217 * config - (IN) TSN stat threshold configuration structure 2218 * Returns: 2219 * BCM_E_XXX 2220 */ 2221 STATIC int 2222 bcmi_gh2_tsn_stat_threshold_select_set( 2223 int unit, 2224 const bcmi_gh2_tsn_stat_threshold_select_t *select_info, 2225 int count, 2226 bcm_tsn_stat_t stat, 2227 bcm_tsn_stat_threshold_config_t *config) 2228 { 2229 const bcmi_gh2_tsn_stat_threshold_select_t *info; 2230 int interrupt_enable = 0, copy_to_cpu = 0; 2231 int idx; 2232 uint32 threshold_value; 2233 uint32 field_value = 0; 2234 uint64 reg_val64; 2235 int is_changed = 0; 2236 2237 /* Input parameter check */ 2238 if ((NULL == config) || (NULL == select_info)) { 2239 return BCM_E_PARAM; 2240 } 2241 2242 threshold_value = config->threshold; 2243 if (config->flags) { 2244 if (!(config->flags & BCM_TSN_STAT_THRESHOLD_EVENT_NOTIFICATION) && 2245 !(config->flags & BCM_TSN_STAT_THRESHOLD_COPY_TO_CPU)) { 2246 return BCM_E_UNAVAIL; 2247 } 2248 2249 /* 2250 * For MTU/STU, should write value (N) to HW register. 2251 * For other counters, should write value (N-1) to HW register. 2252 */ 2253 if (!GH2_TSN_STAT_THRESHOLD_MTU_STU_IS_VALID(unit, stat)) { 2254 if (threshold_value > 0) { 2255 threshold_value -= 1; 2256 } else { 2257 /* Can't write value (0-1=-1) to HW register */ 2258 return BCM_E_CONFIG; 2259 } 2260 } 2261 } else { 2262 /* 2263 * If flags = 0 (threshold disabled), 2264 * ignore the counter value and write maximum to the register 2265 */ 2266 threshold_value = GH2_TSN_STAT_THRESHOLD_DEFAULT_VALUE; 2267 } 2268 2269 /* Event notification */ 2270 if (config->flags & BCM_TSN_STAT_THRESHOLD_EVENT_NOTIFICATION) { 2271 interrupt_enable = 0x1; 2272 } 2273 2274 /* Copy the packet to CPU */ 2275 if (config->flags & BCM_TSN_STAT_THRESHOLD_COPY_TO_CPU) { 2276 copy_to_cpu = 0x1; 2277 } 2278 2279 /* Select the TSN stat type */ 2280 for (idx = 0; idx < count; idx++) { 2281 info = select_info + idx; 2282 if (info->stat_type != stat) { 2283 continue; 2284 } 2285 2286 COMPILER_64_ZERO(reg_val64); 2287 /* Read the specified threshold register */ 2288 BCM_IF_ERROR_RETURN( 2289 soc_reg64_get(unit, info->reg, REG_PORT_ANY, 0, ®_val64)); 2290 2291 /* COUNTER_THRESHOLDf */ 2292 field_value = soc_reg64_field32_get(unit, info->reg, 2293 reg_val64, info->threshold_field); 2294 if (threshold_value != field_value) { 2295 is_changed = 1; 2296 soc_reg64_field32_set(unit, info->reg, ®_val64, 2297 info->threshold_field, threshold_value); 2298 } 2299 2300 /* INTERRUPT_ENABLEf */ 2301 field_value = soc_reg64_field32_get(unit, info->reg, 2302 reg_val64, info->interrupt_field); 2303 if (interrupt_enable != field_value) { 2304 is_changed = 1; 2305 soc_reg64_field32_set(unit, info->reg, ®_val64, 2306 info->interrupt_field, interrupt_enable); 2307 } 2308 2309 /* COPY_TO_CPUf */ 2310 if (info->copy_to_cpu_field != INVALIDf) { 2311 field_value = soc_reg64_field32_get(unit, info->reg, 2312 reg_val64, 2313 info->copy_to_cpu_field); 2314 if (copy_to_cpu != field_value) { 2315 is_changed = 1; 2316 soc_reg64_field32_set(unit, info->reg, ®_val64, 2317 info->copy_to_cpu_field, copy_to_cpu); 2318 } 2319 } else { 2320 if (copy_to_cpu) { 2321 return BCM_E_PARAM; 2322 } 2323 } 2324 2325 if (is_changed) { 2326 /* Write the specified threshold register if any changes */ 2327 BCM_IF_ERROR_RETURN( 2328 soc_reg64_set(unit, info->reg, REG_PORT_ANY, 0, reg_val64)); 2329 } 2330 2331 break; 2332 } 2333 2334 if (idx == count) { 2335 return BCM_E_PARAM; 2336 } 2337 2338 return BCM_E_NONE; 2339 } 2340 2341 /* 2342 * Function: 2343 * bcmi_gh2_tsn_stat_threshold_select_get 2344 * Purpose: 2345 * Get the threshold configuration for a specific stat type based on source 2346 * Parameters: 2347 * unit - (IN) Unit number 2348 * select_info - (IN) TSN stat threshold selected source 2349 * count - (IN) count of TSN stat threshold selected source 2350 * stat - (IN) TSN statistics type (see tsn.h) 2351 * config - (OUT) TSN stat threshold configuration structure 2352 * Returns: 2353 * BCM_E_XXX 2354 */ 2355 STATIC int 2356 bcmi_gh2_tsn_stat_threshold_select_get( 2357 int unit, 2358 const bcmi_gh2_tsn_stat_threshold_select_t *select_info, 2359 int count, 2360 bcm_tsn_stat_t stat, 2361 bcm_tsn_stat_threshold_config_t *config) 2362 { 2363 const bcmi_gh2_tsn_stat_threshold_select_t *info; 2364 int interrupt_enable = 0, copy_to_cpu = 0; 2365 int idx; 2366 uint64 reg_val64; 2367 2368 /* Input parameter check */ 2369 if ((NULL == config) || (NULL == select_info)) { 2370 return BCM_E_PARAM; 2371 } 2372 2373 /* Clear buffer to zero */ 2374 bcm_tsn_stat_threshold_config_t_init(config); 2375 2376 /* Select the TSN stat type */ 2377 for (idx = 0; idx < count; idx++) { 2378 info = select_info + idx; 2379 if (info->stat_type != stat) { 2380 continue; 2381 } 2382 2383 COMPILER_64_ZERO(reg_val64); 2384 /* Read the specified threshold register */ 2385 BCM_IF_ERROR_RETURN( 2386 soc_reg64_get(unit, info->reg, REG_PORT_ANY, 0, ®_val64)); 2387 2388 /* COUNTER_THRESHOLDf */ 2389 config->threshold = soc_reg64_field32_get(unit, info->reg, 2390 reg_val64, 2391 info->threshold_field); 2392 /* INTERRUPT_ENABLEf */ 2393 interrupt_enable = soc_reg64_field32_get(unit, info->reg, 2394 reg_val64, 2395 info->interrupt_field); 2396 /* Event notification */ 2397 if (interrupt_enable) { 2398 config->flags |= BCM_TSN_STAT_THRESHOLD_EVENT_NOTIFICATION; 2399 } 2400 2401 /* COPY_TO_CPUf */ 2402 if (info->copy_to_cpu_field != INVALIDf) { 2403 copy_to_cpu = soc_reg64_field32_get(unit, info->reg, 2404 reg_val64, 2405 info->copy_to_cpu_field); 2406 /* Copy the packet to CPU */ 2407 if (copy_to_cpu) { 2408 config->flags |= BCM_TSN_STAT_THRESHOLD_COPY_TO_CPU; 2409 } 2410 } 2411 2412 break; 2413 } 2414 2415 if (idx == count) { 2416 return BCM_E_PARAM; 2417 } 2418 2419 /* 2420 * For MTU/STU, read value N from HW register should return (N). 2421 * For other counters, read value N from HW register should return (N+1). 2422 */ 2423 if (!GH2_TSN_STAT_THRESHOLD_MTU_STU_IS_VALID(unit, stat)) { 2424 if (config->threshold < GH2_TSN_STAT_THRESHOLD_DEFAULT_VALUE) { 2425 config->threshold += 1; 2426 } 2427 } 2428 2429 return BCM_E_NONE; 2430 } 2431 2432 /* 2433 * Function: 2434 * bcmi_gh2_tsn_stat_threshold_set 2435 * Purpose: 2436 * Configure threshold for a specific stat type on 2437 * a specific source 2438 * Parameters: 2439 * unit - (IN) Unit number 2440 * source - (IN) Stat source for TSN stat threshold check 2441 * stat - (IN) TSN statistics type (see tsn.h) 2442 * config - (IN) TSN stat threshold configuration structure 2443 * Returns: 2444 * BCM_E_XXX 2445 */ 2446 STATIC int 2447 bcmi_gh2_tsn_stat_threshold_set( 2448 int unit, 2449 bcm_tsn_stat_threshold_source_t source, 2450 bcm_tsn_stat_t stat, 2451 bcm_tsn_stat_threshold_config_t *config) 2452 { 2453 int rv = BCM_E_UNAVAIL; 2454 int count = 0; 2455 const bcmi_gh2_tsn_stat_threshold_select_t *select_info; 2456 2457 /* Input parameter check */ 2458 if (NULL == config) { 2459 return BCM_E_PARAM; 2460 } 2461 2462 if (soc_feature(unit, soc_feature_tsn)) { 2463 /* Valid check for stat type */ 2464 if (!GH2_TSN_STAT_THRESHOLD_IS_VALID(unit, stat)) { 2465 return BCM_E_PARAM; 2466 } 2467 2468 /* Select the source type: Port or SR Flow */ 2469 switch (source) { 2470 case bcmTsnStatThresholdSourcePort: 2471 /* 2472 * Set the threshold for a specific TSN stat 2473 * on source port 2474 */ 2475 select_info = gh2_port_count_threshold_info; 2476 count = COUNTOF(gh2_port_count_threshold_info); 2477 break; 2478 case bcmTsnStatThresholdSourceSRFlow: 2479 /* 2480 * Set the threshold for a specific TSN stat 2481 * on source SR flow 2482 */ 2483 select_info = gh2_flow_count_threshold_info; 2484 count = COUNTOF(gh2_flow_count_threshold_info); 2485 break; 2486 default: 2487 return BCM_E_PARAM; 2488 } 2489 2490 rv = bcmi_gh2_tsn_stat_threshold_select_set(unit, select_info, 2491 count, stat, config); 2492 } 2493 2494 return rv; 2495 } 2496 2497 /* 2498 * Function: 2499 * bcmi_gh2_tsn_stat_threshold_get 2500 * Purpose: 2501 * Get the threshold configuration for a specific stat type on 2502 * a specific source 2503 * Parameters: 2504 * unit - (IN) Unit number 2505 * source - (IN) Stat source for TSN stat threshold check 2506 * stat - (IN) TSN statistics type (see tsn.h) 2507 * config - (OUT) TSN stat threshold configuration structure 2508 * Returns: 2509 * BCM_E_XXX 2510 */ 2511 STATIC int 2512 bcmi_gh2_tsn_stat_threshold_get( 2513 int unit, 2514 bcm_tsn_stat_threshold_source_t source, 2515 bcm_tsn_stat_t stat, 2516 bcm_tsn_stat_threshold_config_t *config) 2517 { 2518 int rv = BCM_E_UNAVAIL; 2519 int count = 0; 2520 const bcmi_gh2_tsn_stat_threshold_select_t *select_info; 2521 2522 /* Input parameter check */ 2523 if (NULL == config) { 2524 return BCM_E_PARAM; 2525 } 2526 2527 if (soc_feature(unit, soc_feature_tsn)) { 2528 /* Valid check for stat type */ 2529 if (!GH2_TSN_STAT_THRESHOLD_IS_VALID(unit, stat)) { 2530 return BCM_E_PARAM; 2531 } 2532 2533 /* Select the source type: Port or SR Flow */ 2534 switch (source) { 2535 case bcmTsnStatThresholdSourcePort: 2536 /* 2537 * Get the threshold config for a specific TSN stat 2538 * on source port 2539 */ 2540 select_info = gh2_port_count_threshold_info; 2541 count = COUNTOF(gh2_port_count_threshold_info); 2542 break; 2543 case bcmTsnStatThresholdSourceSRFlow: 2544 /* 2545 * Get the threshold config for a specific TSN stat 2546 * on source SR flow 2547 */ 2548 select_info = gh2_flow_count_threshold_info; 2549 count = COUNTOF(gh2_flow_count_threshold_info); 2550 break; 2551 default: 2552 return BCM_E_PARAM; 2553 } 2554 2555 rv = bcmi_gh2_tsn_stat_threshold_select_get(unit, select_info, 2556 count, stat, config); 2557 } 2558 2559 return rv; 2560 } 2561 2562 /* 2563 * Function: 2564 * bcmi_gh2_tsn_stat_threshold_init 2565 * Purpose: 2566 * Helper function to initialize all TSN counter thresholds 2567 * Parameters: 2568 * unit - (IN) Unit number 2569 * Returns: 2570 * BCM_E_XXX 2571 */ 2572 STATIC int 2573 bcmi_gh2_tsn_stat_threshold_init(int unit) 2574 { 2575 int rv = BCM_E_UNAVAIL; 2576 const bcmi_gh2_tsn_stat_threshold_select_t *info, *select_info; 2577 bcm_tsn_stat_threshold_config_t config; 2578 int idx = 0, count = 0; 2579 2580 bcm_tsn_stat_threshold_config_t_init(&config); 2581 config.threshold = GH2_TSN_STAT_THRESHOLD_DEFAULT_VALUE; 2582 2583 if (soc_feature(unit, soc_feature_tsn)) { 2584 /* TSN Stat threshold for source Port */ 2585 select_info = gh2_port_count_threshold_info; 2586 count = COUNTOF(gh2_port_count_threshold_info); 2587 for (idx = 0; idx < count; idx++) { 2588 info = select_info + idx; 2589 rv = bcmi_gh2_tsn_stat_threshold_select_set(unit, select_info, 2590 count, 2591 info->stat_type, 2592 &config); 2593 } 2594 2595 /* TSN Stat threshold for source SR Flow */ 2596 select_info = gh2_flow_count_threshold_info; 2597 count = COUNTOF(gh2_flow_count_threshold_info); 2598 for (idx = 0; idx < count; idx++) { 2599 info = select_info + idx; 2600 rv = bcmi_gh2_tsn_stat_threshold_select_set(unit, select_info, 2601 count, 2602 info->stat_type, 2603 &config); 2604 } 2605 } 2606 2607 return rv; 2608 } 2609 2610 /* Per-chip TSN stat portcnt device info */ 2611 STATIC const tsn_stat_portcnt_dev_info_t gh2_tsn_stat_portcnt_dev_info = { 2612 portcnt_table, 2613 GH2_TSN_STAT_PORTCNT_TABLE_SIZE 2614 }; 2615 2616 /* Per-chip TSN stat flowcnt device info */ 2617 STATIC const 2618 tsn_stat_flowcnt_dev_info_t gh2_tsn_stat_flowcnt_dev_info = { 2619 /* per-chip control drivers */ 2620 bcmi_gh2_tsn_stat_flowcnt_init, 2621 #if defined(BCM_WARM_BOOT_SUPPORT) 2622 bcmi_gh2_tsn_stat_flowcnt_get_scache_size, 2623 bcmi_gh2_tsn_stat_flowcnt_sync, 2624 bcmi_gh2_tsn_stat_flowcnt_reload_l1, 2625 bcmi_gh2_tsn_stat_flowcnt_reload_l2, 2626 #endif /* BCM_WARM_BOOT_SUPPORT */ 2627 bcmi_gh2_tsn_stat_flowcnt_cleanup, 2628 bcmi_gh2_tsn_stat_flowcnt_counter_sync_all, 2629 bcmi_gh2_tsn_stat_flowcnt_counter_sync_stat, 2630 bcmi_gh2_tsn_stat_flowcnt_group_id_encode, 2631 bcmi_gh2_tsn_stat_flowcnt_group_id_decode, 2632 bcmi_gh2_tsn_stat_flowcnt_group_refcnt_get, 2633 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_set, 2634 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_get, 2635 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_exist_check, 2636 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_insert, 2637 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_delete, 2638 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_encode, 2639 bcmi_gh2_tsn_stat_flowcnt_group_enable_value_decode, 2640 bcmi_gh2_tsn_stat_flowcnt_group_traverse, 2641 bcmi_gh2_tsn_stat_flowcnt_counter_access, 2642 bcmi_gh2_tsn_stat_flowcnt_counter_update, 2643 bcmi_gh2_tsn_stat_flowcnt_flow_set, 2644 bcmi_gh2_tsn_stat_flowcnt_flow_get, 2645 bcmi_gh2_tsn_stat_flowcnt_flow_get_fbmp 2646 }; 2647 2648 /* Per-chip TSN stat threshold control drivers */ 2649 STATIC const tsn_stat_threshold_ctrl_info_t gh2_tsn_stat_threshold_ctrl_info = 2650 { 2651 bcmi_gh2_tsn_stat_threshold_init, 2652 bcmi_gh2_tsn_stat_threshold_set, 2653 bcmi_gh2_tsn_stat_threshold_get 2654 }; 2655 2656 /* Per-chip TSN stat device info */ 2657 STATIC const bcmi_esw_tsn_stat_dev_info_t gh2_tsn_stat_devinfo = { 2658 &gh2_tsn_stat_portcnt_dev_info, 2659 &gh2_tsn_stat_flowcnt_dev_info, 2660 &gh2_tsn_stat_threshold_ctrl_info 2661 }; 2662 2663 /* 2664 * Function: 2665 * bcmi_gh2_tsn_stat_info_init 2666 * Description: 2667 * Setup the chip specific info for TSN stat. 2668 * Parameters: 2669 * unit - (IN) Unit number 2670 * devinfo - (OUT) device info structure. 2671 * Returns: 2672 * BCM_E_XXX 2673 */ 2674 int 2675 bcmi_gh2_tsn_stat_info_init( 2676 int unit, 2677 const bcmi_esw_tsn_stat_dev_info_t **devinfo) 2678 { 2679 int rv = BCM_E_NONE; 2680 2681 if (devinfo == NULL) { 2682 return BCM_E_PARAM; 2683 } 2684 2685 /* Return the chip info structure for TSN stat */ 2686 *devinfo = &gh2_tsn_stat_devinfo; 2687 2688 return rv; 2689 } 2690 2691 #endif /* BCM_GREYHOUND2_SUPPORT && BCM_TSN_SUPPORT */ 2692